Open nirvdrum opened 1 year ago
Right, it seems this is a problem for most To*Node
, they catch NoMethodError and they can't easily know if that's from that method call or some other method call.
I think unfortunately it's semantically incorrect in those cases to use a @Cached(parameters = "PRIVATE_RETURN_MISSING") DispatchNode
(which behaves a bit like rb_check_funcall()
), because e.g. that wouldn't call method_missing
, but IIRC the semantics on such conversion is to call method_missing
.
A possibility is to do it like ToRubyIntegerNode
does it by calling a Ruby helper (rb_to_int_fallback
).
Indeed it calls method_missing
in that case on CRuby (even if respond_to?
is false):
$ ruby -e 'o=Object.new; def o.method_missing(name, *); p name; "foo"; end; p "a " + o'
:to_str
"a foo"
Oh yeah it's really weird and full of corner cases:
ruby 3.1.3p185 (2022-11-24 revision 1a6b16756e) [x86_64-linux]
$ ruby -e 'o=Object.new; def o.respond_to?(m,*); p [:resp, m]; end; def o.method_missing(name, *); p name; "foo"; end; p "a " + o'
[:resp, :to_str]
:to_str
"a foo"
$ ruby -e 'o=Object.new; def o.respond_to?(m,*); p [:resp, m]; false; end; def o.method_missing(name, *); p name; "foo"; end; p "a " + o'
[:resp, :to_str]
-e:1:in `+': no implicit conversion of Object into String (TypeError)
from -e:1:in `<main>'
$ ruby -e 'o=Object.new; def o.method_missing(name, *); p name; "foo"; end; p o.respond_to?(:to_str); p "a " + o'
false
:to_str
"a foo"
So it does call respond_to?
(or at least it calls the custom one), and if a custom respond_to?
returns false
it believes it and doesn't call method_missing
. But if it's the default respond_to?
it calls method_missing
anyway :sweat_smile:
Right, I think this is simply the "full" semantics of rb_check_funcall
in CRuby.
We have them implemented in Truffle::Type.check_funcall
and so I think using Truffle::Type.rb_convert_type
should implement the correct semantics here.
While working on getting the Sorbet test suite passing on TruffleRuby, @paracycle discovered an issue with some of our type coercion logic. In this case, an object is attempted to be coerced to a
String
viato_str
. Ifto_str
raises aNoMethodError
then some of our type coercion logic assumes the type cannot be converted and raises aTypeError
rather than theNoMethodError
.A brief search indicates
ToStringOrSymbolNode
needs to check if the method exists. Our logic inTruffle::Type.try_convert
does perform the extrarespond_to?
check, but it looks like that didn't get carried forward to type coercion performed in Java.MRI 3.1.3 (warnings removed):
TruffleRuby 23.0.0-dev (a6717812, warnings removed):