diff options
author | Jean Boussier <byroot@ruby-lang.org> | 2024-02-12 12:03:36 +0100 |
---|---|---|
committer | Jean Boussier <jean.boussier@gmail.com> | 2024-02-12 18:31:48 +0100 |
commit | de1a586ecc2ee7f465f0c0a69291054136a3a819 (patch) | |
tree | d6825acfea6f796b5f5dbb2746fe7fcb1c07d580 /spec/ruby/core | |
parent | c04782c2cb56c512e1d1b34630cb942da3aeb366 (diff) |
proc.c: get rid of `CLONESETUP`
[Bug #20253]
All the way down to Ruby 1.9, `Proc`, `Method`, `UnboundMethod`
and `Binding` always had their own specific clone and dup routine.
This caused various discrepancies with how other objects behave
on `dup` and `clone. [Bug #20250], [Bug #20253].
This commit get rid of `CLONESETUP` and use the the same codepath
as all other types, so ensure consistency.
NB: It's still not accepting the `freeze` keyword argument on `clone`.
Co-Authored-By: Étienne Barrié <etienne.barrie@gmail.com>
Diffstat (limited to 'spec/ruby/core')
-rw-r--r-- | spec/ruby/core/binding/clone_spec.rb | 6 | ||||
-rw-r--r-- | spec/ruby/core/binding/dup_spec.rb | 6 | ||||
-rw-r--r-- | spec/ruby/core/binding/shared/clone.rb | 22 | ||||
-rw-r--r-- | spec/ruby/core/method/clone_spec.rb | 15 | ||||
-rw-r--r-- | spec/ruby/core/method/dup_spec.rb | 15 | ||||
-rw-r--r-- | spec/ruby/core/method/shared/dup.rb | 32 | ||||
-rw-r--r-- | spec/ruby/core/proc/clone_spec.rb | 9 | ||||
-rw-r--r-- | spec/ruby/core/proc/dup_spec.rb | 7 | ||||
-rw-r--r-- | spec/ruby/core/proc/shared/dup.rb | 23 | ||||
-rw-r--r-- | spec/ruby/core/unboundmethod/clone_spec.rb | 13 | ||||
-rw-r--r-- | spec/ruby/core/unboundmethod/dup_spec.rb | 15 | ||||
-rw-r--r-- | spec/ruby/core/unboundmethod/shared/dup.rb | 32 |
12 files changed, 181 insertions, 14 deletions
diff --git a/spec/ruby/core/binding/clone_spec.rb b/spec/ruby/core/binding/clone_spec.rb index ebd40f5377..f1769ac6de 100644 --- a/spec/ruby/core/binding/clone_spec.rb +++ b/spec/ruby/core/binding/clone_spec.rb @@ -4,4 +4,10 @@ require_relative 'shared/clone' describe "Binding#clone" do it_behaves_like :binding_clone, :clone + + it "preserves frozen status" do + bind = binding.freeze + bind.frozen?.should == true + bind.clone.frozen?.should == true + end end diff --git a/spec/ruby/core/binding/dup_spec.rb b/spec/ruby/core/binding/dup_spec.rb index 43968213c8..55fac6e333 100644 --- a/spec/ruby/core/binding/dup_spec.rb +++ b/spec/ruby/core/binding/dup_spec.rb @@ -4,4 +4,10 @@ require_relative 'shared/clone' describe "Binding#dup" do it_behaves_like :binding_clone, :dup + + it "resets frozen status" do + bind = binding.freeze + bind.frozen?.should == true + bind.dup.frozen?.should == false + end end diff --git a/spec/ruby/core/binding/shared/clone.rb b/spec/ruby/core/binding/shared/clone.rb index 0e934ac1b5..1224b8ec7d 100644 --- a/spec/ruby/core/binding/shared/clone.rb +++ b/spec/ruby/core/binding/shared/clone.rb @@ -31,4 +31,26 @@ describe :binding_clone, shared: true do b2.local_variable_defined?(:x).should == false end end + + ruby_version_is "3.4" do + it "copies instance variables" do + @b1.instance_variable_set(:@ivar, 1) + cl = @b1.send(@method) + cl.instance_variables.should == [:@ivar] + end + + it "copies the finalizer" do + code = <<-RUBY + obj = binding + + ObjectSpace.define_finalizer(obj, Proc.new { STDOUT.write "finalized\n" }) + + obj.clone + + exit 0 + RUBY + + ruby_exe(code).lines.sort.should == ["finalized\n", "finalized\n"] + end + end end diff --git a/spec/ruby/core/method/clone_spec.rb b/spec/ruby/core/method/clone_spec.rb index 3fe4000fb7..b0eb5751a9 100644 --- a/spec/ruby/core/method/clone_spec.rb +++ b/spec/ruby/core/method/clone_spec.rb @@ -1,14 +1,13 @@ require_relative '../../spec_helper' -require_relative 'fixtures/classes' +require_relative 'shared/dup' describe "Method#clone" do - it "returns a copy of the method" do - m1 = MethodSpecs::Methods.new.method(:foo) - m2 = m1.clone + it_behaves_like :method_dup, :clone - m1.should == m2 - m1.should_not equal(m2) - - m1.call.should == m2.call + it "preserves frozen status" do + method = Object.new.method(:method) + method.freeze + method.frozen?.should == true + method.clone.frozen?.should == true end end diff --git a/spec/ruby/core/method/dup_spec.rb b/spec/ruby/core/method/dup_spec.rb new file mode 100644 index 0000000000..e3e29d8a68 --- /dev/null +++ b/spec/ruby/core/method/dup_spec.rb @@ -0,0 +1,15 @@ +require_relative '../../spec_helper' +require_relative 'shared/dup' + +describe "Method#dup" do + ruby_version_is "3.4" do + it_behaves_like :method_dup, :dup + + it "resets frozen status" do + method = Object.new.method(:method) + method.freeze + method.frozen?.should == true + method.dup.frozen?.should == false + end + end +end diff --git a/spec/ruby/core/method/shared/dup.rb b/spec/ruby/core/method/shared/dup.rb new file mode 100644 index 0000000000..1a10b90689 --- /dev/null +++ b/spec/ruby/core/method/shared/dup.rb @@ -0,0 +1,32 @@ +describe :method_dup, shared: true do + it "returns a copy of self" do + a = Object.new.method(:method) + b = a.send(@method) + + a.should == b + a.should_not equal(b) + end + + ruby_version_is "3.4" do + it "copies instance variables" do + method = Object.new.method(:method) + method.instance_variable_set(:@ivar, 1) + cl = method.send(@method) + cl.instance_variables.should == [:@ivar] + end + + it "copies the finalizer" do + code = <<-RUBY + obj = Object.new.method(:method) + + ObjectSpace.define_finalizer(obj, Proc.new { STDOUT.write "finalized\n" }) + + obj.clone + + exit 0 + RUBY + + ruby_exe(code).lines.sort.should == ["finalized\n", "finalized\n"] + end + end +end diff --git a/spec/ruby/core/proc/clone_spec.rb b/spec/ruby/core/proc/clone_spec.rb index a1a1292654..7eca9c561e 100644 --- a/spec/ruby/core/proc/clone_spec.rb +++ b/spec/ruby/core/proc/clone_spec.rb @@ -3,4 +3,13 @@ require_relative 'shared/dup' describe "Proc#clone" do it_behaves_like :proc_dup, :clone + + ruby_bug "cloning a frozen proc is broken on Ruby 3.3", "3.3"..."3.4" do + it "preserves frozen status" do + proc = Proc.new { } + proc.freeze + proc.frozen?.should == true + proc.clone.frozen?.should == true + end + end end diff --git a/spec/ruby/core/proc/dup_spec.rb b/spec/ruby/core/proc/dup_spec.rb index 6da2f3080c..dd19b3c1e9 100644 --- a/spec/ruby/core/proc/dup_spec.rb +++ b/spec/ruby/core/proc/dup_spec.rb @@ -3,4 +3,11 @@ require_relative 'shared/dup' describe "Proc#dup" do it_behaves_like :proc_dup, :dup + + it "resets frozen status" do + proc = Proc.new { } + proc.freeze + proc.frozen?.should == true + proc.dup.frozen?.should == false + end end diff --git a/spec/ruby/core/proc/shared/dup.rb b/spec/ruby/core/proc/shared/dup.rb index 4480f3d0c9..c419a4078a 100644 --- a/spec/ruby/core/proc/shared/dup.rb +++ b/spec/ruby/core/proc/shared/dup.rb @@ -15,4 +15,27 @@ describe :proc_dup, shared: true do cl.new{}.send(@method).class.should == cl end end + + ruby_version_is "3.4" do + it "copies instance variables" do + proc = -> { "hello" } + proc.instance_variable_set(:@ivar, 1) + cl = proc.send(@method) + cl.instance_variables.should == [:@ivar] + end + + it "copies the finalizer" do + code = <<-RUBY + obj = Proc.new { } + + ObjectSpace.define_finalizer(obj, Proc.new { STDOUT.write "finalized\n" }) + + obj.clone + + exit 0 + RUBY + + ruby_exe(code).lines.sort.should == ["finalized\n", "finalized\n"] + end + end end diff --git a/spec/ruby/core/unboundmethod/clone_spec.rb b/spec/ruby/core/unboundmethod/clone_spec.rb index 098ee61476..1e7fb18744 100644 --- a/spec/ruby/core/unboundmethod/clone_spec.rb +++ b/spec/ruby/core/unboundmethod/clone_spec.rb @@ -1,12 +1,13 @@ require_relative '../../spec_helper' -require_relative 'fixtures/classes' +require_relative 'shared/dup' describe "UnboundMethod#clone" do - it "returns a copy of the UnboundMethod" do - um1 = UnboundMethodSpecs::Methods.instance_method(:foo) - um2 = um1.clone + it_behaves_like :unboundmethod_dup, :clone - (um1 == um2).should == true - um1.bind(UnboundMethodSpecs::Methods.new).call.should == um2.bind(UnboundMethodSpecs::Methods.new).call + it "preserves frozen status" do + method = Class.instance_method(:instance_method) + method.freeze + method.frozen?.should == true + method.clone.frozen?.should == true end end diff --git a/spec/ruby/core/unboundmethod/dup_spec.rb b/spec/ruby/core/unboundmethod/dup_spec.rb new file mode 100644 index 0000000000..5a78dd8e36 --- /dev/null +++ b/spec/ruby/core/unboundmethod/dup_spec.rb @@ -0,0 +1,15 @@ +require_relative '../../spec_helper' +require_relative 'shared/dup' + +describe "UnboundMethod#dup" do + ruby_version_is "3.4" do + it_behaves_like :unboundmethod_dup, :dup + + it "resets frozen status" do + method = Class.instance_method(:instance_method) + method.freeze + method.frozen?.should == true + method.dup.frozen?.should == false + end + end +end diff --git a/spec/ruby/core/unboundmethod/shared/dup.rb b/spec/ruby/core/unboundmethod/shared/dup.rb new file mode 100644 index 0000000000..943a7faaa3 --- /dev/null +++ b/spec/ruby/core/unboundmethod/shared/dup.rb @@ -0,0 +1,32 @@ +describe :unboundmethod_dup, shared: true do + it "returns a copy of self" do + a = Class.instance_method(:instance_method) + b = a.send(@method) + + a.should == b + a.should_not equal(b) + end + + ruby_version_is "3.4" do + it "copies instance variables" do + method = Class.instance_method(:instance_method) + method.instance_variable_set(:@ivar, 1) + cl = method.send(@method) + cl.instance_variables.should == [:@ivar] + end + + it "copies the finalizer" do + code = <<-RUBY + obj = Class.instance_method(:instance_method) + + ObjectSpace.define_finalizer(obj, Proc.new { STDOUT.write "finalized\n" }) + + obj.clone + + exit 0 + RUBY + + ruby_exe(code).lines.sort.should == ["finalized\n", "finalized\n"] + end + end +end |