Fixes identity for proc object

Previously, the identity of the proc object was verified solely based on the identity of irep.
This patch makes the behavior consistent with CRuby.

The reason I noticed this issue was that when adding multiple proc objects with the same irep to a set object, only one was added.

```ruby
p Set.new(Array.new(3) { -> {} }).size
# => 3 (Ruby 4.0)
# => 1 (mruby without this patch)
```

If the block scope is the same, there is only one in CRuby as well.
However, in CRuby, the result of `Proc#to_s` is not affected by the block scope, so it has been changed to be based on the object's address.
The reason no test for `Proc#to_s` was added is that I couldn't determine whether it should be based on `Proc#hash` or the object's address.

```ruby
b = []
t = 3
while t > 0
  b << -> {}
  t -= 1
end

p Set.new(b).size
# => 1 (Ruby 4.0 and mruby)

p b[0].to_s == b[1].to_s
# => false (Ruby 4.0)
# => true (mruby without this patch)
```
This commit is contained in:
dearblue
2026-02-07 15:32:11 +09:00
parent 167dc8aa4a
commit d94ec9786e
3 changed files with 21 additions and 2 deletions
+1 -1
View File
@@ -104,7 +104,7 @@ proc_inspect(mrb_state *mrb, mrb_value self)
{
struct RProc *p = mrb_proc_ptr(self);
mrb_value str = mrb_str_new_lit(mrb, "#<Proc:");
mrb_str_cat_str(mrb, str, mrb_ptr_to_str(mrb, mrb_cptr(self)));
mrb_str_cat_str(mrb, str, mrb_ptr_to_str(mrb, p));
if (!MRB_PROC_CFUNC_P(p)) {
const mrb_irep *irep = p->body.irep;
+2 -1
View File
@@ -358,6 +358,7 @@ mrb_proc_eql(mrb_state *mrb, mrb_value self, mrb_value other)
}
else if (MRB_PROC_CFUNC_P(p2)) return FALSE;
else if (p1->body.irep != p2->body.irep) return FALSE;
else if (MRB_PROC_ENV(p1) != MRB_PROC_ENV(p2)) return FALSE;
return TRUE;
}
@@ -371,7 +372,7 @@ static mrb_value
proc_hash(mrb_state *mrb, mrb_value self)
{
const struct RProc *p = mrb_proc_ptr(self);
return mrb_int_value(mrb, (mrb_int)(((intptr_t)p->body.irep)^MRB_TT_PROC));
return mrb_int_value(mrb, (mrb_int)((intptr_t)p->body.irep^((intptr_t)MRB_PROC_ENV(p)>>2)^MRB_TT_PROC));
}
/* 15.3.1.2.6 */
+18
View File
@@ -178,3 +178,21 @@ assert('Creation of a proc through the block of a method') do
m{ break }.call
end
end
assert('identity check for proc object') do
b = []
t = 2
while t > 0
b << ->{}
t -= 1
end
assert_true b[0] == b[1]
assert_equal b[0].hash, b[1].hash
b = []
2.times {
b << ->{}
}
assert_false b[0] == b[1]
assert_not_equal b[0].hash, b[1].hash
end