diff graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java @ 18775:a069a87b9a02

Truffle-DSL: Added tests and verification of overridable generic execute methods.
author Christian Humer <christian.humer@gmail.com>
date Mon, 05 Jan 2015 01:31:08 +0100
parents 7382bbcac3a3
children c0fb70634640
line wrap: on
line diff
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java	Mon Jan 05 01:31:07 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java	Mon Jan 05 01:31:08 2015 +0100
@@ -148,7 +148,7 @@
             return node; // error sync point
         }
 
-        node.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, node).parse(elements)));
+        initializeExecutableTypes(elements, node);
         initializeChildren(node);
 
         // ensure the processed element has at least one @Specialization annotation.
@@ -374,7 +374,6 @@
                 }
 
                 Element getter = findGetter(elements, name, childType);
-
                 NodeChildData nodeChild = new NodeChildData(type, childMirror, name, childType, originalChildType, getter, cardinality);
 
                 parsedChildren.add(nodeChild);
@@ -527,6 +526,31 @@
         return executions;
     }
 
+    private void initializeExecutableTypes(List<Element> elements, NodeData node) {
+        node.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, node).parse(elements)));
+        List<ExecutableTypeData> genericExecutes = node.getThisExecution().getChild().findGenericExecutableTypes(context);
+
+        List<ExecutableTypeData> overridableGenericExecutes = new ArrayList<>();
+        for (ExecutableTypeData executableTypeData : genericExecutes) {
+            if (!executableTypeData.getMethod().getModifiers().contains(Modifier.FINAL)) {
+                overridableGenericExecutes.add(executableTypeData);
+            }
+        }
+
+        if (overridableGenericExecutes.isEmpty()) {
+            node.addError("No accessible and overridable generic execute method found. Generic execute methods usually have the "
+                            + "signature 'public abstract {Type} executeGeneric(VirtualFrame)' and must not throw any checked exceptions.");
+        }
+
+        if (overridableGenericExecutes.size() > 1) {
+            List<String> methodSignatures = new ArrayList<>();
+            for (ExecutableTypeData type : overridableGenericExecutes) {
+                methodSignatures.add(type.createReferenceName());
+            }
+            node.addWarning("Multiple accessible and overridable generic execute methods found %s. Remove all but one or mark all but one as final.", methodSignatures);
+        }
+    }
+
     private static Map<Integer, List<ExecutableTypeData>> groupExecutableTypes(List<ExecutableTypeData> executableTypes) {
         Map<Integer, List<ExecutableTypeData>> groupedTypes = new TreeMap<>();
         for (ExecutableTypeData type : executableTypes) {
@@ -556,6 +580,9 @@
                 nodeChild.addError("The @%s of the node and the @%s of the @%s does not match. %s != %s. ", TypeSystem.class.getSimpleName(), TypeSystem.class.getSimpleName(),
                                 NodeChild.class.getSimpleName(), ElementUtils.getSimpleName(node.getTypeSystem().getTemplateType()),
                                 ElementUtils.getSimpleName(fieldNodeData.getTypeSystem().getTemplateType()));
+            } else if (nodeChild.findAnyGenericExecutableType(context) == null) {
+                nodeChild.addError("No generic execute method found for child type %s. Generic execute methods usually have the signature 'Object executeGeneric(VirtualFrame)'.",
+                                ElementUtils.getQualifiedName(nodeChild.getNodeType()));
             }
             if (fieldNodeData != null) {
                 List<ExecutableTypeData> types = nodeChild.findGenericExecutableTypes(context);
@@ -983,13 +1010,18 @@
             NodeChildData child = execution.getChild();
             TypeData genericType = null;
             if (types.size() == 1) {
-                ExecutableTypeData executable = child.findExecutableType(context, types.iterator().next());
+                TypeData singleType = types.iterator().next();
+                ExecutableTypeData executable = child.findExecutableType(singleType);
                 if (executable != null && (signatureIndex == 0 || !executable.hasUnexpectedValue(context))) {
-                    genericType = types.iterator().next();
+                    genericType = singleType;
                 }
             }
             if (genericType == null) {
-                genericType = child.findAnyGenericExecutableType(context).getType();
+                ExecutableTypeData type = child.findAnyGenericExecutableType(context);
+                if (type == null) {
+                    throw new AssertionError("No generic type not yet catched by parser.");
+                }
+                genericType = type.getType();
             }
             return genericType.getPrimitiveType();
         }