diff options
author | Liam Miller-Cushon <cushon@google.com> | 2021-10-01 15:20:24 -0700 |
---|---|---|
committer | Javac Team <javac-team+copybara@google.com> | 2021-10-01 15:21:00 -0700 |
commit | 0b547dc65ba2628d4dc595e8395c6f4cd7652170 (patch) | |
tree | da2d4068f949bacc1653178c8a5d7be241848d61 | |
parent | 3452789854d581fbad3068d22d64b7319d19e8b4 (diff) | |
download | turbine-0b547dc65ba2628d4dc595e8395c6f4cd7652170.tar.gz |
Initial support for sealed classes
PiperOrigin-RevId: 400303125
27 files changed, 229 insertions, 8 deletions
diff --git a/java/com/google/turbine/binder/CanonicalTypeBinder.java b/java/com/google/turbine/binder/CanonicalTypeBinder.java index cbdc025..944563f 100644 --- a/java/com/google/turbine/binder/CanonicalTypeBinder.java +++ b/java/com/google/turbine/binder/CanonicalTypeBinder.java @@ -67,6 +67,7 @@ public final class CanonicalTypeBinder { ImmutableList<FieldInfo> fields = fields(base.source(), env, sym, base.fields()); return new SourceTypeBoundClass( interfaceTypes.build(), + base.permits(), superClassType, typParamTypes, base.access(), diff --git a/java/com/google/turbine/binder/CompUnitPreprocessor.java b/java/com/google/turbine/binder/CompUnitPreprocessor.java index 3323938..0e9f4e5 100644 --- a/java/com/google/turbine/binder/CompUnitPreprocessor.java +++ b/java/com/google/turbine/binder/CompUnitPreprocessor.java @@ -225,6 +225,7 @@ public final class CompUnitPreprocessor { ImmutableList.of(), ImmutableList.of(), ImmutableList.of(), + ImmutableList.of(), TurbineTyKind.INTERFACE, /* javadoc= */ null); } diff --git a/java/com/google/turbine/binder/ConstBinder.java b/java/com/google/turbine/binder/ConstBinder.java index 232370c..3ba059f 100644 --- a/java/com/google/turbine/binder/ConstBinder.java +++ b/java/com/google/turbine/binder/ConstBinder.java @@ -110,6 +110,7 @@ public class ConstBinder { ImmutableList<MethodInfo> methods = bindMethods(base.methods()); return new SourceTypeBoundClass( bindTypes(base.interfaceTypes()), + base.permits(), base.superClassType() != null ? bindType(base.superClassType()) : null, bindTypeParameters(base.typeParameterTypes()), base.access(), diff --git a/java/com/google/turbine/binder/DisambiguateTypeAnnotations.java b/java/com/google/turbine/binder/DisambiguateTypeAnnotations.java index 4929962..65c1021 100644 --- a/java/com/google/turbine/binder/DisambiguateTypeAnnotations.java +++ b/java/com/google/turbine/binder/DisambiguateTypeAnnotations.java @@ -71,6 +71,7 @@ public final class DisambiguateTypeAnnotations { SourceTypeBoundClass base, Env<ClassSymbol, TypeBoundClass> env) { return new SourceTypeBoundClass( base.interfaceTypes(), + base.permits(), base.superClassType(), base.typeParameterTypes(), base.access(), diff --git a/java/com/google/turbine/binder/TypeBinder.java b/java/com/google/turbine/binder/TypeBinder.java index f4b4849..ccc0ad3 100644 --- a/java/com/google/turbine/binder/TypeBinder.java +++ b/java/com/google/turbine/binder/TypeBinder.java @@ -229,6 +229,15 @@ public class TypeBinder { interfaceTypes.add(bindClassTy(bindingScope, i)); } + ImmutableList.Builder<ClassSymbol> permits = ImmutableList.builder(); + for (Tree.ClassTy i : base.decl().permits()) { + Type type = bindClassTy(bindingScope, i); + if (!type.tyKind().equals(Type.TyKind.CLASS_TY)) { + throw new AssertionError(type.tyKind()); + } + permits.add(((Type.ClassTy) type).sym()); + } + CompoundScope scope = base.scope() .toScope(Resolve.resolveFunction(env, owner)) @@ -251,6 +260,7 @@ public class TypeBinder { return new SourceTypeBoundClass( interfaceTypes.build(), + permits.build(), superClassType, typeParameterTypes, base.access(), diff --git a/java/com/google/turbine/binder/bound/SourceTypeBoundClass.java b/java/com/google/turbine/binder/bound/SourceTypeBoundClass.java index fb3ee27..5e9817e 100644 --- a/java/com/google/turbine/binder/bound/SourceTypeBoundClass.java +++ b/java/com/google/turbine/binder/bound/SourceTypeBoundClass.java @@ -44,6 +44,7 @@ public class SourceTypeBoundClass implements TypeBoundClass { private final ImmutableMap<TyVarSymbol, TyVarInfo> typeParameterTypes; private final @Nullable Type superClassType; private final ImmutableList<Type> interfaceTypes; + private final ImmutableList<ClassSymbol> permits; private final ImmutableList<RecordComponentInfo> components; private final ImmutableList<MethodInfo> methods; private final ImmutableList<FieldInfo> fields; @@ -57,6 +58,7 @@ public class SourceTypeBoundClass implements TypeBoundClass { public SourceTypeBoundClass( ImmutableList<Type> interfaceTypes, + ImmutableList<ClassSymbol> permits, @Nullable Type superClassType, ImmutableMap<TyVarSymbol, TyVarInfo> typeParameterTypes, int access, @@ -75,6 +77,7 @@ public class SourceTypeBoundClass implements TypeBoundClass { SourceFile source, Tree.TyDecl decl) { this.interfaceTypes = interfaceTypes; + this.permits = permits; this.superClassType = superClassType; this.typeParameterTypes = typeParameterTypes; this.access = access; @@ -117,6 +120,11 @@ public class SourceTypeBoundClass implements TypeBoundClass { } @Override + public ImmutableList<ClassSymbol> permits() { + return permits; + } + + @Override public int access() { return access; } diff --git a/java/com/google/turbine/binder/bound/TypeBoundClass.java b/java/com/google/turbine/binder/bound/TypeBoundClass.java index cc28901..8321bde 100644 --- a/java/com/google/turbine/binder/bound/TypeBoundClass.java +++ b/java/com/google/turbine/binder/bound/TypeBoundClass.java @@ -18,6 +18,7 @@ package com.google.turbine.binder.bound; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.turbine.binder.sym.ClassSymbol; import com.google.turbine.binder.sym.FieldSymbol; import com.google.turbine.binder.sym.MethodSymbol; import com.google.turbine.binder.sym.ParamSymbol; @@ -43,6 +44,9 @@ public interface TypeBoundClass extends HeaderBoundClass { /** Implemented interface types. */ ImmutableList<Type> interfaceTypes(); + /** The permitted direct subclasses. */ + ImmutableList<ClassSymbol> permits(); + ImmutableMap<TyVarSymbol, TyVarInfo> typeParameterTypes(); /** Declared fields. */ diff --git a/java/com/google/turbine/binder/bytecode/BytecodeBoundClass.java b/java/com/google/turbine/binder/bytecode/BytecodeBoundClass.java index 516a027..9be2dd1 100644 --- a/java/com/google/turbine/binder/bytecode/BytecodeBoundClass.java +++ b/java/com/google/turbine/binder/bytecode/BytecodeBoundClass.java @@ -306,6 +306,11 @@ public class BytecodeBoundClass implements TypeBoundClass { return interfaceTypes.get(); } + @Override + public ImmutableList<ClassSymbol> permits() { + return ImmutableList.of(); + } + private final Supplier<ImmutableMap<TyVarSymbol, TyVarInfo>> typeParameterTypes = Suppliers.memoize( new Supplier<ImmutableMap<TyVarSymbol, TyVarInfo>>() { diff --git a/java/com/google/turbine/bytecode/Attribute.java b/java/com/google/turbine/bytecode/Attribute.java index 581de3d..ad6ffc1 100644 --- a/java/com/google/turbine/bytecode/Attribute.java +++ b/java/com/google/turbine/bytecode/Attribute.java @@ -45,7 +45,8 @@ interface Attribute { NEST_HOST("NestHost"), NEST_MEMBERS("NestMembers"), RECORD("Record"), - TURBINE_TRANSITIVE_JAR("TurbineTransitiveJar"); + TURBINE_TRANSITIVE_JAR("TurbineTransitiveJar"), + PERMITTED_SUBCLASSES("PermittedSubclasses"); private final String signature; @@ -396,6 +397,20 @@ interface Attribute { } } + /** A JVMS ยง4.7.31 PermittedSubclasses attribute. */ + class PermittedSubclasses implements Attribute { + final List<String> permits; + + public PermittedSubclasses(List<String> permits) { + this.permits = permits; + } + + @Override + public Kind kind() { + return Kind.PERMITTED_SUBCLASSES; + } + } + /** A custom attribute for recording the original jar of repackaged transitive classes. */ class TurbineTransitiveJar implements Attribute { diff --git a/java/com/google/turbine/bytecode/AttributeWriter.java b/java/com/google/turbine/bytecode/AttributeWriter.java index ed7b2ab..6aac19a 100644 --- a/java/com/google/turbine/bytecode/AttributeWriter.java +++ b/java/com/google/turbine/bytecode/AttributeWriter.java @@ -95,6 +95,9 @@ public class AttributeWriter { case RECORD: writeRecord(output, (Attribute.Record) attribute); break; + case PERMITTED_SUBCLASSES: + writePermittedSubclasses(output, (Attribute.PermittedSubclasses) attribute); + break; case TURBINE_TRANSITIVE_JAR: writeTurbineTransitiveJar(output, (Attribute.TurbineTransitiveJar) attribute); break; @@ -318,6 +321,16 @@ public class AttributeWriter { output.write(data); } + private void writePermittedSubclasses( + ByteArrayDataOutput output, Attribute.PermittedSubclasses attribute) { + output.writeShort(pool.utf8(attribute.kind().signature())); + output.writeInt(2 + attribute.permits.size() * 2); + output.writeShort(attribute.permits.size()); + for (String permits : attribute.permits) { + output.writeShort(pool.classInfo(permits)); + } + } + private void writeTurbineTransitiveJar( ByteArrayDataOutput output, TurbineTransitiveJar attribute) { output.writeShort(pool.utf8(attribute.kind().signature())); diff --git a/java/com/google/turbine/bytecode/ClassFile.java b/java/com/google/turbine/bytecode/ClassFile.java index 124e03c..820f17d 100644 --- a/java/com/google/turbine/bytecode/ClassFile.java +++ b/java/com/google/turbine/bytecode/ClassFile.java @@ -37,6 +37,7 @@ public class ClassFile { private final @Nullable String signature; private final @Nullable String superClass; private final List<String> interfaces; + private final List<String> permits; private final List<MethodInfo> methods; private final List<FieldInfo> fields; private final List<AnnotationInfo> annotations; @@ -55,6 +56,7 @@ public class ClassFile { @Nullable String signature, @Nullable String superClass, List<String> interfaces, + List<String> permits, List<MethodInfo> methods, List<FieldInfo> fields, List<AnnotationInfo> annotations, @@ -71,6 +73,7 @@ public class ClassFile { this.signature = signature; this.superClass = superClass; this.interfaces = interfaces; + this.permits = permits; this.methods = methods; this.fields = fields; this.annotations = annotations; @@ -113,6 +116,11 @@ public class ClassFile { return interfaces; } + /** The permitted direct subclasses. */ + public List<String> permits() { + return permits; + } + /** Methods declared by this class or interfaces type. */ public List<MethodInfo> methods() { return methods; diff --git a/java/com/google/turbine/bytecode/ClassReader.java b/java/com/google/turbine/bytecode/ClassReader.java index b429032..0f08fc3 100644 --- a/java/com/google/turbine/bytecode/ClassReader.java +++ b/java/com/google/turbine/bytecode/ClassReader.java @@ -143,6 +143,7 @@ public class ClassReader { signature, superClass, interfaces, + /* permits= */ ImmutableList.of(), methodinfos, fieldinfos, annotations.build(), diff --git a/java/com/google/turbine/bytecode/LowerAttributes.java b/java/com/google/turbine/bytecode/LowerAttributes.java index 54937fc..8952dff 100644 --- a/java/com/google/turbine/bytecode/LowerAttributes.java +++ b/java/com/google/turbine/bytecode/LowerAttributes.java @@ -54,6 +54,9 @@ public final class LowerAttributes { if (classfile.record() != null) { attributes.add(recordAttribute(classfile.record())); } + if (!classfile.permits().isEmpty()) { + attributes.add(new Attribute.PermittedSubclasses(classfile.permits())); + } if (classfile.transitiveJar() != null) { attributes.add(new Attribute.TurbineTransitiveJar(classfile.transitiveJar())); } diff --git a/java/com/google/turbine/deps/Transitive.java b/java/com/google/turbine/deps/Transitive.java index 62d15c3..fa3d475 100644 --- a/java/com/google/turbine/deps/Transitive.java +++ b/java/com/google/turbine/deps/Transitive.java @@ -95,6 +95,7 @@ public final class Transitive { cf.signature(), cf.superName(), cf.interfaces(), + cf.permits(), // drop methods, except for annotations where we need to resolve key/value information (cf.access() & TurbineFlag.ACC_ANNOTATION) == TurbineFlag.ACC_ANNOTATION ? cf.methods() diff --git a/java/com/google/turbine/lower/Lower.java b/java/com/google/turbine/lower/Lower.java index 0f3eb24..ff7e13c 100644 --- a/java/com/google/turbine/lower/Lower.java +++ b/java/com/google/turbine/lower/Lower.java @@ -192,6 +192,7 @@ public class Lower { /* signature= */ null, /* superClass= */ null, /* interfaces= */ ImmutableList.of(), + /* permits= */ ImmutableList.of(), /* methods= */ ImmutableList.of(), /* fields= */ ImmutableList.of(), annotations, @@ -259,6 +260,10 @@ public class Lower { for (ClassSymbol i : info.interfaces()) { interfaces.add(sig.descriptor(i)); } + List<String> permits = new ArrayList<>(); + for (ClassSymbol i : info.permits()) { + permits.add(sig.descriptor(i)); + } ClassFile.RecordInfo record = null; if (info.kind().equals(TurbineTyKind.RECORD)) { @@ -310,6 +315,7 @@ public class Lower { signature, superName, interfaces, + permits, methods, fields.build(), annotations, diff --git a/java/com/google/turbine/model/TurbineFlag.java b/java/com/google/turbine/model/TurbineFlag.java index c138d46..6e8d64b 100644 --- a/java/com/google/turbine/model/TurbineFlag.java +++ b/java/com/google/turbine/model/TurbineFlag.java @@ -55,5 +55,8 @@ public final class TurbineFlag { /** Synthetic constructors (e.g. of inner classes and enums). */ public static final int ACC_SYNTH_CTOR = 1 << 18; + public static final int ACC_SEALED = 1 << 19; + public static final int ACC_NON_SEALED = 1 << 20; + private TurbineFlag() {} } diff --git a/java/com/google/turbine/parse/Parser.java b/java/com/google/turbine/parse/Parser.java index 06b3db6..ed8958e 100644 --- a/java/com/google/turbine/parse/Parser.java +++ b/java/com/google/turbine/parse/Parser.java @@ -17,8 +17,10 @@ package com.google.turbine.parse; import static com.google.turbine.parse.Token.COMMA; +import static com.google.turbine.parse.Token.IDENT; import static com.google.turbine.parse.Token.INTERFACE; import static com.google.turbine.parse.Token.LPAREN; +import static com.google.turbine.parse.Token.MINUS; import static com.google.turbine.parse.Token.RPAREN; import static com.google.turbine.parse.Token.SEMI; import static com.google.turbine.tree.TurbineModifier.PROTECTED; @@ -187,12 +189,25 @@ public class Parser { { Ident ident = ident(); if (ident.value().equals("record")) { - ident = eatIdent(); + next(); decls.add(recordDeclaration(access, annos.build())); access = EnumSet.noneOf(TurbineModifier.class); annos = ImmutableList.builder(); break; } + if (ident.value().equals("sealed")) { + next(); + access.add(TurbineModifier.SEALED); + break; + } + if (ident.value().equals("non")) { + int start = position; + next(); + eatNonSealed(start); + next(); + access.add(TurbineModifier.NON_SEALED); + break; + } if (access.isEmpty() && (ident.value().equals("module") || ident.value().equals("open"))) { boolean open = false; @@ -216,6 +231,22 @@ public class Parser { } } + // Handle the hypenated pseudo-keyword 'non-sealed'. + // + // This will need to be updated to handle other hyphenated keywords if when/they are introduced. + private void eatNonSealed(int start) { + eat(Token.MINUS); + if (token != IDENT) { + throw error(token); + } + if (!ident().value().equals("sealed")) { + throw error(token); + } + if (position != start + "non-".length()) { + throw error(token); + } + } + private void next() { token = lexer.next(); position = lexer.position(); @@ -255,6 +286,7 @@ public class Parser { typarams, Optional.<ClassTy>empty(), interfaces.build(), + /* permits= */ ImmutableList.of(), members, formals.build(), TurbineTyKind.RECORD, @@ -279,6 +311,15 @@ public class Parser { interfaces.add(classty()); } while (maybe(Token.COMMA)); } + ImmutableList.Builder<ClassTy> permits = ImmutableList.builder(); + if (token == Token.IDENT) { + if (ident().value().equals("permits")) { + eat(Token.IDENT); + do { + permits.add(classty()); + } while (maybe(Token.COMMA)); + } + } eat(Token.LBRACE); ImmutableList<Tree> members = classMembers(); eat(Token.RBRACE); @@ -290,6 +331,7 @@ public class Parser { typarams, Optional.<ClassTy>empty(), interfaces.build(), + permits.build(), members, ImmutableList.of(), TurbineTyKind.INTERFACE, @@ -312,6 +354,7 @@ public class Parser { ImmutableList.<TyParam>of(), Optional.<ClassTy>empty(), ImmutableList.<ClassTy>of(), + ImmutableList.of(), members, ImmutableList.of(), TurbineTyKind.ANNOTATION, @@ -342,6 +385,7 @@ public class Parser { ImmutableList.<TyParam>of(), Optional.<ClassTy>empty(), interfaces.build(), + ImmutableList.of(), members, ImmutableList.of(), TurbineTyKind.ENUM, @@ -569,6 +613,15 @@ public class Parser { interfaces.add(classty()); } while (maybe(Token.COMMA)); } + ImmutableList.Builder<ClassTy> permits = ImmutableList.builder(); + if (token == Token.IDENT) { + if (ident().value().equals("permits")) { + eat(Token.IDENT); + do { + permits.add(classty()); + } while (maybe(Token.COMMA)); + } + } switch (token) { case LBRACE: next(); @@ -588,6 +641,7 @@ public class Parser { tyParams, Optional.ofNullable(xtnds), interfaces.build(), + permits.build(), members, ImmutableList.of(), TurbineTyKind.CLASS, @@ -665,8 +719,22 @@ public class Parser { case IDENT: Ident ident = ident(); + if (ident.value().equals("non")) { + int pos = position; + next(); + if (token != MINUS) { + acc.addAll(member(access, annos.build(), ImmutableList.of(), pos, ident)); + access = EnumSet.noneOf(TurbineModifier.class); + annos = ImmutableList.builder(); + } else { + eatNonSealed(pos); + next(); + access.add(TurbineModifier.NON_SEALED); + } + break; + } if (ident.value().equals("record")) { - eat(Token.IDENT); + eat(IDENT); acc.add(recordDeclaration(access, annos.build())); access = EnumSet.noneOf(TurbineModifier.class); annos = ImmutableList.builder(); @@ -758,13 +826,13 @@ public class Parser { case IDENT: int pos = position; Ident ident = eatIdent(); - return classMemberIdent(access, annos, typaram, pos, ident); + return member(access, annos, typaram, pos, ident); default: throw error(token); } } - private ImmutableList<Tree> classMemberIdent( + private ImmutableList<Tree> member( EnumSet<TurbineModifier> access, ImmutableList<Anno> annos, ImmutableList<TyParam> typaram, @@ -820,6 +888,7 @@ public class Parser { ImmutableList.<Type>of(), ImmutableList.of()); break; + default: throw error(token); } diff --git a/java/com/google/turbine/tree/Pretty.java b/java/com/google/turbine/tree/Pretty.java index 84b4ab5..788ab58 100644 --- a/java/com/google/turbine/tree/Pretty.java +++ b/java/com/google/turbine/tree/Pretty.java @@ -459,6 +459,17 @@ public class Pretty implements Tree.Visitor<@Nullable Void, @Nullable Void> { first = false; } } + if (!tyDecl.permits().isEmpty()) { + append(" permits "); + boolean first = true; + for (Tree.ClassTy t : tyDecl.permits()) { + if (!first) { + append(", "); + } + t.accept(this, null); + first = false; + } + } append(" {").append('\n'); indent++; switch (tyDecl.tykind()) { @@ -522,6 +533,8 @@ public class Pretty implements Tree.Visitor<@Nullable Void, @Nullable Void> { case TRANSIENT: case DEFAULT: case TRANSITIVE: + case SEALED: + case NON_SEALED: append(mod.toString()).append(' '); break; case ACC_SUPER: diff --git a/java/com/google/turbine/tree/Tree.java b/java/com/google/turbine/tree/Tree.java index ce32628..f7917b9 100644 --- a/java/com/google/turbine/tree/Tree.java +++ b/java/com/google/turbine/tree/Tree.java @@ -934,6 +934,7 @@ public abstract class Tree { private final ImmutableList<TyParam> typarams; private final Optional<ClassTy> xtnds; private final ImmutableList<ClassTy> impls; + private final ImmutableList<ClassTy> permits; private final ImmutableList<Tree> members; private final ImmutableList<VarDecl> components; private final TurbineTyKind tykind; @@ -947,6 +948,7 @@ public abstract class Tree { ImmutableList<TyParam> typarams, Optional<ClassTy> xtnds, ImmutableList<ClassTy> impls, + ImmutableList<ClassTy> permits, ImmutableList<Tree> members, ImmutableList<VarDecl> components, TurbineTyKind tykind, @@ -958,6 +960,7 @@ public abstract class Tree { this.typarams = typarams; this.xtnds = xtnds; this.impls = impls; + this.permits = permits; this.members = members; this.components = components; this.tykind = tykind; @@ -999,6 +1002,10 @@ public abstract class Tree { return impls; } + public ImmutableList<ClassTy> permits() { + return permits; + } + public ImmutableList<Tree> members() { return members; } diff --git a/java/com/google/turbine/tree/TurbineModifier.java b/java/com/google/turbine/tree/TurbineModifier.java index 35dc11c..e5153b9 100644 --- a/java/com/google/turbine/tree/TurbineModifier.java +++ b/java/com/google/turbine/tree/TurbineModifier.java @@ -45,7 +45,9 @@ public enum TurbineModifier { ACC_SYNTHETIC(TurbineFlag.ACC_SYNTHETIC), ACC_BRIDGE(TurbineFlag.ACC_BRIDGE), DEFAULT(TurbineFlag.ACC_DEFAULT), - TRANSITIVE(TurbineFlag.ACC_TRANSITIVE); + TRANSITIVE(TurbineFlag.ACC_TRANSITIVE), + SEALED(TurbineFlag.ACC_SEALED), + NON_SEALED(TurbineFlag.ACC_NON_SEALED); private final int flag; @@ -59,6 +61,6 @@ public enum TurbineModifier { @Override public String toString() { - return name().toLowerCase(ENGLISH); + return name().replace('_', '-').toLowerCase(ENGLISH); } } diff --git a/javatests/com/google/turbine/bytecode/ClassWriterTest.java b/javatests/com/google/turbine/bytecode/ClassWriterTest.java index 4ca5e36..a6f9234 100644 --- a/javatests/com/google/turbine/bytecode/ClassWriterTest.java +++ b/javatests/com/google/turbine/bytecode/ClassWriterTest.java @@ -186,6 +186,7 @@ public class ClassWriterTest { /* signature= */ null, /* superClass= */ "java/lang/Record", /* interfaces= */ ImmutableList.of(), + /* permits= */ ImmutableList.of(), /* methods= */ ImmutableList.of(), /* fields= */ ImmutableList.of(), /* annotations= */ ImmutableList.of(), @@ -240,6 +241,7 @@ public class ClassWriterTest { /* signature= */ null, /* superClass= */ null, /* interfaces= */ ImmutableList.of(), + /* permits= */ ImmutableList.of(), /* methods= */ ImmutableList.of(), /* fields= */ ImmutableList.of(), /* annotations= */ ImmutableList.of(), diff --git a/javatests/com/google/turbine/lower/LowerIntegrationTest.java b/javatests/com/google/turbine/lower/LowerIntegrationTest.java index 9e16075..db73ec0 100644 --- a/javatests/com/google/turbine/lower/LowerIntegrationTest.java +++ b/javatests/com/google/turbine/lower/LowerIntegrationTest.java @@ -44,7 +44,9 @@ import org.junit.runners.Parameterized.Parameters; public class LowerIntegrationTest { private static final ImmutableMap<String, Integer> SOURCE_VERSION = - ImmutableMap.of("record.test", 16); + ImmutableMap.of( + "record.test", 16, + "sealed.test", 17); @Parameters(name = "{index}: {0}") public static Iterable<Object[]> parameters() { @@ -60,6 +62,7 @@ public class LowerIntegrationTest { "B8148131.test", "abstractenum.test", "access1.test", + "ambiguous_identifier.test", "anno_const_coerce.test", "anno_const_scope.test", "anno_nested.test", @@ -264,6 +267,7 @@ public class LowerIntegrationTest { "record.test", "rek.test", "samepkg.test", + "sealed.test", "self.test", "semi.test", // https://bugs.openjdk.java.net/browse/JDK-8054064 ? diff --git a/javatests/com/google/turbine/lower/LowerTest.java b/javatests/com/google/turbine/lower/LowerTest.java index e560321..c679228 100644 --- a/javatests/com/google/turbine/lower/LowerTest.java +++ b/javatests/com/google/turbine/lower/LowerTest.java @@ -185,6 +185,7 @@ public class LowerTest { SourceTypeBoundClass c = new SourceTypeBoundClass( interfaceTypes, + ImmutableList.of(), xtnds, tps, access, @@ -206,6 +207,7 @@ public class LowerTest { SourceTypeBoundClass i = new SourceTypeBoundClass( ImmutableList.of(), + ImmutableList.of(), Type.ClassTy.OBJECT, ImmutableMap.of(), TurbineFlag.ACC_STATIC | TurbineFlag.ACC_PROTECTED, diff --git a/javatests/com/google/turbine/lower/testdata/ambiguous_identifier.test b/javatests/com/google/turbine/lower/testdata/ambiguous_identifier.test new file mode 100644 index 0000000..d7bbc54 --- /dev/null +++ b/javatests/com/google/turbine/lower/testdata/ambiguous_identifier.test @@ -0,0 +1,14 @@ +=== Test.java === +class Test { + static final int non = 42; + static final int sealed = 1; + // here 'non-sealed' is a binary expression subtracting two identifiers, + // not a contextual hyphenated keyword + static final int x = non-sealed; +} + +// handle backtracking when we see 'non', but it isn't part of a contextualy +// hyphenated keyword 'non-sealed' +class non { + non self; +} diff --git a/javatests/com/google/turbine/lower/testdata/sealed.test b/javatests/com/google/turbine/lower/testdata/sealed.test new file mode 100644 index 0000000..0bac7b1 --- /dev/null +++ b/javatests/com/google/turbine/lower/testdata/sealed.test @@ -0,0 +1,11 @@ +=== Sealed.java === + +sealed class Sealed permits Sealed.Foo, Sealed.Bar { + static final class Foo extends Sealed {} + static final class Bar extends Sealed {} +} + +sealed interface ISealed permits ISealed.Foo, ISealed.Bar { + static final class Foo implements ISealed {} + static non-sealed class Bar implements ISealed {} +} diff --git a/javatests/com/google/turbine/parse/ParserIntegrationTest.java b/javatests/com/google/turbine/parse/ParserIntegrationTest.java index ade6bf0..2f37a84 100644 --- a/javatests/com/google/turbine/parse/ParserIntegrationTest.java +++ b/javatests/com/google/turbine/parse/ParserIntegrationTest.java @@ -76,6 +76,7 @@ public class ParserIntegrationTest { "type_annotations.input", "module-info.input", "record.input", + "sealed.input", }; return Iterables.transform( Arrays.asList(tests), diff --git a/javatests/com/google/turbine/parse/testdata/sealed.input b/javatests/com/google/turbine/parse/testdata/sealed.input new file mode 100644 index 0000000..5a277b8 --- /dev/null +++ b/javatests/com/google/turbine/parse/testdata/sealed.input @@ -0,0 +1,15 @@ +sealed class Sealed permits Sealed.Foo, Sealed.Bar { + static final class Foo extends Sealed { + } + + static final class Bar extends Sealed { + } +} + +sealed interface ISealed permits ISealed.Foo, ISealed.Bar { + static final class Foo implements ISealed { + } + + static non-sealed class Bar implements ISealed { + } +} |