Skip to content

Commit

Permalink
check for respond_to? :to_c on Complex(arg) (resolves #4483)
Browse files Browse the repository at this point in the history
  • Loading branch information
kares committed Feb 17, 2017
1 parent 47e07f1 commit f555a75
Showing 1 changed file with 27 additions and 16 deletions.
43 changes: 27 additions & 16 deletions core/src/main/java/org/jruby/RubyComplex.java
Expand Up @@ -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;

Expand Down Expand Up @@ -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");
}
}
}
}

Expand All @@ -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,
Expand Down Expand Up @@ -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;
}
}

Expand All @@ -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 &&
Expand Down

0 comments on commit f555a75

Please sign in to comment.