diff --git a/java/com/google/turbine/model/TurbineConstantTypeKind.java b/java/com/google/turbine/model/TurbineConstantTypeKind.java index bb5bea15..8968a4db 100644 --- a/java/com/google/turbine/model/TurbineConstantTypeKind.java +++ b/java/com/google/turbine/model/TurbineConstantTypeKind.java @@ -27,7 +27,7 @@ public enum TurbineConstantTypeKind { BOOLEAN("boolean"), BYTE("byte"), STRING("String"), - NULL("null"); + NULL(""); private final String name; diff --git a/java/com/google/turbine/processing/TurbineTypeMirror.java b/java/com/google/turbine/processing/TurbineTypeMirror.java index 8352850f..a0ee3ffa 100644 --- a/java/com/google/turbine/processing/TurbineTypeMirror.java +++ b/java/com/google/turbine/processing/TurbineTypeMirror.java @@ -527,7 +527,7 @@ public TypeMirror getUpperBound() { public TypeMirror getLowerBound() { return info().lowerBound() != null ? factory.asTypeMirror(info().lowerBound()) - : factory.noType(); + : factory.nullType(); } @Override diff --git a/java/com/google/turbine/processing/TurbineTypes.java b/java/com/google/turbine/processing/TurbineTypes.java index 13458ec8..0e639584 100644 --- a/java/com/google/turbine/processing/TurbineTypes.java +++ b/java/com/google/turbine/processing/TurbineTypes.java @@ -413,7 +413,8 @@ private boolean isArraySubtype(ArrayTy a, Type b, boolean strict) { // https://docs.oracle.com/javase/specs/jls/se11/html/jls-4.html#jls-4.10.1 private static boolean isPrimSubtype(PrimTy a, Type other) { if (other.tyKind() != TyKind.PRIM_TY) { - return false; + // The null reference can always be assigned or cast to any reference type, see JLS 4.1 + return a.primkind() == TurbineConstantTypeKind.NULL && isReferenceType(other); } PrimTy b = (PrimTy) other; switch (a.primkind()) { @@ -483,7 +484,7 @@ private static boolean isPrimSubtype(PrimTy a, Type other) { case BOOLEAN: return a.primkind() == b.primkind(); case NULL: - break; + return isReferenceType(other); } throw new AssertionError(a.primkind()); } @@ -672,8 +673,12 @@ public boolean isAssignable(TypeMirror a1, TypeMirror a2) { private boolean isAssignable(Type t1, Type t2) { switch (t1.tyKind()) { case PRIM_TY: + TurbineConstantTypeKind primkind = ((PrimTy) t1).primkind(); + if (primkind == TurbineConstantTypeKind.NULL) { + return isReferenceType(t2); + } if (t2.tyKind() == TyKind.CLASS_TY) { - ClassSymbol boxed = boxedClass(((PrimTy) t1).primkind()); + ClassSymbol boxed = boxedClass(primkind); t1 = ClassTy.asNonParametricClassTy(boxed); } break; @@ -700,6 +705,14 @@ private static boolean isObjectType(Type type) { return type.tyKind() == TyKind.CLASS_TY && ((ClassTy) type).sym().equals(ClassSymbol.OBJECT); } + private static boolean isReferenceType(Type type) { + return switch (type.tyKind()) { + case CLASS_TY, ARRAY_TY, TY_VAR, WILD_TY, INTERSECTION_TY, ERROR_TY -> true; + case PRIM_TY -> ((PrimTy) type).primkind() == TurbineConstantTypeKind.NULL; + case NONE_TY, METHOD_TY, VOID_TY -> false; + }; + } + @Override public boolean contains(TypeMirror a, TypeMirror b) { return contains(asTurbineType(a), asTurbineType(b), /* strict= */ true); diff --git a/java/com/google/turbine/type/Type.java b/java/com/google/turbine/type/Type.java index 41d8b7b4..51b76c17 100644 --- a/java/com/google/turbine/type/Type.java +++ b/java/com/google/turbine/type/Type.java @@ -308,6 +308,8 @@ public final String toString() { } /** A primitive type. */ + // TODO: cushon - consider renaming this, since it models things like String and null that can + // appear as constants and not primitives. @AutoValue abstract class PrimTy implements Type { diff --git a/javatests/com/google/turbine/processing/AbstractTurbineTypesTest.java b/javatests/com/google/turbine/processing/AbstractTurbineTypesTest.java index 307b71ad..822283b3 100644 --- a/javatests/com/google/turbine/processing/AbstractTurbineTypesTest.java +++ b/javatests/com/google/turbine/processing/AbstractTurbineTypesTest.java @@ -462,6 +462,9 @@ public CharSequence getCharContent(boolean ignoreEncodingErrors) { /** * Discover all types contained in the given element, keyed by their immediate enclosing element. + * + *

This method is executed for both javac and Turbine and is expected to produce the same + * results in each case. */ private static void getTypes( Types typeUtils, Element element, Multimap types) { @@ -508,6 +511,7 @@ public Void visitTypeVariable(TypeVariable t, Void aVoid) { if (t.getUpperBound() != null) { types.put(key(e), t.getUpperBound()); } + types.put(String.format("getLowerBound(%s)", key(e)), t.getLowerBound()); return null; } }, diff --git a/javatests/com/google/turbine/processing/TurbineTypeMirrorTest.java b/javatests/com/google/turbine/processing/TurbineTypeMirrorTest.java index bf08f899..787e9cf9 100644 --- a/javatests/com/google/turbine/processing/TurbineTypeMirrorTest.java +++ b/javatests/com/google/turbine/processing/TurbineTypeMirrorTest.java @@ -226,7 +226,7 @@ public void tyVar() { .getTypeParameters()) .asType(); assertThat(t.getKind()).isEqualTo(TypeKind.TYPEVAR); - assertThat(t.getLowerBound().getKind()).isEqualTo(TypeKind.NONE); + assertThat(t.getLowerBound().getKind()).isEqualTo(TypeKind.NULL); assertThat(t.getUpperBound().toString()).isEqualTo("java.lang.Comparable"); } diff --git a/pom.xml b/pom.xml index d78c0f34..12fa494c 100644 --- a/pom.xml +++ b/pom.xml @@ -296,7 +296,7 @@ maven-javadoc-plugin 3.3.1 - 8 + 16 false true turbine ${project.version} API