Skip to content
Permalink
Browse files
[Truffle] Check for ambiguous default arguments using reflection.
  • Loading branch information
eregon committed Jan 31, 2015
1 parent 0b8305a commit 7951249519f0eccc3b54c73b8b025b5d8e8b4d0f
Showing 1 changed file with 42 additions and 0 deletions.
@@ -12,7 +12,9 @@
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.dsl.GeneratedBy;
import com.oracle.truffle.api.dsl.NodeFactory;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.NodeUtil;

import org.jruby.runtime.Visibility;
import org.jruby.truffle.nodes.CoreSourceSection;
import org.jruby.truffle.nodes.RubyNode;
@@ -30,6 +32,7 @@
import org.jruby.truffle.runtime.methods.SharedMethodInfo;
import org.jruby.truffle.runtime.util.ArrayUtils;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -190,13 +193,52 @@ private static RubyRootNode makeGenericMethod(RubyContext context, MethodDetails
}
}

assert assertNoAmbiguousDefaultArguments(methodDetails);

final CheckArityNode checkArity = new CheckArityNode(context, sourceSection, arity);
final RubyNode block = SequenceNode.sequence(context, sourceSection, checkArity, methodNode);
final ExceptionTranslatingNode exceptionTranslatingNode = new ExceptionTranslatingNode(context, sourceSection, block, methodDetails.getMethodAnnotation().unsupportedOperationBehavior());

return new RubyRootNode(context, sourceSection, null, sharedMethodInfo, exceptionTranslatingNode);
}

private static boolean assertNoAmbiguousDefaultArguments(MethodDetails methodDetails) {
if (methodDetails.getMethodAnnotation().optional() > 0) {
int opt = methodDetails.getMethodAnnotation().optional();
int argc = methodDetails.getNodeFactory().getExecutionSignature().size();
Class<?> node = methodDetails.getNodeFactory().getNodeClass();

boolean undefined = false, object = false;

for (int i = 1; i <= opt; i++) {
for (Method method : node.getDeclaredMethods()) {
if (method.isAnnotationPresent(Specialization.class)) {
// use getParameterTypes().length to ignore optional VirtualFrame in front.
Class<?> c = method.getParameterTypes()[method.getParameterTypes().length - i];
if (c == UndefinedPlaceholder.class) {
undefined |= true;
} else if (c == Object.class) {
String[] guards = method.getAnnotation(Specialization.class).guards();
boolean guarded = false;
for (String guard : guards) {
if (guard.equals("!isUndefinedPlaceholder(arguments[" + (argc - i) + "])")) {
guarded = true;
}
}
object |= (guarded == false);
}
}
}

if (undefined && object) {
System.out.println("Ambiguous default argument " + (argc - i) + " in " + node.getCanonicalName());
}
}
}

return true;
}

public static class MethodDetails {

private final CoreClass classAnnotation;

0 comments on commit 7951249

Please sign in to comment.