diff options
author | Liam Miller-Cushon <cushon@google.com> | 2023-01-23 14:13:40 -0800 |
---|---|---|
committer | Javac Team <javac-team+copybara@google.com> | 2023-01-23 14:14:45 -0800 |
commit | 7a40bb4dfb0f2fc9dc4f1b95434abe268752ec6c (patch) | |
tree | 5ce99b3ecf5e8c87b5762b8654a0fa16149a7434 | |
parent | 52699ff1ba8f358a02842b894dc10337def0e7fc (diff) | |
download | turbine-7a40bb4dfb0f2fc9dc4f1b95434abe268752ec6c.tar.gz |
Check interface and non-interface types in `extends` and `implements` lists
PiperOrigin-RevId: 504078954
6 files changed, 74 insertions, 11 deletions
diff --git a/java/com/google/turbine/binder/TypeBinder.java b/java/com/google/turbine/binder/TypeBinder.java index edfacba..ec579e7 100644 --- a/java/com/google/turbine/binder/TypeBinder.java +++ b/java/com/google/turbine/binder/TypeBinder.java @@ -206,7 +206,8 @@ public class TypeBinder { break; case CLASS: if (base.decl().xtnds().isPresent()) { - superClassType = bindClassTy(bindingScope, base.decl().xtnds().get()); + superClassType = + checkClassType(bindingScope, base.decl().xtnds().get(), /* expectInterface= */ false); } else if (owner.equals(ClassSymbol.OBJECT)) { // java.lang.Object doesn't have a superclass superClassType = null; @@ -228,7 +229,7 @@ public class TypeBinder { } for (Tree.ClassTy i : base.decl().impls()) { - interfaceTypes.add(bindClassTy(bindingScope, i)); + interfaceTypes.add(checkClassType(bindingScope, i, /* expectInterface= */ true)); } ImmutableList.Builder<ClassSymbol> permits = ImmutableList.builder(); @@ -449,6 +450,30 @@ public class TypeBinder { throw new AssertionError(a.tyKind()); } + private Type checkClassType(CompoundScope scope, ClassTy tree, boolean expectInterface) { + Type type = bindClassTy(scope, tree); + if (type.tyKind().equals(Type.TyKind.ERROR_TY)) { + return type; + } + HeaderBoundClass info = env.getNonNull(((Type.ClassTy) type).sym()); + boolean isInterface; + switch (info.kind()) { + case INTERFACE: + case ANNOTATION: + isInterface = true; + break; + default: + isInterface = false; + break; + } + if (expectInterface != isInterface) { + log.error( + tree.position(), + expectInterface ? ErrorKind.EXPECTED_INTERFACE : ErrorKind.UNEXPECTED_INTERFACE); + } + return type; + } + /** * A generated for synthetic {@link MethodSymbol}s. * diff --git a/java/com/google/turbine/diag/TurbineError.java b/java/com/google/turbine/diag/TurbineError.java index f839345..8031fa5 100644 --- a/java/com/google/turbine/diag/TurbineError.java +++ b/java/com/google/turbine/diag/TurbineError.java @@ -57,6 +57,8 @@ public class TurbineError extends Error { BAD_MODULE_INFO("unexpected declaration found in module-info"), UNCLOSED_COMMENT("unclosed comment"), UNEXPECTED_TYPE("unexpected type %s"), + EXPECTED_INTERFACE("expected interface type"), + UNEXPECTED_INTERFACE("unexpected interface type"), UNEXPECTED_MODIFIER("unexpected modifier: %s"), PROC("%s"); diff --git a/javatests/com/google/turbine/binder/BinderErrorTest.java b/javatests/com/google/turbine/binder/BinderErrorTest.java index 1a83f0d..a1bea05 100644 --- a/javatests/com/google/turbine/binder/BinderErrorTest.java +++ b/javatests/com/google/turbine/binder/BinderErrorTest.java @@ -681,7 +681,9 @@ public class BinderErrorTest { "class T extends T {}", }, { - "<>:1: error: cycle in class hierarchy: T", "class T extends T {}", " ^", + "<>:1: error: cycle in class hierarchy: T", // + "class T extends T {}", + " ^", }, }, { @@ -692,6 +694,19 @@ public class BinderErrorTest { "<>:1: error: cycle in class hierarchy: T", "class T implements T {}", " ^", + "<>:1: error: expected interface type", + "class T implements T {}", + " ^", + }, + }, + { + { + "interface T extends T {}", + }, + { + "<>:1: error: cycle in class hierarchy: T", + "interface T extends T {}", + " ^", }, }, { @@ -768,7 +783,9 @@ public class BinderErrorTest { "@interface Test {}", }, { - "<>:3: error: missing required annotation argument: value", "@Retention", "^", + "<>:3: error: missing required annotation argument: value", // + "@Retention", + "^", }, }, { @@ -958,6 +975,25 @@ public class BinderErrorTest { }, { { + "class C {}", // + "interface I {}", + "class A extends I implements C {}", + "interface B extends C {}", + }, + { + "<>:3: error: unexpected interface type", + "class A extends I implements C {}", + " ^", + "<>:3: error: expected interface type", + "class A extends I implements C {}", + " ^", + "<>:4: error: expected interface type", + "interface B extends C {}", + " ^", + }, + }, + { + { "class T<X, X> {", // " <Y, Y> void f() {}", "}", diff --git a/javatests/com/google/turbine/binder/BinderTest.java b/javatests/com/google/turbine/binder/BinderTest.java index 40387ac..52b769b 100644 --- a/javatests/com/google/turbine/binder/BinderTest.java +++ b/javatests/com/google/turbine/binder/BinderTest.java @@ -265,7 +265,7 @@ public class BinderTest { parseLines( "import java.lang.annotation.Target;", "import java.lang.annotation.ElementType;", - "public class C implements B {", + "public class C extends B {", " @Target(ElementType.TYPE_USE)", " @interface A {};", "}")); diff --git a/javatests/com/google/turbine/lower/LowerTest.java b/javatests/com/google/turbine/lower/LowerTest.java index fdcfbb3..f04ef27 100644 --- a/javatests/com/google/turbine/lower/LowerTest.java +++ b/javatests/com/google/turbine/lower/LowerTest.java @@ -545,7 +545,7 @@ public class LowerTest { .put( "Test.java", lines( - "public class Test extends B.BM {", // + "public class Test implements B.BM {", // " I i;", "}")) .build(); diff --git a/javatests/com/google/turbine/processing/TurbineElementsGetAllMembersTest.java b/javatests/com/google/turbine/processing/TurbineElementsGetAllMembersTest.java index 11dedbf..bc6d9e6 100644 --- a/javatests/com/google/turbine/processing/TurbineElementsGetAllMembersTest.java +++ b/javatests/com/google/turbine/processing/TurbineElementsGetAllMembersTest.java @@ -77,17 +77,17 @@ public class TurbineElementsGetAllMembersTest { }, { "=== I.java ===", - "abstract class I {", - " abstract Integer f();", + "interface I {", + " default Integer f() {}", "}", "=== J.java ===", - "interface J extends I {", - " default Integer f() {", + "class J implements I {", + " Integer f() {", " return 42;", " }", "}", "=== Test.java ===", // - "class Test extends I implements J {", + "class Test extends J implements I {", "}", }, { |