From f555a7537c94ba17e8ff16158886c8474cc274ef Mon Sep 17 00:00:00 2001 From: kares Date: Fri, 17 Feb 2017 10:37:17 +0100 Subject: [PATCH] check for respond_to? :to_c on Complex(arg) (resolves #4483) --- core/src/main/java/org/jruby/RubyComplex.java | 43 ++++++++++++------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/core/src/main/java/org/jruby/RubyComplex.java b/core/src/main/java/org/jruby/RubyComplex.java index 211688031f5..296077891f3 100644 --- a/core/src/main/java/org/jruby/RubyComplex.java +++ b/core/src/main/java/org/jruby/RubyComplex.java @@ -68,6 +68,7 @@ import org.jruby.runtime.ThreadContext; import org.jruby.runtime.Visibility; import org.jruby.runtime.builtin.IRubyObject; +import org.jruby.runtime.callsite.RespondToCallSite; import org.jruby.util.ByteList; import org.jruby.util.Numeric; @@ -295,9 +296,9 @@ private static void realCheck(ThreadContext context, IRubyObject num) { case RATIONAL: break; default: - if (!(num instanceof RubyNumeric ) || !f_real_p(context, num).isTrue()) { + if (!(num instanceof RubyNumeric ) || !f_real_p(context, num).isTrue()) { throw context.runtime.newTypeError("not a real"); - } + } } } @@ -312,15 +313,16 @@ private static IRubyObject canonicalizeInternal(ThreadContext context, IRubyObje canonicalization) return real; } - if (f_real_p(context, real).isTrue() && - f_real_p(context, image).isTrue()) { + if (f_real_p(context, real).isTrue() && f_real_p(context, image).isTrue()) { return new RubyComplex(context.runtime, clazz, real, image); - } else if (f_real_p(context, real).isTrue()) { + } + if (f_real_p(context, real).isTrue()) { RubyComplex complex = (RubyComplex)image; return new RubyComplex(context.runtime, clazz, f_sub(context, real, complex.image), f_add(context, RubyFixnum.zero(context.runtime), complex.real)); - } else if (f_real_p(context, image).isTrue()) { + } + if (f_real_p(context, image).isTrue()) { RubyComplex complex = (RubyComplex)real; return new RubyComplex(context.runtime, clazz, complex.real, @@ -432,33 +434,41 @@ public static IRubyObject convert(ThreadContext context, IRubyObject clazz, IRub * */ @JRubyMethod(name = "convert", meta = true, visibility = Visibility.PRIVATE) - public static IRubyObject convert(ThreadContext context, IRubyObject recv, IRubyObject a1) { - return convertCommon(context, recv, a1, context.runtime.getNil()); + public static IRubyObject convert(ThreadContext context, IRubyObject recv, IRubyObject arg) { + return convertCommon(context, recv, arg, context.nil, true); } + private static boolean responds_to_to_c(ThreadContext context, IRubyObject obj) { + return respond_to_to_c.respondsTo(context, obj, obj); + } + + // TODO: wasn't sure whether to put this on NumericSites, here for now - should move + static final RespondToCallSite respond_to_to_c = new RespondToCallSite("to_c"); + /** nucomp_s_convert * */ @JRubyMethod(name = "convert", meta = true, visibility = Visibility.PRIVATE) public static IRubyObject convert(ThreadContext context, IRubyObject recv, IRubyObject a1, IRubyObject a2) { - return convertCommon(context, recv, a1, a2); + return convertCommon(context, recv, a1, a2, false); } - private static IRubyObject convertCommon(ThreadContext context, IRubyObject recv, IRubyObject a1, IRubyObject a2) { + private static IRubyObject convertCommon(ThreadContext context, IRubyObject recv, + IRubyObject a1, IRubyObject a2, final boolean singleArg) { if (a1 instanceof RubyString) a1 = str_to_c_strict(context, a1); if (a2 instanceof RubyString) a2 = str_to_c_strict(context, a2); if (a1 instanceof RubyComplex) { - RubyComplex a1Complex = (RubyComplex)a1; - if (k_exact_p(a1Complex.image) && f_zero_p(context, a1Complex.image)) { - a1 = a1Complex.real; + RubyComplex a1c = (RubyComplex) a1; + if (k_exact_p(a1c.image) && f_zero_p(context, a1c.image)) { + a1 = a1c.real; } } if (a2 instanceof RubyComplex) { - RubyComplex a2Complex = (RubyComplex)a2; - if (k_exact_p(a2Complex.image) && f_zero_p(context, a2Complex.image)) { - a2 = a2Complex.real; + RubyComplex a2c = (RubyComplex) a2; + if (k_exact_p(a2c.image) && f_zero_p(context, a2c.image)) { + a2 = a2c.real; } } @@ -468,6 +478,7 @@ private static IRubyObject convertCommon(ThreadContext context, IRubyObject recv if (a2.isNil()) { if (a1 instanceof RubyNumeric && !f_real_p(context, a1).isTrue()) return a1; + if (singleArg && responds_to_to_c(context, a1) ) return a1.callMethod(context, "to_c"); return newInstance(context, recv, a1); } else { if (a1 instanceof RubyNumeric && a2 instanceof RubyNumeric &&