changeset 18782:3ea386a1036f

Truffle-DSL: breaking: @TypeCheck and @TypeCast now require casted/checked type as explicit parameter. Previously the type was parsed from the method name. (GRAAL-446 #resolve)
author Christian Humer <christian.humer@gmail.com>
date Mon, 05 Jan 2015 20:23:22 +0100
parents 941761f6b736
children 7d67a33e1bbb
files graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ArrayTest.java graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TypeSystemErrorsTest.java graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TypeSystemTest.java graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/TypeCast.java graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/TypeCheck.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeCastParser.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeCheckParser.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemMethodParser.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLTypes.java
diffstat 10 files changed, 133 insertions(+), 161 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ArrayTest.java	Mon Jan 05 20:23:22 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ArrayTest.java	Mon Jan 05 20:23:22 2015 +0100
@@ -109,12 +109,12 @@
             return newArray;
         }
 
-        @TypeCheck
-        public static boolean isIntArray(Object array) {
+        @TypeCheck(int[].class)
+        public static boolean isIntArray2(Object array) {
             return array instanceof int[];
         }
 
-        @TypeCast
+        @TypeCast(int[].class)
         public static int[] asIntArray(Object array) {
             return (int[]) array;
         }
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TypeSystemErrorsTest.java	Mon Jan 05 20:23:22 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TypeSystemErrorsTest.java	Mon Jan 05 20:23:22 2015 +0100
@@ -38,33 +38,82 @@
 
     }
 
-    @TypeSystem({int.class, boolean.class})
-    public static class Types2 {
-
-        @TypeCast
-        @ExpectError("The provided return type \"String\" does not match expected return type \"int\".%")
-        String asInteger(Object value) {
-            return (String) value;
-        }
-
-    }
-
-    @TypeSystem({int.class, boolean.class})
-    public static class Types3 {
-
-        @TypeCast
-        @ExpectError("The provided return type \"boolean\" does not match expected return type \"int\".%")
-        boolean asInteger(Object value) {
-            return (boolean) value;
-        }
-
-    }
-
     @TypeSystemReference(Types0.class)
     @NodeChild
     @ExpectError("The @TypeSystem of the node and the @TypeSystem of the @NodeChild does not match. Types0 != SimpleTypes. ")
     abstract static class ErrorNode1 extends ValueNode {
+    }
 
+    @TypeSystem({int.class})
+    public static class CastError1 {
+        @TypeCast(int.class)
+        @ExpectError("The provided return type \"String\" does not match expected return type \"int\".%")
+        public static String asInteger(Object value) {
+            return (String) value;
+        }
+    }
+
+    @TypeSystem({int.class})
+    public static class CastError2 {
+        @TypeCast(int.class)
+        @ExpectError("The provided return type \"boolean\" does not match expected return type \"int\".%")
+        public static boolean asInteger(Object value) {
+            return (boolean) value;
+        }
+    }
+
+    @TypeSystem({boolean.class})
+    public static class CastError3 {
+        @ExpectError("The type 'int' is not declared in the @TypeSystem.")
+        @TypeCast(int.class)
+        public static int asInt(Object value) {
+            return (int) value;
+        }
+    }
+
+    @TypeSystem({int.class})
+    public static class CastError4 {
+        @ExpectError("@TypeCast annotated method asInt must be public and static.")
+        @TypeCast(int.class)
+        public int asInt(Object value) {
+            return (int) value;
+        }
+    }
+
+    @TypeSystem({int.class})
+    public static class CastError5 {
+        @ExpectError("@TypeCast annotated method asInt must be public and static.")
+        @TypeCast(int.class)
+        static int asInt(Object value) {
+            return (int) value;
+        }
+    }
+
+    @TypeSystem({boolean.class})
+    public static class CheckError1 {
+        @ExpectError("The type 'int' is not declared in the @TypeSystem.")
+        @TypeCheck(int.class)
+        public static boolean isInt(Object value) {
+            return value instanceof Integer;
+        }
+    }
+
+    @TypeSystem({int.class})
+    public static class CheckError2 {
+        @ExpectError("@TypeCheck annotated method isInt must be public and static.")
+        @TypeCheck(int.class)
+        public boolean isInt(Object value) {
+            return value instanceof Integer;
+        }
+    }
+
+    @TypeSystem({int.class})
+    public static class CheckError3 {
+        @ExpectError("@TypeCheck annotated method isInt must be public and static.")
+        @TypeCheck(int.class)
+        static boolean isInt(Object value) {
+            return value instanceof Integer;
+        }
     }
 
 }
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TypeSystemTest.java	Mon Jan 05 20:23:22 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TypeSystemTest.java	Mon Jan 05 20:23:22 2015 +0100
@@ -41,13 +41,13 @@
         static int intCheck;
         static int intCast;
 
-        @TypeCheck
+        @TypeCheck(int.class)
         public static boolean isInteger(Object value) {
             intCheck++;
             return value instanceof Integer;
         }
 
-        @TypeCast
+        @TypeCast(int.class)
         public static int asInteger(Object value) {
             intCast++;
             return (int) value;
--- a/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/TypeCast.java	Mon Jan 05 20:23:22 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/TypeCast.java	Mon Jan 05 20:23:22 2015 +0100
@@ -26,8 +26,30 @@
 
 import java.lang.annotation.*;
 
+/**
+ * Overrides the standard way of casting a certain type in a {@link TypeSystem}. This is useful for
+ * types where the guest language specific type cast can be implemented more efficiently than an
+ * instanceof check. The annotated method must be contained in a {@link TypeSystem} annotated class.
+ * Type checks must conform to the following signature: <code>public static Type as{TypeName}(Object
+ * value)</code>. The casted type must be a type declared in the {@link TypeSystem}.
+ *
+ * <p>
+ * If no {@link TypeCast} is declared then the type system implicitly uses a type cast that can be
+ * declared as follows:
+ *
+ * <pre>
+ * {@literal @}TypeCast(Type.class)
+ * public static Type asType(Object value) {
+ *         return (Type) value;
+ * }
+ * </pre>
+ *
+ * @see TypeCheck
+ */
 @Retention(RetentionPolicy.CLASS)
 @Target({ElementType.METHOD})
 public @interface TypeCast {
 
+    Class<?> value();
+
 }
--- a/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/TypeCheck.java	Mon Jan 05 20:23:22 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/TypeCheck.java	Mon Jan 05 20:23:22 2015 +0100
@@ -27,54 +27,29 @@
 import java.lang.annotation.*;
 
 /**
- * <p>
- * Provides a way to define a custom type check for a defined type. The name of the annotated method
- * must fit to the pattern is${typeName} (eg. isInteger), where ${typeName} must be a valid type
- * defined in the parent {@link TypeSystem}. The annotated method must have exactly one argument
- * where the type of the argument is the generic type {@link Object} or a more specific one from the
- * {@link TypeSystem}. You can define multiple overloaded {@link TypeCheck} methods for the same
- * type. This can be used to reduce the boxing overhead in type conversions.
- * </p>
+ * Overrides the standard way of checking for a certain type in a {@link TypeSystem}. This is useful
+ * for types where the guest language specific type check can be implemented more efficiently than a
+ * direct cast. The annotated method must be contained in a {@link TypeSystem} annotated class. Type
+ * checks must conform to the following signature: <code>public static boolean is{TypeName}(Object
+ * value)</code>. The checked type must be a type declared in the {@link TypeSystem}.
  *
  * <p>
- * By default the system generates type checks for all types in the parent {@link TypeSystem} which
- * look like the follows:
+ * If no {@link TypeCheck} is declared then the type system implicitly uses a type check that can be
+ * declared as follows:
  *
  * <pre>
- * {@literal @}TypeCheck
- * boolean is${typeName}(Object value) {
- *         return value instanceof ${typeName};
+ * {@literal @}TypeCheck(Type.class)
+ * public static boolean isType(Object value) {
+ *         return value instanceof Type;
  * }
  * </pre>
  *
- * <b>Example:</b>
- * <p>
- * A type check for BigInteger with one overloaded optimized variant to reduce boxing.
- * </p>
- *
- * <pre>
- *
- *
- * {@literal @}TypeSystem(types = {int.class, BigInteger.class, String.class}, nodeBaseClass = TypedNode.class)
- * public abstract class Types {
- * 
- *     {@literal @}TypeCheck
- *     public boolean isBigInteger(Object value) {
- *         return value instanceof Integer || value instanceof BigInteger;
- *     }
- * 
- *     {@literal @}TypeCheck
- *     public boolean isBigInteger(int value) {
- *         return true;
- *     }
- * 
- * }
- * </pre>
- *
- *
+ * @see TypeCast
  */
 @Retention(RetentionPolicy.CLASS)
 @Target({ElementType.METHOD})
 public @interface TypeCheck {
 
+    Class<?> value();
+
 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeCastParser.java	Mon Jan 05 20:23:22 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeCastParser.java	Mon Jan 05 20:23:22 2015 +0100
@@ -25,6 +25,7 @@
 import java.lang.annotation.*;
 
 import javax.lang.model.element.*;
+import javax.lang.model.type.*;
 
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.dsl.processor.*;
@@ -39,39 +40,17 @@
 
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
-        TypeData targetType = findTypeByMethodName(method.getSimpleName().toString(), "as");
-        if (targetType == null) {
-            return null;
-        }
-        MethodSpec spec = new MethodSpec(new ParameterSpec("returnType", targetType.getPrimitiveType()));
-        spec.addRequired(new ParameterSpec("value", getTypeSystem().getPrimitiveTypeMirrors(), getTypeSystem().getTypeIdentifiers()));
+        TypeMirror targetTypeMirror = ElementUtils.getAnnotationValue(TypeMirror.class, mirror, "value");
+        MethodSpec spec = new MethodSpec(new ParameterSpec("returnType", targetTypeMirror));
+        spec.addRequired(new ParameterSpec("value", getTypeSystem().getGenericType()));
         return spec;
     }
 
     @Override
     public TypeCastData create(TemplateMethod method, boolean invalid) {
-        if (invalid) {
-            return new TypeCastData(method, null, null);
-        }
-
-        TypeData targetType = findTypeByMethodName(method, "as");
-        Parameter parameter = method.findParameter("valueValue");
-
-        TypeData sourceType = null;
-        if (parameter != null) {
-            sourceType = getTypeSystem().findTypeData(parameter.getType());
-        }
-        TypeCastData cast = new TypeCastData(method, sourceType, targetType);
-
-        if (!method.getMethod().getModifiers().contains(Modifier.STATIC)) {
-            cast.addError("@%s annotated method %s must be static.", TypeCast.class.getSimpleName(), method.getMethodName());
-        }
-
-        if (targetType != method.getReturnType().getTypeSystemType()) {
-            cast.addError("Cast type %s does not match to the returned type %s.", ElementUtils.getSimpleName(targetType.getPrimitiveType()),
-                            method.getReturnType() != null ? ElementUtils.getSimpleName(method.getReturnType().getTypeSystemType().getPrimitiveType()) : null);
-        }
-        return cast;
+        TypeData targetType = resolveCastOrCheck(method);
+        TypeData sourceType = getTypeSystem().getGenericTypeData();
+        return new TypeCastData(method, sourceType, targetType);
     }
 
     @Override
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeCheckParser.java	Mon Jan 05 20:23:22 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeCheckParser.java	Mon Jan 05 20:23:22 2015 +0100
@@ -38,25 +38,15 @@
 
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
-        TypeData targetType = findTypeByMethodName(method.getSimpleName().toString(), "is");
-        if (targetType == null) {
-            return null;
-        }
         MethodSpec spec = new MethodSpec(new ParameterSpec("returnType", getContext().getType(boolean.class)));
-        spec.addRequired(new ParameterSpec("value", getTypeSystem().getPrimitiveTypeMirrors(), getTypeSystem().getTypeIdentifiers()));
+        spec.addRequired(new ParameterSpec("value", getTypeSystem().getGenericType()));
         return spec;
     }
 
     @Override
     public TypeCheckData create(TemplateMethod method, boolean invalid) {
-        TypeData checkedType = findTypeByMethodName(method, "is");
-        assert checkedType != null;
-        Parameter parameter = method.findParameter("valueValue");
-        assert parameter != null;
-        if (!method.getMethod().getModifiers().contains(Modifier.STATIC)) {
-            method.addError("@%s annotated method %s must be static.", TypeCheck.class.getSimpleName(), method.getMethodName());
-        }
-        return new TypeCheckData(method, checkedType, parameter.getTypeSystemType());
+        TypeData targetType = resolveCastOrCheck(method);
+        return new TypeCheckData(method, targetType, targetType);
     }
 
     @Override
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemMethodParser.java	Mon Jan 05 20:23:22 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemMethodParser.java	Mon Jan 05 20:23:22 2015 +0100
@@ -23,6 +23,7 @@
 package com.oracle.truffle.dsl.processor.parser;
 
 import javax.lang.model.element.*;
+import javax.lang.model.type.*;
 
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.dsl.processor.*;
@@ -40,28 +41,18 @@
         return ElementUtils.findAnnotationMirror(getContext().getEnvironment(), method, getAnnotationType()) != null;
     }
 
-    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 = ElementUtils.getSimpleName(method.getMessageAnnotation().getAnnotationType());
-            method.addError("Methods annotated with %s must match the pattern '%s'.", annotationName, String.format("%s${typeName}", prefix));
+    protected final TypeData resolveCastOrCheck(TemplateMethod method) {
+        Class<?> annotationType = getAnnotationType();
+        TypeMirror targetTypeMirror = ElementUtils.getAnnotationValue(TypeMirror.class, method.getMessageAnnotation(), "value");
+        TypeData targetType = getTypeSystem().findTypeData(targetTypeMirror);
+        if (targetType == null) {
+            method.addError("The type '%s' is not declared in the @%s.", ElementUtils.getSimpleName(targetTypeMirror), TypeSystem.class.getSimpleName());
             return null;
         }
-        String typeName = methodName.substring(prefix.length(), methodName.length());
-        TypeData type = getTypeSystem().findType(typeName);
-        if (type == null) {
-            String annotationName = TypeSystem.class.getSimpleName();
-            method.addError("Type '%s' is not declared in this @%s.", typeName, annotationName);
-            return null;
+        if (!method.getMethod().getModifiers().contains(Modifier.PUBLIC) || !method.getMethod().getModifiers().contains(Modifier.STATIC)) {
+            method.addError("@%s annotated method %s must be public and static.", annotationType.getSimpleName(), method.getMethodName());
         }
-
-        return type;
+        return targetType;
     }
 
 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java	Mon Jan 05 20:23:22 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java	Mon Jan 05 20:23:22 2015 +0100
@@ -121,7 +121,6 @@
             cast.getTargetType().addTypeCast(cast);
         }
 
-        verifyGenericTypeChecksAndCasts(typeSystem);
         verifyMethodSignatures(typeSystem);
         verifyNamesUnique(typeSystem);
 
@@ -150,39 +149,6 @@
         }
     }
 
-    private static void verifyGenericTypeChecksAndCasts(TypeSystemData typeSystem) {
-        for (TypeData type : typeSystem.getTypes()) {
-            if (!type.getTypeChecks().isEmpty()) {
-                boolean hasGeneric = false;
-                for (TypeCheckData typeCheck : type.getTypeChecks()) {
-                    if (typeCheck.isGeneric()) {
-                        hasGeneric = true;
-                        break;
-                    }
-                }
-                if (!hasGeneric) {
-                    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), ElementUtils.getSimpleName(type.getBoxedType()), TypeCheck.class.getSimpleName(),
-                                    Object.class.getSimpleName());
-                }
-            }
-            if (!type.getTypeCasts().isEmpty()) {
-                boolean hasGeneric = false;
-                for (TypeCastData typeCast : type.getTypeCasts()) {
-                    if (typeCast.isGeneric()) {
-                        hasGeneric = true;
-                        break;
-                    }
-                }
-                if (!hasGeneric) {
-                    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), ElementUtils.getSimpleName(type.getBoxedType()), TypeCast.class.getSimpleName(),
-                                    Object.class.getSimpleName());
-                }
-            }
-        }
-    }
-
     private List<TypeData> parseTypes(TypeSystemData typeSystem) {
         List<TypeData> types = new ArrayList<>();
         List<TypeMirror> typeMirrors = ElementUtils.getAnnotationValueList(TypeMirror.class, typeSystem.getTemplateTypeAnnotation(), "value");
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLTypes.java	Mon Jan 05 20:23:22 2015 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLTypes.java	Mon Jan 05 20:23:22 2015 +0100
@@ -45,7 +45,7 @@
      * {@code instanceof} check, because we know that there is only a {@link SLNull#SINGLETON
      * singleton} instance.
      */
-    @TypeCheck
+    @TypeCheck(SLNull.class)
     public static boolean isSLNull(Object value) {
         return value == SLNull.SINGLETON;
     }
@@ -55,7 +55,7 @@
      * that the Truffle DSL would generate. For {@link SLNull}, we do not need an actual cast,
      * because we know that there is only a {@link SLNull#SINGLETON singleton} instance.
      */
-    @TypeCast
+    @TypeCast(SLNull.class)
     public static SLNull asSLNull(Object value) {
         assert isSLNull(value);
         return SLNull.SINGLETON;