# HG changeset patch # User Christian Humer # Date 1429125223 -7200 # Node ID 6361fa2e33219fe3c4b00075a6dc8b69d4204305 # Parent b99da6d86cfecfc29adc1234771df0e453fa2762 Truffle-DSL: further fixes for polymorphic execute signatures. diff -r b99da6d86cfe -r 6361fa2e3321 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteEvaluatedTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteEvaluatedTest.java Wed Apr 15 21:35:51 2015 +0200 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteEvaluatedTest.java Wed Apr 15 21:13:43 2015 +0200 @@ -287,4 +287,51 @@ } } + @SuppressWarnings("unused") + @NodeChildren({@NodeChild(value = "a", type = ValueNode.class), @NodeChild(value = "b", type = ValueNode.class)}) + abstract static class TestEvaluatedShortCircuit1 extends Node { + + public abstract Object execute1(VirtualFrame frame, Object value); + + public abstract Object execute2(VirtualFrame frame, Object value, boolean hasB); + + public abstract Object execute3(VirtualFrame frame, Object value, boolean hasB, Object b); + + @ShortCircuit("b") + public boolean needsB(Object a) { + return true; + } + + @Specialization + int call(Object a, boolean hasB, Object b) { + return 42; + } + } + + @SuppressWarnings("unused") + @NodeChildren({@NodeChild(value = "a", type = ValueNode.class), @NodeChild(value = "b", type = ValueNode.class)}) + abstract static class TestEvaluatedShortCircuit2 extends Node { + + public abstract Object execute1(VirtualFrame frame, Object value); + + public abstract Object execute2(VirtualFrame frame, Object value, boolean hasB); + + public abstract Object execute3(VirtualFrame frame, Object value, boolean hasB, Object b); + + @ShortCircuit("b") + public boolean needsB(Object a) { + return true; + } + + @Specialization + int call(int a, boolean hasB, int b) { + return 42; + } + + @Specialization + int call(Object a, boolean hasB, Object b) { + return 42; + } + } + } diff -r b99da6d86cfe -r 6361fa2e3321 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteGroupingTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteGroupingTest.java Wed Apr 15 21:35:51 2015 +0200 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteGroupingTest.java Wed Apr 15 21:13:43 2015 +0200 @@ -144,18 +144,18 @@ } @Specialization(rewriteOn = RuntimeException.class) - int s1() { + double s1() { return 42; } @Specialization - int s2() { + double s2() { return 42; } } - @ExpectError("Incompatible abstract execute methods found [executeDouble(), executeInt()].%") + @ExpectError("Incompatible abstract execute methods found %") abstract static class IncompatibleAbstract1 extends Node { // we don't know how to implement executeDouble @@ -164,7 +164,7 @@ abstract int executeInt(); @Specialization - int s1() { + double s1() { return 42; } diff -r b99da6d86cfe -r 6361fa2e3321 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java Wed Apr 15 21:35:51 2015 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java Wed Apr 15 21:13:43 2015 +0200 @@ -66,7 +66,9 @@ private final boolean singleSpecializable; private final int varArgsThreshold; private final Set expectedTypes = new HashSet<>(); + private final Set usedExecuteChildMethods = new HashSet<>(); private boolean nextUsed; + private List usedTypes; private List reachableSpecializations; @@ -210,7 +212,7 @@ } for (ExecutableTypeData execType : usedTypes) { - if (execType.getMethod() == null) { + if (!singleSpecializable && execType.getMethod() == null) { continue; } clazz.add(createExecutableTypeOverride(usedTypes, execType)); @@ -273,7 +275,7 @@ private Element createUnsupportedMethod() { LocalContext locals = LocalContext.load(this); - CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED), getType(UnsupportedSpecializationException.class), "unsupported"); + CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED), getType(UnsupportedSpecializationException.class), "unsupported", varArgsThreshold); CodeTreeBuilder builder = method.createBuilder(); builder.startReturn(); @@ -380,6 +382,16 @@ baseSpecialization.addOptional(createCreatePolymorphic(generated)); baseSpecialization.addOptional(createGetNext(baseSpecialization)); + for (NodeExecutionData execution : node.getChildExecutions()) { + Collection specializedTypes = node.findSpecializedTypes(execution); + specializedTypes.add(genericType); + for (TypeMirror specializedType : specializedTypes) { + if (isExecuteChildShared(execution, specializedType)) { + baseSpecialization.addOptional(createExecuteChildMethod(execution, specializedType)); + } + } + } + return node.getUninitializedSpecialization(); } @@ -418,28 +430,13 @@ clazz.add(createFastPathExecuteMethod(null, type, usedTypes)); } - for (NodeExecutionData execution : node.getChildExecutions()) { - Collection specializedTypes = node.findSpecializedTypes(execution); - specializedTypes.add(genericType); - for (TypeMirror specializedType : specializedTypes) { - if (isExecuteChildShared(execution, specializedType)) { - clazz.add(createExecuteChildMethod(execution, specializedType)); - } - } - } - return clazz; } private Element createAcceptAndExecute() { - - TypeMirror[] parameters = new TypeMirror[node.getSignatureSize()]; - Arrays.fill(parameters, genericType); - - ExecutableTypeData executableElement = new ExecutableTypeData(genericType, "acceptAndExecute", context.getType(Frame.class), Arrays.asList(parameters)); - - LocalContext currentLocals = LocalContext.load(this, node.getSignatureSize(), varArgsThreshold); - CodeExecutableElement executable = createExecuteMethod(null, executableElement, currentLocals, false); + ExecutableTypeData executableElement = createSpecializationNodeSignature(node.getSignatureSize()); + LocalContext currentLocals = LocalContext.load(this, executableElement, varArgsThreshold); + CodeExecutableElement executable = createExecuteMethod(null, executableElement, currentLocals, false, varArgsThreshold); executable.getModifiers().add(FINAL); CodeTreeBuilder builder = executable.createBuilder(); @@ -451,6 +448,12 @@ return executable; } + private ExecutableTypeData createSpecializationNodeSignature(int argumentCount) { + TypeMirror[] parameters = new TypeMirror[argumentCount]; + Arrays.fill(parameters, genericType); + return new ExecutableTypeData(node, genericType, "acceptAndExecute", context.getType(Frame.class), Arrays.asList(parameters)); + } + private boolean shouldImplementExecutableType(SpecializationData specialization, ExecutableTypeData executableType) { // always implement the root execute method. they are declared abstract in the base node. if (executableType.getDelegatedTo() == null) { @@ -458,7 +461,7 @@ } // specializations with more parameters are just ignored - if (executableType.getEvaluatedCount() > node.getSignatureSize()) { + if (executableType.getEvaluatedCount() > node.getExecutionCount()) { return false; } @@ -468,8 +471,9 @@ // the evaluated signature might be compatible to the specialization boolean specializationCompatible = true; - for (int i = 0; i < executableType.getEvaluatedCount(); i++) { - TypeMirror evaluatedType = executableType.getEvaluatedParameters().get(i); + List signatureParameters = executableType.getSignatureParameters(); + for (int i = 0; i < signatureParameters.size(); i++) { + TypeMirror evaluatedType = signatureParameters.get(i); TypeMirror specializedType = specialization.findParameterOrDie(node.getChildExecutions().get(i)).getType(); if (!isSubtypeBoxed(context, evaluatedType, specializedType) && !isSubtypeBoxed(context, specializedType, evaluatedType)) { @@ -489,7 +493,7 @@ } // trigger type boxing elimination for unevaluated arguments - for (int i = executableType.getEvaluatedCount(); i < node.getSignatureSize(); i++) { + for (int i = executableType.getEvaluatedCount(); i < node.getExecutionCount(); i++) { NodeExecutionData execution = node.getChildExecutions().get(i); TypeMirror specializedType = specialization.findParameterOrDie(execution).getType(); if (isTypeBoxingOptimized(options.monomorphicTypeBoxingOptimization(), specializedType)) { @@ -512,8 +516,8 @@ } // trigger generation for evaluated assignable type matches other than generic - for (int i = 0; i < executableType.getEvaluatedCount(); i++) { - TypeMirror evaluatedType = executableType.getEvaluatedParameters().get(i); + for (int i = 0; i < signatureParameters.size(); i++) { + TypeMirror evaluatedType = signatureParameters.get(i); NodeExecutionData execution = node.getChildExecutions().get(i); TypeMirror specializedType = specialization.findParameterOrDie(execution).getType(); @@ -664,12 +668,12 @@ return null; } - LocalContext currentLocals = LocalContext.load(this, node.getSignatureSize(), varArgsThreshold); + LocalContext currentLocals = LocalContext.load(this, createSpecializationNodeSignature(node.getSignatureSize()), varArgsThreshold); currentLocals.loadFastPathState(specialization); CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getType(boolean.class), "isIdentical"); method.addParameter(new CodeVariableElement(getType(SpecializationNode.class), "other")); - currentLocals.addParametersTo(method, FRAME_VALUE); + currentLocals.addParametersTo(method, varArgsThreshold, FRAME_VALUE); method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); final CodeTreeBuilder builder = method.createBuilder(); @@ -729,11 +733,11 @@ return null; } TypeMirror specializationNodeType = getType(SpecializationNode.class); - LocalContext currentLocals = LocalContext.load(this, node.getSignatureSize(), varArgsThreshold); + LocalContext currentLocals = LocalContext.load(this, createSpecializationNodeSignature(node.getSignatureSize()), varArgsThreshold); CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), specializationNodeType, "merge"); executable.addParameter(new CodeVariableElement(specializationNodeType, "newNode")); - currentLocals.addParametersTo(executable, FRAME_VALUE); + currentLocals.addParametersTo(executable, varArgsThreshold, FRAME_VALUE); executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); CodeTreeBuilder builder = executable.createBuilder(); @@ -802,7 +806,7 @@ private CodeExecutableElement createCreateNext(final Map specializationClasses) { final LocalContext locals = LocalContext.load(this); - CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), getType(SpecializationNode.class), "createNext", FRAME_VALUE); + CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), getType(SpecializationNode.class), "createNext", varArgsThreshold, FRAME_VALUE); method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); CodeTreeBuilder builder = method.createBuilder(); @@ -834,7 +838,7 @@ locals.removeValue(FRAME_VALUE); } - CodeExecutableElement boundaryMethod = locals.createMethod(modifiers(PRIVATE), getType(boolean.class), "guardFallback", FRAME_VALUE); + CodeExecutableElement boundaryMethod = locals.createMethod(modifiers(PRIVATE), getType(boolean.class), "guardFallback", varArgsThreshold, FRAME_VALUE); if (!frameUsed) { boundaryMethod.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(TruffleBoundary.class))); } @@ -887,7 +891,7 @@ } LocalContext locals = LocalContext.load(this); - CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), genericType, "unsupported", FRAME_VALUE); + CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), genericType, "unsupported", varArgsThreshold, FRAME_VALUE); method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); CodeTreeBuilder builder = method.createBuilder(); @@ -950,8 +954,8 @@ } private CodeExecutableElement createExecutableTypeOverride(List usedExecutables, ExecutableTypeData execType) { - LocalContext locals = LocalContext.load(this, execType.getEvaluatedCount(), Integer.MAX_VALUE); - CodeExecutableElement method = createExecuteMethod(null, execType, locals, true); + LocalContext locals = LocalContext.load(this, execType, Integer.MAX_VALUE); + CodeExecutableElement method = createExecuteMethod(null, execType, locals, true, Integer.MAX_VALUE); CodeTreeBuilder builder = method.createBuilder(); if (singleSpecializable) { @@ -1043,17 +1047,38 @@ values.add(createTypeSafeReference(frameLocal, method.getFrameParameter())); } } - for (int parameterIndex = 0; parameterIndex < method.getEvaluatedCount(); parameterIndex++) { - TypeMirror targetParameter = method.getEvaluatedParameters().get(parameterIndex); - LocalVariable variable; - if (executeWith != null && parameterIndex < executeWith.size()) { - variable = currentValues.getValue(executeWith.get(parameterIndex)); + + int evaluatedIndex = 0; + for (int executionIndex = 0; executionIndex < node.getExecutionCount(); executionIndex++) { + NodeExecutionData parameterExecution; + if (executeWith != null && executionIndex < executeWith.size()) { + parameterExecution = executeWith.get(executionIndex); } else { - variable = currentValues.getValue(parameterIndex); + parameterExecution = node.getChildExecutions().get(executionIndex); } - values.add(createTypeSafeReference(variable, targetParameter)); + if (parameterExecution.isShortCircuit()) { + if (evaluatedIndex < method.getEvaluatedCount()) { + TypeMirror targetType = method.getEvaluatedParameters().get(evaluatedIndex); + LocalVariable shortCircuit = currentValues.getShortCircuit(parameterExecution); + if (shortCircuit != null) { + values.add(createTypeSafeReference(shortCircuit, targetType)); + } else { + values.add(CodeTreeBuilder.createBuilder().defaultValue(targetType).build()); + } + evaluatedIndex++; + } + } + if (evaluatedIndex < method.getEvaluatedCount()) { + TypeMirror targetType = method.getEvaluatedParameters().get(evaluatedIndex); + LocalVariable value = currentValues.getValue(parameterExecution); + if (value != null) { + values.add(createTypeSafeReference(value, targetType)); + } else { + values.add(CodeTreeBuilder.createBuilder().defaultValue(targetType).build()); + } + evaluatedIndex++; + } } - return values.toArray(new CodeTree[values.size()]); } @@ -1518,8 +1543,11 @@ } private CodeTree expect(TypeMirror sourceType, TypeMirror forType, CodeTree tree) { - expectedTypes.add(forType); - return TypeSystemCodeGenerator.expect(typeSystem, sourceType, forType, tree); + if (sourceType == null || ElementUtils.needsCastTo(sourceType, forType)) { + expectedTypes.add(forType); + return TypeSystemCodeGenerator.expect(typeSystem, forType, tree); + } + return tree; } private Set findSpecializedExecutableTypes(NodeExecutionData execution, TypeMirror type) { @@ -1554,8 +1582,8 @@ } private Element createFastPathExecuteMethod(SpecializationData specialization, ExecutableTypeData executedType, List allTypes) { - LocalContext currentLocals = LocalContext.load(this, executedType.getEvaluatedCount(), varArgsThreshold); - CodeExecutableElement executable = createExecuteMethod(specialization, executedType, currentLocals, false); + LocalContext currentLocals = LocalContext.load(this, executedType, Integer.MAX_VALUE); + CodeExecutableElement executable = createExecuteMethod(specialization, executedType, currentLocals, false, Integer.MAX_VALUE); CodeTreeBuilder builder = executable.createBuilder(); if (specialization == null) { if (executedType.getDelegatedTo() == null) { @@ -1569,28 +1597,17 @@ return executable; } - private CodeExecutableElement createExecuteMethod(SpecializationData specialization, ExecutableTypeData executedType, LocalContext currentLocals, boolean originalOverride) { + private static final String VARARGS_NAME = "args"; + + private CodeExecutableElement createExecuteMethod(SpecializationData specialization, ExecutableTypeData executedType, LocalContext currentLocals, boolean originalOverride, int varArgs) { TypeMirror returnType = executedType.getReturnType(); - TypeMirror frame = executedType.getFrameParameter(); - List evaluatedParameters = executedType.getEvaluatedParameters(); if (specialization != null) { currentLocals.loadFastPathState(specialization); } - if (frame == null) { - currentLocals.removeValue(FRAME_VALUE); - } else { - currentLocals.set(FRAME_VALUE, currentLocals.get(FRAME_VALUE).newType(frame)); - } - - for (int i = 0; i < Math.min(node.getChildExecutions().size(), evaluatedParameters.size()); i++) { - NodeExecutionData execution = node.getChildExecutions().get(i); - currentLocals.setValue(execution, currentLocals.getValue(execution).newType(evaluatedParameters.get(i))); - } - String methodName; - if (originalOverride) { + if (originalOverride && executedType.getMethod() != null) { methodName = executedType.getMethod().getSimpleName().toString(); } else { methodName = executedType.getUniqueName(); @@ -1608,32 +1625,13 @@ ((CodeVariableElement) executable.getParameters().get(0)).setName(FRAME_VALUE); } - final String varArgsName = "args"; if (executable.isVarArgs()) { - ((CodeVariableElement) executable.getParameters().get(executable.getParameters().size() - 1)).setName(varArgsName); + ((CodeVariableElement) executable.getParameters().get(executable.getParameters().size() - 1)).setName(VARARGS_NAME); } - // rename varargs parameter - int signatureIndex = 0; - for (TypeMirror parameter : executedType.getEvaluatedParameters()) { - LocalVariable var = currentLocals.getValue(signatureIndex); - if (var != null) { - int varArgsIndex = executedType.getVarArgsIndex(executedType.getParameterIndex(signatureIndex)); - if (varArgsIndex >= 0) { - var = var.accessWith(CodeTreeBuilder.singleString(varArgsName + "[" + varArgsIndex + "]")); - } else { - ((CodeVariableElement) executable.getParameters().get(executedType.getParameterIndex(signatureIndex))).setName(var.getName()); - } - if (!isObject(parameter)) { - var = var.newType(parameter); - } - currentLocals.setValue(node.getChildExecutions().get(signatureIndex), var); - } - - signatureIndex++; - } + renameOriginalParameters(executedType, executable, currentLocals); } else { - executable = currentLocals.createMethod(modifiers(PUBLIC), returnType, methodName, FRAME_VALUE); + executable = currentLocals.createMethod(modifiers(PUBLIC), returnType, methodName, varArgs, FRAME_VALUE); } executable.getThrownTypes().clear(); @@ -1644,6 +1642,47 @@ return executable; } + private void renameOriginalParameters(ExecutableTypeData executedType, CodeExecutableElement executable, LocalContext currentLocals) { + // rename varargs parameter + int evaluatedIndex = 0; + for (int executionIndex = 0; executionIndex < node.getExecutionCount(); executionIndex++) { + NodeExecutionData execution = node.getChildExecutions().get(executionIndex); + if (execution.isShortCircuit()) { + if (evaluatedIndex < executedType.getEvaluatedCount()) { + TypeMirror evaluatedType = executedType.getEvaluatedParameters().get(evaluatedIndex); + LocalVariable shortCircuit = currentLocals.getShortCircuit(execution); + if (shortCircuit != null) { + currentLocals.setShortCircuitValue(execution, renameExecutableTypeParameter(executable, executedType, evaluatedIndex, evaluatedType, shortCircuit)); + } + evaluatedIndex++; + } + } + if (evaluatedIndex < executedType.getEvaluatedCount()) { + TypeMirror evaluatedType = executedType.getEvaluatedParameters().get(evaluatedIndex); + LocalVariable value = currentLocals.getValue(execution); + if (value != null) { + currentLocals.setValue(execution, renameExecutableTypeParameter(executable, executedType, evaluatedIndex, evaluatedType, value)); + } + evaluatedIndex++; + } + } + } + + private static LocalVariable renameExecutableTypeParameter(CodeExecutableElement method, ExecutableTypeData executedType, int evaluatedIndex, TypeMirror targetType, LocalVariable var) { + int parameterIndex = executedType.getParameterIndex(evaluatedIndex); + int varArgsIndex = executedType.getVarArgsIndex(parameterIndex); + LocalVariable returnVar = var; + if (varArgsIndex >= 0) { + returnVar = returnVar.accessWith(CodeTreeBuilder.singleString(VARARGS_NAME + "[" + varArgsIndex + "]")); + } else { + ((CodeVariableElement) method.getParameters().get(parameterIndex)).setName(returnVar.getName()); + } + if (!isObject(targetType)) { + returnVar = returnVar.newType(targetType); + } + return returnVar; + } + private boolean needsUnexpectedResultException(ExecutableTypeData executedType) { if (!executedType.hasUnexpectedValue(context)) { return false; @@ -1670,8 +1709,9 @@ delegate = findFastPathDelegate((specialization != null ? specialization.getReturnType().getType() : genericType), executableType, allTypes); } + int delegateSignatureCount = delegate != null ? delegate.getSignatureParameters().size() : 0; for (NodeExecutionData execution : node.getChildExecutions()) { - if (specialization == null && delegate != null && execution.getIndex() >= delegate.getEvaluatedCount()) { + if (specialization == null && delegate != null && execution.getIndex() >= delegateSignatureCount) { // we just evaluate children for the next delegate continue; } else if (specialization != null && delegate != null) { @@ -1794,15 +1834,21 @@ private LocalVariable resolveShortCircuit(SpecializationData specialization, NodeExecutionData execution, LocalContext currentLocals) { LocalVariable shortCircuit = null; - SpecializationData resolvedSpecialization = specialization; - if (specialization == null) { - resolvedSpecialization = node.getGenericSpecialization(); - } - if (execution.isShortCircuit()) { - ShortCircuitData shortCircuitData = resolvedSpecialization.getShortCircuits().get(calculateShortCircuitIndex(execution)); - CodeTree access = callTemplateMethod(accessParent(null), shortCircuitData, currentLocals); - shortCircuit = currentLocals.createShortCircuitValue(execution).accessWith(access); + shortCircuit = currentLocals.getShortCircuit(execution); + + if (shortCircuit == null) { + SpecializationData resolvedSpecialization = specialization; + if (specialization == null) { + resolvedSpecialization = node.getGenericSpecialization(); + } + ShortCircuitData shortCircuitData = resolvedSpecialization.getShortCircuits().get(calculateShortCircuitIndex(execution)); + CodeTree access = callTemplateMethod(accessParent(null), shortCircuitData, currentLocals); + shortCircuit = currentLocals.createShortCircuitValue(execution).accessWith(access); + } else { + CodeTree access = shortCircuit.createReference(); + shortCircuit = shortCircuit.nextName().accessWith(access); + } } return shortCircuit; } @@ -2016,9 +2062,13 @@ } private CodeExecutableElement createExecuteChildMethod(NodeExecutionData execution, TypeMirror targetType) { - LocalContext locals = LocalContext.load(this, 0, varArgsThreshold); - - CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), targetType, executeChildMethodName(execution, targetType), FRAME_VALUE); + if (!usedExecuteChildMethods.contains(execution)) { + return null; + } + + LocalContext locals = LocalContext.load(this, createSpecializationNodeSignature(0), Integer.MAX_VALUE); + + CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), targetType, executeChildMethodName(execution, targetType), Integer.MAX_VALUE, FRAME_VALUE); if (hasChildUnexpectedResult(execution, targetType)) { method.getThrownTypes().add(getType(UnexpectedResultException.class)); } @@ -2047,6 +2097,10 @@ private CodeVariableElement createImplicitProfileParameter(NodeExecutionData execution, TypeMirror targetType) { if (typeSystem.hasImplicitSourceTypes(targetType)) { + if (typeEquals(node.getGenericType(execution), targetType)) { + return null; + } + switch (options.implicitCastOptimization()) { case NONE: return null; @@ -2185,6 +2239,7 @@ if (!isExecuteChildShared(execution, targetValue.getTypeMirror())) { throw new AssertionError("Execute child not shared with method but called."); } + usedExecuteChildMethods.add(execution); CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); builder.tree(targetValue.createReference()).string(" = "); @@ -2594,20 +2649,59 @@ } } - public CodeExecutableElement createMethod(Set modifiers, TypeMirror returnType, String name, String... optionalArguments) { + public CodeExecutableElement createMethod(Set modifiers, TypeMirror returnType, String name, int varArgsThreshold, String... optionalArguments) { CodeExecutableElement method = new CodeExecutableElement(modifiers, returnType, name); - addParametersTo(method, optionalArguments); + addParametersTo(method, varArgsThreshold, optionalArguments); return method; } - public static LocalContext load(NodeGenFactory factory, int signatureSize, int varargsThreshold) { + public static LocalContext load(NodeGenFactory factory, ExecutableTypeData type, int varargsThreshold) { LocalContext context = new LocalContext(factory); - context.loadValues(signatureSize, varargsThreshold); + context.loadEvaluatedValues(type, varargsThreshold); return context; } + private void loadEvaluatedValues(ExecutableTypeData executedType, int varargsThreshold) { + TypeMirror frame = executedType.getFrameParameter(); + if (frame == null) { + removeValue(FRAME_VALUE); + } else { + set(FRAME_VALUE, new LocalVariable(frame, FRAME_VALUE, null, null)); + } + for (NodeFieldData field : factory.node.getFields()) { + String fieldName = fieldValueName(field); + values.put(fieldName, new LocalVariable(field.getType(), fieldName, factory.accessParent(field.getName()), null)); + } + boolean varargs = needsVarargs(false, varargsThreshold); + List evaluatedParameter = executedType.getEvaluatedParameters(); + int evaluatedIndex = 0; + for (int executionIndex = 0; executionIndex < factory.node.getExecutionCount(); executionIndex++) { + NodeExecutionData execution = factory.node.getChildExecutions().get(executionIndex); + if (execution.isShortCircuit()) { + if (evaluatedIndex < executedType.getEvaluatedCount()) { + TypeMirror evaluatedType = evaluatedParameter.get(evaluatedIndex); + LocalVariable shortCircuit = createShortCircuitValue(execution).newType(evaluatedType); + if (varargs) { + shortCircuit = shortCircuit.accessWith(createReadVarargs(evaluatedIndex)); + } + values.put(shortCircuit.getName(), shortCircuit.makeOriginal()); + evaluatedIndex++; + } + } + if (evaluatedIndex < executedType.getEvaluatedCount()) { + TypeMirror evaluatedType = evaluatedParameter.get(evaluatedIndex); + LocalVariable value = createValue(execution, evaluatedType); + if (varargs) { + value = value.accessWith(createReadVarargs(evaluatedIndex)); + } + values.put(value.getName(), value.makeOriginal()); + evaluatedIndex++; + } + } + } + public static LocalContext load(NodeGenFactory factory) { - return load(factory, factory.node.getSignatureSize(), factory.varArgsThreshold); + return load(factory, factory.createSpecializationNodeSignature(factory.node.getSignatureSize()), factory.varArgsThreshold); } public LocalContext copy() { @@ -2701,36 +2795,6 @@ return size >= varArgsThreshold; } - private void loadValues(int evaluatedArguments, int varargsThreshold) { - values.put(FRAME_VALUE, new LocalVariable(factory.getType(Frame.class), FRAME_VALUE, null, null)); - - for (NodeFieldData field : factory.node.getFields()) { - String fieldName = fieldValueName(field); - values.put(fieldName, new LocalVariable(field.getType(), fieldName, factory.accessParent(field.getName()), null)); - } - - boolean varargs = needsVarargs(false, varargsThreshold); - for (int i = 0; i < evaluatedArguments; i++) { - List childExecutions = factory.node.getChildExecutions(); - if (i >= childExecutions.size()) { - break; - } - NodeExecutionData execution = childExecutions.get(i); - if (execution.isShortCircuit()) { - LocalVariable shortCircuit = createShortCircuitValue(execution).makeGeneric(factory.context); - if (varargs) { - shortCircuit = shortCircuit.accessWith(createReadVarargs(i)); - } - values.put(shortCircuit.getName(), shortCircuit.makeOriginal()); - } - LocalVariable value = createValue(execution, factory.genericType); - if (varargs) { - value = value.accessWith(createReadVarargs(i)); - } - values.put(value.getName(), value.makeOriginal()); - } - } - private static CodeTree createReadVarargs(int i) { return CodeTreeBuilder.createBuilder().string("args_[").string(String.valueOf(i)).string("]").build(); } @@ -2766,14 +2830,14 @@ } } - public void addParametersTo(CodeExecutableElement method, String... optionalNames) { + public void addParametersTo(CodeExecutableElement method, int varArgsThreshold, String... optionalNames) { for (String var : optionalNames) { LocalVariable local = values.get(var); if (local != null) { method.addParameter(local.createParameter()); } } - if (needsVarargs(true, factory.varArgsThreshold)) { + if (needsVarargs(true, varArgsThreshold)) { method.addParameter(new CodeVariableElement(factory.getType(Object[].class), "args_")); method.setVarArgs(true); } else { diff -r b99da6d86cfe -r 6361fa2e3321 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java Wed Apr 15 21:35:51 2015 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java Wed Apr 15 21:13:43 2015 +0200 @@ -163,21 +163,36 @@ if (typeEquals(type1, type2)) { return type1; } - TypeElement element1 = fromTypeMirror(type1); - TypeElement element2 = fromTypeMirror(type2); - if (element1 == null || element2 == null) { - if (element1 != null) { - return type1; - } else if (element2 != null) { - return type2; - } + if (isVoid(type1)) { + return type2; + } else if (isVoid(type2)) { + return type1; + } + if (isObject(type1)) { + return type1; + } else if (isObject(type2)) { + return type2; + } + + if (isPrimitive(type1) || isPrimitive(type2)) { return context.getType(Object.class); } - List element1Types = getDirectSuperTypes(element1); - element1Types.add(0, element1); - List element2Types = getDirectSuperTypes(element2); - element2Types.add(0, element2); + if (isSubtype(type1, type2)) { + return type2; + } else if (isSubtype(type2, type1)) { + return type1; + } + + TypeElement element1 = fromTypeMirror(type1); + TypeElement element2 = fromTypeMirror(type2); + + if (element1 == null || element2 == null) { + return context.getType(Object.class); + } + + List element1Types = getSuperTypes(element1); + List element2Types = getSuperTypes(element2); for (TypeElement superType1 : element1Types) { for (TypeElement superType2 : element2Types) { @@ -186,6 +201,7 @@ } } } + return context.getType(Object.class); } diff -r b99da6d86cfe -r 6361fa2e3321 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/AnnotatedParameterSpec.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/AnnotatedParameterSpec.java Wed Apr 15 21:35:51 2015 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/AnnotatedParameterSpec.java Wed Apr 15 21:13:43 2015 +0200 @@ -43,6 +43,11 @@ } @Override + public boolean isAnnotated() { + return true; + } + + @Override public boolean matches(VariableElement variable) { if (ElementUtils.findAnnotationMirror(variable.getAnnotationMirrors(), annotationType) != null) { return true; diff -r b99da6d86cfe -r 6361fa2e3321 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ExecutableTypeData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ExecutableTypeData.java Wed Apr 15 21:35:51 2015 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ExecutableTypeData.java Wed Apr 15 21:13:43 2015 +0200 @@ -35,6 +35,7 @@ public class ExecutableTypeData extends MessageContainer implements Comparable { + private final NodeData node; private final ExecutableElement method; private final TypeMirror returnType; private final TypeMirror frameParameter; @@ -44,7 +45,8 @@ private String uniqueName; - public ExecutableTypeData(TypeMirror returnType, String uniqueName, TypeMirror frameParameter, List evaluatedParameters) { + public ExecutableTypeData(NodeData node, TypeMirror returnType, String uniqueName, TypeMirror frameParameter, List evaluatedParameters) { + this.node = node; this.returnType = returnType; this.frameParameter = frameParameter; this.evaluatedParameters = evaluatedParameters; @@ -52,7 +54,8 @@ this.method = null; } - public ExecutableTypeData(ExecutableElement method, int signatureSize, List frameTypes) { + public ExecutableTypeData(NodeData node, ExecutableElement method, int signatureSize, List frameTypes) { + this.node = node; this.method = method; this.returnType = method.getReturnType(); TypeMirror foundFrameParameter = null; @@ -123,6 +126,21 @@ return evaluatedParameters; } + public List getSignatureParameters() { + List signaturetypes = new ArrayList<>(); + int index = 0; + for (NodeExecutionData execution : node.getChildExecutions()) { + if (execution.isShortCircuit()) { + index++; + } + if (index < getEvaluatedCount()) { + signaturetypes.add(getEvaluatedParameters().get(index)); + } + index++; + } + return signaturetypes; + } + public int getVarArgsIndex(int parameterIndex) { if (method.isVarArgs()) { int index = parameterIndex - (method.getParameters().size() - 1); @@ -159,7 +177,7 @@ return evaluatedParameters.size(); } - public boolean canDelegateTo(NodeData node, ExecutableTypeData to) { + public boolean canDelegateTo(ExecutableTypeData to) { ExecutableTypeData from = this; if (to.getEvaluatedCount() < from.getEvaluatedCount()) { return false; @@ -189,8 +207,10 @@ } } - for (int i = from.getEvaluatedCount(); i < to.getEvaluatedCount(); i++) { - TypeMirror delegateToParameter = to.getEvaluatedParameters().get(i); + List fromSignatureParameters = from.getSignatureParameters(); + List toSignatureParameters = to.getSignatureParameters(); + for (int i = fromSignatureParameters.size(); i < toSignatureParameters.size(); i++) { + TypeMirror delegateToParameter = toSignatureParameters.get(i); if (i < node.getChildExecutions().size()) { TypeMirror genericType = node.getGenericType(node.getChildExecutions().get(i)); if (!isSubtypeBoxed(context, genericType, delegateToParameter)) { @@ -206,6 +226,14 @@ ExecutableTypeData o1 = this; ProcessorContext context = ProcessorContext.getInstance(); + if (canDelegateTo(o2)) { + if (!o2.canDelegateTo(this)) { + return 1; + } + } else if (o2.canDelegateTo(this)) { + return -1; + } + int result = Integer.compare(o2.getEvaluatedCount(), o1.getEvaluatedCount()); if (result != 0) { return result; @@ -282,9 +310,22 @@ } } + public String getName() { + if (method != null) { + return method.getSimpleName().toString(); + } else { + return getUniqueName(); + } + + } + + private static String formatType(TypeMirror type) { + return type == null ? "null" : ElementUtils.getSimpleName(type); + } + @Override public String toString() { - return method != null ? ElementUtils.createReferenceName(method) : getUniqueName() + evaluatedParameters.toString(); + return String.format("%s %s(%s,%s)", formatType(getReturnType()), getName(), formatType(getFrameParameter()), getEvaluatedParameters()); } public boolean sameParameters(ExecutableTypeData other) { diff -r b99da6d86cfe -r 6361fa2e3321 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java Wed Apr 15 21:35:51 2015 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java Wed Apr 15 21:13:43 2015 +0200 @@ -134,8 +134,19 @@ return types; } + public int getExecutionCount() { + return getChildExecutions().size(); + } + public int getSignatureSize() { - return getChildExecutions().size(); + int count = 0; + for (NodeExecutionData execution : getChildExecutions()) { + if (execution.isShortCircuit()) { + count++; + } + count++; + } + return count; } public boolean isFrameUsedByAnyGuard() { @@ -567,20 +578,17 @@ if (executable.hasUnexpectedValue(getContext())) { continue; } - if (!typeSystem.hasImplicitSourceTypes(executable.getReturnType())) { - types.add(executable.getReturnType()); - } + types.add(executable.getReturnType()); } } int executionIndex = execution.getIndex(); if (executionIndex >= 0) { for (ExecutableTypeData typeData : getExecutableTypes()) { - if (executionIndex < typeData.getEvaluatedCount()) { - TypeMirror genericType = typeData.getEvaluatedParameters().get(executionIndex); - if (!typeSystem.hasImplicitSourceTypes(genericType)) { - types.add(genericType); - } + List signatureParameters = typeData.getSignatureParameters(); + if (executionIndex < signatureParameters.size()) { + TypeMirror genericType = signatureParameters.get(executionIndex); + types.add(genericType); } } } diff -r b99da6d86cfe -r 6361fa2e3321 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ParameterSpec.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ParameterSpec.java Wed Apr 15 21:35:51 2015 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ParameterSpec.java Wed Apr 15 21:13:43 2015 +0200 @@ -59,6 +59,10 @@ this.anyType = anyTypeTemp; } + public boolean isAnnotated() { + return false; + } + public ParameterSpec(ParameterSpec original, TypeMirror newType) { this(original.name, newType); this.local = original.local; diff -r b99da6d86cfe -r 6361fa2e3321 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java Wed Apr 15 21:35:51 2015 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java Wed Apr 15 21:13:43 2015 +0200 @@ -167,14 +167,6 @@ return kind == SpecializationKind.POLYMORPHIC; } - public List getDynamicParameters() { - List uncachedParameters = new ArrayList<>(getParameters()); - for (CacheExpression cacheExpression : getCaches()) { - uncachedParameters.remove(cacheExpression.getParameter()); - } - return uncachedParameters; - } - @Override protected List findChildContainers() { List sinks = new ArrayList<>(); @@ -304,7 +296,7 @@ @Override public String toString() { - return String.format("%s [id = %s, method = %s, guards = %s, signature = %s]", getClass().getSimpleName(), getId(), getMethod(), getGuards(), getTypeSignature()); + return String.format("%s [id = %s, method = %s, guards = %s, signature = %s]", getClass().getSimpleName(), getId(), getMethod(), getGuards(), getDynamicTypes()); } public boolean isFrameUsed() { diff -r b99da6d86cfe -r 6361fa2e3321 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethod.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethod.java Wed Apr 15 21:35:51 2015 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethod.java Wed Apr 15 21:13:43 2015 +0200 @@ -153,6 +153,14 @@ newParameter.setMethod(this); } + public Iterable getDynamicParameters() { + return new FilteredIterable<>(getParameters(), new Predicate() { + public boolean evaluate(Parameter value) { + return !value.getSpecification().isLocal() && !value.getSpecification().isAnnotated(); + } + }); + } + public Iterable getSignatureParameters() { return new FilteredIterable<>(getParameters(), new Predicate() { public boolean evaluate(Parameter value) { @@ -291,8 +299,8 @@ } public int compareBySignature(TemplateMethod compareMethod) { - List signature1 = getSignatureTypes(this); - List signature2 = getSignatureTypes(compareMethod); + List signature1 = getDynamicTypes(); + List signature2 = compareMethod.getDynamicTypes(); int result = 0; for (int i = 0; i < Math.max(signature1.size(), signature2.size()); i++) { @@ -307,9 +315,9 @@ return result; } - public static List getSignatureTypes(TemplateMethod method) { + public List getDynamicTypes() { List types = new ArrayList<>(); - for (Parameter param : method.getSignatureParameters()) { + for (Parameter param : getDynamicParameters()) { types.add(param.getType()); } return types; diff -r b99da6d86cfe -r 6361fa2e3321 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java Wed Apr 15 21:35:51 2015 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java Wed Apr 15 21:13:43 2015 +0200 @@ -148,7 +148,7 @@ node.getFields().addAll(parseFields(lookupTypes, members)); node.getChildren().addAll(parseChildren(lookupTypes, members)); node.getChildExecutions().addAll(parseExecutions(node.getFields(), node.getChildren(), members)); - node.getExecutableTypes().addAll(parseExecutableTypeData(members, node.getChildExecutions().size(), context.getFrameTypes(), false)); + node.getExecutableTypes().addAll(parseExecutableTypeData(node, members, node.getSignatureSize(), context.getFrameTypes(), false)); initializeExecutableTypes(node); initializeImportGuards(node, lookupTypes, members); @@ -188,8 +188,13 @@ SpecializationData polymorphic = node.getPolymorphicSpecialization(); if (polymorphic != null) { boolean polymorphicSignatureFound = false; - TypeMirror frame = polymorphic.getFrame() != null ? polymorphic.getFrame().getType() : null; - ExecutableTypeData polymorphicType = new ExecutableTypeData(polymorphic.getReturnType().getType(), "execute", frame, TemplateMethod.getSignatureTypes(polymorphic)); + List dynamicTypes = polymorphic.getDynamicTypes(); + TypeMirror frame = null; + if (polymorphic.getFrame() != null) { + frame = dynamicTypes.remove(0); + } + + ExecutableTypeData polymorphicType = new ExecutableTypeData(node, polymorphic.getReturnType().getType(), "execute", frame, dynamicTypes); for (ExecutableTypeData type : node.getExecutableTypes()) { if (polymorphicType.sameSignature(type)) { polymorphicSignatureFound = true; @@ -214,9 +219,11 @@ } } if (!additionalAbstractRootTypes.isEmpty()) { - node.addError("Incompatible abstract execute methods found %s.", rootTypes); + node.addError("Incompatible abstract execute methods found %s.", additionalAbstractRootTypes); } + namesUnique(node.getExecutableTypes()); + } private static List buildExecutableHierarchy(NodeData node) { @@ -235,7 +242,7 @@ private static void buildExecutableHierarchy(NodeData node, ExecutableTypeData parent, ListIterator executesIterator) { while (executesIterator.hasNext()) { ExecutableTypeData other = executesIterator.next(); - if (other.canDelegateTo(node, parent)) { + if (other.canDelegateTo(parent)) { parent.addDelegatedFrom(other); executesIterator.remove(); } @@ -574,7 +581,7 @@ return executions; } - private List parseExecutableTypeData(List elements, int signatureSize, List frameTypes, boolean includeFinals) { + private List parseExecutableTypeData(NodeData node, List elements, int signatureSize, List frameTypes, boolean includeFinals) { List typeData = new ArrayList<>(); for (ExecutableElement method : ElementFilter.methodsIn(elements)) { Set modifiers = method.getModifiers(); @@ -592,7 +599,7 @@ continue; } - ExecutableTypeData executableType = new ExecutableTypeData(method, signatureSize, context.getFrameTypes()); + ExecutableTypeData executableType = new ExecutableTypeData(node, method, signatureSize, context.getFrameTypes()); if (executableType.getFrameParameter() != null) { boolean supportedType = false; @@ -610,8 +617,12 @@ typeData.add(executableType); } - Collections.sort(typeData); + namesUnique(typeData); + return typeData; + } + + private static void namesUnique(List typeData) { List names = new ArrayList<>(); for (ExecutableTypeData type : typeData) { names.add(type.getUniqueName()); @@ -623,8 +634,6 @@ for (int i = 0; i < typeData.size(); i++) { typeData.get(i).setUniqueName(names.get(i)); } - - return typeData; } private void initializeExecutableTypes(NodeData node) { @@ -632,9 +641,7 @@ Set inconsistentFrameTypes = new HashSet<>(); TypeMirror frameType = null; - Set evaluatedCounts = new HashSet<>(); for (ExecutableTypeData execute : allExecutes) { - evaluatedCounts.add(execute.getEvaluatedCount()); TypeMirror frame = execute.getFrameParameter(); TypeMirror resolvedFrameType; @@ -788,7 +795,7 @@ if (parentNode.getFrameType() != null) { frameTypes = Arrays.asList(parentNode.getFrameType()); } - node.getExecutableTypes().addAll(parseExecutableTypeData(members, child.getExecuteWith().size(), frameTypes, true)); + node.getExecutableTypes().addAll(parseExecutableTypeData(node, members, child.getExecuteWith().size(), frameTypes, true)); node.setFrameType(parentNode.getFrameType()); return node; } @@ -1297,26 +1304,11 @@ } } - private void initializeUninitialized(final NodeData node) { + private static void initializeUninitialized(final NodeData node) { SpecializationData generic = node.getGenericSpecialization(); if (generic == null) { return; } - for (Parameter parameter : generic.getReturnTypeAndParameters()) { - if (ElementUtils.isObject(parameter.getType())) { - continue; - } - Set types = new HashSet<>(); - for (SpecializationData specialization : node.getSpecializations()) { - Parameter actualParameter = specialization.findParameter(parameter.getLocalName()); - if (actualParameter != null) { - types.add(ElementUtils.getQualifiedName(actualParameter.getType())); - } - } - if (types.size() > 1) { - generic.replaceParameter(parameter.getLocalName(), new Parameter(parameter, context.getType(Object.class))); - } - } TemplateMethod uninializedMethod = new TemplateMethod("Uninitialized", -1, node, generic.getSpecification(), null, null, generic.getReturnType(), generic.getParameters()); // should not use messages from generic specialization uninializedMethod.getMessages().clear(); @@ -1329,7 +1321,6 @@ } SpecializationData generic = node.getGenericSpecialization(); - List types = new ArrayList<>(); Collection frameTypes = new HashSet<>(); @@ -1338,6 +1329,10 @@ frameTypes.add(specialization.getFrame().getType()); } } + if (node.supportsFrame()) { + frameTypes.add(node.getFrameType()); + } + if (!frameTypes.isEmpty()) { frameTypes = ElementUtils.uniqueSortedTypes(frameTypes); TypeMirror frameType; @@ -1378,13 +1373,15 @@ if (usedTypes.size() == 1) { polymorphicType = usedTypes.iterator().next(); + } else { + polymorphicType = ElementUtils.getCommonSuperType(context, usedTypes); + } - if (!isReturnParameter && node.getTypeSystem().hasImplicitSourceTypes(polymorphicType)) { - polymorphicType = context.getType(Object.class); - } - } else { - polymorphicType = context.getType(Object.class); + NodeExecutionData execution = genericParameter.getSpecification().getExecution(); + if (execution != null && !ElementUtils.isSubtypeBoxed(context, polymorphicType, node.getGenericType(execution))) { + throw new AssertionError(String.format("Polymorphic types %s not compatible to generic type %s.", polymorphicType, node.getGenericType(execution))); } + } if (isReturnParameter) { returnType = polymorphicType; @@ -1395,8 +1392,11 @@ } SpecializationMethodParser parser = new SpecializationMethodParser(context, node); + SpecializationData polymorphic = parser.create("Polymorphic", TemplateMethod.NO_NATURAL_ORDER, null, null, returnType, types); + if (polymorphic == null) { + throw new AssertionError("Failed to parse polymorphic signature. " + parser.createDefaultMethodSpec(null, null, false, null) + " Types: " + returnType + " - " + types); + } - SpecializationData polymorphic = parser.create("Polymorphic", TemplateMethod.NO_NATURAL_ORDER, null, null, returnType, types); polymorphic.setKind(SpecializationKind.POLYMORPHIC); node.getSpecializations().add(polymorphic); }