changeset 18770:2c669386b5d0

Truffle-DSL: fix crash if type in rewriteOn is not of type Throwable. Improved error messages for Specialization#rewriteOn.
author Christian Humer <christian.humer@gmail.com>
date Fri, 02 Jan 2015 14:31:51 +0100
parents 144fba40c979
children 15fe16c45d64
files graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/SpecializationFallthroughTest.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ExecutableTypeData.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationMethodParser.java
diffstat 4 files changed, 36 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/SpecializationFallthroughTest.java	Wed Dec 31 17:35:10 2014 +0000
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/SpecializationFallthroughTest.java	Fri Jan 02 14:31:51 2015 +0100
@@ -334,36 +334,37 @@
 
     }
 
+    /* Throwing RuntimeExceptions without rewriteOn is allowed. */
     @NodeChildren({@NodeChild("a")})
-    static class FallthroughTest6 extends ValueNode {
+    static class FallthroughExceptionType0 extends ValueNode {
 
-        static int fallthrough1;
-        static int fallthrough2;
-        static int fallthrough3;
-        static int fallthrough4;
-
-        @Specialization(order = 1, rewriteOn = ArithmeticException.class)
-        int do4(int a) throws ArithmeticException {
+        @Specialization
+        int do4(int a) throws RuntimeException {
             return a;
         }
 
-        @Specialization(order = 2, rewriteOn = ArithmeticException.class)
-        int do2(int a) throws ArithmeticException {
+    }
+
+    /* Non runtime exceptions must be verified. */
+    @NodeChildren({@NodeChild("a")})
+    static class FallthroughExceptionType1 extends ValueNode {
+
+        @ExpectError("A rewriteOn checked exception was specified but not thrown in the method's throws clause. The @Specialization method must specify a throws clause with the exception type 'java.lang.Throwable'.")
+        @Specialization(rewriteOn = Throwable.class)
+        int do4(int a) {
             return a;
         }
 
-        @Specialization(order = 3, rewriteOn = ArithmeticException.class)
-        int do3(int a) throws ArithmeticException {
-            return a;
-        }
+    }
 
-        @Specialization(order = 4, rewriteOn = ArithmeticException.class)
-        int do1(int a) throws ArithmeticException {
-            return a;
-        }
+    /* Checked exception must be verified. */
+    @NodeChildren({@NodeChild("a")})
+    static class FallthroughExceptionType2 extends ValueNode {
 
+        @ExpectError("A checked exception 'java.lang.Throwable' is thrown but is not specified using the rewriteOn property. "
+                        + "Checked exceptions that are not used for rewriting are not handled by the DSL. Use RuntimeExceptions for this purpose instead.")
         @Specialization
-        double do5(double a) {
+        int do4(int a) throws Throwable {
             return a;
         }
 
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java	Wed Dec 31 17:35:10 2014 +0000
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java	Fri Jan 02 14:31:51 2015 +0100
@@ -988,9 +988,7 @@
         }
 
         // search for any super types
-        TypeElement exceptionTypeElement = fromTypeMirror(exceptionType);
-        List<TypeElement> superTypes = getSuperTypes(exceptionTypeElement);
-        for (TypeElement typeElement : superTypes) {
+        for (TypeElement typeElement : getSuperTypes(fromTypeMirror(exceptionType))) {
             if (ElementUtils.containsType(thrownTypes, typeElement.asType())) {
                 return true;
             }
@@ -1022,11 +1020,7 @@
 
     private static boolean isRuntimeException(TypeMirror type) {
         Set<String> typeSuperSet = new HashSet<>(getQualifiedSuperTypeNames(fromTypeMirror(type)));
-        String typeName = getQualifiedName(type);
-        if (!typeSuperSet.contains(Throwable.class.getCanonicalName()) && !typeName.equals(Throwable.class.getCanonicalName())) {
-            throw new IllegalArgumentException("Given type does not extend Throwable.");
-        }
-        return typeSuperSet.contains(RuntimeException.class.getCanonicalName()) || typeName.equals(RuntimeException.class.getCanonicalName());
+        return typeSuperSet.contains(RuntimeException.class.getCanonicalName()) || getQualifiedName(type).equals(RuntimeException.class.getCanonicalName());
     }
 
     private static boolean containsType(Collection<? extends TypeMirror> collection, TypeMirror type) {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ExecutableTypeData.java	Wed Dec 31 17:35:10 2014 +0000
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ExecutableTypeData.java	Fri Jan 02 14:31:51 2015 +0100
@@ -24,6 +24,7 @@
 
 import javax.lang.model.element.*;
 
+import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.dsl.processor.*;
 import com.oracle.truffle.dsl.processor.java.*;
 
@@ -50,7 +51,7 @@
     }
 
     public boolean hasUnexpectedValue(ProcessorContext context) {
-        return ElementUtils.canThrowType(getMethod().getThrownTypes(), context.getTruffleTypes().getUnexpectedValueException());
+        return ElementUtils.canThrowType(getMethod().getThrownTypes(), context.getType(UnexpectedResultException.class));
     }
 
     public boolean isFinal() {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationMethodParser.java	Wed Dec 31 17:35:10 2014 +0000
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationMethodParser.java	Fri Jan 02 14:31:51 2015 +0100
@@ -59,14 +59,25 @@
         AnnotationValue rewriteValue = ElementUtils.getAnnotationValue(method.getMarkerAnnotation(), "rewriteOn");
         List<TypeMirror> exceptionTypes = ElementUtils.getAnnotationValueList(TypeMirror.class, method.getMarkerAnnotation(), "rewriteOn");
         List<SpecializationThrowsData> exceptionData = new ArrayList<>();
+        List<TypeMirror> rewriteOnTypes = new ArrayList<>();
         for (TypeMirror exceptionType : exceptionTypes) {
             SpecializationThrowsData throwsData = new SpecializationThrowsData(method.getMarkerAnnotation(), rewriteValue, exceptionType);
             if (!ElementUtils.canThrowType(method.getMethod().getThrownTypes(), exceptionType)) {
-                throwsData.addError("Method must specify a throws clause with the exception type '%s'.", ElementUtils.getQualifiedName(exceptionType));
+                method.addError("A rewriteOn checked exception was specified but not thrown in the method's throws clause. The @%s method must specify a throws clause with the exception type '%s'.",
+                                Specialization.class.getSimpleName(), ElementUtils.getQualifiedName(exceptionType));
             }
+            rewriteOnTypes.add(throwsData.getJavaClass());
             exceptionData.add(throwsData);
         }
 
+        for (TypeMirror typeMirror : method.getMethod().getThrownTypes()) {
+            if (!ElementUtils.canThrowType(rewriteOnTypes, typeMirror)) {
+                method.addError(rewriteValue,
+                                "A checked exception '%s' is thrown but is not specified using the rewriteOn property. Checked exceptions that are not used for rewriting are not handled by the DSL. Use RuntimeExceptions for this purpose instead.",
+                                ElementUtils.getQualifiedName(typeMirror));
+            }
+        }
+
         Collections.sort(exceptionData, new Comparator<SpecializationThrowsData>() {
 
             @Override