# HG changeset patch # User Christian Humer # Date 1420485802 -3600 # Node ID 3ea386a1036f0c1b04b7f4cee69c42c4aab9f422 # Parent 941761f6b7362c8c99eea59bb8042494015c9709 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) diff -r 941761f6b736 -r 3ea386a1036f graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ArrayTest.java --- 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; } diff -r 941761f6b736 -r 3ea386a1036f graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TypeSystemErrorsTest.java --- 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; + } } } diff -r 941761f6b736 -r 3ea386a1036f graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TypeSystemTest.java --- 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; diff -r 941761f6b736 -r 3ea386a1036f graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/TypeCast.java --- 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: public static Type as{TypeName}(Object + * value). The casted type must be a type declared in the {@link TypeSystem}. + * + *

+ * If no {@link TypeCast} is declared then the type system implicitly uses a type cast that can be + * declared as follows: + * + *

+ * {@literal @}TypeCast(Type.class)
+ * public static Type asType(Object value) {
+ *         return (Type) value;
+ * }
+ * 
+ * + * @see TypeCheck + */ @Retention(RetentionPolicy.CLASS) @Target({ElementType.METHOD}) public @interface TypeCast { + Class value(); + } diff -r 941761f6b736 -r 3ea386a1036f graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/TypeCheck.java --- 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.*; /** - *

- * 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. - *

+ * 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: public static boolean is{TypeName}(Object + * value). The checked type must be a type declared in the {@link TypeSystem}. * *

- * 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: * *

- * {@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;
  * }
  * 
* - * Example: - *

- * A type check for BigInteger with one overloaded optimized variant to reduce boxing. - *

- * - *
- *
- *
- * {@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;
- *     }
- * 
- * }
- * 
- * - * + * @see TypeCast */ @Retention(RetentionPolicy.CLASS) @Target({ElementType.METHOD}) public @interface TypeCheck { + Class value(); + } diff -r 941761f6b736 -r 3ea386a1036f graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeCastParser.java --- 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 diff -r 941761f6b736 -r 3ea386a1036f graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeCheckParser.java --- 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 diff -r 941761f6b736 -r 3ea386a1036f graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemMethodParser.java --- 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; } } diff -r 941761f6b736 -r 3ea386a1036f graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java --- 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 parseTypes(TypeSystemData typeSystem) { List types = new ArrayList<>(); List typeMirrors = ElementUtils.getAnnotationValueList(TypeMirror.class, typeSystem.getTemplateTypeAnnotation(), "value"); diff -r 941761f6b736 -r 3ea386a1036f graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLTypes.java --- 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;