changeset 8252:0905d796944a

Refactored codegen error model to make error redirection a lot easier.
author Christian Humer <christian.humer@gmail.com>
date Wed, 13 Mar 2013 19:58:28 +0100
parents cb70ed101b5f
children 4c0d72c98797
files graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/AbstractParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Log.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleProcessor.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ext/ExtensionParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeMethodParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationGuardData.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationThrowsData.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ParameterSpec.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/Template.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCastParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCheckParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeData.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemCodeGenerator.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemData.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemMethodParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemParser.java
diffstat 28 files changed, 573 insertions(+), 513 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/AbstractParser.java	Wed Mar 13 11:32:43 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/AbstractParser.java	Wed Mar 13 19:58:28 2013 +0100
@@ -58,12 +58,22 @@
             if (!context.getTruffleTypes().verify(context, element, mirror)) {
                 return null;
             }
-            return parse(element, mirror);
+            M model = parse(element, mirror);
+            if (model == null) {
+                return null;
+            }
+
+            model.emitMessages((TypeElement) element, log);
+            return filterErrorElements(model);
         } finally {
             this.roundEnv = null;
         }
     }
 
+    protected M filterErrorElements(M model) {
+        return model.hasErrors() ? null : model;
+    }
+
     protected abstract M parse(Element element, AnnotationMirror mirror);
 
     public abstract Class<? extends Annotation> getAnnotationType();
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Log.java	Wed Mar 13 11:32:43 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Log.java	Wed Mar 13 19:58:28 2013 +0100
@@ -41,30 +41,6 @@
         this.processingEnv = env;
     }
 
-    public void warning(Element element, String format, Object... args) {
-        message(Kind.WARNING, element, null, null, format, args);
-    }
-
-    public void warning(Element element, AnnotationMirror mirror, String format, Object... args) {
-        message(Kind.WARNING, element, mirror, null, format, args);
-    }
-
-    public void error(Element element, String format, Object... args) {
-        message(Kind.ERROR, element, null, null, format, args);
-    }
-
-    public void error(String format, Object... args) {
-        message(Kind.ERROR, null, null, null, format, args);
-    }
-
-    public void error(Element element, AnnotationMirror mirror, String format, Object... args) {
-        message(Kind.ERROR, element, mirror, null, format, args);
-    }
-
-    public void error(Element element, AnnotationMirror mirror, AnnotationValue value, String format, Object... args) {
-        message(Kind.ERROR, element, mirror, value, format, args);
-    }
-
     public void message(Kind kind, Element element, AnnotationMirror mirror, AnnotationValue value, String format, Object... args) {
         AnnotationMirror usedMirror = mirror;
         Element usedElement = element;
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleProcessor.java	Wed Mar 13 11:32:43 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleProcessor.java	Wed Mar 13 19:58:28 2013 +0100
@@ -28,6 +28,7 @@
 import javax.annotation.processing.*;
 import javax.lang.model.*;
 import javax.lang.model.element.*;
+import javax.tools.Diagnostic.*;
 
 import com.oracle.truffle.codegen.processor.ProcessorContext.ProcessCallback;
 import com.oracle.truffle.codegen.processor.node.*;
@@ -95,7 +96,7 @@
 
     private static void handleThrowable(AnnotationProcessor generator, Throwable t, Element e) {
         String message = "Uncaught error in " + generator.getClass().getSimpleName() + " while processing " + e;
-        generator.getContext().getLog().error(e, message + ": " + Utils.printException(t));
+        generator.getContext().getLog().message(Kind.ERROR, e, null, null, message + ": " + Utils.printException(t));
     }
 
     @SuppressWarnings("unchecked")
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java	Wed Mar 13 11:32:43 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java	Wed Mar 13 19:58:28 2013 +0100
@@ -26,6 +26,7 @@
 
 import javax.lang.model.element.*;
 import javax.lang.model.type.*;
+import javax.tools.Diagnostic.*;
 
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.intrinsics.*;
@@ -66,7 +67,7 @@
         }
 
         for (String error : errors) {
-            context.getLog().error(element, mirror, error);
+            context.getLog().message(Kind.ERROR, element, mirror, null, error);
         }
 
         return false;
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ext/ExtensionParser.java	Wed Mar 13 11:32:43 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ext/ExtensionParser.java	Wed Mar 13 19:58:28 2013 +0100
@@ -31,6 +31,7 @@
 import com.oracle.truffle.codegen.processor.*;
 import com.oracle.truffle.codegen.processor.api.*;
 import com.oracle.truffle.codegen.processor.api.element.*;
+import com.oracle.truffle.codegen.processor.template.*;
 
 public class ExtensionParser {
 
@@ -45,25 +46,25 @@
         this.extensionContext = new ExtensionContextImpl(context.getEnvironment(), null, factory);
     }
 
-    public List<WritableElement> parseAll(TypeElement typeElement, List<? extends Element> elements) {
+    public List<WritableElement> parseAll(Template template, List<? extends Element> elements) {
         List<WritableElement> generatedMethods = new ArrayList<>();
-        parseElement(generatedMethods, typeElement);
+        parseElement(template, generatedMethods, template.getTemplateType());
 
         List<? extends ExecutableElement> methods = ElementFilter.methodsIn(elements);
         for (ExecutableElement method : methods) {
             for (VariableElement var : method.getParameters()) {
-                parseElement(generatedMethods, var);
+                parseElement(template, generatedMethods, var);
             }
-            parseElement(generatedMethods, method);
+            parseElement(template, generatedMethods, method);
         }
 
         return generatedMethods;
     }
 
-    private void parseElement(List<WritableElement> elements, Element element) {
+    private void parseElement(Template template, List<WritableElement> elements, Element element) {
         List<? extends AnnotationMirror> mirrors = element.getAnnotationMirrors();
         for (AnnotationMirror mirror : mirrors) {
-            ExtensionProcessor processor = findProcessor(element, mirror);
+            ExtensionProcessor processor = findProcessor(template, mirror);
             if (processor != null) {
                 try {
                     factory.generatorAnnotationMirror = mirror;
@@ -71,7 +72,7 @@
                     processor.process(extensionContext, mirror, element);
                     elements.addAll(extensionContext.returnElements());
                 } catch (Throwable e) {
-                    context.getLog().error(element, mirror, "Processor for '%s' failed with exception: \n\n%s.", Utils.getQualifiedName(mirror.getAnnotationType()), Utils.printException(e));
+                    template.addError("Processor for '%s' failed with exception: \n\n%s.", Utils.getQualifiedName(mirror.getAnnotationType()), Utils.printException(e));
                 } finally {
                     factory.generatorAnnotationMirror = null;
                     factory.generatorElement = null;
@@ -80,7 +81,7 @@
         }
     }
 
-    private ExtensionProcessor findProcessor(Element element, AnnotationMirror mirror) {
+    private ExtensionProcessor findProcessor(Template template, AnnotationMirror mirror) {
         String processorName = Utils.getQualifiedName(mirror.getAnnotationType());
         ExtensionProcessor processor = null;
         if (extensions.containsKey(processorName)) {
@@ -93,19 +94,19 @@
                 try {
                     processorClass = Class.forName(className);
                 } catch (ClassNotFoundException e) {
-                    context.getLog().error(element, mirror, "Could not find processor class '%s' configured in '@%s'.", className, processorName);
+                    template.addError("Could not find processor class '%s' configured in '@%s'.", className, processorName);
                     return null;
                 }
                 try {
                     processor = (ExtensionProcessor) processorClass.newInstance();
                 } catch (InstantiationException e) {
-                    context.getLog().error(element, mirror, "Could not instantiate processor class '%s' configured in '@%s'.", className, processorName);
+                    template.addError("Could not instantiate processor class '%s' configured in '@%s'.", className, processorName);
                     return null;
                 } catch (IllegalAccessException e) {
-                    context.getLog().error(element, mirror, "Could not access processor class '%s' configured in '@%s'.", className, processorName);
+                    template.addError("Could not access processor class '%s' configured in '@%s'.", className, processorName);
                     return null;
                 } catch (ClassCastException e) {
-                    context.getLog().error(element, mirror, "Processor class '%s' configured in '@%s' does not implement '%s'.", className, processorName, ExtensionProcessor.class.getName());
+                    template.addError("Processor class '%s' configured in '@%s' does not implement '%s'.", className, processorName, ExtensionProcessor.class.getName());
                     return null;
                 }
             }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeMethodParser.java	Wed Mar 13 11:32:43 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeMethodParser.java	Wed Mar 13 19:58:28 2013 +0100
@@ -44,10 +44,10 @@
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
         List<TypeMirror> types = new ArrayList<>();
-        types.addAll(Arrays.asList(getNode().getTypeSystem().getPrimitiveTypeMirrors()));
+        types.addAll(getNode().getTypeSystem().getPrimitiveTypeMirrors());
         types.add(getContext().getType(void.class));
 
-        ParameterSpec returnTypeSpec = new ParameterSpec("executedValue", types.toArray(new TypeMirror[types.size()]), false, Cardinality.ONE);
+        ParameterSpec returnTypeSpec = new ParameterSpec("executedValue", types, false, Cardinality.ONE);
 
         List<ParameterSpec> parameters = new ArrayList<>();
         parameters.add(new ParameterSpec("frame", getContext().getTruffleTypes().getFrame(), true));
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java	Wed Mar 13 11:32:43 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java	Wed Mar 13 19:58:28 2013 +0100
@@ -51,8 +51,7 @@
         for (ExecutableTypeData type : execTypes) {
             types.add(type.getType().getPrimitiveType());
         }
-        TypeMirror[] array = types.toArray(new TypeMirror[types.size()]);
-        return new ParameterSpec(valueName, array, false, Cardinality.ONE);
+        return new ParameterSpec(valueName, types, false, Cardinality.ONE);
     }
 
     @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java	Wed Mar 13 11:32:43 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java	Wed Mar 13 19:58:28 2013 +0100
@@ -182,13 +182,17 @@
         body.startCall(method.getSimpleName().toString());
     }
 
-    private static String generatedGenericMethodName(SpecializationData specialization) {
+    private String generatedGenericMethodName(SpecializationData specialization) {
         final String prefix = "generic";
 
         if (specialization == null) {
             return prefix;
         }
 
+        if (!specialization.getNode().getGenericSpecialization().isUseSpecializationsForGeneric() || !specialization.getNode().needsRewrites(context)) {
+            return prefix;
+        }
+
         SpecializationData prev = null;
         for (SpecializationData current : specialization.getNode().getSpecializations()) {
             if (specialization == current) {
@@ -250,26 +254,25 @@
         }
 
         if (implicitGuards == null && explicitGuards == null && conditionPrefix != null && !conditionPrefix.isEmpty()) {
-            builder.startIf().string(conditionPrefix).end().startBlock();
+            builder.startIf();
+            builder.string(conditionPrefix);
+            builder.end().startBlock();
             ifCount++;
         }
 
         builder.tree(guardedStatements);
 
         builder.end(ifCount);
-        if (ifCount > 0 && elseStatements != null) {
-            builder.startElseBlock();
+        if (elseStatements != null && ifCount > 0) {
             builder.tree(elseStatements);
-            builder.end();
         }
-
         return builder.getRoot();
     }
 
     private CodeTree createExplicitGuards(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization, boolean onSpecialization) {
         CodeTreeBuilder builder = new CodeTreeBuilder(parent);
         String andOperator = conditionPrefix != null ? conditionPrefix + " && " : "";
-        if (guardedSpecialization.getGuards().length > 0) {
+        if (guardedSpecialization.getGuards().size() > 0) {
             // Explicitly specified guards
             for (SpecializationGuardData guard : guardedSpecialization.getGuards()) {
                 if ((guard.isOnSpecialization() && onSpecialization) || (guard.isOnExecution() && !onSpecialization)) {
@@ -514,9 +517,11 @@
                     clazz.add(createCreateSpecializedMethod(node, createVisibility));
                 }
 
-                if (node.needsRewrites(getContext())) {
+                if (node.needsRewrites(context)) {
                     clazz.add(createSpecializeMethod(node));
+                }
 
+                if (node.getGenericSpecialization() != null) {
                     List<CodeExecutableElement> genericMethods = createGeneratedGenericMethod(node);
                     for (CodeExecutableElement method : genericMethods) {
                         clazz.add(method);
@@ -600,7 +605,7 @@
             classType = types.getDeclaredType(Utils.fromTypeMirror(classType), wildcardNodeType);
             TypeMirror returnType = types.getDeclaredType(listType, classType);
 
-            CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getChildrenSignature");
+            CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getExecutionSignature");
             CodeTreeBuilder builder = method.createBuilder();
 
             List<TypeMirror> signatureTypes = new ArrayList<>();
@@ -934,7 +939,7 @@
 
         private List<CodeExecutableElement> createGeneratedGenericMethod(NodeData node) {
             TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getActualType();
-            if (node.getGenericSpecialization().isUseSpecializationsForGeneric()) {
+            if (node.getGenericSpecialization().isUseSpecializationsForGeneric() && node.needsRewrites(context)) {
                 List<CodeExecutableElement> methods = new ArrayList<>();
 
                 List<SpecializationData> specializations = node.getSpecializations();
@@ -974,18 +979,20 @@
             CodeTree invokeMethod = invokeMethodBuilder.getRoot();
 
             if (next != null) {
-                invokeMethod = createGuardAndCast(builder, null, current.getNode().getGenericSpecialization(), current, false, invokeMethod, null);
+                CodeTreeBuilder nextBuilder = builder.create();
+
+                nextBuilder.startReturn().startCall(generatedGenericMethodName(next));
+                nextBuilder.string(THIS_NODE_LOCAL_VAR_NAME);
+                addValueParameterNames(nextBuilder, next, null, true, true);
+                nextBuilder.end().end();
+
+                invokeMethod = createGuardAndCast(builder, null, current.getNode().getGenericSpecialization(), current, false, invokeMethod, nextBuilder.getRoot());
             }
 
             builder.tree(invokeMethod);
 
             if (next != null) {
                 builder.end();
-
-                builder.startReturn().startCall(generatedGenericMethodName(next));
-                builder.string(THIS_NODE_LOCAL_VAR_NAME);
-                addValueParameterNames(builder, next, null, true, true);
-                builder.end().end();
             }
         }
 
@@ -1209,7 +1216,7 @@
                 builder.startTryBlock();
             }
 
-            if (specialization.getMethod() == null) {
+            if (specialization.getMethod() == null && !node.needsRewrites(context)) {
                 emitEncounteredSynthetic(builder);
             } else if (specialization.isUninitialized() || specialization.isGeneric()) {
                 builder.startReturn().startCall(factoryClassName(node), generatedGenericMethodName(null));
@@ -1349,7 +1356,7 @@
             }
 
             builder.startStatement().type(shortCircuitParam.getActualType()).string(" ").string(valueName(shortCircuitParam)).string(" = ");
-            ShortCircuitData shortCircuitData = specialization.getShortCircuits()[shortCircuitIndex];
+            ShortCircuitData shortCircuitData = specialization.getShortCircuits().get(shortCircuitIndex);
 
             startCallOperationMethod(builder, shortCircuitData, false);
             addValueParameterNames(builder, shortCircuitData, exceptionParam != null ? exceptionParam.getName() : null, false, false);
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java	Wed Mar 13 11:32:43 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java	Wed Mar 13 19:58:28 2013 +0100
@@ -39,7 +39,7 @@
     private NodeData declaringNode;
     private List<NodeData> declaredChildren = new ArrayList<>();
 
-    private final TypeSystemData typeSystem;
+    private TypeSystemData typeSystem;
     private List<NodeFieldData> fields;
     private TypeMirror nodeType;
     private ParameterSpec instanceParameterSpec;
@@ -50,25 +50,58 @@
     private List<ExecutableTypeData> executableTypes;
     private List<ShortCircuitData> shortCircuits;
 
-    public NodeData(TypeElement type, TypeSystemData typeSystem, String id) {
+    public NodeData(TypeElement type, String id) {
         super(type, null, null);
         this.nodeId = id;
+    }
+
+    public NodeData(NodeData splitSource, String templateMethodName, String nodeId) {
+        super(splitSource.getTemplateType(), templateMethodName, null);
+        this.nodeId = nodeId;
+        this.declaringNode = splitSource.declaringNode;
+        this.declaredChildren = splitSource.declaredChildren;
+        this.typeSystem = splitSource.typeSystem;
+        this.nodeType = splitSource.nodeType;
+        this.specializations = splitSource.specializations;
+        this.specializationListeners = splitSource.specializationListeners;
+        this.guards = splitSource.guards;
+        this.executableTypes = splitSource.executableTypes;
+        this.shortCircuits = splitSource.shortCircuits;
+        this.fields = splitSource.fields;
+    }
+
+    void setTypeSystem(TypeSystemData typeSystem) {
         this.typeSystem = typeSystem;
     }
 
-    public NodeData(NodeData copy, String templateMethodName, String nodeId) {
-        super(copy.getTemplateType(), templateMethodName, null);
-        this.nodeId = nodeId;
-        this.declaringNode = copy.declaringNode;
-        this.declaredChildren = copy.declaredChildren;
-        this.typeSystem = copy.typeSystem;
-        this.nodeType = copy.nodeType;
-        this.specializations = copy.specializations;
-        this.specializationListeners = copy.specializationListeners;
-        this.guards = copy.guards;
-        this.executableTypes = copy.executableTypes;
-        this.shortCircuits = copy.shortCircuits;
-        this.fields = copy.fields;
+    @Override
+    protected List<MessageContainer> findChildContainers() {
+        List<MessageContainer> sinks = new ArrayList<>();
+        if (declaredChildren != null) {
+            sinks.addAll(declaredChildren);
+        }
+        if (typeSystem != null) {
+            sinks.add(typeSystem);
+        }
+        if (specializations != null) {
+            sinks.addAll(specializations);
+        }
+        if (specializationListeners != null) {
+            sinks.addAll(specializationListeners);
+        }
+        if (guards != null) {
+            sinks.addAll(guards);
+        }
+        if (executableTypes != null) {
+            sinks.addAll(executableTypes);
+        }
+        if (shortCircuits != null) {
+            sinks.addAll(shortCircuits);
+        }
+        if (fields != null) {
+            sinks.addAll(fields);
+        }
+        return sinks;
     }
 
     public ParameterSpec getInstanceParameterSpec() {
@@ -146,9 +179,6 @@
 
         for (SpecializationData specialization : getSpecializations()) {
             methods.add(specialization);
-            if (specialization.getShortCircuits() != null) {
-                methods.addAll(Arrays.asList(specialization.getShortCircuits()));
-            }
         }
 
         methods.addAll(getSpecializationListeners());
@@ -271,19 +301,52 @@
     }
 
     public TypeSystemData getTypeSystem() {
-        if (typeSystem != null) {
-            return typeSystem;
-        } else {
-            return null;
-        }
+        return typeSystem;
     }
 
     public String dump() {
-        StringBuilder b = new StringBuilder();
-        b.append(String.format("[id = %s, name = %s\n  typeSystem = %s\n  fields = %s\n  types = %s\n  specializations = %s\n  guards = %s\n  enclosing = %s\n  enclosed = %s\n]", getNodeId(),
-                        Utils.getQualifiedName(getTemplateType()), getTypeSystem(), dumpList(fields), dumpList(getExecutableTypes()), dumpList(getSpecializations()), dumpList(guards),
-                        dumpList(getDeclaredChildren()), getParent()));
-        return b.toString();
+        return dump(0);
+    }
+
+    private String dump(int level) {
+        String indent = "";
+        for (int i = 0; i < level; i++) {
+            indent += "  ";
+        }
+        StringBuilder builder = new StringBuilder();
+
+        builder.append(String.format("%s%s {", indent, toString()));
+
+        dumpProperty(builder, indent, "templateClass", Utils.getQualifiedName(getTemplateType()));
+        dumpProperty(builder, indent, "typeSystem", getTypeSystem());
+        dumpProperty(builder, indent, "fields", getFields());
+        dumpProperty(builder, indent, "executableTypes", getExecutableTypes());
+        dumpProperty(builder, indent, "specializations", getSpecializations());
+        dumpProperty(builder, indent, "guards", getGuards());
+        dumpProperty(builder, indent, "messages", collectMessages());
+        if (getDeclaredChildren().size() > 0) {
+            builder.append(String.format("\n%s  children = [", indent));
+            for (NodeData node : getDeclaredChildren()) {
+                builder.append("\n");
+                builder.append(node.dump(level + 1));
+            }
+            builder.append(String.format("\n%s  ]", indent));
+        }
+        builder.append(String.format("%s}", indent));
+        return builder.toString();
+    }
+
+    private static void dumpProperty(StringBuilder b, String indent, String propertyName, Object value) {
+        if (value instanceof List) {
+            List<?> list = (List<?>) value;
+            if (!list.isEmpty()) {
+                b.append(String.format("\n%s  %s = %s", indent, propertyName, dumpList((List<?>) value)));
+            }
+        } else {
+            if (value != null) {
+                b.append(String.format("\n%s  %s = %s", indent, propertyName, value));
+            }
+        }
     }
 
     private static String dumpList(List<?> array) {
@@ -291,6 +354,12 @@
             return "null";
         }
 
+        if (array.isEmpty()) {
+            return "[]";
+        } else if (array.size() == 1) {
+            return "[" + array.get(0).toString() + "]";
+        }
+
         StringBuilder b = new StringBuilder();
         b.append("[");
         for (Object object : array) {
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java	Wed Mar 13 11:32:43 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java	Wed Mar 13 19:58:28 2013 +0100
@@ -25,7 +25,9 @@
 import javax.lang.model.element.*;
 import javax.lang.model.type.*;
 
-public class NodeFieldData {
+import com.oracle.truffle.codegen.processor.template.*;
+
+public class NodeFieldData extends MessageContainer {
 
     public enum FieldKind {
         CHILD, CHILDREN
@@ -43,11 +45,10 @@
     private final ExecutionKind executionKind;
     private NodeData nodeData;
 
-    public NodeFieldData(NodeData typeNodeData, VariableElement fieldElement, Element accessElement, AnnotationMirror childAnnotationMirror, FieldKind fieldKind, ExecutionKind executionKind) {
+    public NodeFieldData(VariableElement fieldElement, Element accessElement, AnnotationMirror childAnnotationMirror, FieldKind fieldKind, ExecutionKind executionKind) {
         this.fieldElement = fieldElement;
         this.accessElement = accessElement;
         this.childAnnotationMirror = childAnnotationMirror;
-        this.nodeData = typeNodeData;
         this.fieldKind = fieldKind;
         this.executionKind = executionKind;
     }
@@ -61,12 +62,18 @@
         this.nodeData = field.nodeData;
     }
 
+    @Override
+    public Element getMessageElement() {
+        return fieldElement;
+    }
+
     public boolean isShortCircuit() {
         return executionKind == ExecutionKind.SHORT_CIRCUIT;
     }
 
     void setNode(NodeData nodeData) {
         this.nodeData = nodeData;
+        getMessages().addAll(nodeData.collectMessages());
     }
 
     public VariableElement getFieldElement() {
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java	Wed Mar 13 11:32:43 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java	Wed Mar 13 19:58:28 2013 +0100
@@ -28,6 +28,7 @@
 import javax.lang.model.element.*;
 import javax.lang.model.type.*;
 import javax.lang.model.util.*;
+import javax.tools.Diagnostic.*;
 
 import com.oracle.truffle.api.codegen.*;
 import com.oracle.truffle.api.nodes.Node.Child;
@@ -56,13 +57,36 @@
         try {
             parsedNodes = new HashMap<>();
             node = resolveNode((TypeElement) element);
+            if (Log.DEBUG) {
+                NodeData parsed = parsedNodes.get(Utils.getQualifiedName((TypeElement) element));
+                if (node != null) {
+                    String dump = parsed.dump();
+                    log.message(Kind.ERROR, null, null, null, dump);
+                    System.out.println(dump);
+                }
+            }
         } finally {
             parsedNodes = null;
         }
+
         return node;
     }
 
     @Override
+    protected NodeData filterErrorElements(NodeData model) {
+        for (Iterator<NodeData> iterator = model.getDeclaredChildren().iterator(); iterator.hasNext();) {
+            NodeData node = filterErrorElements(iterator.next());
+            if (node == null) {
+                iterator.remove();
+            }
+        }
+        if (model.hasErrors()) {
+            return null;
+        }
+        return model;
+    }
+
+    @Override
     public boolean isDelegateToRootDeclaredType() {
         return true;
     }
@@ -82,9 +106,11 @@
                 children.add(childNode);
             }
         }
+
         NodeData rootNode = parseNode(rootType);
-        if (rootNode == null && children.size() > 0) {
-            rootNode = new NodeData(rootType, null, rootType.getSimpleName().toString());
+        boolean hasErrors = rootNode != null ? rootNode.hasErrors() : false;
+        if ((rootNode == null || hasErrors) && children.size() > 0) {
+            rootNode = new NodeData(rootType, rootType.getSimpleName().toString());
         }
 
         parsedNodes.put(typeName, rootNode);
@@ -94,17 +120,6 @@
             rootNode.setDeclaredChildren(children);
         }
 
-        if (Log.DEBUG) {
-            NodeData parsed = parsedNodes.get(typeName);
-            if (parsed != null) {
-                String dump = parsed.dump();
-                String valid = rootNode != null ? "" : " failed";
-                String msg = String.format("Node parsing %s : %s", valid, dump);
-                log.error(msg);
-                System.out.println(msg);
-            }
-        }
-
         return rootNode;
     }
 
@@ -121,7 +136,8 @@
         }
 
         if (type.getModifiers().contains(Modifier.PRIVATE)) {
-            return null; // not visible
+            // TODO error message here!?
+            return null; // not visible, not a node
         }
 
         TypeElement nodeType;
@@ -135,43 +151,32 @@
         }
 
         NodeData nodeData = parseNodeData(type, nodeType);
-        if (nodeData == null) {
-            return null;
+        if (nodeData.hasErrors()) {
+            return nodeData; // error sync point
         }
 
         List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(type));
-        nodeData.setExtensionElements(getExtensionParser().parseAll(type, elements));
+        nodeData.setExtensionElements(getExtensionParser().parseAll(nodeData, elements));
         if (nodeData.getExtensionElements() != null) {
             elements.addAll(nodeData.getExtensionElements());
         }
+        parseMethods(nodeData, elements);
 
-        if (!parseMethods(nodeData, elements)) {
-            return null;
+        if (nodeData.hasErrors()) {
+            return nodeData;
         }
 
         List<NodeData> nodes;
         if (needsSplit) {
             nodes = splitNodeData(nodeData);
-            if (nodes == null) {
-                return null;
-            }
         } else {
             nodes = new ArrayList<>();
             nodes.add(nodeData);
         }
 
-        boolean valid = true;
         for (NodeData splittedNode : nodes) {
-            if (!finalizeSpecializations(splittedNode)) {
-                valid = false;
-            }
-            if (!verifyNode(splittedNode)) {
-                valid = false;
-            }
-        }
-
-        if (!valid) {
-            return null;
+            finalizeSpecializations(splittedNode);
+            verifyNode(splittedNode);
         }
 
         if (needsSplit) {
@@ -237,31 +242,25 @@
         return grouped;
     }
 
-    private boolean parseMethods(final NodeData node, List<Element> elements) {
+    private void parseMethods(final NodeData node, List<Element> elements) {
         node.setGuards(new GuardParser(context, node, node.getTypeSystem()).parse(elements));
         node.setShortCircuits(new ShortCircuitParser(context, node).parse(elements));
         node.setSpecializationListeners(new SpecializationListenerParser(context, node).parse(elements));
         List<SpecializationData> generics = new GenericParser(context, node).parse(elements);
         List<SpecializationData> specializations = new SpecializationMethodParser(context, node).parse(elements);
 
-        if (generics == null || specializations == null || node.getGuards() == null || node.getShortCircuits() == null || node.getSpecializationListeners() == null) {
-            return false;
-        }
-
         List<SpecializationData> allSpecializations = new ArrayList<>();
         allSpecializations.addAll(generics);
         allSpecializations.addAll(specializations);
 
         node.setSpecializations(allSpecializations);
-
-        return true;
     }
 
-    private boolean finalizeSpecializations(final NodeData node) {
+    private void finalizeSpecializations(final NodeData node) {
         List<SpecializationData> specializations = new ArrayList<>(node.getSpecializations());
 
         if (specializations.isEmpty()) {
-            return true;
+            return;
         }
 
         List<SpecializationData> generics = new ArrayList<>();
@@ -273,22 +272,18 @@
 
         if (generics.size() == 1 && specializations.size() == 1) {
             for (SpecializationData generic : generics) {
-                log.error(generic.getMethod(), "@%s defined but no @%s.", Generic.class.getSimpleName(), Specialization.class.getSimpleName());
+                generic.addError("@%s defined but no @%s.", Generic.class.getSimpleName(), Specialization.class.getSimpleName());
             }
         }
 
         SpecializationData genericSpecialization = null;
         if (generics.size() > 1) {
             for (SpecializationData generic : generics) {
-                log.error(generic.getMethod(), "Only @%s is allowed per operation.", Generic.class.getSimpleName());
+                generic.addError("Only @%s is allowed per operation.", Generic.class.getSimpleName());
             }
-            return false;
+            return;
         } else if (generics.size() == 1) {
             genericSpecialization = generics.get(0);
-            if (!node.needsRewrites(context)) {
-                log.error(genericSpecialization.getMethod(), "Generic specialization is not reachable.", Generic.class.getSimpleName());
-                return false;
-            }
         } else if (node.needsRewrites(context)) {
             SpecializationData specialization = specializations.get(0);
             GenericParser parser = new GenericParser(context, node);
@@ -343,8 +338,6 @@
         for (SpecializationData specialization : specializations) {
             specialization.setId(findUniqueSpecializationId(specialization));
         }
-
-        return true;
     }
 
     private static String findUniqueSpecializationId(SpecializationData specialization) {
@@ -435,28 +428,18 @@
         }
     }
 
-    private boolean verifyNode(NodeData nodeData) {
+    private void verifyNode(NodeData nodeData) {
         // verify specialization parameter length
-        if (!verifySpecializationParameters(nodeData)) {
-            return false;
-        }
+        verifySpecializationParameters(nodeData);
 
         // verify order is not ambiguous
-        if (!verifySpecializationOrder(nodeData)) {
-            return false;
-        }
+        verifySpecializationOrder(nodeData);
 
-        if (!verifyMissingAbstractMethods(nodeData)) {
-            return false;
-        }
+        verifyMissingAbstractMethods(nodeData);
 
-        if (!assignShortCircuitsToSpecializations(nodeData)) {
-            return false;
-        }
+        assignShortCircuitsToSpecializations(nodeData);
 
-        if (!verifyConstructors(nodeData)) {
-            return false;
-        }
+        verifyConstructors(nodeData);
 
 // if (!verifyNamingConvention(specializations, "do")) {
 // return null;
@@ -466,54 +449,42 @@
 // return null;
 // }
 
-        if (!verifyNamingConvention(nodeData.getShortCircuits(), "needs")) {
-            return false;
-        }
+        verifyNamingConvention(nodeData.getShortCircuits(), "needs");
 
-        if (!verifySpecializationThrows(nodeData)) {
-            return false;
-        }
-
-        return true;
+        verifySpecializationThrows(nodeData);
     }
 
     private NodeData parseNodeData(TypeElement templateType, TypeElement nodeType) {
         List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(nodeType));
         List<TypeElement> typeHierarchy = findSuperClasses(new ArrayList<TypeElement>(), nodeType);
         Collections.reverse(typeHierarchy);
+        NodeData nodeData = new NodeData(templateType, templateType.getSimpleName().toString());
 
         AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class);
         if (typeSystemMirror == null) {
-            log.error(templateType, "No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), nodeType.getQualifiedName().toString());
-            return null;
+            nodeData.addError("No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), nodeType.getQualifiedName().toString());
+            return nodeData;
         }
 
         TypeMirror typeSytemType = Utils.getAnnotationValue(TypeMirror.class, typeSystemMirror, "value");
         final TypeSystemData typeSystem = (TypeSystemData) context.getTemplate(typeSytemType, true);
         if (typeSystem == null) {
-            log.error(templateType, "The used type system '%s' is invalid.", Utils.getQualifiedName(typeSytemType));
-            return null;
+            nodeData.addError("The used type system '%s' is invalid.", Utils.getQualifiedName(typeSytemType));
+            return nodeData;
         }
 
-        NodeData nodeData = new NodeData(templateType, typeSystem, templateType.getSimpleName().toString());
         nodeData.setNodeType(nodeType.asType());
+        nodeData.setTypeSystem(typeSystem);
 
         List<ExecutableTypeData> executableTypes = filterExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements));
-
         nodeData.setExecutableTypes(executableTypes);
-
         parsedNodes.put(Utils.getQualifiedName(templateType), nodeData);
-
-        List<NodeFieldData> fields = parseFields(nodeData, elements, typeHierarchy);
-        if (fields == null) {
-            return null;
-        }
-        nodeData.setFields(fields);
+        nodeData.setFields(parseFields(nodeData, elements, typeHierarchy));
 
         return nodeData;
     }
 
-    private boolean verifySpecializationParameters(NodeData nodeData) {
+    private static void verifySpecializationParameters(NodeData nodeData) {
         boolean valid = true;
         int args = -1;
         for (SpecializationData specializationData : nodeData.getSpecializations()) {
@@ -531,17 +502,16 @@
         }
         if (!valid) {
             for (SpecializationData specialization : nodeData.getSpecializations()) {
-                context.getLog().error(specialization.getMethod(), specialization.getMarkerAnnotation(), "All specializations must have the same number of arguments.");
+                specialization.addError("All specializations must have the same number of arguments.");
             }
         }
-        return valid;
     }
 
-    private boolean verifyMissingAbstractMethods(NodeData nodeData) {
-        if (nodeData.needsFactory()) {
+    private void verifyMissingAbstractMethods(NodeData nodeData) {
+        if (!nodeData.needsFactory()) {
             // missing abstract methods only needs to be implemented
             // if we need go generate factory for it.
-            return true;
+            return;
         }
 
         List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(nodeData.getTemplateType()));
@@ -554,24 +524,20 @@
             unusedElements.removeAll(nodeData.getExtensionElements());
         }
 
-        boolean valid = true;
         for (ExecutableElement unusedMethod : ElementFilter.methodsIn(unusedElements)) {
             if (unusedMethod.getModifiers().contains(Modifier.ABSTRACT)) {
-                context.getLog().error(nodeData.getTemplateType(), "The type %s must implement the inherited abstract method %s.", Utils.getSimpleName(nodeData.getTemplateType()),
-                                Utils.getReadableSignature(unusedMethod));
-                valid = false;
+                nodeData.addError("The type %s must implement the inherited abstract method %s.", Utils.getSimpleName(nodeData.getTemplateType()), Utils.getReadableSignature(unusedMethod));
             }
         }
+    }
+
+    private void verifyConstructors(NodeData nodeData) {
+        if (!nodeData.needsRewrites(context)) {
+            // no specialization constructor is needed if the node never rewrites.
+            return;
+        }
 
-        return valid;
-    }
-
-    private boolean verifyConstructors(NodeData nodeData) {
         TypeElement type = Utils.fromTypeMirror(nodeData.getNodeType());
-        if (!nodeData.needsRewrites(context)) {
-            // no specialization constructor is needed if the node never rewrites.
-            return true;
-        }
 
         List<ExecutableElement> constructors = ElementFilter.constructorsIn(type.getEnclosedElements());
         for (ExecutableElement e : constructors) {
@@ -579,20 +545,17 @@
                 TypeMirror firstArg = e.getParameters().get(0).asType();
                 if (Utils.typeEquals(firstArg, nodeData.getNodeType())) {
                     if (e.getModifiers().contains(Modifier.PRIVATE)) {
-                        context.getLog().error(e, "The specialization constructor must not be private.");
-                        return false;
+                        nodeData.addError("The specialization constructor must not be private.");
                     } else if (constructors.size() <= 1) {
-                        context.getLog().error(e, "The specialization constructor must not be the only constructor. The definition of an alternative constructor is required.");
-                        return false;
+                        nodeData.addError("The specialization constructor must not be the only constructor. The definition of an alternative constructor is required.");
                     }
-                    return true;
+                    return;
                 }
             }
         }
 
         // not found
-        context.getLog().error(type, "Specialization constructor '%s(%s previousNode) { this(...); }' is required.", Utils.getSimpleName(type), Utils.getSimpleName(type));
-        return false;
+        nodeData.addError("Specialization constructor '%s(%s previousNode) { this(...); }' is required.", Utils.getSimpleName(type), Utils.getSimpleName(type));
     }
 
     private static List<ExecutableTypeData> filterExecutableTypes(List<ExecutableTypeData> executableTypes) {
@@ -657,8 +620,6 @@
             }
         }
 
-        boolean valid = true;
-
         List<NodeFieldData> fields = new ArrayList<>();
         for (VariableElement var : ElementFilter.fieldsIn(elements)) {
             if (var.getModifiers().contains(Modifier.STATIC)) {
@@ -672,20 +633,10 @@
             }
 
             NodeFieldData field = parseField(nodeData, var, shortCircuits);
-            if (field != null) {
-                if (field.getExecutionKind() != ExecutionKind.IGNORE) {
-                    fields.add(field);
-                }
-            } else {
-                valid = false;
+            if (field.getExecutionKind() != ExecutionKind.IGNORE) {
+                fields.add(field);
             }
         }
-
-        // TODO parse getters
-        if (!valid) {
-            return null;
-        }
-
         sortByExecutionOrder(fields, executionDefinition == null ? Collections.<String> emptyList() : executionDefinition, typeHierarchy);
         return fields;
     }
@@ -721,19 +672,15 @@
             kind = null;
         }
 
-        NodeData fieldNodeData = null;
+        NodeFieldData fieldData = new NodeFieldData(var, findAccessElement(var), mirror, kind, execution);
         if (nodeType != null) {
-            fieldNodeData = resolveNode(Utils.fromTypeMirror(nodeType));
-            Element errorElement = Utils.typeEquals(parentNodeData.getTemplateType().asType(), var.getEnclosingElement().asType()) ? var : parentNodeData.getTemplateType();
+            NodeData fieldNodeData = resolveNode(Utils.fromTypeMirror(nodeType));
+            fieldData.setNode(fieldNodeData);
 
             if (fieldNodeData == null) {
-                // TODO redirect errors from resolve.
-                context.getLog().error(errorElement, "Node type '%s' is invalid.", Utils.getQualifiedName(nodeType));
-                return null;
+                fieldData.addError("Node type '%s' is invalid.", Utils.getQualifiedName(nodeType));
             } else if (fieldNodeData.findGenericExecutableTypes(context).isEmpty()) {
-                // TODO better error handling for (no or multiple?)
-                context.getLog().error(errorElement, "No executable generic types found for node '%s'.", Utils.getQualifiedName(nodeType));
-                return null;
+                fieldData.addError("No executable generic types found for node '%s'.", Utils.getQualifiedName(nodeType));
             }
 
             // TODO correct handling of access elements
@@ -741,7 +688,7 @@
                 execution = ExecutionKind.IGNORE;
             }
         }
-        return new NodeFieldData(fieldNodeData, var, findAccessElement(var), mirror, kind, execution);
+        return fieldData;
     }
 
     private Element findAccessElement(VariableElement variableElement) {
@@ -795,17 +742,16 @@
         });
     }
 
-    private boolean assignShortCircuitsToSpecializations(NodeData node) {
+    private void assignShortCircuitsToSpecializations(NodeData node) {
         Map<String, List<ShortCircuitData>> groupedShortCircuits = groupShortCircuits(node.getShortCircuits());
 
         boolean valid = true;
-
         for (NodeFieldData field : node.filterFields(null, ExecutionKind.SHORT_CIRCUIT)) {
             String valueName = field.getName();
             List<ShortCircuitData> availableCircuits = groupedShortCircuits.get(valueName);
 
             if (availableCircuits == null || availableCircuits.isEmpty()) {
-                log.error(node.getTemplateType(), "@%s method for short cut value '%s' required.", ShortCircuit.class.getSimpleName(), valueName);
+                node.addError("@%s method for short cut value '%s' required.", ShortCircuit.class.getSimpleName(), valueName);
                 valid = false;
                 continue;
             }
@@ -820,7 +766,7 @@
 
             if (!sameMethodName) {
                 for (ShortCircuitData circuit : availableCircuits) {
-                    log.error(circuit.getMethod(), circuit.getMarkerAnnotation(), "All short circuits for short cut value '%s' must have the same method name.", valueName);
+                    circuit.addError("All short circuits for short cut value '%s' must have the same method name.", valueName);
                 }
                 valid = false;
                 continue;
@@ -835,7 +781,7 @@
             }
 
             if (genericCircuit == null) {
-                log.error(node.getTemplateType(), "No generic @%s method available for short cut value '%s'.", ShortCircuit.class.getSimpleName(), valueName);
+                node.addError("No generic @%s method available for short cut value '%s'.", ShortCircuit.class.getSimpleName(), valueName);
                 valid = false;
                 continue;
             }
@@ -848,62 +794,42 @@
         }
 
         if (!valid) {
-            return valid;
+            return;
         }
 
         NodeFieldData[] fields = node.filterFields(null, ExecutionKind.SHORT_CIRCUIT);
         for (SpecializationData specialization : node.getSpecializations()) {
-            ShortCircuitData[] assignedShortCuts = new ShortCircuitData[fields.length];
+            List<ShortCircuitData> assignedShortCuts = new ArrayList<>(fields.length);
 
             for (int i = 0; i < fields.length; i++) {
                 List<ShortCircuitData> availableShortCuts = groupedShortCircuits.get(fields[i].getName());
 
                 ShortCircuitData genericShortCircuit = null;
+                ShortCircuitData compatibleShortCircuit = null;
                 for (ShortCircuitData circuit : availableShortCuts) {
                     if (circuit.isGeneric()) {
                         genericShortCircuit = circuit;
                     } else if (circuit.isCompatibleTo(specialization)) {
-                        assignedShortCuts[i] = circuit;
+                        compatibleShortCircuit = circuit;
                     }
                 }
 
-                if (assignedShortCuts[i] == null) {
-                    assignedShortCuts[i] = genericShortCircuit;
+                if (compatibleShortCircuit == null) {
+                    compatibleShortCircuit = genericShortCircuit;
                 }
+                assignedShortCuts.add(compatibleShortCircuit);
             }
             specialization.setShortCircuits(assignedShortCuts);
         }
-        return true;
     }
 
-    private boolean verifyNamingConvention(List<? extends TemplateMethod> methods, String prefix) {
-        boolean valid = true;
+    private static void verifyNamingConvention(List<? extends TemplateMethod> methods, String prefix) {
         for (int i = 0; i < methods.size(); i++) {
             TemplateMethod m1 = methods.get(i);
             if (m1.getMethodName().length() < 3 || !m1.getMethodName().startsWith(prefix)) {
-                log.error(m1.getMethod(), m1.getMarkerAnnotation(), "Naming convention: method name must start with '%s'.", prefix);
-                valid = false;
+                m1.addError("Naming convention: method name must start with '%s'.", prefix);
             }
         }
-        return valid;
-    }
-
-    @SuppressWarnings("unused")
-    private boolean verifyNamesUnique(List<? extends TemplateMethod> methods) {
-        boolean valid = true;
-        for (int i = 0; i < methods.size(); i++) {
-            TemplateMethod m1 = methods.get(i);
-            for (int j = i + 1; j < methods.size(); j++) {
-                TemplateMethod m2 = methods.get(j);
-
-                if (m1.getMethodName().equalsIgnoreCase(m2.getMethodName())) {
-                    log.error(m1.getMethod(), m1.getMarkerAnnotation(), "Method name '%s' used multiple times", m1.getMethodName());
-                    log.error(m2.getMethod(), m2.getMarkerAnnotation(), "Method name '%s' used multiple times", m1.getMethodName());
-                    return false;
-                }
-            }
-        }
-        return valid;
     }
 
     private boolean isGenericShortCutMethod(NodeData node, TemplateMethod method) {
@@ -958,7 +884,7 @@
         return collection;
     }
 
-    private boolean verifySpecializationOrder(NodeData node) {
+    private static void verifySpecializationOrder(NodeData node) {
         TypeSystemData typeSystem = node.getTypeSystem();
         List<SpecializationData> specializations = node.getSpecializations();
 
@@ -971,44 +897,39 @@
                 if (m1.getOrder() != Specialization.DEFAULT_ORDER && m2.getOrder() != Specialization.DEFAULT_ORDER) {
                     int specOrder = m1.getOrder() - m2.getOrder();
                     if (specOrder == 0) {
-                        log.error(m1.getMethod(), m1.getMarkerAnnotation(), "Order value %d used multiple times", m1.getOrder());
-                        log.error(m2.getMethod(), m2.getMarkerAnnotation(), "Order value %d used multiple times", m1.getOrder());
-                        return false;
+                        m1.addError("Order value %d used multiple times", m1.getOrder());
+                        m2.addError("Order value %d used multiple times", m1.getOrder());
+                        return;
                     } else if ((specOrder < 0 && inferredOrder > 0) || (specOrder > 0 && inferredOrder < 0)) {
-                        log.error(m1.getMethod(), m1.getMarkerAnnotation(), "Explicit order values %d and %d are inconsistent with type lattice ordering.", m1.getOrder(), m2.getOrder());
-                        log.error(m2.getMethod(), m2.getMarkerAnnotation(), "Explicit order values %d and %d are inconsistent with type lattice ordering.", m1.getOrder(), m2.getOrder());
-                        return false;
+                        m1.addError("Explicit order values %d and %d are inconsistent with type lattice ordering.", m1.getOrder(), m2.getOrder());
+                        m2.addError("Explicit order values %d and %d are inconsistent with type lattice ordering.", m1.getOrder(), m2.getOrder());
+                        return;
                     }
                 } else if (inferredOrder == 0) {
                     SpecializationData m = (m1.getOrder() == Specialization.DEFAULT_ORDER ? m1 : m2);
-                    log.error(m.getMethod(), m.getMarkerAnnotation(), "Cannot calculate a consistent order for this specialization. Define the order attribute to resolve this.");
-                    return false;
+                    m.addError("Cannot calculate a consistent order for this specialization. Define the order attribute to resolve this.");
+                    return;
                 }
             }
         }
-        return true;
     }
 
-    private boolean verifySpecializationThrows(NodeData node) {
+    private static void verifySpecializationThrows(NodeData node) {
         Map<String, SpecializationData> specializationMap = new HashMap<>();
         for (SpecializationData spec : node.getSpecializations()) {
             specializationMap.put(spec.getMethodName(), spec);
         }
-        boolean valid = true;
         for (SpecializationData sourceSpecialization : node.getSpecializations()) {
             if (sourceSpecialization.getExceptions() != null) {
                 for (SpecializationThrowsData throwsData : sourceSpecialization.getExceptions()) {
                     for (SpecializationThrowsData otherThrowsData : sourceSpecialization.getExceptions()) {
                         if (otherThrowsData != throwsData && Utils.typeEquals(otherThrowsData.getJavaClass(), throwsData.getJavaClass())) {
-                            AnnotationValue javaClassValue = Utils.getAnnotationValue(throwsData.getAnnotationMirror(), "rewriteOn");
-                            log.error(throwsData.getSpecialization().getMethod(), throwsData.getAnnotationMirror(), javaClassValue, "Duplicate exception type.");
-                            valid = false;
+                            throwsData.addError("Duplicate exception type.");
                         }
                     }
                 }
             }
         }
-        return valid;
     }
 
     private static int compareSpecialization(TypeSystemData typeSystem, SpecializationData m1, SpecializationData m2) {
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitParser.java	Wed Mar 13 11:32:43 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitParser.java	Wed Mar 13 19:58:28 2013 +0100
@@ -49,12 +49,6 @@
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
         String shortCircuitValue = Utils.getAnnotationValue(String.class, mirror, "value");
-
-        if (!shortCircuitValues.contains(shortCircuitValue)) {
-            getContext().getLog().error(method, mirror, "Invalid short circuit value %s.", shortCircuitValue);
-            return null;
-        }
-
         return createDefaultMethodSpec(method, mirror, shortCircuitValue);
     }
 
@@ -66,8 +60,11 @@
     @Override
     public ShortCircuitData create(TemplateMethod method) {
         String shortCircuitValue = Utils.getAnnotationValue(String.class, method.getMarkerAnnotation(), "value");
-        assert shortCircuitValue != null;
-        assert shortCircuitValues.contains(shortCircuitValue);
+
+        if (!shortCircuitValues.contains(shortCircuitValue)) {
+            method.addError("Invalid short circuit value %s.", shortCircuitValue);
+        }
+
         return new ShortCircuitData(method, shortCircuitValue);
     }
 
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java	Wed Mar 13 11:32:43 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java	Wed Mar 13 19:58:28 2013 +0100
@@ -34,8 +34,8 @@
     private final boolean generic;
     private final boolean uninitialized;
     private final List<SpecializationThrowsData> exceptions;
-    private SpecializationGuardData[] guards;
-    private ShortCircuitData[] shortCircuits;
+    private List<SpecializationGuardData> guards;
+    private List<ShortCircuitData> shortCircuits;
     private boolean useSpecializationsForGeneric = true;
     private NodeData node;
 
@@ -60,15 +60,27 @@
         this.generic = generic;
         this.uninitialized = uninitialized;
         this.exceptions = Collections.emptyList();
-        this.guards = new SpecializationGuardData[0];
+        this.guards = new ArrayList<>();
         this.synthetic = synthetic;
     }
 
+    @Override
+    protected List<MessageContainer> findChildContainers() {
+        List<MessageContainer> sinks = new ArrayList<>();
+        if (exceptions != null) {
+            sinks.addAll(exceptions);
+        }
+        if (guards != null) {
+            sinks.addAll(guards);
+        }
+        return sinks;
+    }
+
     public boolean hasRewrite(ProcessorContext context) {
-        if (getExceptions().size() > 0) {
+        if (!getExceptions().isEmpty()) {
             return true;
         }
-        if (getGuards().length > 0) {
+        if (!getGuards().isEmpty()) {
             return true;
         }
         for (ActualParameter parameter : getParameters()) {
@@ -92,7 +104,7 @@
         this.node = node;
     }
 
-    public void setGuards(SpecializationGuardData[] guards) {
+    public void setGuards(List<SpecializationGuardData> guards) {
         this.guards = guards;
     }
 
@@ -116,15 +128,15 @@
         return exceptions;
     }
 
-    public SpecializationGuardData[] getGuards() {
+    public List<SpecializationGuardData> getGuards() {
         return guards;
     }
 
-    public void setShortCircuits(ShortCircuitData[] shortCircuits) {
+    public void setShortCircuits(List<ShortCircuitData> shortCircuits) {
         this.shortCircuits = shortCircuits;
     }
 
-    public ShortCircuitData[] getShortCircuits() {
+    public List<ShortCircuitData> getShortCircuits() {
         return shortCircuits;
     }
 
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationGuardData.java	Wed Mar 13 11:32:43 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationGuardData.java	Wed Mar 13 19:58:28 2013 +0100
@@ -22,20 +22,42 @@
  */
 package com.oracle.truffle.codegen.processor.node;
 
+import javax.lang.model.element.*;
+
+import com.oracle.truffle.codegen.processor.template.*;
 import com.oracle.truffle.codegen.processor.typesystem.*;
 
-public class SpecializationGuardData {
+public class SpecializationGuardData extends MessageContainer {
 
+    private final SpecializationData specialization;
+    private final AnnotationValue value;
     private final String guardMethod;
     private final boolean onSpecialization;
     private final boolean onExecution;
 
     private GuardData guardDeclaration;
 
-    public SpecializationGuardData(String guardMethod, boolean onSpecialization, boolean onExecution) {
+    public SpecializationGuardData(SpecializationData specialization, AnnotationValue value, String guardMethod, boolean onSpecialization, boolean onExecution) {
+        this.specialization = specialization;
         this.guardMethod = guardMethod;
         this.onSpecialization = onSpecialization;
         this.onExecution = onExecution;
+        this.value = value;
+    }
+
+    @Override
+    public Element getMessageElement() {
+        return specialization.getMessageElement();
+    }
+
+    @Override
+    public AnnotationMirror getMessageAnnotation() {
+        return specialization.getMessageAnnotation();
+    }
+
+    @Override
+    public AnnotationValue getMessageAnnotationValue() {
+        return value;
     }
 
     public String getGuardMethod() {
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.java	Wed Mar 13 11:32:43 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.java	Wed Mar 13 19:58:28 2013 +0100
@@ -57,19 +57,19 @@
     private SpecializationData parseSpecialization(TemplateMethod method) {
         int order = Utils.getAnnotationValue(Integer.class, method.getMarkerAnnotation(), "order");
         if (order < 0 && order != Specialization.DEFAULT_ORDER) {
-            getContext().getLog().error(method.getMethod(), method.getMarkerAnnotation(), "Invalid order attribute %d. The value must be >= 0 or the default value.");
+            method.addError("Invalid order attribute %d. The value must be >= 0 or the default value.");
             return null;
         }
 
+        AnnotationValue rewriteValue = Utils.getAnnotationValue(method.getMarkerAnnotation(), "rewriteOn");
         List<TypeMirror> exceptionTypes = Utils.getAnnotationValueList(TypeMirror.class, method.getMarkerAnnotation(), "rewriteOn");
         List<SpecializationThrowsData> exceptionData = new ArrayList<>();
         for (TypeMirror exceptionType : exceptionTypes) {
-            exceptionData.add(new SpecializationThrowsData(method.getMarkerAnnotation(), exceptionType));
-
+            SpecializationThrowsData throwsData = new SpecializationThrowsData(method.getMarkerAnnotation(), rewriteValue, exceptionType);
             if (!Utils.canThrowType(method.getMethod().getThrownTypes(), exceptionType)) {
-                getContext().getLog().error(method.getMethod(), "Method must specify a throws clause with the exception type '%s'.", Utils.getQualifiedName(exceptionType));
-                return null;
+                throwsData.addError("Method must specify a throws clause with the exception type '%s'.", Utils.getQualifiedName(exceptionType));
             }
+            exceptionData.add(throwsData);
         }
 
         Collections.sort(exceptionData, new Comparator<SpecializationThrowsData>() {
@@ -81,26 +81,19 @@
         });
         SpecializationData specialization = new SpecializationData(method, order, exceptionData);
         boolean valid = true;
+        AnnotationValue guardsValue = Utils.getAnnotationValue(method.getMarkerAnnotation(), "guards");
         List<String> guardDefs = Utils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "guards");
-        SpecializationGuardData[] guardData = new SpecializationGuardData[guardDefs.size()];
-        for (int i = 0; i < guardData.length; i++) {
+        List<SpecializationGuardData> guardData = new ArrayList<>(guardDefs.size());
+        for (int i = 0; i < guardDefs.size(); i++) {
             String guardMethod = guardDefs.get(i);
 
-            boolean onSpecialization = true;
-            boolean onExecution = true;
+            SpecializationGuardData assignedGuard = new SpecializationGuardData(specialization, guardsValue, guardMethod, true, true);
+
+            guardData.add(assignedGuard);
 
-            if (!onSpecialization && !onExecution) {
-                String message = "Either onSpecialization, onExecution or both must be enabled.";
-                getContext().getLog().error(method.getMethod(), message);
-                valid = false;
-                continue;
-            }
-
-            guardData[i] = new SpecializationGuardData(guardMethod, onSpecialization, onExecution);
-
-            GuardData compatibleGuard = matchSpecializationGuard(specialization, guardData[i]);
+            GuardData compatibleGuard = matchSpecializationGuard(specialization, assignedGuard);
             if (compatibleGuard != null) {
-                guardData[i].setGuardDeclaration(compatibleGuard);
+                assignedGuard.setGuardDeclaration(compatibleGuard);
             } else {
                 valid = false;
             }
@@ -136,9 +129,7 @@
             }
             List<TypeDef> typeDefs = createTypeDefinitions(returnTypeSpec, expectedParameterSpecs);
             String expectedSignature = TemplateMethodParser.createExpectedSignature(specializationGuard.getGuardMethod(), returnTypeSpec, expectedParameterSpecs, typeDefs);
-            AnnotationValue value = Utils.getAnnotationValue(specialization.getMarkerAnnotation(), "guards");
-            getContext().getLog().error(specialization.getMethod(), specialization.getMarkerAnnotation(), value, "No guard with signature '%s' found in type system.", expectedSignature);
-            return null;
+            specializationGuard.addError("No guard with signature '%s' found in type system.", expectedSignature);
         }
 
         return compatibleGuard;
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationThrowsData.java	Wed Mar 13 11:32:43 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationThrowsData.java	Wed Mar 13 19:58:28 2013 +0100
@@ -25,14 +25,18 @@
 import javax.lang.model.element.*;
 import javax.lang.model.type.*;
 
-public class SpecializationThrowsData {
+import com.oracle.truffle.codegen.processor.template.*;
 
+public class SpecializationThrowsData extends MessageContainer {
+
+    private final AnnotationValue annotationValue;
     private final AnnotationMirror annotationMirror;
     private final TypeMirror javaClass;
     private SpecializationData specialization;
 
-    public SpecializationThrowsData(AnnotationMirror annotationMirror, TypeMirror javaClass) {
+    public SpecializationThrowsData(AnnotationMirror annotationMirror, AnnotationValue value, TypeMirror javaClass) {
         this.annotationMirror = annotationMirror;
+        this.annotationValue = value;
         this.javaClass = javaClass;
     }
 
@@ -40,6 +44,21 @@
         this.specialization = specialization;
     }
 
+    @Override
+    public Element getMessageElement() {
+        return specialization.getMessageElement();
+    }
+
+    @Override
+    public AnnotationMirror getMessageAnnotation() {
+        return annotationMirror;
+    }
+
+    @Override
+    public AnnotationValue getMessageAnnotationValue() {
+        return annotationValue;
+    }
+
     public TypeMirror getJavaClass() {
         return javaClass;
     }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ParameterSpec.java	Wed Mar 13 11:32:43 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ParameterSpec.java	Wed Mar 13 19:58:28 2013 +0100
@@ -37,12 +37,12 @@
     }
 
     private final String name;
-    private final TypeMirror[] allowedTypes;
+    private final List<TypeMirror> allowedTypes;
     private final boolean optional;
     private Cardinality cardinality;
     private boolean indexed;
 
-    public ParameterSpec(String name, TypeMirror[] allowedTypes, boolean optional, Cardinality cardinality) {
+    public ParameterSpec(String name, List<TypeMirror> allowedTypes, boolean optional, Cardinality cardinality) {
         this.allowedTypes = allowedTypes;
         this.name = name;
         this.optional = optional;
@@ -51,7 +51,7 @@
 
     /** Type constructor. */
     public ParameterSpec(String name, TypeMirror singleFixedType, boolean optional) {
-        this(name, new TypeMirror[]{singleFixedType}, optional, Cardinality.ONE);
+        this(name, Arrays.asList(singleFixedType), optional, Cardinality.ONE);
     }
 
     /** Type system value constructor. */
@@ -76,7 +76,7 @@
         this.cardinality = cardinality;
     }
 
-    private static TypeMirror[] nodeTypeMirrors(NodeData nodeData) {
+    private static List<TypeMirror> nodeTypeMirrors(NodeData nodeData) {
         Set<TypeMirror> typeMirrors = new LinkedHashSet<>();
 
         for (ExecutableTypeData typeData : nodeData.getExecutableTypes()) {
@@ -85,7 +85,7 @@
 
         typeMirrors.add(nodeData.getTypeSystem().getGenericType());
 
-        return typeMirrors.toArray(new TypeMirror[typeMirrors.size()]);
+        return new ArrayList<>(typeMirrors);
     }
 
     public final String getName() {
@@ -100,15 +100,13 @@
         return cardinality;
     }
 
-    public TypeMirror[] getAllowedTypes() {
+    public List<TypeMirror> getAllowedTypes() {
         return allowedTypes;
     }
 
     public boolean matches(TypeMirror actualType) {
-        for (int i = 0; i < allowedTypes.length; i++) {
-            TypeMirror mirror = allowedTypes[i];
+        for (TypeMirror mirror : allowedTypes) {
             if (Utils.typeEquals(actualType, mirror)) {
-
                 return true;
             }
         }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/Template.java	Wed Mar 13 11:32:43 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/Template.java	Wed Mar 13 19:58:28 2013 +0100
@@ -29,7 +29,7 @@
 import com.oracle.truffle.codegen.processor.*;
 import com.oracle.truffle.codegen.processor.api.element.*;
 
-public abstract class Template {
+public abstract class Template extends MessageContainer {
 
     private final TypeElement templateType;
     private final String templateMethodName;
@@ -43,6 +43,16 @@
         this.annotation = annotation;
     }
 
+    @Override
+    public Element getMessageElement() {
+        return templateType;
+    }
+
+    @Override
+    protected List<MessageContainer> findChildContainers() {
+        return Collections.emptyList();
+    }
+
     public String getTemplateMethodName() {
         return templateMethodName;
     }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java	Wed Mar 13 11:32:43 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java	Wed Mar 13 19:58:28 2013 +0100
@@ -29,7 +29,7 @@
 
 import com.oracle.truffle.codegen.processor.*;
 
-public class TemplateMethod {
+public class TemplateMethod extends MessageContainer {
 
     private String id;
     private final Template template;
@@ -58,6 +58,22 @@
 
     public TemplateMethod(TemplateMethod method) {
         this(method.id, method.template, method.specification, method.method, method.markerAnnotation, method.returnType, method.parameters);
+        getMessages().addAll(method.getMessages());
+    }
+
+    @Override
+    public Element getMessageElement() {
+        return method;
+    }
+
+    @Override
+    public AnnotationMirror getMessageAnnotation() {
+        return markerAnnotation;
+    }
+
+    @Override
+    protected List<MessageContainer> findChildContainers() {
+        return Collections.emptyList();
     }
 
     public void setId(String id) {
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java	Wed Mar 13 11:32:43 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java	Wed Mar 13 19:58:28 2013 +0100
@@ -96,13 +96,14 @@
                 mirror = Utils.findAnnotationMirror(getContext().getEnvironment(), method, annotationType);
             }
 
+            E parsedMethod = parse(method, mirror);
+
             if (method.getModifiers().contains(Modifier.PRIVATE) && emitErrors) {
-                getContext().getLog().error(method, "Method must not be private.");
+                parsedMethod.addError("Method must not be private.");
                 valid = false;
                 continue;
             }
 
-            E parsedMethod = parse(method, mirror);
             if (parsedMethod != null) {
                 parsedMethods.add(parsedMethod);
             } else {
@@ -121,6 +122,12 @@
             return null;
         }
 
+        String id = method.getSimpleName().toString();
+        AnnotationMirror idAnnotation = Utils.findAnnotationMirror(context.getEnvironment(), method, NodeId.class);
+        if (idAnnotation != null) {
+            id = Utils.getAnnotationValue(String.class, idAnnotation, "value");
+        }
+
         List<TypeDef> typeDefs = createTypeDefinitions(methodSpecification.getReturnType(), methodSpecification.getParameters());
 
         ParameterSpec returnTypeSpec = methodSpecification.getReturnType();
@@ -129,16 +136,18 @@
 
         ActualParameter returnTypeMirror = matchParameter(returnTypeSpec, method.getReturnType(), template, 0, false);
         if (returnTypeMirror == null) {
-            if (isEmitErrors()) {
+            if (emitErrors) {
+                E invalidMethod = create(new TemplateMethod(id, template, methodSpecification, method, annotation, returnTypeMirror, Collections.<ActualParameter> emptyList()));
                 String expectedReturnType = createTypeSignature(returnTypeSpec, typeDefs, true);
                 String actualReturnType = Utils.getSimpleName(method.getReturnType());
 
                 String message = String.format("The provided return type \"%s\" does not match expected return type \"%s\".\nExpected signature: \n %s", actualReturnType, expectedReturnType,
                                 createExpectedSignature(method.getSimpleName().toString(), returnTypeSpec, parameterSpecs, typeDefs));
-
-                context.getLog().error(method, annotation, message);
+                invalidMethod.addError(message);
+                return invalidMethod;
+            } else {
+                return null;
             }
-            return null;
         }
 
         List<TypeMirror> parameterTypes = new ArrayList<>();
@@ -150,17 +159,14 @@
         List<ActualParameter> parameters = parseParameters(parameterTypes, parameterSpecs, methodSpecification.getImplicitTypes().size());
         if (parameters == null) {
             if (isEmitErrors()) {
+                E invalidMethod = create(new TemplateMethod(id, template, methodSpecification, method, annotation, returnTypeMirror, Collections.<ActualParameter> emptyList()));
                 String message = String.format("Method signature %s does not match to the expected signature: \n%s", createActualSignature(methodSpecification, method),
                                 createExpectedSignature(method.getSimpleName().toString(), returnTypeSpec, parameterSpecs, typeDefs));
-                context.getLog().error(method, annotation, message);
+                invalidMethod.addError(message);
+                return invalidMethod;
+            } else {
+                return null;
             }
-            return null;
-        }
-
-        String id = method.getSimpleName().toString();
-        AnnotationMirror idAnnotation = Utils.findAnnotationMirror(context.getEnvironment(), method, NodeId.class);
-        if (idAnnotation != null) {
-            id = Utils.getAnnotationValue(String.class, idAnnotation, "value");
         }
 
         return create(new TemplateMethod(id, template, methodSpecification, method, annotation, returnTypeMirror, parameters));
@@ -256,12 +262,12 @@
 
         int defIndex = 0;
         for (ParameterSpec spec : allParams) {
-            TypeMirror[] allowedTypes = spec.getAllowedTypes();
-            TypeMirror[] types = spec.getAllowedTypes();
-            if (types != null && allowedTypes.length > 1) {
+            List<TypeMirror> allowedTypes = spec.getAllowedTypes();
+            List<TypeMirror> types = spec.getAllowedTypes();
+            if (types != null && allowedTypes.size() > 1) {
                 TypeDef foundDef = null;
                 for (TypeDef def : typeDefs) {
-                    if (Arrays.equals(allowedTypes, def.getTypes())) {
+                    if (allowedTypes.equals(def.getTypes())) {
                         foundDef = def;
                         break;
                     }
@@ -281,11 +287,11 @@
 
     protected static class TypeDef {
 
-        private final TypeMirror[] types;
+        private final List<TypeMirror> types;
         private final String name;
         private final List<ParameterSpec> parameters = new ArrayList<>();
 
-        public TypeDef(TypeMirror[] types, String name) {
+        public TypeDef(List<TypeMirror> types, String name) {
             this.types = types;
             this.name = name;
         }
@@ -294,7 +300,7 @@
             return parameters;
         }
 
-        public TypeMirror[] getTypes() {
+        public List<TypeMirror> getTypes() {
             return types;
         }
 
@@ -363,7 +369,7 @@
 
     private static String createTypeSignature(ParameterSpec spec, List<TypeDef> typeDefs, boolean typeOnly) {
         StringBuilder builder = new StringBuilder();
-        if (spec.getAllowedTypes().length > 1) {
+        if (spec.getAllowedTypes().size() > 1) {
             TypeDef foundTypeDef = null;
             for (TypeDef typeDef : typeDefs) {
                 if (typeDef.getParameters().contains(spec)) {
@@ -374,8 +380,8 @@
             if (foundTypeDef != null) {
                 builder.append("<" + foundTypeDef.getName() + ">");
             }
-        } else if (spec.getAllowedTypes().length == 1) {
-            builder.append(Utils.getSimpleName(spec.getAllowedTypes()[0]));
+        } else if (spec.getAllowedTypes().size() == 1) {
+            builder.append(Utils.getSimpleName(spec.getAllowedTypes().get(0)));
         } else {
             builder.append("void");
         }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateParser.java	Wed Mar 13 11:32:43 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateParser.java	Wed Mar 13 19:58:28 2013 +0100
@@ -43,9 +43,8 @@
         return extensionParser;
     }
 
-    protected boolean verifyExclusiveMethodAnnotation(TypeElement type, Class<?>... annotationTypes) {
-        boolean valid = true;
-        List<ExecutableElement> methods = ElementFilter.methodsIn(type.getEnclosedElements());
+    protected void verifyExclusiveMethodAnnotation(Template template, Class<?>... annotationTypes) {
+        List<ExecutableElement> methods = ElementFilter.methodsIn(template.getTemplateType().getEnclosedElements());
         for (ExecutableElement method : methods) {
             List<AnnotationMirror> foundAnnotations = new ArrayList<>();
             for (int i = 0; i < annotationTypes.length; i++) {
@@ -61,34 +60,9 @@
                     annotationNames.add("@" + Utils.getSimpleName(mirror.getAnnotationType()));
                 }
 
-                for (AnnotationMirror mirror : foundAnnotations) {
-                    context.getLog().error(method, mirror, "Non exclusive usage of annotations %s.", annotationNames);
-                }
-                valid = false;
+                template.addError("Non exclusive usage of annotations %s.", annotationNames);
             }
         }
-        return valid;
-    }
-
-    protected boolean verifyTemplateType(TypeElement template, AnnotationMirror annotation) {
-        // annotation type on class path!?
-        boolean valid = true;
-        TypeElement annotationTypeElement = processingEnv.getElementUtils().getTypeElement(getAnnotationType().getCanonicalName());
-        if (annotationTypeElement == null) {
-            log.error(template, annotation, "Required class " + getAnnotationType().getName() + " is not on the classpath.");
-            valid = false;
-        }
-        if (template.getModifiers().contains(Modifier.PRIVATE)) {
-            log.error(template, annotation, "The annotated class must have at least package protected visibility.");
-            valid = false;
-        }
-
-        if (template.getModifiers().contains(Modifier.FINAL)) {
-            log.error(template, annotation, "The annotated class must not be final.");
-            valid = false;
-        }
-
-        return valid;
     }
 
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCastParser.java	Wed Mar 13 11:32:43 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCastParser.java	Wed Mar 13 19:58:28 2013 +0100
@@ -41,7 +41,7 @@
 
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
-        TypeData targetType = findTypeByMethodName(method, mirror, "as");
+        TypeData targetType = findTypeByMethodName(method.getSimpleName().toString(), "as");
         if (targetType == null) {
             return null;
         }
@@ -54,7 +54,7 @@
 
     @Override
     public TypeCastData create(TemplateMethod method) {
-        TypeData targetType = findTypeByMethodName(method.getMethod(), method.getMarkerAnnotation(), "as");
+        TypeData targetType = findTypeByMethodName(method, "as");
         ActualParameter parameter = method.findParameter("valueValue");
         return new TypeCastData(method, parameter.getActualTypeData(getTypeSystem()), targetType);
     }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCheckParser.java	Wed Mar 13 11:32:43 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCheckParser.java	Wed Mar 13 19:58:28 2013 +0100
@@ -41,7 +41,7 @@
 
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
-        TypeData targetType = findTypeByMethodName(method, mirror, "is");
+        TypeData targetType = findTypeByMethodName(method.getSimpleName().toString(), "is");
         if (targetType == null) {
             return null;
         }
@@ -54,7 +54,7 @@
 
     @Override
     public TypeCheckData create(TemplateMethod method) {
-        TypeData checkedType = findTypeByMethodName(method.getMethod(), method.getMarkerAnnotation(), "is");
+        TypeData checkedType = findTypeByMethodName(method, "is");
         assert checkedType != null;
         ActualParameter parameter = method.findParameter("valueValue");
         assert parameter != null;
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeData.java	Wed Mar 13 11:32:43 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeData.java	Wed Mar 13 19:58:28 2013 +0100
@@ -30,21 +30,38 @@
 import com.oracle.truffle.codegen.processor.*;
 import com.oracle.truffle.codegen.processor.template.*;
 
-public class TypeData extends Template {
+public class TypeData extends MessageContainer {
 
-    protected TypeSystemData typeSystem;
+    private final TypeSystemData typeSystem;
+    private final AnnotationValue annotationValue;
     private final TypeMirror primitiveType;
     private final TypeMirror boxedType;
 
     private final List<TypeCastData> typeCasts = new ArrayList<>();
     private final List<TypeCheckData> typeChecks = new ArrayList<>();
 
-    public TypeData(TypeElement templateType, AnnotationMirror annotation, TypeMirror primitiveType, TypeMirror boxedType) {
-        super(templateType, null, annotation);
+    public TypeData(TypeSystemData typeSystem, AnnotationValue value, TypeMirror primitiveType, TypeMirror boxedType) {
+        this.typeSystem = typeSystem;
+        this.annotationValue = value;
         this.primitiveType = primitiveType;
         this.boxedType = boxedType;
     }
 
+    @Override
+    public Element getMessageElement() {
+        return typeSystem.getMessageElement();
+    }
+
+    @Override
+    public AnnotationMirror getMessageAnnotation() {
+        return typeSystem.getMessageAnnotation();
+    }
+
+    @Override
+    public AnnotationValue getMessageAnnotationValue() {
+        return annotationValue;
+    }
+
     void addTypeCast(TypeCastData typeCast) {
         this.typeCasts.add(typeCast);
     }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemCodeGenerator.java	Wed Mar 13 11:32:43 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemCodeGenerator.java	Wed Mar 13 19:58:28 2013 +0100
@@ -167,8 +167,8 @@
 
             CodeTreeBuilder builder = method.createBuilder();
             builder.startReturn();
-            if (typeSystem.getTypes().length > 0) {
-                builder.typeLiteral(typeSystem.getTypes()[0].getBoxedType());
+            if (!typeSystem.getTypes().isEmpty()) {
+                builder.typeLiteral(typeSystem.getTypes().get(0).getBoxedType());
             } else {
                 builder.null_();
             }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemData.java	Wed Mar 13 11:32:43 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemData.java	Wed Mar 13 19:58:28 2013 +0100
@@ -32,35 +32,42 @@
 
 public class TypeSystemData extends Template {
 
-    private final TypeData[] types;
-    private final TypeMirror[] primitiveTypeMirrors;
-    private final TypeMirror[] boxedTypeMirrors;
+    private List<TypeData> types;
+    private List<TypeMirror> primitiveTypeMirrors = new ArrayList<>();
+    private List<TypeMirror> boxedTypeMirrors = new ArrayList<>();
 
-    private final TypeMirror genericType;
+    private TypeMirror genericType;
+    private TypeData voidType;
+
+    public TypeSystemData(TypeElement templateType, AnnotationMirror annotation) {
+        super(templateType, null, annotation);
+    }
 
-    private final TypeData voidType;
+    void setTypes(List<TypeData> types) {
+        this.types = types;
+        if (types != null) {
+            for (TypeData typeData : types) {
+                primitiveTypeMirrors.add(typeData.getPrimitiveType());
+                boxedTypeMirrors.add(typeData.getBoxedType());
+            }
+        }
+    }
 
-    public TypeSystemData(TypeElement templateType, AnnotationMirror annotation, TypeData[] types, TypeMirror genericType, TypeData voidType) {
-        super(templateType, null, annotation);
-        this.types = types;
+    void setGenericType(TypeMirror genericType) {
         this.genericType = genericType;
+    }
+
+    void setVoidType(TypeData voidType) {
         this.voidType = voidType;
-        this.primitiveTypeMirrors = new TypeMirror[types.length];
-        for (int i = 0; i < types.length; i++) {
-            primitiveTypeMirrors[i] = types[i].getPrimitiveType();
-        }
+    }
 
-        this.boxedTypeMirrors = new TypeMirror[types.length];
-        for (int i = 0; i < types.length; i++) {
-            boxedTypeMirrors[i] = types[i].getBoxedType();
+    @Override
+    protected List<MessageContainer> findChildContainers() {
+        List<MessageContainer> sinks = new ArrayList<>();
+        if (types != null) {
+            sinks.addAll(types);
         }
-
-        for (TypeData type : types) {
-            type.typeSystem = this;
-        }
-        if (voidType != null) {
-            voidType.typeSystem = this;
-        }
+        return sinks;
     }
 
     public boolean isGeneric(TypeMirror type) {
@@ -71,16 +78,16 @@
         return voidType;
     }
 
-    public TypeData[] getTypes() {
-        return types;
+    public List<TypeMirror> getBoxedTypeMirrors() {
+        return boxedTypeMirrors;
     }
 
-    public TypeMirror[] getPrimitiveTypeMirrors() {
+    public List<TypeMirror> getPrimitiveTypeMirrors() {
         return primitiveTypeMirrors;
     }
 
-    public TypeMirror[] getBoxedTypeMirrors() {
-        return boxedTypeMirrors;
+    public List<TypeData> getTypes() {
+        return types;
     }
 
     public TypeMirror getGenericType() {
@@ -88,7 +95,7 @@
     }
 
     public TypeData getGenericTypeData() {
-        TypeData result = types[types.length - 1];
+        TypeData result = types.get(types.size() - 1);
         assert result.getBoxedType() == genericType;
         return result;
     }
@@ -111,7 +118,7 @@
         if (index == -1) {
             return null;
         }
-        return types[index];
+        return types.get(index);
     }
 
     public int findType(TypeData typeData) {
@@ -119,8 +126,8 @@
     }
 
     public int findType(TypeMirror type) {
-        for (int i = 0; i < types.length; i++) {
-            if (Utils.typeEquals(types[i].getPrimitiveType(), type)) {
+        for (int i = 0; i < types.size(); i++) {
+            if (Utils.typeEquals(types.get(i).getPrimitiveType(), type)) {
                 return i;
             }
         }
@@ -129,7 +136,7 @@
 
     @Override
     public String toString() {
-        return getClass().getSimpleName() + "[template = " + Utils.getSimpleName(getTemplateType()) + ", types = " + Arrays.toString(types) + "]";
+        return getClass().getSimpleName() + "[template = " + Utils.getSimpleName(getTemplateType()) + ", types = " + types + "]";
     }
 
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemMethodParser.java	Wed Mar 13 11:32:43 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemMethodParser.java	Wed Mar 13 19:58:28 2013 +0100
@@ -43,18 +43,24 @@
         return Utils.findAnnotationMirror(getContext().getEnvironment(), method, getAnnotationType()) != null;
     }
 
-    protected TypeData findTypeByMethodName(ExecutableElement method, AnnotationMirror annotationMirror, String prefix) {
-        String methodName = method.getSimpleName().toString();
+    protected TypeData findTypeByMethodName(String methodName, String prefix) {
+        String typeName = methodName.substring(prefix.length(), methodName.length());
+        TypeData type = getTypeSystem().findType(typeName);
+        return type;
+    }
+
+    protected TypeData findTypeByMethodName(TemplateMethod method, String prefix) {
+        String methodName = method.getMethodName();
         if (!methodName.startsWith(prefix)) {
-            String annotationName = Utils.getSimpleName(annotationMirror.getAnnotationType());
-            getContext().getLog().error(method, "Methods annotated with %s must match the pattern '%s'.", annotationName, String.format("%s${typeName}", prefix));
+            String annotationName = Utils.getSimpleName(method.getMessageAnnotation().getAnnotationType());
+            method.addError("Methods annotated with %s must match the pattern '%s'.", annotationName, String.format("%s${typeName}", prefix));
             return null;
         }
         String typeName = methodName.substring(prefix.length(), methodName.length());
         TypeData type = getTypeSystem().findType(typeName);
         if (type == null) {
             String annotationName = TypeSystem.class.getSimpleName();
-            getContext().getLog().error(method, "Type '%s' is not declared in this @%s.", typeName, annotationName);
+            method.addError("Type '%s' is not declared in this @%s.", typeName, annotationName);
             return null;
         }
 
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemParser.java	Wed Mar 13 11:32:43 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemParser.java	Wed Mar 13 19:58:28 2013 +0100
@@ -52,27 +52,39 @@
     protected TypeSystemData parse(Element element, AnnotationMirror mirror) {
         TypeElement templateType = (TypeElement) element;
         AnnotationMirror templateTypeAnnotation = mirror;
+        TypeSystemData typeSystem = new TypeSystemData(templateType, templateTypeAnnotation);
 
-        if (!verifyTemplateType(templateType, templateTypeAnnotation)) {
-            return null;
+        // annotation type on class path!?
+        TypeElement annotationTypeElement = processingEnv.getElementUtils().getTypeElement(getAnnotationType().getCanonicalName());
+        if (annotationTypeElement == null) {
+            typeSystem.addError("Required class %s is not on the classpath.", getAnnotationType().getName());
+        }
+        if (templateType.getModifiers().contains(Modifier.PRIVATE)) {
+            typeSystem.addError("A @%s must have at least package protected visibility.", getAnnotationType().getName());
         }
 
-        TypeData[] types = parseTypes(templateType, templateTypeAnnotation);
-        if (types == null) {
-            return null;
+        if (templateType.getModifiers().contains(Modifier.FINAL)) {
+            typeSystem.addError("The @%s must not be final.", getAnnotationType().getName());
+        }
+        if (typeSystem.hasErrors()) {
+            return typeSystem;
+        }
+
+        typeSystem.setTypes(parseTypes(typeSystem));
+        if (typeSystem.getTypes() == null) {
+            return typeSystem;
         }
 
         TypeMirror genericType = context.getType(Object.class);
-        TypeData voidType = new TypeData(templateType, templateTypeAnnotation, context.getType(void.class), context.getType(Void.class));
-
-        TypeSystemData typeSystem = new TypeSystemData(templateType, templateTypeAnnotation, types, genericType, voidType);
+        TypeData voidType = new TypeData(typeSystem, null, context.getType(void.class), context.getType(Void.class));
 
-        if (!verifyExclusiveMethodAnnotation(templateType, TypeCast.class, TypeCheck.class)) {
-            return null;
-        }
+        typeSystem.setGenericType(genericType);
+        typeSystem.setVoidType(voidType);
+
+        verifyExclusiveMethodAnnotation(typeSystem, TypeCast.class, TypeCheck.class);
 
         List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(templateType));
-        typeSystem.setExtensionElements(getExtensionParser().parseAll(templateType, elements));
+        typeSystem.setExtensionElements(getExtensionParser().parseAll(typeSystem, elements));
         if (typeSystem.getExtensionElements() != null) {
             elements.addAll(typeSystem.getExtensionElements());
         }
@@ -81,7 +93,7 @@
         List<TypeCheckData> checks = new TypeCheckParser(context, typeSystem).parse(elements);
 
         if (casts == null || checks == null) {
-            return null;
+            return typeSystem;
         }
 
         for (TypeCheckData check : checks) {
@@ -92,24 +104,15 @@
             cast.getTargetType().addTypeCast(cast);
         }
 
-        if (!verifyGenericTypeChecksAndCasts(types)) {
-            return null;
-        }
-
-        if (!verifyMethodSignatures(element, types)) {
-            return null;
-        }
-
-        if (!verifyNamesUnique(templateType, templateTypeAnnotation, types)) {
-            return null;
-        }
+        verifyGenericTypeChecksAndCasts(typeSystem);
+        verifyMethodSignatures(typeSystem);
+        verifyNamesUnique(typeSystem);
 
         return typeSystem;
     }
 
-    private boolean verifyGenericTypeChecksAndCasts(TypeData[] types) {
-        boolean valid = true;
-        for (TypeData type : types) {
+    private static void verifyGenericTypeChecksAndCasts(TypeSystemData typeSystem) {
+        for (TypeData type : typeSystem.getTypes()) {
             if (!type.getTypeChecks().isEmpty()) {
                 boolean hasGeneric = false;
                 for (TypeCheckData typeCheck : type.getTypeChecks()) {
@@ -119,10 +122,9 @@
                     }
                 }
                 if (!hasGeneric) {
-                    log.error(type.getTypeSystem().getTemplateType(), "No generic but specific @%s method %s for type %s specified. "
-                                    + "Specify a generic @%s method with parameter type %s to resolve this.", TypeCheck.class.getSimpleName(), TypeSystemCodeGenerator.isTypeMethodName(type),
-                                    Utils.getSimpleName(type.getBoxedType()), TypeCheck.class.getSimpleName(), Object.class.getSimpleName());
-                    valid = false;
+                    type.addError("No generic but specific @%s method %s for type %s specified. " + "Specify a generic @%s method with parameter type %s to resolve this.",
+                                    TypeCheck.class.getSimpleName(), TypeSystemCodeGenerator.isTypeMethodName(type), Utils.getSimpleName(type.getBoxedType()), TypeCheck.class.getSimpleName(),
+                                    Object.class.getSimpleName());
                 }
             }
             if (!type.getTypeCasts().isEmpty()) {
@@ -134,60 +136,55 @@
                     }
                 }
                 if (!hasGeneric) {
-                    log.error(type.getTypeSystem().getTemplateType(), "No generic but specific @%s method %s for type %s specified. "
-                                    + "Specify a generic @%s method with parameter type %s to resolve this.", TypeCast.class.getSimpleName(), TypeSystemCodeGenerator.asTypeMethodName(type),
-                                    Utils.getSimpleName(type.getBoxedType()), TypeCast.class.getSimpleName(), Object.class.getSimpleName());
-                    valid = false;
+                    type.addError("No generic but specific @%s method %s for type %s specified. " + "Specify a generic @%s method with parameter type %s to resolve this.",
+                                    TypeCast.class.getSimpleName(), TypeSystemCodeGenerator.asTypeMethodName(type), Utils.getSimpleName(type.getBoxedType()), TypeCast.class.getSimpleName(),
+                                    Object.class.getSimpleName());
                 }
             }
         }
-        return valid;
     }
 
-    private TypeData[] parseTypes(TypeElement templateType, AnnotationMirror templateTypeAnnotation) {
-        List<TypeMirror> typeMirrors = Utils.getAnnotationValueList(TypeMirror.class, templateTypeAnnotation, "value");
-        if (typeMirrors.size() == 0) {
-            log.error(templateType, templateTypeAnnotation, "At least one type must be defined.");
-            return null;
+    private List<TypeData> parseTypes(TypeSystemData typeSystem) {
+        List<TypeData> types = new ArrayList<>();
+        List<TypeMirror> typeMirrors = Utils.getAnnotationValueList(TypeMirror.class, typeSystem.getTemplateTypeAnnotation(), "value");
+        if (typeMirrors.isEmpty()) {
+            typeSystem.addError("At least one type must be defined.");
+            return types;
         }
 
-        final AnnotationValue annotationValue = Utils.getAnnotationValue(templateTypeAnnotation, "value");
+        final AnnotationValue annotationValue = Utils.getAnnotationValue(typeSystem.getTemplateTypeAnnotation(), "value");
         final TypeMirror objectType = context.getType(Object.class);
 
-        List<TypeData> types = new ArrayList<>();
         for (TypeMirror primitiveType : typeMirrors) {
+            TypeMirror boxedType = Utils.boxType(context, primitiveType);
+            TypeData typeData = new TypeData(typeSystem, annotationValue, primitiveType, boxedType);
 
             if (isPrimitiveWrapper(primitiveType)) {
-                log.error(templateType, templateTypeAnnotation, annotationValue, "Types must not contain primitive wrapper types.");
-                continue;
+                typeData.addError("Types must not contain primitive wrapper types.");
             }
 
-            TypeMirror boxedType = Utils.boxType(context, primitiveType);
-
             if (Utils.typeEquals(boxedType, objectType)) {
-                log.error(templateType, templateTypeAnnotation, annotationValue, "Types must not contain the generic type java.lang.Object.");
-                continue;
+                typeData.addError("Types must not contain the generic type java.lang.Object.");
             }
 
-            types.add(new TypeData(templateType, templateTypeAnnotation, primitiveType, boxedType));
+            types.add(typeData);
         }
 
-        verifyTypeOrder(templateType, templateTypeAnnotation, annotationValue, types);
+        verifyTypeOrder(types);
 
-        types.add(new TypeData(templateType, templateTypeAnnotation, objectType, objectType));
+        types.add(new TypeData(typeSystem, annotationValue, objectType, objectType));
 
-        return types.toArray(new TypeData[types.size()]);
+        return types;
     }
 
-    private void verifyTypeOrder(TypeElement templateType, AnnotationMirror templateTypeAnnotation, AnnotationValue annotationValue, List<TypeData> types) {
+    private static void verifyTypeOrder(List<TypeData> types) {
         Map<String, List<String>> invalidTypes = new HashMap<>();
 
         for (int i = types.size() - 1; i >= 0; i--) {
             TypeData typeData = types.get(i);
             TypeMirror type = typeData.getBoxedType();
             if (invalidTypes.containsKey(Utils.getQualifiedName(type))) {
-                log.error(templateType, templateTypeAnnotation, annotationValue, "Invalid type order. The type(s) %s are inherited from a earlier defined type %s.",
-                                invalidTypes.get(Utils.getQualifiedName(type)), Utils.getQualifiedName(type));
+                typeData.addError("Invalid type order. The type(s) %s are inherited from a earlier defined type %s.", invalidTypes.get(Utils.getQualifiedName(type)), Utils.getQualifiedName(type));
             }
             List<String> nextInvalidTypes = Utils.getQualifiedSuperTypeNames(Utils.fromTypeMirror(type));
             nextInvalidTypes.add(getQualifiedName(type));
@@ -216,19 +213,18 @@
         return false;
     }
 
-    private boolean verifyMethodSignatures(Element element, TypeData[] types) {
+    private void verifyMethodSignatures(TypeSystemData typeSystem) {
         Set<String> generatedIsMethodNames = new HashSet<>();
         Set<String> generatedAsMethodNames = new HashSet<>();
         Set<String> generatedExpectMethodNames = new HashSet<>();
 
-        for (TypeData typeData : types) {
+        for (TypeData typeData : typeSystem.getTypes()) {
             generatedIsMethodNames.add(TypeSystemCodeGenerator.isTypeMethodName(typeData));
             generatedAsMethodNames.add(TypeSystemCodeGenerator.asTypeMethodName(typeData));
             generatedExpectMethodNames.add(TypeSystemCodeGenerator.expectTypeMethodName(typeData));
         }
 
-        boolean valid = true;
-        List<ExecutableElement> methods = ElementFilter.methodsIn(element.getEnclosedElements());
+        List<ExecutableElement> methods = ElementFilter.methodsIn(typeSystem.getTemplateType().getEnclosedElements());
         for (ExecutableElement method : methods) {
             if (method.getModifiers().contains(Modifier.PRIVATE)) {
                 // will not conflict overridden methods
@@ -238,51 +234,48 @@
             }
             String methodName = method.getSimpleName().toString();
             if (generatedIsMethodNames.contains(methodName)) {
-                valid &= verifyIsMethod(method);
+                verifyIsMethod(typeSystem, method);
             } else if (generatedAsMethodNames.contains(methodName)) {
-                valid &= verifyAsMethod(method);
+                verifyAsMethod(typeSystem, method);
             } else if (generatedExpectMethodNames.contains(methodName)) {
-                valid &= verifyExpectMethod(method);
+                verifyExpectMethod(typeSystem);
             }
         }
-        return valid;
     }
 
-    private boolean verifyIsMethod(ExecutableElement method) {
+    private boolean verifyIsMethod(TypeSystemData typeSystem, ExecutableElement method) {
         AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, TypeCheck.class);
         if (mirror == null) {
-            log.error(method, "Method starting with the pattern is${typeName} must be annotated with @%s.", TypeCheck.class.getSimpleName());
+            typeSystem.addError("Method starting with the pattern is${typeName} must be annotated with @%s.", TypeCheck.class.getSimpleName());
             return false;
         }
         return true;
     }
 
-    private boolean verifyAsMethod(ExecutableElement method) {
+    private boolean verifyAsMethod(TypeSystemData typeSystem, ExecutableElement method) {
         AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, TypeCast.class);
         if (mirror == null) {
-            log.error(method, "Method starting with the pattern as${typeName} must be annotated with @%s.", TypeCast.class.getSimpleName());
+            typeSystem.addError("Method starting with the pattern as${typeName} must be annotated with @%s.", TypeCast.class.getSimpleName());
             return false;
         }
         return true;
     }
 
-    private boolean verifyExpectMethod(ExecutableElement method) {
-        log.error(method, "Method starting with the pattern expect${typeName} must not be declared manually.");
+    private static boolean verifyExpectMethod(TypeSystemData typeSystem) {
+        typeSystem.addError("Method starting with the pattern expect${typeName} must not be declared manually.");
         return false;
     }
 
-    private boolean verifyNamesUnique(TypeElement templateType, AnnotationMirror templateTypeAnnotation, TypeData[] types) {
-        boolean valid = true;
-        for (int i = 0; i < types.length; i++) {
-            for (int j = i + 1; j < types.length; j++) {
-                String name1 = Utils.getSimpleName(types[i].getBoxedType());
-                String name2 = Utils.getSimpleName(types[j].getBoxedType());
+    private static void verifyNamesUnique(TypeSystemData typeSystem) {
+        List<TypeData> types = typeSystem.getTypes();
+        for (int i = 0; i < types.size(); i++) {
+            for (int j = i + 1; j < types.size(); j++) {
+                String name1 = Utils.getSimpleName(types.get(i).getBoxedType());
+                String name2 = Utils.getSimpleName(types.get(j).getBoxedType());
                 if (name1.equalsIgnoreCase(name2)) {
-                    log.error(templateType, templateTypeAnnotation, "Two types result in the same name: %s, %s.", name1, name2);
-                    valid = false;
+                    typeSystem.addError("Two types result in the same name: %s, %s.", name1, name2);
                 }
             }
         }
-        return valid;
     }
 }