comparison graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java @ 18776:c0fb70634640

Truffle-DSL: support for frame types Frame, MaterializedFrame. Added validation for frame type consistency. Some refactorings along the way.
author Christian Humer <christian.humer@gmail.com>
date Mon, 05 Jan 2015 01:31:08 +0100
parents a069a87b9a02
children 941761f6b736
comparison
equal deleted inserted replaced
18775:a069a87b9a02 18776:c0fb70634640
43 public class NodeParser extends AbstractParser<NodeData> { 43 public class NodeParser extends AbstractParser<NodeData> {
44 44
45 public static final List<Class<? extends Annotation>> ANNOTATIONS = Arrays.asList(Fallback.class, TypeSystemReference.class, ShortCircuit.class, Specialization.class, NodeChild.class, 45 public static final List<Class<? extends Annotation>> ANNOTATIONS = Arrays.asList(Fallback.class, TypeSystemReference.class, ShortCircuit.class, Specialization.class, NodeChild.class,
46 NodeChildren.class); 46 NodeChildren.class);
47 47
48 private Map<String, NodeData> parsedNodes;
49
50 @Override 48 @Override
51 protected NodeData parse(Element element, AnnotationMirror mirror) { 49 protected NodeData parse(Element element, AnnotationMirror mirror) {
52 NodeData node = null; 50 NodeData node = parseRootType((TypeElement) element);
53 try { 51 if (Log.isDebug() && node != null) {
54 parsedNodes = new HashMap<>(); 52 String dump = node.dump();
55 node = resolveNode((TypeElement) element); 53 log.message(Kind.ERROR, null, null, null, dump);
56 if (Log.DEBUG) { 54 }
57 NodeData parsed = parsedNodes.get(ElementUtils.getQualifiedName((TypeElement) element));
58 if (node != null) {
59 String dump = parsed.dump();
60 log.message(Kind.ERROR, null, null, null, dump);
61 }
62 }
63 } finally {
64 parsedNodes = null;
65 }
66
67 return node; 55 return node;
68 } 56 }
69 57
70 @Override 58 @Override
71 protected NodeData filterErrorElements(NodeData model) { 59 protected NodeData filterErrorElements(NodeData model) {
94 @Override 82 @Override
95 public List<Class<? extends Annotation>> getTypeDelegatedAnnotationTypes() { 83 public List<Class<? extends Annotation>> getTypeDelegatedAnnotationTypes() {
96 return ANNOTATIONS; 84 return ANNOTATIONS;
97 } 85 }
98 86
99 private NodeData resolveNode(TypeElement rootType) { 87 private NodeData parseRootType(TypeElement rootType) {
100 String typeName = ElementUtils.getQualifiedName(rootType);
101 if (parsedNodes.containsKey(typeName)) {
102 return parsedNodes.get(typeName);
103 }
104
105 List<NodeData> enclosedNodes = new ArrayList<>(); 88 List<NodeData> enclosedNodes = new ArrayList<>();
106 for (TypeElement enclosedType : ElementFilter.typesIn(rootType.getEnclosedElements())) { 89 for (TypeElement enclosedType : ElementFilter.typesIn(rootType.getEnclosedElements())) {
107 NodeData enclosedChild = resolveNode(enclosedType); 90 NodeData enclosedChild = parseRootType(enclosedType);
108 if (enclosedChild != null) { 91 if (enclosedChild != null) {
109 enclosedNodes.add(enclosedChild); 92 enclosedNodes.add(enclosedChild);
110 } 93 }
111 } 94 }
112
113 NodeData node = parseNode(rootType); 95 NodeData node = parseNode(rootType);
114 if (node == null && !enclosedNodes.isEmpty()) { 96 if (node == null && !enclosedNodes.isEmpty()) {
115 node = new NodeData(context, rootType); 97 node = new NodeData(context, rootType);
116 } 98 }
117 99
118 if (node != null) { 100 if (node != null) {
119 for (NodeData enclosedNode : enclosedNodes) { 101 for (NodeData enclosedNode : enclosedNodes) {
120 node.addEnclosedNode(enclosedNode); 102 node.addEnclosedNode(enclosedNode);
121 } 103 }
122 } 104 }
123
124 parsedNodes.put(typeName, node);
125 return node; 105 return node;
126 } 106 }
127 107
128 private NodeData parseNode(TypeElement originalTemplateType) { 108 private NodeData parseNode(TypeElement originalTemplateType) {
129 // reloading the type elements is needed for ecj 109 // reloading the type elements is needed for ecj
132 if (ElementUtils.findAnnotationMirror(processingEnv, originalTemplateType, GeneratedBy.class) != null) { 112 if (ElementUtils.findAnnotationMirror(processingEnv, originalTemplateType, GeneratedBy.class) != null) {
133 // generated nodes should not get called again. 113 // generated nodes should not get called again.
134 return null; 114 return null;
135 } 115 }
136 116
137 List<TypeElement> lookupTypes = collectSuperClasses(new ArrayList<TypeElement>(), templateType);
138 if (!ElementUtils.isAssignable(templateType.asType(), context.getTruffleTypes().getNode())) { 117 if (!ElementUtils.isAssignable(templateType.asType(), context.getTruffleTypes().getNode())) {
139 return null; 118 return null;
140 } 119 }
141 List<Element> elements = new ArrayList<>(CompilerFactory.getCompiler(templateType).getAllMembersInDeclarationOrder(context.getEnvironment(), templateType)); 120
142 121 List<TypeElement> lookupTypes = collectSuperClasses(new ArrayList<TypeElement>(), templateType);
143 NodeData node = parseNodeData(templateType, elements, lookupTypes); 122 List<Element> members = loadMembers(templateType);
144 123 // ensure the processed element has at least one @Specialization annotation.
145 parseImportGuards(node, lookupTypes, elements); 124 if (!containsSpecializations(members)) {
125 return null;
126 }
127
128 NodeData node = parseNodeData(templateType, lookupTypes);
129
130 node.getAssumptions().addAll(parseAssumptions(lookupTypes));
131 node.getFields().addAll(parseFields(lookupTypes, members));
132 node.getChildren().addAll(parseChildren(lookupTypes, members));
133 node.getChildExecutions().addAll(parseExecutions(node.getChildren(), members));
134 node.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, node, context.getFrameTypes()).parse(members)));
135
136 initializeExecutableTypes(node);
137 initializeImportGuards(node, lookupTypes, members);
146 138
147 if (node.hasErrors()) { 139 if (node.hasErrors()) {
148 return node; // error sync point 140 return node; // error sync point
149 } 141 }
150 142
151 initializeExecutableTypes(elements, node);
152 initializeChildren(node); 143 initializeChildren(node);
153 144
154 // ensure the processed element has at least one @Specialization annotation. 145 if (node.hasErrors()) {
146 return node; // error sync point
147 }
148
149 node.getSpecializations().addAll(new SpecializationMethodParser(context, node).parse(members));
150 node.getSpecializations().addAll(new GenericParser(context, node).parse(members));
151 node.getCasts().addAll(new CreateCastParser(context, node).parse(members));
152 node.getShortCircuits().addAll(new ShortCircuitParser(context, node).parse(members));
153
154 if (node.hasErrors()) {
155 return node; // error sync point
156 }
157
158 verifySpecializationSameLength(node);
159 initializeSpecializations(members, node);
160 initializeShortCircuits(node); // requires specializations and polymorphic specializations
161
162 verifyVisibilities(node);
163 verifyMissingAbstractMethods(node, members);
164 verifyConstructors(node);
165 verifyNamingConvention(node.getShortCircuits(), "needs");
166 verifySpecializationThrows(node);
167 return node;
168 }
169
170 private ArrayList<Element> loadMembers(TypeElement templateType) {
171 return new ArrayList<>(CompilerFactory.getCompiler(templateType).getAllMembersInDeclarationOrder(context.getEnvironment(), templateType));
172 }
173
174 private boolean containsSpecializations(List<Element> elements) {
155 boolean foundSpecialization = false; 175 boolean foundSpecialization = false;
156 for (ExecutableElement method : ElementFilter.methodsIn(elements)) { 176 for (ExecutableElement method : ElementFilter.methodsIn(elements)) {
157 if (ElementUtils.findAnnotationMirror(processingEnv, method, Specialization.class) != null) { 177 if (ElementUtils.findAnnotationMirror(processingEnv, method, Specialization.class) != null) {
158 foundSpecialization = true; 178 foundSpecialization = true;
159 break; 179 break;
160 } 180 }
161 } 181 }
162 if (!foundSpecialization) { 182 return foundSpecialization;
163 return node; 183 }
164 } 184
165 185 private void initializeImportGuards(NodeData node, List<TypeElement> lookupTypes, List<Element> elements) {
166 if (node.hasErrors()) {
167 return node; // error sync point
168 }
169
170 node.getSpecializations().addAll(new SpecializationMethodParser(context, node).parse(elements));
171 node.getSpecializations().addAll(new GenericParser(context, node).parse(elements));
172 node.getCasts().addAll(new CreateCastParser(context, node).parse(elements));
173 node.getShortCircuits().addAll(new ShortCircuitParser(context, node).parse(elements));
174
175 if (node.hasErrors()) {
176 return node; // error sync point
177 }
178
179 verifySpecializationSameLength(node);
180 initializeSpecializations(elements, node);
181 initializeShortCircuits(node); // requires specializations and polymorphic specializations
182
183 verifyVisibilities(node);
184 verifyMissingAbstractMethods(node, elements);
185 verifyConstructors(node);
186 verifyNamingConvention(node.getShortCircuits(), "needs");
187 verifySpecializationThrows(node);
188 return node;
189 }
190
191 private void parseImportGuards(NodeData node, List<TypeElement> lookupTypes, List<Element> elements) {
192 for (TypeElement lookupType : lookupTypes) { 186 for (TypeElement lookupType : lookupTypes) {
193 AnnotationMirror importAnnotation = ElementUtils.findAnnotationMirror(processingEnv, lookupType, ImportGuards.class); 187 AnnotationMirror importAnnotation = ElementUtils.findAnnotationMirror(processingEnv, lookupType, ImportGuards.class);
194 if (importAnnotation == null) { 188 if (importAnnotation == null) {
195 continue; 189 continue;
196 } 190 }
226 } 220 }
227 } 221 }
228 } 222 }
229 } 223 }
230 224
231 private NodeData parseNodeData(TypeElement templateType, List<? extends Element> elements, List<TypeElement> typeHierarchy) { 225 private NodeData parseNodeData(TypeElement templateType, List<TypeElement> typeHierarchy) {
232 AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class); 226 AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class);
233 if (typeSystemMirror == null) { 227 if (typeSystemMirror == null) {
234 NodeData nodeData = new NodeData(context, templateType); 228 NodeData nodeData = new NodeData(context, templateType);
235 nodeData.addError("No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), ElementUtils.getQualifiedName(templateType)); 229 nodeData.addError("No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), ElementUtils.getQualifiedName(templateType));
236 return nodeData; 230 return nodeData;
242 NodeData nodeData = new NodeData(context, templateType); 236 NodeData nodeData = new NodeData(context, templateType);
243 nodeData.addError("The used type system '%s' is invalid. Fix errors in the type system first.", ElementUtils.getQualifiedName(typeSystemType)); 237 nodeData.addError("The used type system '%s' is invalid. Fix errors in the type system first.", ElementUtils.getQualifiedName(typeSystemType));
244 return nodeData; 238 return nodeData;
245 } 239 }
246 240
241 AnnotationMirror nodeInfoMirror = findFirstAnnotation(typeHierarchy, NodeInfo.class);
242 String shortName = null;
243 if (nodeInfoMirror != null) {
244 shortName = ElementUtils.getAnnotationValue(String.class, nodeInfoMirror, "shortName");
245 }
246 boolean useNodeFactory = findFirstAnnotation(typeHierarchy, GenerateNodeFactory.class) != null;
247 return new NodeData(context, templateType, shortName, typeSystem, useNodeFactory);
248
249 }
250
251 private List<String> parseAssumptions(List<TypeElement> typeHierarchy) {
247 List<String> assumptionsList = new ArrayList<>(); 252 List<String> assumptionsList = new ArrayList<>();
248 for (int i = typeHierarchy.size() - 1; i >= 0; i--) { 253 for (int i = typeHierarchy.size() - 1; i >= 0; i--) {
249 TypeElement type = typeHierarchy.get(i); 254 TypeElement type = typeHierarchy.get(i);
250 AnnotationMirror assumptions = ElementUtils.findAnnotationMirror(context.getEnvironment(), type, NodeAssumptions.class); 255 AnnotationMirror assumptions = ElementUtils.findAnnotationMirror(context.getEnvironment(), type, NodeAssumptions.class);
251 if (assumptions != null) { 256 if (assumptions != null) {
256 } 261 }
257 assumptionsList.add(string); 262 assumptionsList.add(string);
258 } 263 }
259 } 264 }
260 } 265 }
261 AnnotationMirror nodeInfoMirror = findFirstAnnotation(typeHierarchy, NodeInfo.class); 266 return assumptionsList;
262 String shortName = null;
263 if (nodeInfoMirror != null) {
264 shortName = ElementUtils.getAnnotationValue(String.class, nodeInfoMirror, "shortName");
265 }
266
267 List<NodeFieldData> fields = parseFields(typeHierarchy, elements);
268 List<NodeChildData> children = parseChildren(typeHierarchy, elements);
269 List<NodeExecutionData> executions = parseExecutions(children, elements);
270 boolean useNodeFactory = findFirstAnnotation(typeHierarchy, GenerateNodeFactory.class) != null;
271
272 NodeData nodeData = new NodeData(context, templateType, shortName, typeSystem, children, executions, fields, assumptionsList, useNodeFactory);
273
274 parsedNodes.put(ElementUtils.getQualifiedName(templateType), nodeData);
275
276 return nodeData;
277 } 267 }
278 268
279 private List<NodeFieldData> parseFields(List<TypeElement> typeHierarchy, List<? extends Element> elements) { 269 private List<NodeFieldData> parseFields(List<TypeElement> typeHierarchy, List<? extends Element> elements) {
280 Set<String> names = new HashSet<>(); 270 Set<String> names = new HashSet<>();
281 271
467 } else { 457 } else {
468 maxSignatureSize = children.size(); 458 maxSignatureSize = children.size();
469 } 459 }
470 } 460 }
471 461
472 // pre-parse specializations 462 List<TypeMirror> frameTypes = context.getFrameTypes();
463 // pre-parse specializations to find signature size
473 for (ExecutableElement method : methods) { 464 for (ExecutableElement method : methods) {
474 AnnotationMirror mirror = ElementUtils.findAnnotationMirror(processingEnv, method, Specialization.class); 465 AnnotationMirror mirror = ElementUtils.findAnnotationMirror(processingEnv, method, Specialization.class);
475 if (mirror == null) { 466 if (mirror == null) {
476 continue; 467 continue;
477 } 468 }
478 469
479 int currentArgumentCount = 0; 470 int currentArgumentIndex = 0;
480 boolean skipShortCircuit = false; 471 boolean skipShortCircuit = false;
481 for (VariableElement var : method.getParameters()) { 472 outer: for (VariableElement var : method.getParameters()) {
482 TypeMirror type = var.asType(); 473 TypeMirror type = var.asType();
483 if (currentArgumentCount == 0) { 474 if (currentArgumentIndex == 0) {
484 // skip optionals 475 // skip optionals
485 if (ElementUtils.typeEquals(type, context.getTruffleTypes().getFrame())) { 476 for (TypeMirror frameType : frameTypes) {
486 continue; 477 if (ElementUtils.typeEquals(type, frameType)) {
478 continue outer;
479 }
487 } 480 }
488 // TODO skip optional fields? 481 }
489 } 482 int childIndex = currentArgumentIndex < children.size() ? currentArgumentIndex : children.size() - 1;
490 int childIndex = currentArgumentCount < children.size() ? currentArgumentCount : children.size() - 1;
491 if (childIndex == -1) { 483 if (childIndex == -1) {
492 continue; 484 continue;
493 } 485 }
494 if (!skipShortCircuit) { 486 if (!skipShortCircuit) {
495 NodeChildData child = children.get(childIndex); 487 NodeChildData child = children.get(childIndex);
496 if (shortCircuits.contains(NodeExecutionData.createShortCircuitId(child, currentArgumentCount - childIndex))) { 488 if (shortCircuits.contains(NodeExecutionData.createShortCircuitId(child, currentArgumentIndex - childIndex))) {
497 skipShortCircuit = true; 489 skipShortCircuit = true;
498 continue; 490 continue;
499 } 491 }
500 } else { 492 } else {
501 skipShortCircuit = false; 493 skipShortCircuit = false;
502 } 494 }
503 495
504 currentArgumentCount++; 496 currentArgumentIndex++;
505 } 497 }
506 maxSignatureSize = Math.max(maxSignatureSize, currentArgumentCount); 498 maxSignatureSize = Math.max(maxSignatureSize, currentArgumentIndex);
507 } 499 }
508 500
509 List<NodeExecutionData> executions = new ArrayList<>(); 501 List<NodeExecutionData> executions = new ArrayList<>();
510 for (int i = 0; i < maxSignatureSize; i++) { 502 for (int i = 0; i < maxSignatureSize; i++) {
511 int childIndex = i; 503 int childIndex = i;
524 executions.add(new NodeExecutionData(child, varArgsIndex, shortCircuit)); 516 executions.add(new NodeExecutionData(child, varArgsIndex, shortCircuit));
525 } 517 }
526 return executions; 518 return executions;
527 } 519 }
528 520
529 private void initializeExecutableTypes(List<Element> elements, NodeData node) { 521 private void initializeExecutableTypes(NodeData node) {
530 node.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, node).parse(elements))); 522 List<ExecutableTypeData> genericExecutes = node.findGenericExecutableTypes(context, 0);
531 List<ExecutableTypeData> genericExecutes = node.getThisExecution().getChild().findGenericExecutableTypes(context); 523 List<ExecutableTypeData> allExecutes = node.getExecutableTypes();
532 524
533 List<ExecutableTypeData> overridableGenericExecutes = new ArrayList<>(); 525 Set<String> inconsistentFrameTypes = new HashSet<>();
526 TypeMirror frameType = null;
527 Set<Integer> evaluatedCounts = new HashSet<>();
528 for (ExecutableTypeData execute : allExecutes) {
529 evaluatedCounts.add(execute.getEvaluatedCount());
530
531 Parameter frame = execute.getFrame();
532 TypeMirror resolvedFrameType;
533 if (frame == null) {
534 resolvedFrameType = node.getTypeSystem().getVoidType().getPrimitiveType();
535 } else {
536 resolvedFrameType = frame.getType();
537 }
538
539 if (frameType == null) {
540 frameType = resolvedFrameType;
541 } else {
542 if (!ElementUtils.typeEquals(frameType, resolvedFrameType)) {
543 // found inconsistent frame types
544 inconsistentFrameTypes.add(ElementUtils.getSimpleName(frameType));
545 inconsistentFrameTypes.add(ElementUtils.getSimpleName(resolvedFrameType));
546 }
547 }
548 }
549 if (!inconsistentFrameTypes.isEmpty()) {
550 // ensure they are sorted somehow
551 List<String> inconsistentFrameTypesList = new ArrayList<>(inconsistentFrameTypes);
552 Collections.sort(inconsistentFrameTypesList);
553 node.addError("Invalid inconsistent frame types %s found for the declared execute methods. The frame type must be identical for all execute methods.", inconsistentFrameTypesList);
554 }
555 node.setFrameType(frameType);
556
557 int nonFinalCount = 0;
558 int voidCount = 0;
534 for (ExecutableTypeData executableTypeData : genericExecutes) { 559 for (ExecutableTypeData executableTypeData : genericExecutes) {
535 if (!executableTypeData.getMethod().getModifiers().contains(Modifier.FINAL)) { 560 if (!executableTypeData.getMethod().getModifiers().contains(Modifier.FINAL)) {
536 overridableGenericExecutes.add(executableTypeData); 561 nonFinalCount++;
537 } 562 }
538 } 563 if (ElementUtils.isVoid(executableTypeData.getReturnType().getType())) {
539 564 voidCount++;
540 if (overridableGenericExecutes.isEmpty()) { 565 }
566 }
567
568 // no generic executes
569 if (nonFinalCount == 0 && voidCount == 0) {
541 node.addError("No accessible and overridable generic execute method found. Generic execute methods usually have the " 570 node.addError("No accessible and overridable generic execute method found. Generic execute methods usually have the "
542 + "signature 'public abstract {Type} executeGeneric(VirtualFrame)' and must not throw any checked exceptions."); 571 + "signature 'public abstract {Type} execute(VirtualFrame)' and must not throw any checked exceptions.");
543 } 572 }
544 573
545 if (overridableGenericExecutes.size() > 1) { 574 // multiple generic execute
575 if (voidCount > 1 || (nonFinalCount - voidCount) > 1) {
546 List<String> methodSignatures = new ArrayList<>(); 576 List<String> methodSignatures = new ArrayList<>();
547 for (ExecutableTypeData type : overridableGenericExecutes) { 577 for (ExecutableTypeData type : genericExecutes) {
548 methodSignatures.add(type.createReferenceName()); 578 methodSignatures.add(type.createReferenceName());
549 } 579 }
550 node.addWarning("Multiple accessible and overridable generic execute methods found %s. Remove all but one or mark all but one as final.", methodSignatures); 580 node.addWarning("Multiple accessible and overridable generic execute methods found %s. Remove all but one or mark all but one as final.", methodSignatures);
551 } 581 }
552 } 582 }
569 } 599 }
570 return groupedTypes; 600 return groupedTypes;
571 } 601 }
572 602
573 private void initializeChildren(NodeData node) { 603 private void initializeChildren(NodeData node) {
574 for (NodeChildData nodeChild : node.getChildren()) { 604 for (NodeChildData child : node.getChildren()) {
575 NodeData fieldNodeData = resolveNode(ElementUtils.fromTypeMirror(nodeChild.getNodeType())); 605 TypeMirror nodeType = child.getNodeType();
576 nodeChild.setNode(fieldNodeData); 606 NodeData fieldNodeData = parseChildNodeData(node, ElementUtils.fromTypeMirror(nodeType));
577 if (fieldNodeData == null) { 607
578 nodeChild.addError("Node type '%s' is invalid or not a valid Node.", ElementUtils.getQualifiedName(nodeChild.getNodeType())); 608 child.setNode(fieldNodeData);
609 if (fieldNodeData == null || fieldNodeData.hasErrors()) {
610 child.addError("Node type '%s' is invalid or not a subclass of Node.", ElementUtils.getQualifiedName(nodeType));
579 } else if (!ElementUtils.typeEquals(fieldNodeData.getTypeSystem().getTemplateType().asType(), (node.getTypeSystem().getTemplateType().asType()))) { 611 } else if (!ElementUtils.typeEquals(fieldNodeData.getTypeSystem().getTemplateType().asType(), (node.getTypeSystem().getTemplateType().asType()))) {
580 nodeChild.addError("The @%s of the node and the @%s of the @%s does not match. %s != %s. ", TypeSystem.class.getSimpleName(), TypeSystem.class.getSimpleName(), 612 child.addError("The @%s of the node and the @%s of the @%s does not match. %s != %s. ", TypeSystem.class.getSimpleName(), TypeSystem.class.getSimpleName(),
581 NodeChild.class.getSimpleName(), ElementUtils.getSimpleName(node.getTypeSystem().getTemplateType()), 613 NodeChild.class.getSimpleName(), ElementUtils.getSimpleName(node.getTypeSystem().getTemplateType()),
582 ElementUtils.getSimpleName(fieldNodeData.getTypeSystem().getTemplateType())); 614 ElementUtils.getSimpleName(fieldNodeData.getTypeSystem().getTemplateType()));
583 } else if (nodeChild.findAnyGenericExecutableType(context) == null) { 615 } else {
584 nodeChild.addError("No generic execute method found for child type %s. Generic execute methods usually have the signature 'Object executeGeneric(VirtualFrame)'.", 616 List<ExecutableTypeData> types = child.findGenericExecutableTypes(context);
585 ElementUtils.getQualifiedName(nodeChild.getNodeType()));
586 }
587 if (fieldNodeData != null) {
588 List<ExecutableTypeData> types = nodeChild.findGenericExecutableTypes(context);
589 if (types.isEmpty()) { 617 if (types.isEmpty()) {
590 AnnotationValue executeWithValue = ElementUtils.getAnnotationValue(nodeChild.getMessageAnnotation(), "executeWith"); 618 AnnotationValue executeWithValue = ElementUtils.getAnnotationValue(child.getMessageAnnotation(), "executeWith");
591 nodeChild.addError(executeWithValue, "No generic execute method found with %s evaluated arguments for node type %s.", nodeChild.getExecuteWith().size(), 619 child.addError(executeWithValue, "No generic execute method found with %s evaluated arguments for node type %s and frame types %s.", child.getExecuteWith().size(),
592 ElementUtils.getSimpleName(nodeChild.getNodeType())); 620 ElementUtils.getSimpleName(nodeType), ElementUtils.getUniqueIdentifiers(createAllowedChildFrameTypes(node)));
593 } 621 }
594 } 622 }
595 } 623 }
624 }
625
626 private NodeData parseChildNodeData(NodeData parentNode, TypeElement originalTemplateType) {
627 TypeElement templateType = ElementUtils.fromTypeMirror(context.reloadTypeElement(originalTemplateType));
628
629 if (ElementUtils.findAnnotationMirror(processingEnv, originalTemplateType, GeneratedBy.class) != null) {
630 // generated nodes should not get called again.
631 return null;
632 }
633
634 if (!ElementUtils.isAssignable(templateType.asType(), context.getTruffleTypes().getNode())) {
635 return null;
636 }
637
638 List<TypeElement> lookupTypes = collectSuperClasses(new ArrayList<TypeElement>(), templateType);
639
640 // Declaration order is not required for child nodes.
641 List<? extends Element> members = processingEnv.getElementUtils().getAllMembers(templateType);
642 NodeData node = parseNodeData(templateType, lookupTypes);
643
644 node.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, node, createAllowedChildFrameTypes(parentNode)).parse(members)));
645 node.setFrameType(parentNode.getFrameType());
646 return node;
647 }
648
649 private List<TypeMirror> createAllowedChildFrameTypes(NodeData parentNode) {
650 List<TypeMirror> allowedFrameTypes = new ArrayList<>();
651 for (TypeMirror frameType : context.getFrameTypes()) {
652 if (ElementUtils.isAssignable(parentNode.getFrameType(), frameType)) {
653 allowedFrameTypes.add(frameType);
654 }
655 }
656 return allowedFrameTypes;
596 } 657 }
597 658
598 private void initializeSpecializations(List<? extends Element> elements, final NodeData node) { 659 private void initializeSpecializations(List<? extends Element> elements, final NodeData node) {
599 if (node.getSpecializations().isEmpty()) { 660 if (node.getSpecializations().isEmpty()) {
600 return; 661 return;