summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--proc.c62
-rw-r--r--spec/ruby/core/proc/eql_spec.rb8
-rw-r--r--spec/ruby/core/proc/equal_value_spec.rb8
-rw-r--r--spec/ruby/core/proc/shared/equal.rb14
-rw-r--r--test/ruby/test_proc.rb10
5 files changed, 93 insertions, 9 deletions
diff --git a/proc.c b/proc.c
index 4af42c04bd..82b48dff9f 100644
--- a/proc.c
+++ b/proc.c
@@ -1255,6 +1255,66 @@ rb_proc_get_iseq(VALUE self, int *is_proc)
}
static VALUE
+proc_eq(VALUE self, VALUE other)
+{
+ const rb_proc_t *self_proc, *other_proc;
+ const struct rb_block *self_block, *other_block;
+ const struct rb_captured_block *self_cblock, *other_cblock;
+
+ if (rb_obj_class(self) != rb_obj_class(other)) {
+ return Qfalse;
+ }
+
+ GetProcPtr(self, self_proc);
+ GetProcPtr(other, other_proc);
+
+ if (self_proc->is_from_method != other_proc->is_from_method ||
+ self_proc->is_lambda != other_proc->is_lambda) {
+ return Qfalse;
+ }
+
+ self_block = &self_proc->block;
+ other_block = &other_proc->block;
+
+ if (vm_block_type(self_block) != vm_block_type(other_block)) {
+ return Qfalse;
+ }
+
+ switch (vm_block_type(self_block)) {
+ case block_type_iseq:
+ if (self_block->as.captured.ep != \
+ other_block->as.captured.ep ||
+ self_block->as.captured.code.iseq != \
+ other_block->as.captured.code.iseq) {
+ return Qfalse;
+
+ }
+ break;
+ case block_type_ifunc:
+ if (self_block->as.captured.ep != \
+ other_block->as.captured.ep ||
+ self_block->as.captured.code.ifunc != \
+ other_block->as.captured.code.ifunc) {
+ return Qfalse;
+
+ }
+ break;
+ case block_type_proc:
+ if (self_block->as.proc != other_block->as.proc) {
+ return Qfalse;
+ }
+ break;
+ case block_type_symbol:
+ if (self_block->as.symbol != other_block->as.symbol) {
+ return Qfalse;
+ }
+ break;
+ }
+
+ return Qtrue;
+}
+
+static VALUE
iseq_location(const rb_iseq_t *iseq)
{
VALUE loc[2];
@@ -3970,6 +4030,8 @@ Init_Proc(void)
rb_define_method(rb_cProc, "curry", proc_curry, -1);
rb_define_method(rb_cProc, "<<", proc_compose_to_left, 1);
rb_define_method(rb_cProc, ">>", proc_compose_to_right, 1);
+ rb_define_method(rb_cProc, "==", proc_eq, 1);
+ rb_define_method(rb_cProc, "eql?", proc_eq, 1);
rb_define_method(rb_cProc, "source_location", rb_proc_location, 0);
rb_define_method(rb_cProc, "parameters", rb_proc_parameters, 0);
rb_define_method(rb_cProc, "ruby2_keywords", proc_ruby2_keywords, 0);
diff --git a/spec/ruby/core/proc/eql_spec.rb b/spec/ruby/core/proc/eql_spec.rb
index a3c5a5658d..d95e890c29 100644
--- a/spec/ruby/core/proc/eql_spec.rb
+++ b/spec/ruby/core/proc/eql_spec.rb
@@ -2,5 +2,11 @@ require_relative '../../spec_helper'
require_relative 'shared/equal'
describe "Proc#eql?" do
- it_behaves_like :proc_equal_undefined, :eql?
+ ruby_version_is "0"..."2.8" do
+ it_behaves_like :proc_equal_undefined, :eql?
+ end
+
+ ruby_version_is "2.8" do
+ it_behaves_like :proc_equal, :eql?
+ end
end
diff --git a/spec/ruby/core/proc/equal_value_spec.rb b/spec/ruby/core/proc/equal_value_spec.rb
index 1b6ac792cf..fb465992e9 100644
--- a/spec/ruby/core/proc/equal_value_spec.rb
+++ b/spec/ruby/core/proc/equal_value_spec.rb
@@ -2,5 +2,11 @@ require_relative '../../spec_helper'
require_relative 'shared/equal'
describe "Proc#==" do
- it_behaves_like :proc_equal_undefined, :==
+ ruby_version_is "0"..."2.8" do
+ it_behaves_like :proc_equal_undefined, :==
+ end
+
+ ruby_version_is "2.8" do
+ it_behaves_like :proc_equal, :==
+ end
end
diff --git a/spec/ruby/core/proc/shared/equal.rb b/spec/ruby/core/proc/shared/equal.rb
index 46a1894424..0c0020ca7f 100644
--- a/spec/ruby/core/proc/shared/equal.rb
+++ b/spec/ruby/core/proc/shared/equal.rb
@@ -36,26 +36,26 @@ describe :proc_equal, shared: true do
a.send(@method, b).should be_false
end
- it "returns true if both procs have the same body and environment" do
+ it "returns false if procs are distinct but have the same body and environment" do
p = proc { :foo }
p2 = proc { :foo }
- p.send(@method, p2).should be_true
+ p.send(@method, p2).should be_false
end
- it "returns true if both lambdas with the same body and environment" do
+ it "returns false if lambdas are distinct but have same body and environment" do
x = -> { :foo }
x2 = -> { :foo }
- x.send(@method, x2).should be_true
+ x.send(@method, x2).should be_false
end
- it "returns true if both different kinds of procs with the same body and env" do
+ it "returns false if using comparing lambda to proc, even with the same body and env" do
p = -> { :foo }
p2 = proc { :foo }
- p.send(@method, p2).should be_true
+ p.send(@method, p2).should be_false
x = proc { :bar }
x2 = -> { :bar }
- x.send(@method, x2).should be_true
+ x.send(@method, x2).should be_false
end
it "returns false if other is not a Proc" do
diff --git a/test/ruby/test_proc.rb b/test/ruby/test_proc.rb
index 765b400dbe..0cc5d488c2 100644
--- a/test/ruby/test_proc.rb
+++ b/test/ruby/test_proc.rb
@@ -137,6 +137,14 @@ class TestProc < Test::Unit::TestCase
lambda { x }
end
+ def m_nest0(&block)
+ block
+ end
+
+ def m_nest(&block)
+ [m_nest0(&block), m_nest0(&block)]
+ end
+
def test_eq
a = m(1)
b = m(2)
@@ -148,6 +156,8 @@ class TestProc < Test::Unit::TestCase
a = lambda {|x| lambda {} }.call(1)
b = lambda {}
assert_not_equal(a, b, "[ruby-dev:22601]")
+
+ assert_equal(*m_nest{}, "[ruby-core:84583] Feature #14627")
end
def test_block_par