Skip to content

Commit 47b44a4

Browse files
committed
[GR-32001] Replace ReadCallerFrameNode by AlwaysInlinedMethodNode
PullRequest: truffleruby/3458
2 parents 94399c8 + 6eb9c98 commit 47b44a4

21 files changed

+453
-491
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ Compatibility:
3838
* Implement `rb_ivar_foreach` to iterate over instance and class variables like in CRuby (#2701, @aardvark179).
3939
* Fix the absolute path of the main script after chdir (#2709, @eregon).
4040
* Fix exception for `Fiddle::Handle.new` with a missing library (#2714, @eregon).
41+
* Fix arguments implicit type conversion for `BasicObject#instance_eval`, `Module#class_eval`, `Module#module_eval`, `Module#define_method` (@andrykonchin).
42+
* Raise `ArgumentError` unconditionally when `Proc.new` is called without a block argument (@andrykonchin).
43+
4144

4245
Performance:
4346

spec/ruby/core/basicobject/instance_eval_spec.rb

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,18 @@
2020
a.instance_eval('self').equal?(a).should be_true
2121
end
2222

23-
it "expects a block with no arguments" do
24-
-> { "hola".instance_eval }.should raise_error(ArgumentError)
23+
it "raises an ArgumentError when no arguments and no block are given" do
24+
-> { "hola".instance_eval }.should raise_error(ArgumentError, "wrong number of arguments (given 0, expected 1..3)")
2525
end
2626

27-
it "takes no arguments with a block" do
28-
-> { "hola".instance_eval(4, 5) {|a,b| a + b } }.should raise_error(ArgumentError)
27+
it "raises an ArgumentError when a block and normal arguments are given" do
28+
-> { "hola".instance_eval(4, 5) {|a,b| a + b } }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 0)")
29+
end
30+
31+
it "raises an ArgumentError when more than 3 arguments are given" do
32+
-> {
33+
"hola".instance_eval("1 + 1", "some file", 0, "bogus")
34+
}.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 1..3)")
2935
end
3036

3137
it "yields the object to the block" do
@@ -185,4 +191,58 @@ def meth(arg); arg; end
185191

186192
x.should == :value
187193
end
194+
195+
it "converts string argument with #to_str method" do
196+
source_code = Object.new
197+
def source_code.to_str() "1" end
198+
199+
a = BasicObject.new
200+
a.instance_eval(source_code).should == 1
201+
end
202+
203+
it "raises ArgumentError if returned value is not String" do
204+
source_code = Object.new
205+
def source_code.to_str() :symbol end
206+
207+
a = BasicObject.new
208+
-> { a.instance_eval(source_code) }.should raise_error(TypeError, /can't convert Object to String/)
209+
end
210+
211+
it "converts filename argument with #to_str method" do
212+
filename = Object.new
213+
def filename.to_str() "file.rb" end
214+
215+
err = begin
216+
Object.new.instance_eval("raise", filename)
217+
rescue => e
218+
e
219+
end
220+
err.backtrace.first.split(":")[0].should == "file.rb"
221+
end
222+
223+
it "raises ArgumentError if returned value is not String" do
224+
filename = Object.new
225+
def filename.to_str() :symbol end
226+
227+
-> { Object.new.instance_eval("raise", filename) }.should raise_error(TypeError, /can't convert Object to String/)
228+
end
229+
230+
it "converts lineno argument with #to_int method" do
231+
lineno = Object.new
232+
def lineno.to_int() 15 end
233+
234+
err = begin
235+
Object.new.instance_eval("raise", "file.rb", lineno)
236+
rescue => e
237+
e
238+
end
239+
err.backtrace.first.split(":")[1].should == "15"
240+
end
241+
242+
it "raises ArgumentError if returned value is not Integer" do
243+
lineno = Object.new
244+
def lineno.to_int() :symbol end
245+
246+
-> { Object.new.instance_eval("raise", "file.rb", lineno) }.should raise_error(TypeError, /can't convert Object to Integer/)
247+
end
188248
end

spec/ruby/core/module/define_method_spec.rb

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -219,18 +219,55 @@ class DefineMethodSpecClass
219219
o.block_test2.should == o
220220
end
221221

222+
it "raises TypeError if name cannot converted to String" do
223+
-> {
224+
Class.new { define_method(1001, -> {}) }
225+
}.should raise_error(TypeError, /is not a symbol nor a string/)
226+
227+
-> {
228+
Class.new { define_method([], -> {}) }
229+
}.should raise_error(TypeError, /is not a symbol nor a string/)
230+
end
231+
232+
it "converts non-String name to String with #to_str" do
233+
obj = Object.new
234+
def obj.to_str() "foo" end
235+
236+
new_class = Class.new { define_method(obj, -> { :called }) }
237+
new_class.new.foo.should == :called
238+
end
239+
240+
it "raises TypeError when #to_str called on non-String name returns non-String value" do
241+
obj = Object.new
242+
def obj.to_str() [] end
243+
244+
-> {
245+
Class.new { define_method(obj, -> {}) }
246+
}.should raise_error(TypeError, /can't convert Object to String/)
247+
end
248+
222249
it "raises a TypeError when the given method is no Method/Proc" do
223250
-> {
224251
Class.new { define_method(:test, "self") }
225-
}.should raise_error(TypeError)
252+
}.should raise_error(TypeError, "wrong argument type String (expected Proc/Method/UnboundMethod)")
226253

227254
-> {
228255
Class.new { define_method(:test, 1234) }
229-
}.should raise_error(TypeError)
256+
}.should raise_error(TypeError, "wrong argument type Integer (expected Proc/Method/UnboundMethod)")
230257

231258
-> {
232259
Class.new { define_method(:test, nil) }
233-
}.should raise_error(TypeError)
260+
}.should raise_error(TypeError, "wrong argument type NilClass (expected Proc/Method/UnboundMethod)")
261+
end
262+
263+
it "uses provided Method/Proc even if block is specified" do
264+
new_class = Class.new do
265+
define_method(:test, -> { :method_is_called }) do
266+
:block_is_called
267+
end
268+
end
269+
270+
new_class.new.test.should == :method_is_called
234271
end
235272

236273
it "raises an ArgumentError when no block is given" do

spec/ruby/core/module/instance_method_spec.rb

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,36 @@
5151
@mod_um.inspect.should =~ /\bModuleSpecs::InstanceMethChild\b/
5252
end
5353

54-
it "raises a TypeError if not passed a symbol" do
55-
-> { Object.instance_method([]) }.should raise_error(TypeError)
56-
-> { Object.instance_method(0) }.should raise_error(TypeError)
54+
it "raises a TypeError if the given name is not a String/Symbol" do
55+
-> { Object.instance_method([]) }.should raise_error(TypeError, /is not a symbol nor a string/)
56+
-> { Object.instance_method(0) }.should raise_error(TypeError, /is not a symbol nor a string/)
57+
-> { Object.instance_method(nil) }.should raise_error(TypeError, /is not a symbol nor a string/)
58+
-> { Object.instance_method(mock('x')) }.should raise_error(TypeError, /is not a symbol nor a string/)
5759
end
5860

59-
it "raises a TypeError if the given name is not a string/symbol" do
60-
-> { Object.instance_method(nil) }.should raise_error(TypeError)
61-
-> { Object.instance_method(mock('x')) }.should raise_error(TypeError)
61+
it "accepts String name argument" do
62+
method = ModuleSpecs::InstanceMeth.instance_method(:foo)
63+
method.should be_kind_of(UnboundMethod)
64+
end
65+
66+
it "accepts Symbol name argument" do
67+
method = ModuleSpecs::InstanceMeth.instance_method("foo")
68+
method.should be_kind_of(UnboundMethod)
69+
end
70+
71+
it "converts non-String name by calling #to_str method" do
72+
obj = Object.new
73+
def obj.to_str() "foo" end
74+
75+
method = ModuleSpecs::InstanceMeth.instance_method(obj)
76+
method.should be_kind_of(UnboundMethod)
77+
end
78+
79+
it "raises TypeError when passed non-String name and #to_str returns non-String value" do
80+
obj = Object.new
81+
def obj.to_str() [] end
82+
83+
-> { ModuleSpecs::InstanceMeth.instance_method(obj) }.should raise_error(TypeError, /can't convert Object to String/)
6284
end
6385

6486
it "raises a NameError if the method has been undefined" do

spec/ruby/core/module/shared/class_eval.rb

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,40 +55,49 @@ def foo
5555
it "converts a non-string filename to a string using to_str" do
5656
(file = mock(__FILE__)).should_receive(:to_str).and_return(__FILE__)
5757
ModuleSpecs.send(@method, "1+1", file)
58+
59+
(file = mock(__FILE__)).should_receive(:to_str).and_return(__FILE__)
60+
ModuleSpecs.send(@method, "1+1", file, 15)
5861
end
5962

6063
it "raises a TypeError when the given filename can't be converted to string using to_str" do
6164
(file = mock('123')).should_receive(:to_str).and_return(123)
62-
-> { ModuleSpecs.send(@method, "1+1", file) }.should raise_error(TypeError)
65+
-> { ModuleSpecs.send(@method, "1+1", file) }.should raise_error(TypeError, /can't convert MockObject to String/)
6366
end
6467

6568
it "converts non string eval-string to string using to_str" do
6669
(o = mock('1 + 1')).should_receive(:to_str).and_return("1 + 1")
6770
ModuleSpecs.send(@method, o).should == 2
71+
72+
(o = mock('1 + 1')).should_receive(:to_str).and_return("1 + 1")
73+
ModuleSpecs.send(@method, o, "file.rb").should == 2
74+
75+
(o = mock('1 + 1')).should_receive(:to_str).and_return("1 + 1")
76+
ModuleSpecs.send(@method, o, "file.rb", 15).should == 2
6877
end
6978

7079
it "raises a TypeError when the given eval-string can't be converted to string using to_str" do
7180
o = mock('x')
72-
-> { ModuleSpecs.send(@method, o) }.should raise_error(TypeError)
81+
-> { ModuleSpecs.send(@method, o) }.should raise_error(TypeError, "no implicit conversion of MockObject into String")
7382

7483
(o = mock('123')).should_receive(:to_str).and_return(123)
75-
-> { ModuleSpecs.send(@method, o) }.should raise_error(TypeError)
84+
-> { ModuleSpecs.send(@method, o) }.should raise_error(TypeError, /can't convert MockObject to String/)
7685
end
7786

7887
it "raises an ArgumentError when no arguments and no block are given" do
79-
-> { ModuleSpecs.send(@method) }.should raise_error(ArgumentError)
88+
-> { ModuleSpecs.send(@method) }.should raise_error(ArgumentError, "wrong number of arguments (given 0, expected 1..3)")
8089
end
8190

8291
it "raises an ArgumentError when more than 3 arguments are given" do
8392
-> {
8493
ModuleSpecs.send(@method, "1 + 1", "some file", 0, "bogus")
85-
}.should raise_error(ArgumentError)
94+
}.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 1..3)")
8695
end
8796

8897
it "raises an ArgumentError when a block and normal arguments are given" do
8998
-> {
9099
ModuleSpecs.send(@method, "1 + 1") { 1 + 1 }
91-
}.should raise_error(ArgumentError)
100+
}.should raise_error(ArgumentError, "wrong number of arguments (given 1, expected 0)")
92101
end
93102

94103
# This case was found because Rubinius was caching the compiled
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
fails:BasicObject#instance_eval gets constants in the receiver if a string given
2+
fails:BasicObject#instance_eval raises an ArgumentError when more than 3 arguments are given
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
fails:Module#class_eval activates refinements from the eval scope
22
fails:Module#class_eval activates refinements from the eval scope with block
3+
fails:Module#class_eval raises an ArgumentError when more than 3 arguments are given
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
fails:Module#module_eval activates refinements from the eval scope
22
fails:Module#module_eval activates refinements from the eval scope with block
3+
fails:Module#module_eval raises an ArgumentError when more than 3 arguments are given

spec/tags/core/proc/new_tags.txt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1 @@
11
fails:Proc.new with an associated block raises a LocalJumpError when context of the block no longer exists
2-
fails:Proc.new without a block can be created if invoked from within a method with a block
3-
fails:Proc.new without a block can be created if invoked on a subclass from within a method with a block
4-
fails:Proc.new without a block can be create when called with no block
5-
fails:Proc.new without a block raises an ArgumentError when passed no block

spec/truffle/always_inlined_spec.rb

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,42 @@
8787
}.should raise_error(ArgumentError) { |e| e.backtrace_locations[0].label.should == 'initialize_copy' }
8888
end
8989

90+
it "for Symbol#to_proc" do
91+
-> {
92+
:a.to_proc(:wrong)
93+
}.should raise_error(ArgumentError) { |e| e.backtrace_locations[0].label.should == 'to_proc' }
94+
end
95+
96+
it "for BasicObject#instance_eval" do
97+
-> {
98+
BasicObject.new.instance_eval
99+
}.should raise_error(ArgumentError) { |e| e.backtrace_locations[0].label.should == 'instance_eval' }
100+
end
101+
102+
it "for Module#class_eval" do
103+
-> {
104+
Module.new.class_eval
105+
}.should raise_error(ArgumentError) { |e| e.backtrace_locations[0].label.should == 'class_eval' }
106+
end
107+
108+
it "for Module#module_eval" do
109+
-> {
110+
Module.new.module_eval
111+
}.should raise_error(ArgumentError) { |e| e.backtrace_locations[0].label.should == 'module_eval' }
112+
end
113+
114+
it "for Module#define_method" do
115+
-> {
116+
Module.new.define_method(:wrong)
117+
}.should raise_error(ArgumentError) { |e| e.backtrace_locations[0].label.should == 'define_method' }
118+
end
119+
120+
it "for Module#instance_method" do
121+
-> {
122+
Module.new.instance_method([])
123+
}.should raise_error(TypeError) { |e| e.backtrace_locations[0].label.should == 'instance_method' }
124+
end
125+
90126
guard -> { RUBY_ENGINE != "ruby" } do
91127
it "for #send" do
92128
-> {

0 commit comments

Comments
 (0)