mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
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:
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user