aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2019-01-24 10:28:32 -0800
committerandroid-build-merger <android-build-merger@google.com>2019-01-24 10:28:32 -0800
commit9268aadd478f66072573b0fe425014f42ced6cb0 (patch)
treefc48c84a601aa4170462d011afff6fb597364019
parentbd5271b08e24853993ac5df3e26e0f6272777d66 (diff)
parent6d5f9e3e611533de9397480f7b84277f47e6189b (diff)
downloadturbine-9268aadd478f66072573b0fe425014f42ced6cb0.tar.gz
Merge remote-tracking branch 'aosp/upstream-master' into master am: 3fec25b908
am: 6d5f9e3e61 Change-Id: I06d4da764fa8be08604a3e9e52ef6130106b1148
-rw-r--r--.travis.yml32
-rw-r--r--appveyor.yml5
-rw-r--r--java/com/google/turbine/binder/Binder.java57
-rw-r--r--java/com/google/turbine/binder/CanonicalTypeBinder.java68
-rw-r--r--java/com/google/turbine/binder/ClassPathBinder.java9
-rw-r--r--java/com/google/turbine/binder/CompUnitPreprocessor.java11
-rw-r--r--java/com/google/turbine/binder/ConstBinder.java50
-rw-r--r--java/com/google/turbine/binder/ConstEvaluator.java58
-rw-r--r--java/com/google/turbine/binder/CtSymClassBinder.java16
-rw-r--r--java/com/google/turbine/binder/DisambiguateTypeAnnotations.java45
-rw-r--r--java/com/google/turbine/binder/HierarchyBinder.java45
-rw-r--r--java/com/google/turbine/binder/JimageClassBinder.java20
-rw-r--r--java/com/google/turbine/binder/ModuleBinder.java11
-rw-r--r--java/com/google/turbine/binder/Resolve.java58
-rw-r--r--java/com/google/turbine/binder/TypeBinder.java179
-rw-r--r--java/com/google/turbine/binder/bound/AnnotationMetadata.java18
-rw-r--r--java/com/google/turbine/binder/bound/AnnotationValue.java15
-rw-r--r--java/com/google/turbine/binder/bound/ClassValue.java11
-rw-r--r--java/com/google/turbine/binder/bound/EnumConstantValue.java10
-rw-r--r--java/com/google/turbine/binder/bound/SourceTypeBoundClass.java53
-rw-r--r--java/com/google/turbine/binder/bound/TypeBoundClass.java31
-rw-r--r--java/com/google/turbine/binder/bytecode/BytecodeBinder.java125
-rw-r--r--java/com/google/turbine/binder/bytecode/BytecodeBoundClass.java177
-rw-r--r--java/com/google/turbine/binder/lookup/CanonicalSymbolResolver.java3
-rw-r--r--java/com/google/turbine/binder/lookup/ImportIndex.java56
-rw-r--r--java/com/google/turbine/binder/lookup/ImportScope.java3
-rw-r--r--java/com/google/turbine/binder/lookup/LookupKey.java11
-rw-r--r--java/com/google/turbine/binder/lookup/LookupResult.java8
-rw-r--r--java/com/google/turbine/binder/lookup/MemberImportIndex.java7
-rw-r--r--java/com/google/turbine/binder/lookup/SimpleTopLevelIndex.java33
-rw-r--r--java/com/google/turbine/binder/lookup/WildImportIndex.java9
-rw-r--r--java/com/google/turbine/bytecode/ClassReader.java176
-rw-r--r--java/com/google/turbine/bytecode/ConstantPoolReader.java2
-rw-r--r--java/com/google/turbine/bytecode/sig/SigParser.java3
-rw-r--r--java/com/google/turbine/deps/Dependencies.java2
-rw-r--r--java/com/google/turbine/diag/TurbineDiagnostic.java128
-rw-r--r--java/com/google/turbine/diag/TurbineError.java63
-rw-r--r--java/com/google/turbine/diag/TurbineLog.java56
-rw-r--r--java/com/google/turbine/lower/Lower.java26
-rw-r--r--java/com/google/turbine/lower/LowerSignature.java56
-rw-r--r--java/com/google/turbine/main/Main.java42
-rw-r--r--java/com/google/turbine/main/UsageException.java64
-rw-r--r--java/com/google/turbine/model/Const.java142
-rw-r--r--java/com/google/turbine/model/TurbineElementType.java32
-rw-r--r--java/com/google/turbine/options/TurbineOptions.java51
-rw-r--r--java/com/google/turbine/options/TurbineOptionsParser.java3
-rw-r--r--java/com/google/turbine/parse/ConstExpressionParser.java31
-rw-r--r--java/com/google/turbine/parse/Parser.java150
-rw-r--r--java/com/google/turbine/parse/StreamLexer.java20
-rw-r--r--java/com/google/turbine/tree/Pretty.java23
-rw-r--r--java/com/google/turbine/tree/Tree.java121
-rw-r--r--java/com/google/turbine/type/AnnoInfo.java19
-rw-r--r--java/com/google/turbine/type/Type.java199
-rw-r--r--java/com/google/turbine/types/Canonicalize.java219
-rw-r--r--java/com/google/turbine/types/Erasure.java28
-rw-r--r--javatests/com/google/turbine/binder/BinderErrorTest.java107
-rw-r--r--javatests/com/google/turbine/binder/BinderTest.java50
-rw-r--r--javatests/com/google/turbine/binder/ClassPathBinderTest.java50
-rw-r--r--javatests/com/google/turbine/binder/JimageClassBinderTest.java18
-rw-r--r--javatests/com/google/turbine/binder/bytecode/BytecodeBoundClassTest.java149
-rw-r--r--javatests/com/google/turbine/binder/lookup/TopLevelIndexTest.java35
-rw-r--r--javatests/com/google/turbine/bytecode/ClassReaderTest.java1
-rw-r--r--javatests/com/google/turbine/bytecode/sig/SigIntegrationTest.java2
-rw-r--r--javatests/com/google/turbine/deps/DependenciesTest.java4
-rw-r--r--javatests/com/google/turbine/lower/IntegrationTestSupport.java6
-rw-r--r--javatests/com/google/turbine/lower/LowerIntegrationTest.java7
-rw-r--r--javatests/com/google/turbine/lower/LowerSignatureTest.java60
-rw-r--r--javatests/com/google/turbine/lower/LowerTest.java88
-rw-r--r--javatests/com/google/turbine/lower/ModuleIntegrationTest.java10
-rw-r--r--javatests/com/google/turbine/lower/moduletestdata/classpath.test7
-rw-r--r--javatests/com/google/turbine/lower/moduletestdata/module-info.test84
-rw-r--r--javatests/com/google/turbine/lower/moduletestdata/multimodule.test13
-rw-r--r--javatests/com/google/turbine/lower/testdata/anno_void.test8
-rw-r--r--javatests/com/google/turbine/lower/testdata/golden/outer.txt2
-rw-r--r--javatests/com/google/turbine/lower/testdata/shadow_inherited.test8
-rw-r--r--javatests/com/google/turbine/lower/testdata/static_final_boxed.test11
-rw-r--r--javatests/com/google/turbine/lower/testdata/type_anno_c_array.test28
-rw-r--r--javatests/com/google/turbine/main/MainTest.java13
-rw-r--r--javatests/com/google/turbine/model/ConstTest.java85
-rw-r--r--javatests/com/google/turbine/options/TurbineOptionsTest.java17
-rw-r--r--javatests/com/google/turbine/parse/ParseErrorTest.java48
-rw-r--r--pom.xml96
82 files changed, 2744 insertions, 1153 deletions
diff --git a/.travis.yml b/.travis.yml
index 273556e..3ea8885 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,29 +1,27 @@
language: java
+jdk:
+ - oraclejdk8
+ - oraclejdk9
+ - openjdk10
+ - openjdk11
+ - openjdk-ea
+
matrix:
allow_failures:
- - jdk: oraclejdk9
- include:
-# JDK 8
- - jdk: oraclejdk8
- env: JDK_RELEASE='8'
-# JDK 9
- - jdk: oraclejdk9
- env: JDK_RELEASE='9'
+ - jdk: openjdk-ea
+
+# see https://github.com/travis-ci/travis-ci/issues/8408
+before_install:
+- unset _JAVA_OPTIONS
# use travis-ci docker based infrastructure
sudo: false
-# https://github.com/travis-ci/travis-ci/issues/3259#issuecomment-130860338
-addons:
- apt:
- packages:
- - oracle-java8-installer
-
cache:
directories:
- $HOME/.m2
-install: mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V
-
-script: mvn test -B
+script:
+- mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V
+- mvn test -B
diff --git a/appveyor.yml b/appveyor.yml
index bcbf5dc..44ff736 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,5 +1,10 @@
os: Visual Studio 2015
+environment:
+ matrix:
+ - JAVA_HOME: C:\Program Files\Java\jdk9
+ - JAVA_HOME: C:\Program Files\Java\jdk10
+
install:
- ps: |
Add-Type -AssemblyName System.IO.Compression.FileSystem
diff --git a/java/com/google/turbine/binder/Binder.java b/java/com/google/turbine/binder/Binder.java
index d4b151f..cffe291 100644
--- a/java/com/google/turbine/binder/Binder.java
+++ b/java/com/google/turbine/binder/Binder.java
@@ -16,8 +16,6 @@
package com.google.turbine.binder;
-
-import com.google.common.base.Optional;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -55,6 +53,7 @@ import com.google.turbine.binder.sym.FieldSymbol;
import com.google.turbine.binder.sym.ModuleSymbol;
import com.google.turbine.diag.TurbineError;
import com.google.turbine.diag.TurbineError.ErrorKind;
+import com.google.turbine.diag.TurbineLog;
import com.google.turbine.model.Const;
import com.google.turbine.model.TurbineFlag;
import com.google.turbine.tree.Tree;
@@ -62,6 +61,7 @@ import com.google.turbine.tree.Tree.CompUnit;
import com.google.turbine.tree.Tree.ModDecl;
import com.google.turbine.type.Type;
import java.util.List;
+import java.util.Optional;
/** The entry point for analysis. */
public class Binder {
@@ -91,17 +91,24 @@ public class Binder {
CompoundEnv<ModuleSymbol, ModuleInfo> classPathModuleEnv =
CompoundEnv.of(classpath.moduleEnv()).append(bootclasspath.moduleEnv());
+ TurbineLog log = new TurbineLog();
+
BindPackagesResult bindPackagesResult =
- bindPackages(ienv, tli, preProcessedUnits, classPathEnv);
+ bindPackages(log, ienv, tli, preProcessedUnits, classPathEnv);
SimpleEnv<ClassSymbol, PackageSourceBoundClass> psenv = bindPackagesResult.classes;
SimpleEnv<ModuleSymbol, PackageSourceBoundModule> modules = bindPackagesResult.modules;
- Env<ClassSymbol, SourceHeaderBoundClass> henv = bindHierarchy(syms, psenv, classPathEnv);
+ Env<ClassSymbol, SourceHeaderBoundClass> henv = bindHierarchy(log, syms, psenv, classPathEnv);
Env<ClassSymbol, SourceTypeBoundClass> tenv =
bindTypes(
- syms, henv, CompoundEnv.<ClassSymbol, HeaderBoundClass>of(classPathEnv).append(henv));
+ log,
+ syms,
+ henv,
+ CompoundEnv.<ClassSymbol, HeaderBoundClass>of(classPathEnv).append(henv));
+
+ log.maybeThrow();
tenv =
constants(
@@ -157,6 +164,7 @@ public class Binder {
/** Initializes scopes for compilation unit and package-level lookup. */
private static BindPackagesResult bindPackages(
+ TurbineLog log,
Env<ClassSymbol, SourceBoundClass> ienv,
TopLevelIndex tli,
ImmutableList<PreprocessedCompUnit> units,
@@ -177,9 +185,10 @@ public class Binder {
Scope packageScope = tli.lookupPackage(packagename);
CanonicalSymbolResolver importResolver =
new CanonicalResolver(
- packagename, CompoundEnv.<ClassSymbol, BoundClass>of(classPathEnv).append(ienv));
+ unit.packageName(),
+ CompoundEnv.<ClassSymbol, BoundClass>of(classPathEnv).append(ienv));
ImportScope importScope =
- ImportIndex.create(unit.source(), importResolver, tli, unit.imports());
+ ImportIndex.create(log.withSource(unit.source()), importResolver, tli, unit.imports());
ImportScope wildImportScope = WildImportIndex.create(importResolver, tli, unit.imports());
MemberImportIndex memberImports =
new MemberImportIndex(unit.source(), importResolver, tli, unit.imports());
@@ -203,6 +212,7 @@ public class Binder {
/** Binds the type hierarchy (superclasses and interfaces) for all classes in the compilation. */
private static Env<ClassSymbol, SourceHeaderBoundClass> bindHierarchy(
+ TurbineLog log,
Iterable<ClassSymbol> syms,
final SimpleEnv<ClassSymbol, PackageSourceBoundClass> psenv,
CompoundEnv<ClassSymbol, BytecodeBoundClass> classPathEnv) {
@@ -216,7 +226,8 @@ public class Binder {
@Override
public SourceHeaderBoundClass complete(
Env<ClassSymbol, HeaderBoundClass> henv, ClassSymbol sym) {
- return HierarchyBinder.bind(sym, psenv.get(sym), henv);
+ PackageSourceBoundClass base = psenv.get(sym);
+ return HierarchyBinder.bind(log.withSource(base.source()), sym, base, henv);
}
});
}
@@ -224,12 +235,14 @@ public class Binder {
}
private static Env<ClassSymbol, SourceTypeBoundClass> bindTypes(
+ TurbineLog log,
ImmutableSet<ClassSymbol> syms,
Env<ClassSymbol, SourceHeaderBoundClass> shenv,
Env<ClassSymbol, HeaderBoundClass> henv) {
SimpleEnv.Builder<ClassSymbol, SourceTypeBoundClass> builder = SimpleEnv.builder();
for (ClassSymbol sym : syms) {
- builder.put(sym, TypeBinder.bind(henv, sym, shenv.get(sym)));
+ SourceHeaderBoundClass base = shenv.get(sym);
+ builder.put(sym, TypeBinder.bind(log.withSource(base.source()), henv, sym, base));
}
return builder.build();
}
@@ -257,20 +270,18 @@ public class Binder {
new Env<ModuleSymbol, ModuleInfo>() {
@Override
public ModuleInfo get(ModuleSymbol sym) {
- if (modules.asMap().containsKey(sym)) {
- PackageSourceBoundModule info = modules.get(sym);
- if (info != null) {
- return new ModuleInfo(
- info.module().moduleName(),
- moduleVersion.orNull(),
- /* flags= */ 0,
- /* annos= */ ImmutableList.of(),
- /* requires= */ ImmutableList.of(),
- /* exports= */ ImmutableList.of(),
- /* opens= */ ImmutableList.of(),
- /* uses= */ ImmutableList.of(),
- /* provides= */ ImmutableList.of());
- }
+ PackageSourceBoundModule info = modules.get(sym);
+ if (info != null) {
+ return new ModuleInfo(
+ info.module().moduleName(),
+ moduleVersion.orElse(null),
+ /* flags= */ 0,
+ /* annos= */ ImmutableList.of(),
+ /* requires= */ ImmutableList.of(),
+ /* exports= */ ImmutableList.of(),
+ /* opens= */ ImmutableList.of(),
+ /* uses= */ ImmutableList.of(),
+ /* provides= */ ImmutableList.of());
}
return null;
}
diff --git a/java/com/google/turbine/binder/CanonicalTypeBinder.java b/java/com/google/turbine/binder/CanonicalTypeBinder.java
index 20db0d7..934ec54 100644
--- a/java/com/google/turbine/binder/CanonicalTypeBinder.java
+++ b/java/com/google/turbine/binder/CanonicalTypeBinder.java
@@ -30,6 +30,8 @@ import com.google.turbine.binder.sym.TyVarSymbol;
import com.google.turbine.diag.SourceFile;
import com.google.turbine.type.Type;
import com.google.turbine.type.Type.ClassTy;
+import com.google.turbine.type.Type.IntersectionTy;
+import com.google.turbine.type.Type.TyKind;
import com.google.turbine.types.Canonicalize;
import java.util.Map;
@@ -41,17 +43,28 @@ public class CanonicalTypeBinder {
static SourceTypeBoundClass bind(
ClassSymbol sym, SourceTypeBoundClass base, Env<ClassSymbol, TypeBoundClass> env) {
ClassTy superClassType = null;
- if (base.superClassType() != null) {
+ if (base.superClassType() != null && base.superClassType().tyKind() == TyKind.CLASS_TY) {
superClassType =
- Canonicalize.canonicalizeClassTy(base.source(), env, base.owner(), base.superClassType());
+ Canonicalize.canonicalizeClassTy(
+ base.source(),
+ base.decl().position(),
+ env,
+ base.owner(),
+ (ClassTy) base.superClassType());
}
- ImmutableList.Builder<ClassTy> interfaceTypes = ImmutableList.builder();
- for (ClassTy i : base.interfaceTypes()) {
- interfaceTypes.add(Canonicalize.canonicalizeClassTy(base.source(), env, base.owner(), i));
+ ImmutableList.Builder<Type> interfaceTypes = ImmutableList.builder();
+ for (Type i : base.interfaceTypes()) {
+ if (i.tyKind() == TyKind.CLASS_TY) {
+ i =
+ Canonicalize.canonicalizeClassTy(
+ base.source(), base.decl().position(), env, base.owner(), (ClassTy) i);
+ }
+ interfaceTypes.add(i);
}
ImmutableMap<TyVarSymbol, TyVarInfo> typParamTypes =
- typeParameters(base.source(), env, sym, base.typeParameterTypes());
- ImmutableList<MethodInfo> methods = methods(base.source(), env, sym, base.methods());
+ typeParameters(base.source(), base.decl().position(), env, sym, base.typeParameterTypes());
+ ImmutableList<MethodInfo> methods =
+ methods(base.source(), base.decl().position(), env, sym, base.methods());
ImmutableList<FieldInfo> fields = fields(base.source(), env, sym, base.fields());
return new SourceTypeBoundClass(
interfaceTypes.build(),
@@ -69,7 +82,8 @@ public class CanonicalTypeBinder {
base.memberImports(),
base.annotationMetadata(),
base.annotations(),
- base.source());
+ base.source(),
+ base.decl());
}
private static ImmutableList<FieldInfo> fields(
@@ -82,7 +96,7 @@ public class CanonicalTypeBinder {
result.add(
new FieldInfo(
base.sym(),
- Canonicalize.canonicalize(source, env, sym, base.type()),
+ Canonicalize.canonicalize(source, base.decl().position(), env, sym, base.type()),
base.access(),
base.annotations(),
base.decl(),
@@ -93,18 +107,21 @@ public class CanonicalTypeBinder {
private static ImmutableList<MethodInfo> methods(
SourceFile source,
+ int position,
Env<ClassSymbol, TypeBoundClass> env,
ClassSymbol sym,
ImmutableList<MethodInfo> methods) {
ImmutableList.Builder<MethodInfo> result = ImmutableList.builder();
for (MethodInfo base : methods) {
- ImmutableMap<TyVarSymbol, TyVarInfo> tps = typeParameters(source, env, sym, base.tyParams());
- Type ret = Canonicalize.canonicalize(source, env, sym, base.returnType());
+ int pos = base.decl() != null ? base.decl().position() : position;
+ ImmutableMap<TyVarSymbol, TyVarInfo> tps =
+ typeParameters(source, pos, env, sym, base.tyParams());
+ Type ret = Canonicalize.canonicalize(source, pos, env, sym, base.returnType());
ImmutableList.Builder<ParamInfo> parameters = ImmutableList.builder();
for (ParamInfo parameter : base.parameters()) {
- parameters.add(param(source, env, sym, parameter));
+ parameters.add(param(source, pos, env, sym, parameter));
}
- ImmutableList<Type> exceptions = canonicalizeList(source, env, sym, base.exceptions());
+ ImmutableList<Type> exceptions = canonicalizeList(source, pos, env, sym, base.exceptions());
result.add(
new MethodInfo(
base.sym(),
@@ -116,15 +133,21 @@ public class CanonicalTypeBinder {
base.defaultValue(),
base.decl(),
base.annotations(),
- base.receiver() != null ? param(source, env, sym, base.receiver()) : null));
+ base.receiver() != null
+ ? param(source, base.decl().position(), env, sym, base.receiver())
+ : null));
}
return result.build();
}
private static ParamInfo param(
- SourceFile source, Env<ClassSymbol, TypeBoundClass> env, ClassSymbol sym, ParamInfo base) {
+ SourceFile source,
+ int position,
+ Env<ClassSymbol, TypeBoundClass> env,
+ ClassSymbol sym,
+ ParamInfo base) {
return new ParamInfo(
- Canonicalize.canonicalize(source, env, sym, base.type()),
+ Canonicalize.canonicalize(source, position, env, sym, base.type()),
base.name(),
base.annotations(),
base.access());
@@ -132,31 +155,28 @@ public class CanonicalTypeBinder {
private static ImmutableMap<TyVarSymbol, TyVarInfo> typeParameters(
SourceFile source,
+ int position,
Env<ClassSymbol, TypeBoundClass> env,
ClassSymbol sym,
Map<TyVarSymbol, TyVarInfo> tps) {
ImmutableMap.Builder<TyVarSymbol, TyVarInfo> result = ImmutableMap.builder();
for (Map.Entry<TyVarSymbol, TyVarInfo> e : tps.entrySet()) {
TyVarInfo info = e.getValue();
- Type superClassBound = null;
- if (info.superClassBound() != null) {
- superClassBound = Canonicalize.canonicalize(source, env, sym, info.superClassBound());
- }
- ImmutableList<Type> interfaceBounds =
- canonicalizeList(source, env, sym, info.interfaceBounds());
- result.put(e.getKey(), new TyVarInfo(superClassBound, interfaceBounds, info.annotations()));
+ Type bound = Canonicalize.canonicalize(source, position, env, sym, info.bound());
+ result.put(e.getKey(), new TyVarInfo((IntersectionTy) bound, info.annotations()));
}
return result.build();
}
private static ImmutableList<Type> canonicalizeList(
SourceFile source,
+ int position,
Env<ClassSymbol, TypeBoundClass> env,
ClassSymbol sym,
ImmutableList<Type> types) {
ImmutableList.Builder<Type> result = ImmutableList.builder();
for (Type type : types) {
- result.add(Canonicalize.canonicalize(source, env, sym, type));
+ result.add(Canonicalize.canonicalize(source, position, env, sym, type));
}
return result.build();
}
diff --git a/java/com/google/turbine/binder/ClassPathBinder.java b/java/com/google/turbine/binder/ClassPathBinder.java
index 2b3a921..5d8db86 100644
--- a/java/com/google/turbine/binder/ClassPathBinder.java
+++ b/java/com/google/turbine/binder/ClassPathBinder.java
@@ -69,9 +69,7 @@ public class ClassPathBinder {
}
for (Map.Entry<ClassSymbol, BytecodeBoundClass> entry : transitive.entrySet()) {
ClassSymbol symbol = entry.getKey();
- if (!map.containsKey(symbol)) {
- map.put(symbol, entry.getValue());
- }
+ map.putIfAbsent(symbol, entry.getValue());
}
SimpleEnv<ClassSymbol, BytecodeBoundClass> env = new SimpleEnv<>(ImmutableMap.copyOf(map));
SimpleEnv<ModuleSymbol, ModuleInfo> moduleEnv = new SimpleEnv<>(ImmutableMap.copyOf(modules));
@@ -128,9 +126,8 @@ public class ClassPathBinder {
continue;
}
ClassSymbol sym = new ClassSymbol(name.substring(0, name.length() - ".class".length()));
- if (!env.containsKey(sym)) {
- env.put(sym, new BytecodeBoundClass(sym, toByteArrayOrDie(ze), benv, path.toString()));
- }
+ env.putIfAbsent(
+ sym, new BytecodeBoundClass(sym, toByteArrayOrDie(ze), benv, path.toString()));
}
}
diff --git a/java/com/google/turbine/binder/CompUnitPreprocessor.java b/java/com/google/turbine/binder/CompUnitPreprocessor.java
index 121b18d..85ff1c0 100644
--- a/java/com/google/turbine/binder/CompUnitPreprocessor.java
+++ b/java/com/google/turbine/binder/CompUnitPreprocessor.java
@@ -17,7 +17,6 @@
package com.google.turbine.binder;
import com.google.common.base.Joiner;
-import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
@@ -31,6 +30,7 @@ import com.google.turbine.model.TurbineFlag;
import com.google.turbine.model.TurbineTyKind;
import com.google.turbine.tree.Tree;
import com.google.turbine.tree.Tree.CompUnit;
+import com.google.turbine.tree.Tree.Ident;
import com.google.turbine.tree.Tree.ImportDecl;
import com.google.turbine.tree.Tree.ModDecl;
import com.google.turbine.tree.Tree.PkgDecl;
@@ -38,6 +38,7 @@ import com.google.turbine.tree.Tree.TyDecl;
import com.google.turbine.tree.TurbineModifier;
import java.util.HashSet;
import java.util.List;
+import java.util.Optional;
import java.util.Set;
/**
@@ -135,11 +136,11 @@ public class CompUnitPreprocessor {
if (member.kind() == Tree.Kind.TY_DECL) {
Tree.TyDecl decl = (Tree.TyDecl) member;
ClassSymbol sym = new ClassSymbol(owner.binaryName() + '$' + decl.name());
- if (!seen.add(decl.name())) {
+ if (!seen.add(decl.name().value())) {
throw TurbineError.format(
source, member.position(), ErrorKind.DUPLICATE_DECLARATION, sym);
}
- result.put(decl.name(), sym);
+ result.put(decl.name().value(), sym);
int access = innerClassAccess(enclosing, decl);
@@ -213,9 +214,9 @@ public class CompUnitPreprocessor {
pkgDecl.position(),
ImmutableSet.of(TurbineModifier.ACC_SYNTHETIC),
pkgDecl.annos(),
- "package-info",
+ new Ident(pkgDecl.position(), "package-info"),
ImmutableList.of(),
- Optional.absent(),
+ Optional.empty(),
ImmutableList.of(),
ImmutableList.of(),
TurbineTyKind.INTERFACE);
diff --git a/java/com/google/turbine/binder/ConstBinder.java b/java/com/google/turbine/binder/ConstBinder.java
index 4b48dd3..e5717b2 100644
--- a/java/com/google/turbine/binder/ConstBinder.java
+++ b/java/com/google/turbine/binder/ConstBinder.java
@@ -37,6 +37,7 @@ import com.google.turbine.model.Const;
import com.google.turbine.model.Const.ArrayInitValue;
import com.google.turbine.model.Const.Kind;
import com.google.turbine.model.Const.Value;
+import com.google.turbine.model.TurbineElementType;
import com.google.turbine.model.TurbineFlag;
import com.google.turbine.model.TurbineTyKind;
import com.google.turbine.type.AnnoInfo;
@@ -44,13 +45,13 @@ import com.google.turbine.type.Type;
import com.google.turbine.type.Type.ArrayTy;
import com.google.turbine.type.Type.ClassTy;
import com.google.turbine.type.Type.ClassTy.SimpleClassTy;
+import com.google.turbine.type.Type.IntersectionTy;
import com.google.turbine.type.Type.TyKind;
import com.google.turbine.type.Type.TyVar;
import com.google.turbine.type.Type.WildLowerBoundedTy;
import com.google.turbine.type.Type.WildTy;
import com.google.turbine.type.Type.WildUnboundedTy;
import com.google.turbine.type.Type.WildUpperBoundedTy;
-import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;
import java.util.Map;
@@ -91,8 +92,8 @@ public class ConstBinder {
ImmutableList<TypeBoundClass.FieldInfo> fields = fields(base.fields());
ImmutableList<MethodInfo> methods = bindMethods(base.methods());
return new SourceTypeBoundClass(
- bindClassTypes(base.interfaceTypes()),
- base.superClassType() != null ? bindClassType(base.superClassType()) : null,
+ bindTypes(base.interfaceTypes()),
+ base.superClassType() != null ? bindType(base.superClassType()) : null,
bindTypeParameters(base.typeParameterTypes()),
base.access(),
methods,
@@ -106,7 +107,8 @@ public class ConstBinder {
base.memberImports(),
bindAnnotationMetadata(base.kind(), annos),
annos,
- base.source());
+ base.source(),
+ base.decl());
}
private ImmutableList<MethodInfo> bindMethods(ImmutableList<MethodInfo> methods) {
@@ -156,7 +158,7 @@ public class ConstBinder {
return null;
}
RetentionPolicy retention = null;
- ImmutableSet<ElementType> target = null;
+ ImmutableSet<TurbineElementType> target = null;
ClassSymbol repeatable = null;
for (AnnoInfo annotation : annotations) {
switch (annotation.sym().binaryName()) {
@@ -188,8 +190,8 @@ public class ConstBinder {
return RetentionPolicy.valueOf(enumValue.sym().name());
}
- private static ImmutableSet<ElementType> bindTarget(AnnoInfo annotation) {
- ImmutableSet.Builder<ElementType> result = ImmutableSet.builder();
+ private static ImmutableSet<TurbineElementType> bindTarget(AnnoInfo annotation) {
+ ImmutableSet.Builder<TurbineElementType> result = ImmutableSet.builder();
Const val = annotation.values().get("value");
switch (val.kind()) {
case ARRAY:
@@ -221,9 +223,9 @@ public class ConstBinder {
}
private static void bindTargetElement(
- ImmutableSet.Builder<ElementType> target, EnumConstantValue enumVal) {
+ ImmutableSet.Builder<TurbineElementType> target, EnumConstantValue enumVal) {
if (enumVal.sym().owner().binaryName().equals("java/lang/annotation/ElementType")) {
- target.add(ElementType.valueOf(enumVal.sym().name()));
+ target.add(TurbineElementType.valueOf(enumVal.sym().name()));
}
}
@@ -268,14 +270,6 @@ public class ConstBinder {
return value;
}
- private ImmutableList<ClassTy> bindClassTypes(ImmutableList<ClassTy> types) {
- ImmutableList.Builder<ClassTy> result = ImmutableList.builder();
- for (ClassTy t : types) {
- result.add(bindClassType(t));
- }
- return result.build();
- }
-
private ImmutableList<Type> bindTypes(ImmutableList<Type> types) {
ImmutableList.Builder<Type> result = ImmutableList.builder();
for (Type t : types) {
@@ -292,8 +286,7 @@ public class ConstBinder {
result.put(
entry.getKey(),
new TyVarInfo(
- info.superClassBound() != null ? bindType(info.superClassBound()) : null,
- bindTypes(info.interfaceBounds()),
+ (IntersectionTy) bindType(info.bound()),
constEvaluator.evaluateAnnotations(info.annotations())));
}
return result.build();
@@ -303,25 +296,26 @@ public class ConstBinder {
switch (type.tyKind()) {
case TY_VAR:
TyVar tyVar = (TyVar) type;
- return new TyVar(tyVar.sym(), constEvaluator.evaluateAnnotations(tyVar.annos()));
+ return TyVar.create(tyVar.sym(), constEvaluator.evaluateAnnotations(tyVar.annos()));
case CLASS_TY:
return bindClassType((ClassTy) type);
case ARRAY_TY:
ArrayTy arrayTy = (ArrayTy) type;
- return new ArrayTy(
+ return ArrayTy.create(
bindType(arrayTy.elementType()), constEvaluator.evaluateAnnotations(arrayTy.annos()));
case WILD_TY:
{
WildTy wildTy = (WildTy) type;
switch (wildTy.boundKind()) {
case NONE:
- return new WildUnboundedTy(constEvaluator.evaluateAnnotations(wildTy.annotations()));
+ return WildUnboundedTy.create(
+ constEvaluator.evaluateAnnotations(wildTy.annotations()));
case UPPER:
- return new WildUpperBoundedTy(
+ return WildUpperBoundedTy.create(
bindType(wildTy.bound()),
constEvaluator.evaluateAnnotations(wildTy.annotations()));
case LOWER:
- return new WildLowerBoundedTy(
+ return WildLowerBoundedTy.create(
bindType(wildTy.bound()),
constEvaluator.evaluateAnnotations(wildTy.annotations()));
default:
@@ -331,6 +325,8 @@ public class ConstBinder {
case PRIM_TY:
case VOID_TY:
return type;
+ case INTERSECTION_TY:
+ return IntersectionTy.create(bindTypes(((IntersectionTy) type).bounds()));
default:
throw new AssertionError(type.tyKind());
}
@@ -339,11 +335,11 @@ public class ConstBinder {
private ClassTy bindClassType(ClassTy type) {
ClassTy classTy = type;
ImmutableList.Builder<SimpleClassTy> classes = ImmutableList.builder();
- for (SimpleClassTy c : classTy.classes) {
+ for (SimpleClassTy c : classTy.classes()) {
classes.add(
- new SimpleClassTy(
+ SimpleClassTy.create(
c.sym(), bindTypes(c.targs()), constEvaluator.evaluateAnnotations(c.annos())));
}
- return new ClassTy(classes.build());
+ return ClassTy.create(classes.build());
}
}
diff --git a/java/com/google/turbine/binder/ConstEvaluator.java b/java/com/google/turbine/binder/ConstEvaluator.java
index 7e79919..2d8ce2d 100644
--- a/java/com/google/turbine/binder/ConstEvaluator.java
+++ b/java/com/google/turbine/binder/ConstEvaluator.java
@@ -39,6 +39,7 @@ import com.google.turbine.diag.SourceFile;
import com.google.turbine.diag.TurbineError;
import com.google.turbine.diag.TurbineError.ErrorKind;
import com.google.turbine.model.Const;
+import com.google.turbine.model.Const.ConstCastError;
import com.google.turbine.model.Const.Value;
import com.google.turbine.model.TurbineConstantTypeKind;
import com.google.turbine.model.TurbineFlag;
@@ -50,6 +51,7 @@ import com.google.turbine.tree.Tree.ClassTy;
import com.google.turbine.tree.Tree.Conditional;
import com.google.turbine.tree.Tree.ConstVarName;
import com.google.turbine.tree.Tree.Expression;
+import com.google.turbine.tree.Tree.Ident;
import com.google.turbine.tree.Tree.PrimTy;
import com.google.turbine.tree.Tree.TypeCast;
import com.google.turbine.tree.Tree.Unary;
@@ -170,13 +172,13 @@ public strictfp class ConstEvaluator {
private Type evalClassLiteralType(Tree.Type type) {
switch (type.kind()) {
case PRIM_TY:
- return new Type.PrimTy(((PrimTy) type).tykind(), ImmutableList.of());
+ return Type.PrimTy.create(((PrimTy) type).tykind(), ImmutableList.of());
case VOID_TY:
return Type.VOID;
case CLASS_TY:
return Type.ClassTy.asNonParametricClassTy(resolveClass((ClassTy) type));
case ARR_TY:
- return new Type.ArrayTy(
+ return Type.ArrayTy.create(
evalClassLiteralType(((Tree.ArrTy) type).elem()), ImmutableList.of());
default:
throw new AssertionError(type.kind());
@@ -193,22 +195,22 @@ public strictfp class ConstEvaluator {
* isn't completed during the hierarchy phase).
*/
private ClassSymbol resolveClass(ClassTy classTy) {
- ArrayDeque<String> flat = new ArrayDeque<>();
- for (ClassTy curr = classTy; curr != null; curr = curr.base().orNull()) {
+ ArrayDeque<Ident> flat = new ArrayDeque<>();
+ for (ClassTy curr = classTy; curr != null; curr = curr.base().orElse(null)) {
flat.addFirst(curr.name());
}
- LookupResult result = scope.lookup(new LookupKey(flat));
+ LookupResult result = scope.lookup(new LookupKey(ImmutableList.copyOf(flat)));
if (result == null) {
throw error(classTy.position(), ErrorKind.CANNOT_RESOLVE, flat.peekFirst());
}
ClassSymbol classSym = (ClassSymbol) result.sym();
- for (String bit : result.remaining()) {
+ for (Ident bit : result.remaining()) {
classSym = resolveNext(classTy.position(), classSym, bit);
}
return classSym;
}
- private ClassSymbol resolveNext(int position, ClassSymbol sym, String bit) {
+ private ClassSymbol resolveNext(int position, ClassSymbol sym, Ident bit) {
ClassSymbol next = Resolve.resolve(env, origin, sym, bit);
if (next == null) {
throw error(
@@ -233,7 +235,7 @@ public strictfp class ConstEvaluator {
}
FieldInfo resolveField(ConstVarName t) {
- String simpleName = t.name().get(0);
+ Ident simpleName = t.name().get(0);
FieldInfo field = lexicalField(env, owner, simpleName);
if (field != null) {
return field;
@@ -242,7 +244,7 @@ public strictfp class ConstEvaluator {
if (field != null) {
return field;
}
- ClassSymbol classSymbol = memberImports.singleMemberImport(simpleName);
+ ClassSymbol classSymbol = memberImports.singleMemberImport(simpleName.value());
if (classSymbol != null) {
field = Resolve.resolveField(env, origin, classSymbol, simpleName);
if (field != null) {
@@ -292,7 +294,7 @@ public strictfp class ConstEvaluator {
/** Search for constant variables in lexically enclosing scopes. */
private FieldInfo lexicalField(
- Env<ClassSymbol, TypeBoundClass> env, ClassSymbol sym, String name) {
+ Env<ClassSymbol, TypeBoundClass> env, ClassSymbol sym, Ident name) {
while (sym != null) {
TypeBoundClass info = env.get(sym);
FieldInfo field = Resolve.resolveField(env, origin, sym, name);
@@ -442,8 +444,9 @@ public strictfp class ConstEvaluator {
{
ClassTy classTy = (ClassTy) t.ty();
// TODO(cushon): check package?
- if (!classTy.name().equals("String")) {
- throw new AssertionError(classTy);
+ if (!classTy.name().value().equals("String")) {
+ // Explicit boxing cases (e.g. `(Boolean) false`) are legal, but not const exprs.
+ return null;
}
return expr.asString();
}
@@ -912,13 +915,13 @@ public strictfp class ConstEvaluator {
template.put(method.name(), method.returnType());
}
- ImmutableMap.Builder<String, Const> values = ImmutableMap.builder();
+ Map<String, Const> values = new LinkedHashMap<>();
for (Expression arg : info.args()) {
Expression expr;
String key;
if (arg.kind() == Tree.Kind.ASSIGN) {
Tree.Assign assign = (Tree.Assign) arg;
- key = assign.name();
+ key = assign.name().value();
expr = assign.expr();
} else {
// expand the implicit 'value' name; `@Foo(42)` is sugar for `@Foo(value=42)`
@@ -927,21 +930,27 @@ public strictfp class ConstEvaluator {
}
Type ty = template.get(key);
if (ty == null) {
- throw error(arg.position(), ErrorKind.CANNOT_RESOLVE, key);
+ throw error(
+ arg.position(),
+ ErrorKind.CANNOT_RESOLVE,
+ String.format("element %s() in %s", key, info.sym()));
}
Const value = evalAnnotationValue(expr, ty);
if (value == null) {
throw error(expr.position(), ErrorKind.EXPRESSION_ERROR);
}
- values.put(key, value);
+ Const existing = values.put(key, value);
+ if (existing != null) {
+ throw error(arg.position(), ErrorKind.INVALID_ANNOTATION_ARGUMENT);
+ }
}
- return info.withValues(values.build());
+ return info.withValues(ImmutableMap.copyOf(values));
}
private AnnotationValue evalAnno(Tree.Anno t) {
LookupResult result = scope.lookup(new LookupKey(t.name()));
ClassSymbol sym = (ClassSymbol) result.sym();
- for (String name : result.remaining()) {
+ for (Ident name : result.remaining()) {
sym = Resolve.resolve(env, sym, sym, name);
}
AnnoInfo annoInfo = evaluateAnnotation(new AnnoInfo(source, sym, t, null));
@@ -997,15 +1006,14 @@ public strictfp class ConstEvaluator {
}
public Const.Value evalFieldInitializer(Expression expression, Type type) {
- Const value;
try {
- value = eval(expression);
- } catch (TurbineError error) {
- return null;
- }
- if (value == null || value.kind() != Const.Kind.PRIMITIVE) {
+ Const value = eval(expression);
+ if (value == null || value.kind() != Const.Kind.PRIMITIVE) {
+ return null;
+ }
+ return (Const.Value) cast(type, value);
+ } catch (TurbineError | ConstCastError error) {
return null;
}
- return (Const.Value) cast(type, value);
}
}
diff --git a/java/com/google/turbine/binder/CtSymClassBinder.java b/java/com/google/turbine/binder/CtSymClassBinder.java
index 0d71b8d..fd2e544 100644
--- a/java/com/google/turbine/binder/CtSymClassBinder.java
+++ b/java/com/google/turbine/binder/CtSymClassBinder.java
@@ -20,6 +20,7 @@ import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableMap;
import com.google.turbine.binder.bound.ModuleInfo;
+import com.google.turbine.binder.bytecode.BytecodeBinder;
import com.google.turbine.binder.bytecode.BytecodeBoundClass;
import com.google.turbine.binder.env.Env;
import com.google.turbine.binder.env.SimpleEnv;
@@ -47,6 +48,7 @@ public class CtSymClassBinder {
throw new IllegalStateException("lib/ct.sym does not exist in " + javaHome);
}
Map<ClassSymbol, BytecodeBoundClass> map = new HashMap<>();
+ Map<ModuleSymbol, ModuleInfo> modules = new HashMap<>();
Env<ClassSymbol, BytecodeBoundClass> benv =
new Env<ClassSymbol, BytecodeBoundClass>() {
@Override
@@ -70,19 +72,21 @@ public class CtSymClassBinder {
if (!ze.name().substring(0, idx).contains(version)) {
continue;
}
- ClassSymbol sym = new ClassSymbol(name.substring(idx + 1, name.length() - ".sig".length()));
- if (!map.containsKey(sym)) {
- map.put(
- sym, new BytecodeBoundClass(sym, toByteArrayOrDie(ze), benv, ctSym + "!" + ze.name()));
+ if (name.substring(name.lastIndexOf('/') + 1).equals("module-info.sig")) {
+ ModuleInfo moduleInfo = BytecodeBinder.bindModuleInfo(name, toByteArrayOrDie(ze));
+ modules.put(new ModuleSymbol(moduleInfo.name()), moduleInfo);
+ continue;
}
+ ClassSymbol sym = new ClassSymbol(name.substring(idx + 1, name.length() - ".sig".length()));
+ map.putIfAbsent(
+ sym, new BytecodeBoundClass(sym, toByteArrayOrDie(ze), benv, ctSym + "!" + ze.name()));
}
if (map.isEmpty()) {
// we didn't find any classes for the desired release
return null;
}
SimpleEnv<ClassSymbol, BytecodeBoundClass> env = new SimpleEnv<>(ImmutableMap.copyOf(map));
- // TODO(cushon): support ct.sym module-infos once they exist (JDK 10?)
- Env<ModuleSymbol, ModuleInfo> moduleEnv = new SimpleEnv<>(ImmutableMap.of());
+ Env<ModuleSymbol, ModuleInfo> moduleEnv = new SimpleEnv<>(ImmutableMap.copyOf(modules));
TopLevelIndex index = SimpleTopLevelIndex.of(env.asMap().keySet());
return new ClassPath() {
@Override
diff --git a/java/com/google/turbine/binder/DisambiguateTypeAnnotations.java b/java/com/google/turbine/binder/DisambiguateTypeAnnotations.java
index 26dce32..9ad20d2 100644
--- a/java/com/google/turbine/binder/DisambiguateTypeAnnotations.java
+++ b/java/com/google/turbine/binder/DisambiguateTypeAnnotations.java
@@ -18,10 +18,10 @@ package com.google.turbine.binder;
import static com.google.common.collect.Iterables.getOnlyElement;
+import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;
import com.google.turbine.binder.bound.AnnotationValue;
import com.google.turbine.binder.bound.SourceTypeBoundClass;
@@ -34,6 +34,7 @@ import com.google.turbine.binder.sym.ClassSymbol;
import com.google.turbine.diag.TurbineError;
import com.google.turbine.diag.TurbineError.ErrorKind;
import com.google.turbine.model.Const;
+import com.google.turbine.model.TurbineElementType;
import com.google.turbine.type.AnnoInfo;
import com.google.turbine.type.Type;
import com.google.turbine.type.Type.ArrayTy;
@@ -41,7 +42,6 @@ import com.google.turbine.type.Type.ClassTy;
import com.google.turbine.type.Type.ClassTy.SimpleClassTy;
import com.google.turbine.type.Type.PrimTy;
import com.google.turbine.type.Type.TyVar;
-import java.lang.annotation.ElementType;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
@@ -84,7 +84,8 @@ public class DisambiguateTypeAnnotations {
base.memberImports(),
base.annotationMetadata(),
groupRepeated(env, base.annotations()),
- base.source());
+ base.source(),
+ base.decl());
}
private static ImmutableList<MethodInfo> bindMethods(
@@ -101,7 +102,9 @@ public class DisambiguateTypeAnnotations {
Type returnType =
disambiguate(
env,
- base.name().equals("<init>") ? ElementType.CONSTRUCTOR : ElementType.METHOD,
+ base.name().equals("<init>")
+ ? TurbineElementType.CONSTRUCTOR
+ : TurbineElementType.METHOD,
base.returnType(),
base.annotations(),
declarationAnnotations);
@@ -131,7 +134,11 @@ public class DisambiguateTypeAnnotations {
ImmutableList.Builder<AnnoInfo> declarationAnnotations = ImmutableList.builder();
Type type =
disambiguate(
- env, ElementType.PARAMETER, base.type(), base.annotations(), declarationAnnotations);
+ env,
+ TurbineElementType.PARAMETER,
+ base.type(),
+ base.annotations(),
+ declarationAnnotations);
return new ParamInfo(type, base.name(), declarationAnnotations.build(), base.access());
}
@@ -141,7 +148,7 @@ public class DisambiguateTypeAnnotations {
*/
private static Type disambiguate(
Env<ClassSymbol, TypeBoundClass> env,
- ElementType declarationTarget,
+ TurbineElementType declarationTarget,
Type type,
ImmutableList<AnnoInfo> annotations,
Builder<AnnoInfo> declarationAnnotations) {
@@ -150,8 +157,8 @@ public class DisambiguateTypeAnnotations {
annotations = groupRepeated(env, annotations);
ImmutableList.Builder<AnnoInfo> typeAnnotations = ImmutableList.builder();
for (AnnoInfo anno : annotations) {
- Set<ElementType> target = env.get(anno.sym()).annotationMetadata().target();
- if (target.contains(ElementType.TYPE_USE)) {
+ Set<TurbineElementType> target = env.get(anno.sym()).annotationMetadata().target();
+ if (target.contains(TurbineElementType.TYPE_USE)) {
typeAnnotations.add(anno);
}
if (target.contains(declarationTarget)) {
@@ -174,7 +181,7 @@ public class DisambiguateTypeAnnotations {
ImmutableList.Builder<AnnoInfo> declarationAnnotations = ImmutableList.builder();
Type type =
disambiguate(
- env, ElementType.FIELD, base.type(), base.annotations(), declarationAnnotations);
+ env, TurbineElementType.FIELD, base.type(), base.annotations(), declarationAnnotations);
return new FieldInfo(
base.sym(), type, base.access(), declarationAnnotations.build(), base.decl(), base.value());
}
@@ -193,23 +200,23 @@ public class DisambiguateTypeAnnotations {
switch (type.tyKind()) {
case PRIM_TY:
PrimTy primTy = (PrimTy) type;
- return new Type.PrimTy(primTy.primkind(), appendAnnotations(primTy.annos(), extra));
+ return Type.PrimTy.create(primTy.primkind(), appendAnnotations(primTy.annos(), extra));
case CLASS_TY:
ClassTy classTy = (ClassTy) type;
- SimpleClassTy base = classTy.classes.get(0);
+ SimpleClassTy base = classTy.classes().get(0);
SimpleClassTy simple =
- new SimpleClassTy(base.sym(), base.targs(), appendAnnotations(base.annos(), extra));
- return new Type.ClassTy(
+ SimpleClassTy.create(base.sym(), base.targs(), appendAnnotations(base.annos(), extra));
+ return Type.ClassTy.create(
ImmutableList.<SimpleClassTy>builder()
.add(simple)
- .addAll(classTy.classes.subList(1, classTy.classes.size()))
+ .addAll(classTy.classes().subList(1, classTy.classes().size()))
.build());
case ARRAY_TY:
ArrayTy arrayTy = (ArrayTy) type;
- return new ArrayTy(addAnnotationsToType(arrayTy.elementType(), extra), arrayTy.annos());
+ return ArrayTy.create(addAnnotationsToType(arrayTy.elementType(), extra), arrayTy.annos());
case TY_VAR:
TyVar tyVar = (TyVar) type;
- return new Type.TyVar(tyVar.sym(), appendAnnotations(tyVar.annos(), extra));
+ return Type.TyVar.create(tyVar.sym(), appendAnnotations(tyVar.annos(), extra));
case VOID_TY:
return type;
case WILD_TY:
@@ -230,12 +237,12 @@ public class DisambiguateTypeAnnotations {
* <p>For example, convert {@code @Foo @Foo} to {@code @Foos({@Foo, @Foo})}.
*
* <p>This method is used by {@link DisambiguateTypeAnnotations} for declaration annotations, and
- * by {@link Lower} for type annotations. We could group type annotations here, but it would
- * require another rewrite pass.
+ * by {@link com.google.turbine.lower.Lower} for type annotations. We could group type annotations
+ * here, but it would require another rewrite pass.
*/
public static ImmutableList<AnnoInfo> groupRepeated(
Env<ClassSymbol, TypeBoundClass> env, ImmutableList<AnnoInfo> annotations) {
- Multimap<ClassSymbol, AnnoInfo> repeated = LinkedHashMultimap.create();
+ Multimap<ClassSymbol, AnnoInfo> repeated = ArrayListMultimap.create();
for (AnnoInfo anno : annotations) {
repeated.put(anno.sym(), anno);
}
diff --git a/java/com/google/turbine/binder/HierarchyBinder.java b/java/com/google/turbine/binder/HierarchyBinder.java
index 2545c17..8549d3a 100644
--- a/java/com/google/turbine/binder/HierarchyBinder.java
+++ b/java/com/google/turbine/binder/HierarchyBinder.java
@@ -27,8 +27,8 @@ import com.google.turbine.binder.lookup.LookupKey;
import com.google.turbine.binder.lookup.LookupResult;
import com.google.turbine.binder.sym.ClassSymbol;
import com.google.turbine.binder.sym.TyVarSymbol;
-import com.google.turbine.diag.TurbineError;
import com.google.turbine.diag.TurbineError.ErrorKind;
+import com.google.turbine.diag.TurbineLog.TurbineLogWithSource;
import com.google.turbine.model.TurbineTyKind;
import com.google.turbine.tree.Tree;
import com.google.turbine.tree.Tree.ClassTy;
@@ -39,20 +39,24 @@ public class HierarchyBinder {
/** Binds the type hierarchy (superclasses and interfaces) for a single class. */
public static SourceHeaderBoundClass bind(
+ TurbineLogWithSource log,
ClassSymbol origin,
PackageSourceBoundClass base,
Env<ClassSymbol, ? extends HeaderBoundClass> env) {
- return new HierarchyBinder(origin, base, env).bind();
+ return new HierarchyBinder(log, origin, base, env).bind();
}
+ private final TurbineLogWithSource log;
private final ClassSymbol origin;
private final PackageSourceBoundClass base;
private final Env<ClassSymbol, ? extends HeaderBoundClass> env;
private HierarchyBinder(
+ TurbineLogWithSource log,
ClassSymbol origin,
PackageSourceBoundClass base,
Env<ClassSymbol, ? extends HeaderBoundClass> env) {
+ this.log = log;
this.origin = origin;
this.base = base;
this.env = env;
@@ -84,7 +88,7 @@ public class HierarchyBinder {
for (Tree.ClassTy i : decl.impls()) {
ClassSymbol result = resolveClass(i);
if (result == null) {
- throw new AssertionError(i);
+ continue;
}
interfaces.add(result);
}
@@ -96,13 +100,12 @@ public class HierarchyBinder {
ImmutableMap.Builder<String, TyVarSymbol> typeParameters = ImmutableMap.builder();
for (Tree.TyParam p : decl.typarams()) {
- typeParameters.put(p.name(), new TyVarSymbol(origin, p.name()));
+ typeParameters.put(p.name().value(), new TyVarSymbol(origin, p.name().value()));
}
return new SourceHeaderBoundClass(base, superclass, interfaces.build(), typeParameters.build());
}
-
/**
* Resolves the {@link ClassSymbol} for the given {@link Tree.ClassTy}, with handling for
* non-canonical qualified type names.
@@ -110,34 +113,41 @@ public class HierarchyBinder {
private ClassSymbol resolveClass(Tree.ClassTy ty) {
// flatten a left-recursive qualified type name to its component simple names
// e.g. Foo<Bar>.Baz -> ["Foo", "Bar"]
- ArrayDeque<String> flat = new ArrayDeque<>();
- for (Tree.ClassTy curr = ty; curr != null; curr = curr.base().orNull()) {
+ ArrayDeque<Tree.Ident> flat = new ArrayDeque<>();
+ for (Tree.ClassTy curr = ty; curr != null; curr = curr.base().orElse(null)) {
flat.addFirst(curr.name());
}
// Resolve the base symbol in the qualified name.
- LookupResult result = lookup(ty, new LookupKey(flat));
+ LookupResult result = lookup(ty, new LookupKey(ImmutableList.copyOf(flat)));
if (result == null) {
- throw TurbineError.format(base.source(), ty.position(), ErrorKind.CANNOT_RESOLVE, ty);
+ log.error(ty.position(), ErrorKind.CANNOT_RESOLVE, ty);
+ return null;
}
// Resolve pieces in the qualified name referring to member types.
// This needs to consider member type declarations inherited from supertypes and interfaces.
ClassSymbol sym = (ClassSymbol) result.sym();
- for (String bit : result.remaining()) {
+ for (Tree.Ident bit : result.remaining()) {
sym = resolveNext(ty, sym, bit);
+ if (sym == null) {
+ break;
+ }
}
return sym;
}
- private ClassSymbol resolveNext(ClassTy ty, ClassSymbol sym, String bit) {
+ private ClassSymbol resolveNext(ClassTy ty, ClassSymbol sym, Tree.Ident bit) {
ClassSymbol next;
try {
next = Resolve.resolve(env, origin, sym, bit);
} catch (LazyBindingError e) {
- throw error(ty.position(), ErrorKind.CYCLIC_HIERARCHY, e.getMessage());
+ log.error(ty.position(), ErrorKind.CYCLIC_HIERARCHY, e.getMessage());
+ return null;
}
if (next == null) {
- throw error(
- ty.position(), ErrorKind.SYMBOL_NOT_FOUND, new ClassSymbol(sym.binaryName() + '$' + bit));
+ log.error(
+ bit.position(),
+ ErrorKind.SYMBOL_NOT_FOUND,
+ new ClassSymbol(sym.binaryName() + '$' + bit));
}
return next;
}
@@ -152,7 +162,8 @@ public class HierarchyBinder {
try {
result = Resolve.resolve(env, origin, curr, lookup.first());
} catch (LazyBindingError e) {
- throw error(tree.position(), ErrorKind.CYCLIC_HIERARCHY, e.getMessage());
+ log.error(tree.position(), ErrorKind.CYCLIC_HIERARCHY, e.getMessage());
+ result = null;
}
if (result != null) {
return new LookupResult(result, lookup);
@@ -162,8 +173,4 @@ public class HierarchyBinder {
// qualified name resolution).
return base.scope().lookup(lookup, Resolve.resolveFunction(env, origin));
}
-
- private TurbineError error(int position, ErrorKind kind, Object... args) {
- return TurbineError.format(base.source(), position, kind, args);
- }
}
diff --git a/java/com/google/turbine/binder/JimageClassBinder.java b/java/com/google/turbine/binder/JimageClassBinder.java
index 40be3a3..72bcb2f 100644
--- a/java/com/google/turbine/binder/JimageClassBinder.java
+++ b/java/com/google/turbine/binder/JimageClassBinder.java
@@ -35,6 +35,7 @@ import com.google.turbine.binder.lookup.Scope;
import com.google.turbine.binder.lookup.TopLevelIndex;
import com.google.turbine.binder.sym.ClassSymbol;
import com.google.turbine.binder.sym.ModuleSymbol;
+import com.google.turbine.tree.Tree.Ident;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.URI;
@@ -112,12 +113,8 @@ public class JimageClassBinder {
if (path == null) {
return null;
}
- try {
- path = path.resolve("module-info.class");
- result = BytecodeBinder.bindModuleInfo(path.toString(), toByteArrayOrDie(path));
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
+ path = path.resolve("module-info.class");
+ result = BytecodeBinder.bindModuleInfo(path.toString(), toByteArrayOrDie(path));
moduleMap.put(moduleName, result);
}
return result;
@@ -197,10 +194,15 @@ public class JimageClassBinder {
// Find the longest prefix of the key that corresponds to a package name.
// TODO(cushon): SimpleTopLevelIndex uses a prefix map for this, does it matter?
Scope scope = null;
- ImmutableList<String> names = lookupKey.simpleNames();
+ ImmutableList<Ident> names = lookupKey.simpleNames();
+ ImmutableList.Builder<String> flatNamesBuilder = ImmutableList.builder();
+ for (Ident name : names) {
+ flatNamesBuilder.add(name.value());
+ }
+ ImmutableList<String> flatNames = flatNamesBuilder.build();
int idx = -1;
for (int i = 1; i < names.size(); i++) {
- Scope cand = lookupPackage(names.subList(0, i));
+ Scope cand = lookupPackage(flatNames.subList(0, i));
if (cand != null) {
scope = cand;
idx = i;
@@ -227,7 +229,7 @@ public class JimageClassBinder {
@Nullable
@Override
public LookupResult lookup(LookupKey lookupKey) {
- ClassSymbol sym = packageClassesBySimpleName.get(packageName, lookupKey.first());
+ ClassSymbol sym = packageClassesBySimpleName.get(packageName, lookupKey.first().value());
return sym != null ? new LookupResult(sym, lookupKey) : null;
}
};
diff --git a/java/com/google/turbine/binder/ModuleBinder.java b/java/com/google/turbine/binder/ModuleBinder.java
index 312ec45..afd8770 100644
--- a/java/com/google/turbine/binder/ModuleBinder.java
+++ b/java/com/google/turbine/binder/ModuleBinder.java
@@ -19,7 +19,6 @@ package com.google.turbine.binder;
import static com.google.common.base.Verify.verifyNotNull;
import com.google.common.base.Joiner;
-import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.turbine.binder.bound.ModuleInfo;
@@ -43,6 +42,7 @@ import com.google.turbine.diag.TurbineError;
import com.google.turbine.diag.TurbineError.ErrorKind;
import com.google.turbine.model.TurbineFlag;
import com.google.turbine.tree.Tree;
+import com.google.turbine.tree.Tree.Ident;
import com.google.turbine.tree.Tree.ModDirective;
import com.google.turbine.tree.Tree.ModExports;
import com.google.turbine.tree.Tree.ModOpens;
@@ -51,6 +51,7 @@ import com.google.turbine.tree.Tree.ModRequires;
import com.google.turbine.tree.Tree.ModUses;
import com.google.turbine.tree.TurbineModifier;
import com.google.turbine.type.AnnoInfo;
+import java.util.Optional;
/** Binding pass for modules. */
public class ModuleBinder {
@@ -149,7 +150,7 @@ public class ModuleBinder {
return new SourceModuleInfo(
module.module().moduleName(),
- moduleVersion.orNull(),
+ moduleVersion.orElse(null),
flags,
annos,
requires.build(),
@@ -195,14 +196,14 @@ public class ModuleBinder {
private ProvideInfo bindProvides(ModProvides directive) {
ClassSymbol sym = resolve(directive.position(), directive.typeName());
ImmutableList.Builder<ClassSymbol> impls = ImmutableList.builder();
- for (ImmutableList<String> impl : directive.implNames()) {
+ for (ImmutableList<Ident> impl : directive.implNames()) {
impls.add(resolve(directive.position(), impl));
}
return new ProvideInfo(sym, impls.build());
}
/* Resolves qualified class names. */
- private ClassSymbol resolve(int pos, ImmutableList<String> simpleNames) {
+ private ClassSymbol resolve(int pos, ImmutableList<Tree.Ident> simpleNames) {
LookupKey key = new LookupKey(simpleNames);
LookupResult result = scope.lookup(key);
if (result == null) {
@@ -210,7 +211,7 @@ public class ModuleBinder {
ErrorKind.SYMBOL_NOT_FOUND, pos, new ClassSymbol(Joiner.on('/').join(simpleNames)));
}
ClassSymbol sym = (ClassSymbol) result.sym();
- for (String name : result.remaining()) {
+ for (Tree.Ident name : result.remaining()) {
sym = Resolve.resolve(env, /* origin= */ null, sym, name);
if (sym == null) {
throw error(
diff --git a/java/com/google/turbine/binder/Resolve.java b/java/com/google/turbine/binder/Resolve.java
index d722373..0a61844 100644
--- a/java/com/google/turbine/binder/Resolve.java
+++ b/java/com/google/turbine/binder/Resolve.java
@@ -16,8 +16,6 @@
package com.google.turbine.binder;
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableList;
import com.google.turbine.binder.bound.BoundClass;
import com.google.turbine.binder.bound.HeaderBoundClass;
import com.google.turbine.binder.bound.TypeBoundClass;
@@ -29,7 +27,10 @@ import com.google.turbine.binder.lookup.CanonicalSymbolResolver;
import com.google.turbine.binder.lookup.ImportScope.ResolveFunction;
import com.google.turbine.binder.sym.ClassSymbol;
import com.google.turbine.model.TurbineVisibility;
+import com.google.turbine.tree.Tree;
+import java.util.HashSet;
import java.util.Objects;
+import java.util.Set;
/** Qualified name resolution. */
public class Resolve {
@@ -43,24 +44,37 @@ public class Resolve {
Env<ClassSymbol, ? extends HeaderBoundClass> env,
ClassSymbol origin,
ClassSymbol sym,
- String simpleName) {
+ Tree.Ident simpleName) {
+ return resolve(env, origin, sym, simpleName, new HashSet<>());
+ }
+
+ private static ClassSymbol resolve(
+ Env<ClassSymbol, ? extends HeaderBoundClass> env,
+ ClassSymbol origin,
+ ClassSymbol sym,
+ Tree.Ident simpleName,
+ Set<ClassSymbol> seen) {
ClassSymbol result;
+ if (!seen.add(sym)) {
+ // Optimize multiple-interface-inheritance, and don't get stuck in cycles.
+ return null;
+ }
HeaderBoundClass bound = env.get(sym);
if (bound == null) {
return null;
}
- result = bound.children().get(simpleName);
+ result = bound.children().get(simpleName.value());
if (result != null) {
return result;
}
if (bound.superclass() != null) {
- result = resolve(env, origin, bound.superclass(), simpleName);
+ result = resolve(env, origin, bound.superclass(), simpleName, seen);
if (result != null && visible(origin, result, env.get(result))) {
return result;
}
}
for (ClassSymbol i : bound.interfaces()) {
- result = resolve(env, origin, i, simpleName);
+ result = resolve(env, origin, i, simpleName, seen);
if (result != null && visible(origin, result, env.get(result))) {
return result;
}
@@ -76,7 +90,7 @@ public class Resolve {
Env<ClassSymbol, ? extends HeaderBoundClass> env, ClassSymbol origin) {
return new ResolveFunction() {
@Override
- public ClassSymbol resolveOne(ClassSymbol base, String name) {
+ public ClassSymbol resolveOne(ClassSymbol base, Tree.Ident name) {
try {
return Resolve.resolve(env, origin, base, name);
} catch (LazyBindingError e) {
@@ -93,19 +107,18 @@ public class Resolve {
private final String packagename;
private final CompoundEnv<ClassSymbol, BoundClass> env;
- public CanonicalResolver(
- ImmutableList<String> packagename, CompoundEnv<ClassSymbol, BoundClass> env) {
- this.packagename = Joiner.on('/').join(packagename);
+ public CanonicalResolver(String packagename, CompoundEnv<ClassSymbol, BoundClass> env) {
+ this.packagename = packagename;
this.env = env;
}
@Override
- public ClassSymbol resolveOne(ClassSymbol sym, String bit) {
+ public ClassSymbol resolveOne(ClassSymbol sym, Tree.Ident bit) {
BoundClass ci = env.get(sym);
if (ci == null) {
return null;
}
- sym = ci.children().get(bit);
+ sym = ci.children().get(bit.value());
if (sym == null) {
return null;
}
@@ -138,24 +151,37 @@ public class Resolve {
* superclasses or interfaces.
*/
public static FieldInfo resolveField(
- Env<ClassSymbol, TypeBoundClass> env, ClassSymbol origin, ClassSymbol sym, String name) {
+ Env<ClassSymbol, TypeBoundClass> env, ClassSymbol origin, ClassSymbol sym, Tree.Ident name) {
+ return resolveField(env, origin, sym, name, new HashSet<>());
+ }
+
+ private static FieldInfo resolveField(
+ Env<ClassSymbol, TypeBoundClass> env,
+ ClassSymbol origin,
+ ClassSymbol sym,
+ Tree.Ident name,
+ Set<ClassSymbol> seen) {
+ if (!seen.add(sym)) {
+ // Optimize multiple-interface-inheritance, and don't get stuck in cycles.
+ return null;
+ }
TypeBoundClass info = env.get(sym);
if (info == null) {
return null;
}
for (FieldInfo f : info.fields()) {
- if (f.name().equals(name)) {
+ if (f.name().equals(name.value())) {
return f;
}
}
if (info.superclass() != null) {
- FieldInfo field = resolveField(env, origin, info.superclass(), name);
+ FieldInfo field = resolveField(env, origin, info.superclass(), name, seen);
if (field != null && visible(origin, field)) {
return field;
}
}
for (ClassSymbol i : info.interfaces()) {
- FieldInfo field = resolveField(env, origin, i, name);
+ FieldInfo field = resolveField(env, origin, i, name, seen);
if (field != null && visible(origin, field)) {
return field;
}
diff --git a/java/com/google/turbine/binder/TypeBinder.java b/java/com/google/turbine/binder/TypeBinder.java
index e0546ac..8cf71e1 100644
--- a/java/com/google/turbine/binder/TypeBinder.java
+++ b/java/com/google/turbine/binder/TypeBinder.java
@@ -36,20 +36,23 @@ import com.google.turbine.binder.sym.FieldSymbol;
import com.google.turbine.binder.sym.MethodSymbol;
import com.google.turbine.binder.sym.Symbol;
import com.google.turbine.binder.sym.TyVarSymbol;
-import com.google.turbine.diag.TurbineError;
import com.google.turbine.diag.TurbineError.ErrorKind;
+import com.google.turbine.diag.TurbineLog.TurbineLogWithSource;
import com.google.turbine.model.TurbineConstantTypeKind;
import com.google.turbine.model.TurbineFlag;
import com.google.turbine.model.TurbineTyKind;
import com.google.turbine.model.TurbineVisibility;
import com.google.turbine.tree.Tree;
+import com.google.turbine.tree.Tree.Anno;
import com.google.turbine.tree.Tree.ClassTy;
+import com.google.turbine.tree.Tree.Ident;
import com.google.turbine.tree.Tree.Kind;
import com.google.turbine.tree.Tree.MethDecl;
import com.google.turbine.tree.Tree.PrimTy;
import com.google.turbine.tree.TurbineModifier;
import com.google.turbine.type.AnnoInfo;
import com.google.turbine.type.Type;
+import com.google.turbine.type.Type.IntersectionTy;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashSet;
@@ -73,7 +76,7 @@ public class TypeBinder {
@Override
public LookupResult lookup(LookupKey lookup) {
- if (name.equals(lookup.first())) {
+ if (name.equals(lookup.first().value())) {
return new LookupResult(sym, lookup);
}
return null;
@@ -90,9 +93,8 @@ public class TypeBinder {
@Override
public LookupResult lookup(LookupKey lookupKey) {
- return tps.containsKey(lookupKey.first())
- ? new LookupResult(tps.get(lookupKey.first()), lookupKey)
- : null;
+ Symbol sym = tps.get(lookupKey.first().value());
+ return sym != null ? new LookupResult(sym, lookupKey) : null;
}
}
@@ -118,7 +120,7 @@ public class TypeBinder {
if (result != null) {
return new LookupResult(result, lookup);
}
- result = info.typeParameters().get(lookup.first());
+ result = info.typeParameters().get(lookup.first().value());
if (result != null) {
return new LookupResult(result, lookup);
}
@@ -130,16 +132,24 @@ public class TypeBinder {
/** Creates {@link SourceTypeBoundClass} nodes for a compilation. */
public static SourceTypeBoundClass bind(
- Env<ClassSymbol, HeaderBoundClass> env, ClassSymbol sym, SourceHeaderBoundClass base) {
- return new TypeBinder(env, sym, base).bind();
+ TurbineLogWithSource log,
+ Env<ClassSymbol, HeaderBoundClass> env,
+ ClassSymbol sym,
+ SourceHeaderBoundClass base) {
+ return new TypeBinder(log, env, sym, base).bind();
}
+ private final TurbineLogWithSource log;
private final Env<ClassSymbol, HeaderBoundClass> env;
private final ClassSymbol owner;
private final SourceHeaderBoundClass base;
private TypeBinder(
- Env<ClassSymbol, HeaderBoundClass> env, ClassSymbol owner, SourceHeaderBoundClass base) {
+ TurbineLogWithSource log,
+ Env<ClassSymbol, HeaderBoundClass> env,
+ ClassSymbol owner,
+ SourceHeaderBoundClass base) {
+ this.log = log;
this.env = env;
this.owner = owner;
this.base = base;
@@ -154,7 +164,7 @@ public class TypeBinder {
CompoundScope enclosingScope =
base.scope()
.toScope(Resolve.resolveFunction(env, owner))
- .append(new SingletonScope(base.decl().name(), owner))
+ .append(new SingletonScope(base.decl().name().value(), owner))
.append(new ClassMemberScope(base.owner(), env));
ImmutableList<AnnoInfo> annotations = bindAnnotations(enclosingScope, base.decl().annos());
@@ -166,14 +176,14 @@ public class TypeBinder {
final ImmutableMap<TyVarSymbol, TyVarInfo> typeParameterTypes =
bindTyParams(base.decl().typarams(), bindingScope, base.typeParameters());
- ImmutableList.Builder<Type.ClassTy> interfaceTypes = ImmutableList.builder();
- Type.ClassTy superClassType;
+ ImmutableList.Builder<Type> interfaceTypes = ImmutableList.builder();
+ Type superClassType;
switch (base.kind()) {
case ENUM:
superClassType =
- new Type.ClassTy(
+ Type.ClassTy.create(
ImmutableList.of(
- new Type.ClassTy.SimpleClassTy(
+ Type.ClassTy.SimpleClassTy.create(
ClassSymbol.ENUM,
ImmutableList.of(Type.ClassTy.asNonParametricClassTy(owner)),
ImmutableList.of())));
@@ -184,7 +194,7 @@ public class TypeBinder {
break;
case CLASS:
if (base.decl().xtnds().isPresent()) {
- superClassType = (Type.ClassTy) bindClassTy(bindingScope, base.decl().xtnds().get());
+ superClassType = bindClassTy(bindingScope, base.decl().xtnds().get());
} else if (owner.equals(ClassSymbol.OBJECT)) {
// java.lang.Object doesn't have a superclass
superClassType = null;
@@ -203,13 +213,13 @@ public class TypeBinder {
}
for (Tree.ClassTy i : base.decl().impls()) {
- interfaceTypes.add((Type.ClassTy) bindClassTy(bindingScope, i));
+ interfaceTypes.add(bindClassTy(bindingScope, i));
}
CompoundScope scope =
base.scope()
.toScope(Resolve.resolveFunction(env, owner))
- .append(new SingletonScope(base.decl().name(), owner))
+ .append(new SingletonScope(base.decl().name().value(), owner))
.append(new ClassMemberScope(owner, env));
List<MethodInfo> methods =
@@ -236,7 +246,8 @@ public class TypeBinder {
base.memberImports(),
/* annotation metadata */ null,
annotations,
- base.source());
+ base.source(),
+ base.decl());
}
/** Collect synthetic and implicit methods, including default constructors and enum methods. */
@@ -315,7 +326,7 @@ public class TypeBinder {
/*synthetic*/
TurbineFlag.ACC_SYNTHETIC),
new ParamInfo(
- new Type.PrimTy(TurbineConstantTypeKind.INT, ImmutableList.of()),
+ Type.PrimTy.create(TurbineConstantTypeKind.INT, ImmutableList.of()),
"$enum$ordinal",
ImmutableList.of(),
/*synthetic*/
@@ -332,7 +343,7 @@ public class TypeBinder {
new MethodInfo(
new MethodSymbol(owner, "values"),
ImmutableMap.of(),
- new Type.ArrayTy(Type.ClassTy.asNonParametricClassTy(owner), ImmutableList.of()),
+ Type.ArrayTy.create(Type.ClassTy.asNonParametricClassTy(owner), ImmutableList.of()),
ImmutableList.of(),
ImmutableList.of(),
access | TurbineFlag.ACC_PUBLIC | TurbineFlag.ACC_STATIC,
@@ -362,7 +373,7 @@ public class TypeBinder {
if (m.kind() != Kind.METH_DECL) {
continue;
}
- if (((MethDecl) m).name().equals("<init>")) {
+ if (((MethDecl) m).name().value().equals("<init>")) {
return true;
}
}
@@ -374,33 +385,21 @@ public class TypeBinder {
ImmutableList<Tree.TyParam> trees, CompoundScope scope, Map<String, TyVarSymbol> symbols) {
ImmutableMap.Builder<TyVarSymbol, TyVarInfo> result = ImmutableMap.builder();
for (Tree.TyParam tree : trees) {
- TyVarSymbol sym = symbols.get(tree.name());
- Type classBound = null;
- ImmutableList.Builder<Type> interfaceBounds = ImmutableList.builder();
- boolean first = true;
- for (Tree bound : tree.bounds()) {
- Type ty = bindTy(scope, bound);
- if (first && !isInterface(ty)) {
- classBound = ty;
- } else {
- interfaceBounds.add(ty);
+ TyVarSymbol sym = symbols.get(tree.name().value());
+ ImmutableList.Builder<Type> bounds = ImmutableList.builder();
+ if (tree.bounds().isEmpty()) {
+ bounds.add(Type.ClassTy.OBJECT);
+ } else {
+ for (Tree bound : tree.bounds()) {
+ bounds.add(bindTy(scope, bound));
}
- first = false;
}
ImmutableList<AnnoInfo> annotations = bindAnnotations(scope, tree.annos());
- result.put(sym, new TyVarInfo(classBound, interfaceBounds.build(), annotations));
+ result.put(sym, new TyVarInfo(IntersectionTy.create(bounds.build()), annotations));
}
return result.build();
}
- private boolean isInterface(Type ty) {
- if (ty.tyKind() != Type.TyKind.CLASS_TY) {
- return false;
- }
- HeaderBoundClass hi = env.get(((Type.ClassTy) ty).sym());
- return hi.kind() == TurbineTyKind.INTERFACE;
- }
-
private List<MethodInfo> bindMethods(CompoundScope scope, ImmutableList<Tree> members) {
List<MethodInfo> methods = new ArrayList<>();
for (Tree member : members) {
@@ -413,13 +412,13 @@ public class TypeBinder {
private MethodInfo bindMethod(CompoundScope scope, Tree.MethDecl t) {
- MethodSymbol sym = new MethodSymbol(owner, t.name());
+ MethodSymbol sym = new MethodSymbol(owner, t.name().value());
ImmutableMap<String, TyVarSymbol> typeParameters;
{
ImmutableMap.Builder<String, TyVarSymbol> builder = ImmutableMap.builder();
for (Tree.TyParam pt : t.typarams()) {
- builder.put(pt.name(), new TyVarSymbol(owner, pt.name()));
+ builder.put(pt.name().value(), new TyVarSymbol(owner, pt.name().value()));
}
typeParameters = builder.build();
}
@@ -437,7 +436,7 @@ public class TypeBinder {
}
ImmutableList.Builder<ParamInfo> parameters = ImmutableList.builder();
- String name = t.name();
+ String name = t.name().value();
if (name.equals("<init>")) {
if (hasEnclosingInstance(base)) {
parameters.add(enclosingInstanceParameter());
@@ -454,10 +453,10 @@ public class TypeBinder {
ParamInfo param =
new ParamInfo(
bindTy(scope, p.ty()),
- p.name(),
+ p.name().value(),
bindAnnotations(scope, p.annos()), /*synthetic*/
access);
- if (p.name().equals("this")) {
+ if (p.name().value().equals("this")) {
receiver = param;
continue;
}
@@ -527,7 +526,8 @@ public class TypeBinder {
if (member.kind() == Tree.Kind.VAR_DECL) {
FieldInfo field = bindField(scope, (Tree.VarDecl) member);
if (!seen.add(field.sym())) {
- throw error(member.position(), ErrorKind.DUPLICATE_DECLARATION, "field: " + field.name());
+ log.error(member.position(), ErrorKind.DUPLICATE_DECLARATION, "field: " + field.name());
+ continue;
}
fields.add(field);
}
@@ -536,7 +536,7 @@ public class TypeBinder {
}
private FieldInfo bindField(CompoundScope scope, Tree.VarDecl decl) {
- FieldSymbol sym = new FieldSymbol(owner, decl.name());
+ FieldSymbol sym = new FieldSymbol(owner, decl.name().value());
Type type = bindTy(scope, decl.ty());
ImmutableList<AnnoInfo> annotations = bindAnnotations(scope, decl.annos());
int access = 0;
@@ -558,27 +558,40 @@ public class TypeBinder {
CompoundScope scope, ImmutableList<Tree.Anno> trees) {
ImmutableList.Builder<AnnoInfo> result = ImmutableList.builder();
for (Tree.Anno tree : trees) {
- LookupResult lookupResult = scope.lookup(new LookupKey(tree.name()));
- if (lookupResult == null) {
- throw error(tree.position(), ErrorKind.CANNOT_RESOLVE, Joiner.on('.').join(tree.name()));
- }
- ClassSymbol sym = (ClassSymbol) lookupResult.sym();
- for (String name : lookupResult.remaining()) {
- sym = resolveNext(tree.position(), sym, name);
- }
- if (env.get(sym).kind() != TurbineTyKind.ANNOTATION) {
- throw error(tree.position(), ErrorKind.NOT_AN_ANNOTATION, sym);
- }
+ ImmutableList<Ident> name = tree.name();
+ LookupResult lookupResult = scope.lookup(new LookupKey(name));
+ ClassSymbol sym = resolveAnnoSymbol(tree, name, lookupResult);
result.add(new AnnoInfo(base.source(), sym, tree, null));
}
return result.build();
}
- private ClassSymbol resolveNext(int position, ClassSymbol sym, String bit) {
+ private ClassSymbol resolveAnnoSymbol(
+ Anno tree, ImmutableList<Ident> name, LookupResult lookupResult) {
+ if (lookupResult == null) {
+ log.error(tree.position(), ErrorKind.CANNOT_RESOLVE, Joiner.on('.').join(name));
+ return null;
+ }
+ ClassSymbol sym = (ClassSymbol) lookupResult.sym();
+ for (Ident ident : lookupResult.remaining()) {
+ sym = resolveNext(sym, ident);
+ if (sym == null) {
+ return null;
+ }
+ }
+ if (env.get(sym).kind() != TurbineTyKind.ANNOTATION) {
+ log.error(tree.position(), ErrorKind.NOT_AN_ANNOTATION, sym);
+ }
+ return sym;
+ }
+
+ private ClassSymbol resolveNext(ClassSymbol sym, Ident bit) {
ClassSymbol next = Resolve.resolve(env, owner, sym, bit);
if (next == null) {
- throw error(
- position, ErrorKind.SYMBOL_NOT_FOUND, new ClassSymbol(sym.binaryName() + '$' + bit));
+ log.error(
+ bit.position(),
+ ErrorKind.SYMBOL_NOT_FOUND,
+ new ClassSymbol(sym.binaryName() + '$' + bit));
}
return next;
}
@@ -620,20 +633,22 @@ public class TypeBinder {
ArrayList<Tree.ClassTy> flat;
{
ArrayDeque<Tree.ClassTy> builder = new ArrayDeque<>();
- for (Tree.ClassTy curr = t; curr != null; curr = curr.base().orNull()) {
+ for (Tree.ClassTy curr = t; curr != null; curr = curr.base().orElse(null)) {
builder.addFirst(curr);
}
flat = new ArrayList<>(builder);
}
// the simple names of all classes in the qualified name
- ArrayList<String> names = new ArrayList<>();
+ ImmutableList.Builder<Tree.Ident> nameBuilder = ImmutableList.builder();
for (Tree.ClassTy curr : flat) {
- names.add(curr.name());
+ nameBuilder.add(curr.name());
}
+ ImmutableList<Tree.Ident> names = nameBuilder.build();
// resolve the prefix to a symbol
LookupResult result = scope.lookup(new LookupKey(names));
if (result == null || result.sym() == null) {
- throw error(t.position(), ErrorKind.CANNOT_RESOLVE, t);
+ log.error(names.get(0).position(), ErrorKind.CANNOT_RESOLVE, Joiner.on('.').join(names));
+ return Type.ErrorTy.create();
}
Symbol sym = result.sym();
int annoIdx = flat.size() - result.remaining().size() - 1;
@@ -644,9 +659,10 @@ public class TypeBinder {
return bindClassTyRest(scope, flat, names, result, (ClassSymbol) sym, annos);
case TY_PARAM:
if (!result.remaining().isEmpty()) {
- throw error(t.position(), ErrorKind.TYPE_PARAMETER_QUALIFIER);
+ log.error(t.position(), ErrorKind.TYPE_PARAMETER_QUALIFIER);
+ return Type.ErrorTy.create();
}
- return new Type.TyVar((TyVarSymbol) sym, annos);
+ return Type.TyVar.create((TyVarSymbol) sym, annos);
default:
throw new AssertionError(sym.symKind());
}
@@ -655,46 +671,45 @@ public class TypeBinder {
private Type bindClassTyRest(
CompoundScope scope,
ArrayList<ClassTy> flat,
- ArrayList<String> bits,
+ ImmutableList<Tree.Ident> bits,
LookupResult result,
ClassSymbol sym,
ImmutableList<AnnoInfo> annotations) {
int idx = bits.size() - result.remaining().size() - 1;
ImmutableList.Builder<Type.ClassTy.SimpleClassTy> classes = ImmutableList.builder();
classes.add(
- new Type.ClassTy.SimpleClassTy(
+ Type.ClassTy.SimpleClassTy.create(
sym, bindTyArgs(scope, flat.get(idx++).tyargs()), annotations));
for (; idx < flat.size(); idx++) {
Tree.ClassTy curr = flat.get(idx);
- sym = resolveNext(curr.position(), sym, curr.name());
+ sym = resolveNext(sym, curr.name());
+ if (sym == null) {
+ return Type.ErrorTy.create();
+ }
annotations = bindAnnotations(scope, curr.annos());
classes.add(
- new Type.ClassTy.SimpleClassTy(sym, bindTyArgs(scope, curr.tyargs()), annotations));
+ Type.ClassTy.SimpleClassTy.create(sym, bindTyArgs(scope, curr.tyargs()), annotations));
}
- return new Type.ClassTy(classes.build());
+ return Type.ClassTy.create(classes.build());
}
private Type.PrimTy bindPrimTy(CompoundScope scope, PrimTy t) {
- return new Type.PrimTy(t.tykind(), bindAnnotations(scope, t.annos()));
+ return Type.PrimTy.create(t.tykind(), bindAnnotations(scope, t.annos()));
}
private Type bindArrTy(CompoundScope scope, Tree.ArrTy t) {
- return new Type.ArrayTy(bindTy(scope, t.elem()), bindAnnotations(scope, t.annos()));
+ return Type.ArrayTy.create(bindTy(scope, t.elem()), bindAnnotations(scope, t.annos()));
}
private Type bindWildTy(CompoundScope scope, Tree.WildTy t) {
ImmutableList<AnnoInfo> annotations = bindAnnotations(scope, t.annos());
if (t.lower().isPresent()) {
- return new Type.WildLowerBoundedTy(bindTy(scope, t.lower().get()), annotations);
+ return Type.WildLowerBoundedTy.create(bindTy(scope, t.lower().get()), annotations);
} else if (t.upper().isPresent()) {
- return new Type.WildUpperBoundedTy(bindTy(scope, t.upper().get()), annotations);
+ return Type.WildUpperBoundedTy.create(bindTy(scope, t.upper().get()), annotations);
} else {
- return new Type.WildUnboundedTy(annotations);
+ return Type.WildUnboundedTy.create(annotations);
}
}
-
- private TurbineError error(int position, ErrorKind kind, Object... args) {
- return TurbineError.format(base.source(), position, kind, args);
- }
}
diff --git a/java/com/google/turbine/binder/bound/AnnotationMetadata.java b/java/com/google/turbine/binder/bound/AnnotationMetadata.java
index 1155e51..9c81a5f 100644
--- a/java/com/google/turbine/binder/bound/AnnotationMetadata.java
+++ b/java/com/google/turbine/binder/bound/AnnotationMetadata.java
@@ -20,7 +20,7 @@ import static com.google.common.base.MoreObjects.firstNonNull;
import com.google.common.collect.ImmutableSet;
import com.google.turbine.binder.sym.ClassSymbol;
-import java.lang.annotation.ElementType;
+import com.google.turbine.model.TurbineElementType;
import java.lang.annotation.RetentionPolicy;
import java.util.EnumSet;
@@ -30,22 +30,22 @@ import java.util.EnumSet;
*/
public class AnnotationMetadata {
- private static final ImmutableSet<ElementType> DEFAULT_TARGETS = getDefaultElements();
+ private static final ImmutableSet<TurbineElementType> DEFAULT_TARGETS = getDefaultElements();
- private static ImmutableSet<ElementType> getDefaultElements() {
- EnumSet<ElementType> values = EnumSet.allOf(ElementType.class);
- values.remove(ElementType.TYPE_PARAMETER);
- values.remove(ElementType.TYPE_USE);
+ private static ImmutableSet<TurbineElementType> getDefaultElements() {
+ EnumSet<TurbineElementType> values = EnumSet.allOf(TurbineElementType.class);
+ values.remove(TurbineElementType.TYPE_PARAMETER);
+ values.remove(TurbineElementType.TYPE_USE);
return ImmutableSet.copyOf(values);
}
private final RetentionPolicy retention;
- private final ImmutableSet<ElementType> target;
+ private final ImmutableSet<TurbineElementType> target;
private final ClassSymbol repeatable;
public AnnotationMetadata(
RetentionPolicy retention,
- ImmutableSet<ElementType> annotationTarget,
+ ImmutableSet<TurbineElementType> annotationTarget,
ClassSymbol repeatable) {
this.retention = firstNonNull(retention, RetentionPolicy.CLASS);
this.target = firstNonNull(annotationTarget, DEFAULT_TARGETS);
@@ -58,7 +58,7 @@ public class AnnotationMetadata {
}
/** Target element types specified by the {@code @Target} meta-annotation. */
- public ImmutableSet<ElementType> target() {
+ public ImmutableSet<TurbineElementType> target() {
return target;
}
diff --git a/java/com/google/turbine/binder/bound/AnnotationValue.java b/java/com/google/turbine/binder/bound/AnnotationValue.java
index 729a20f..fd4ffab 100644
--- a/java/com/google/turbine/binder/bound/AnnotationValue.java
+++ b/java/com/google/turbine/binder/bound/AnnotationValue.java
@@ -19,6 +19,7 @@ package com.google.turbine.binder.bound;
import com.google.common.collect.ImmutableMap;
import com.google.turbine.binder.sym.ClassSymbol;
import com.google.turbine.model.Const;
+import java.util.Objects;
/** An annotation literal constant. */
public class AnnotationValue extends Const {
@@ -50,4 +51,18 @@ public class AnnotationValue extends Const {
public ImmutableMap<String, Const> values() {
return values;
}
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(sym, values);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof AnnotationValue)) {
+ return false;
+ }
+ AnnotationValue that = (AnnotationValue) obj;
+ return sym().equals(that.sym()) && values().equals(that.values());
+ }
}
diff --git a/java/com/google/turbine/binder/bound/ClassValue.java b/java/com/google/turbine/binder/bound/ClassValue.java
index e06fc8d..a75db42 100644
--- a/java/com/google/turbine/binder/bound/ClassValue.java
+++ b/java/com/google/turbine/binder/bound/ClassValue.java
@@ -18,6 +18,7 @@ package com.google.turbine.binder.bound;
import com.google.turbine.model.Const;
import com.google.turbine.type.Type;
+import java.util.Objects;
/** A class literal constant. */
public class ClassValue extends Const {
@@ -42,4 +43,14 @@ public class ClassValue extends Const {
public Type type() {
return type;
}
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(type);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof ClassValue && type().equals(((ClassValue) obj).type());
+ }
}
diff --git a/java/com/google/turbine/binder/bound/EnumConstantValue.java b/java/com/google/turbine/binder/bound/EnumConstantValue.java
index 07bb29c..4083ae3 100644
--- a/java/com/google/turbine/binder/bound/EnumConstantValue.java
+++ b/java/com/google/turbine/binder/bound/EnumConstantValue.java
@@ -36,4 +36,14 @@ public class EnumConstantValue extends Const {
public Kind kind() {
return Kind.ENUM_CONSTANT;
}
+
+ @Override
+ public int hashCode() {
+ return sym.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof EnumConstantValue && sym().equals(((EnumConstantValue) obj).sym());
+ }
}
diff --git a/java/com/google/turbine/binder/bound/SourceTypeBoundClass.java b/java/com/google/turbine/binder/bound/SourceTypeBoundClass.java
index 73f2832..7314f72 100644
--- a/java/com/google/turbine/binder/bound/SourceTypeBoundClass.java
+++ b/java/com/google/turbine/binder/bound/SourceTypeBoundClass.java
@@ -16,19 +16,19 @@
package com.google.turbine.binder.bound;
-import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
import com.google.turbine.binder.lookup.CompoundScope;
import com.google.turbine.binder.lookup.MemberImportIndex;
import com.google.turbine.binder.sym.ClassSymbol;
import com.google.turbine.binder.sym.TyVarSymbol;
import com.google.turbine.diag.SourceFile;
import com.google.turbine.model.TurbineTyKind;
+import com.google.turbine.tree.Tree;
import com.google.turbine.type.AnnoInfo;
import com.google.turbine.type.Type;
import com.google.turbine.type.Type.ClassTy;
+import com.google.turbine.type.Type.TyKind;
import javax.annotation.Nullable;
/** A HeaderBoundClass for classes compiled from source. */
@@ -42,8 +42,8 @@ public class SourceTypeBoundClass implements TypeBoundClass {
private final ImmutableMap<String, TyVarSymbol> typeParameters;
private final ImmutableMap<TyVarSymbol, TyVarInfo> typeParameterTypes;
- private final Type.ClassTy superClassType;
- private final ImmutableList<Type.ClassTy> interfaceTypes;
+ private final Type superClassType;
+ private final ImmutableList<Type> interfaceTypes;
private final ImmutableList<MethodInfo> methods;
private final ImmutableList<FieldInfo> fields;
private final CompoundScope enclosingScope;
@@ -51,11 +51,12 @@ public class SourceTypeBoundClass implements TypeBoundClass {
private final MemberImportIndex memberImports;
private final AnnotationMetadata annotationMetadata;
private final ImmutableList<AnnoInfo> annotations;
+ private final Tree.TyDecl decl;
private final SourceFile source;
public SourceTypeBoundClass(
- ImmutableList<ClassTy> interfaceTypes,
- ClassTy superClassType,
+ ImmutableList<Type> interfaceTypes,
+ Type superClassType,
ImmutableMap<TyVarSymbol, TyVarInfo> typeParameterTypes,
int access,
ImmutableList<MethodInfo> methods,
@@ -69,7 +70,8 @@ public class SourceTypeBoundClass implements TypeBoundClass {
MemberImportIndex memberImports,
AnnotationMetadata annotationMetadata,
ImmutableList<AnnoInfo> annotations,
- SourceFile source) {
+ SourceFile source,
+ Tree.TyDecl decl) {
this.interfaceTypes = interfaceTypes;
this.superClassType = superClassType;
this.typeParameterTypes = typeParameterTypes;
@@ -86,24 +88,29 @@ public class SourceTypeBoundClass implements TypeBoundClass {
this.annotationMetadata = annotationMetadata;
this.annotations = annotations;
this.source = source;
+ this.decl = decl;
}
@Override
public ClassSymbol superclass() {
- return superClassType() != null ? superClassType().sym() : null;
+ if (superClassType == null) {
+ return null;
+ }
+ if (superClassType.tyKind() != TyKind.CLASS_TY) {
+ return null;
+ }
+ return ((ClassTy) superClassType).sym();
}
@Override
public ImmutableList<ClassSymbol> interfaces() {
- return ImmutableList.copyOf(
- Iterables.transform(
- interfaceTypes,
- new Function<ClassTy, ClassSymbol>() {
- @Override
- public ClassSymbol apply(ClassTy classTy) {
- return classTy.sym();
- }
- }));
+ ImmutableList.Builder<ClassSymbol> result = ImmutableList.builder();
+ for (Type type : interfaceTypes) {
+ if (type.tyKind() == TyKind.CLASS_TY) {
+ result.add(((ClassTy) type).sym());
+ }
+ }
+ return result.build();
}
@Override
@@ -132,14 +139,14 @@ public class SourceTypeBoundClass implements TypeBoundClass {
return typeParameters;
}
- /** Implemented interface types. */
- public ImmutableList<Type.ClassTy> interfaceTypes() {
+ @Override
+ public ImmutableList<Type> interfaceTypes() {
return interfaceTypes;
}
/** The super-class type. */
@Override
- public Type.ClassTy superClassType() {
+ public Type superClassType() {
return superClassType;
}
@@ -181,7 +188,7 @@ public class SourceTypeBoundClass implements TypeBoundClass {
return memberImports;
}
- /** Declaration annotations. */
+ @Override
public ImmutableList<AnnoInfo> annotations() {
return annotations;
}
@@ -190,4 +197,8 @@ public class SourceTypeBoundClass implements TypeBoundClass {
public SourceFile source() {
return source;
}
+
+ public Tree.TyDecl decl() {
+ return decl;
+ }
}
diff --git a/java/com/google/turbine/binder/bound/TypeBoundClass.java b/java/com/google/turbine/binder/bound/TypeBoundClass.java
index 560f0e1..350d311 100644
--- a/java/com/google/turbine/binder/bound/TypeBoundClass.java
+++ b/java/com/google/turbine/binder/bound/TypeBoundClass.java
@@ -27,12 +27,16 @@ import com.google.turbine.tree.Tree;
import com.google.turbine.tree.Tree.MethDecl;
import com.google.turbine.type.AnnoInfo;
import com.google.turbine.type.Type;
+import com.google.turbine.type.Type.IntersectionTy;
/** A bound node that augments {@link HeaderBoundClass} with type information. */
public interface TypeBoundClass extends HeaderBoundClass {
/** The super-class type. */
- Type.ClassTy superClassType();
+ Type superClassType();
+
+ /** Implemented interface types. */
+ ImmutableList<Type> interfaceTypes();
ImmutableMap<TyVarSymbol, TyVarInfo> typeParameterTypes();
@@ -48,29 +52,22 @@ public interface TypeBoundClass extends HeaderBoundClass {
*/
AnnotationMetadata annotationMetadata();
+ /** Declaration annotations. */
+ ImmutableList<AnnoInfo> annotations();
+
/** A type parameter declaration. */
class TyVarInfo {
- private final Type superClassBound;
- private final ImmutableList<Type> interfaceBounds;
+ private final IntersectionTy bound;
private final ImmutableList<AnnoInfo> annotations;
- public TyVarInfo(
- Type superClassBound,
- ImmutableList<Type> interfaceBounds,
- ImmutableList<AnnoInfo> annotations) {
- this.superClassBound = superClassBound;
- this.interfaceBounds = interfaceBounds;
+ public TyVarInfo(IntersectionTy bound, ImmutableList<AnnoInfo> annotations) {
+ this.bound = bound;
this.annotations = annotations;
}
- /** A class bound, or {@code null}. */
- public Type superClassBound() {
- return superClassBound;
- }
-
- /** Interface type bounds. */
- public ImmutableList<Type> interfaceBounds() {
- return interfaceBounds;
+ /** The bound. */
+ public IntersectionTy bound() {
+ return bound;
}
/** Type parameter declaration annotations. */
diff --git a/java/com/google/turbine/binder/bytecode/BytecodeBinder.java b/java/com/google/turbine/binder/bytecode/BytecodeBinder.java
index 4b92f11..e5ba343 100644
--- a/java/com/google/turbine/binder/bytecode/BytecodeBinder.java
+++ b/java/com/google/turbine/binder/bytecode/BytecodeBinder.java
@@ -17,21 +17,34 @@
package com.google.turbine.binder.bytecode;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.turbine.binder.bound.AnnotationValue;
+import com.google.turbine.binder.bound.ClassValue;
+import com.google.turbine.binder.bound.EnumConstantValue;
import com.google.turbine.binder.bound.ModuleInfo;
import com.google.turbine.binder.sym.ClassSymbol;
+import com.google.turbine.binder.sym.FieldSymbol;
import com.google.turbine.binder.sym.TyVarSymbol;
import com.google.turbine.bytecode.ClassFile;
+import com.google.turbine.bytecode.ClassFile.AnnotationInfo;
+import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue;
+import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue.ArrayValue;
+import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue.ConstClassValue;
+import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue.ConstValue;
+import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue.EnumConstValue;
import com.google.turbine.bytecode.ClassReader;
import com.google.turbine.bytecode.sig.Sig;
import com.google.turbine.bytecode.sig.Sig.LowerBoundTySig;
import com.google.turbine.bytecode.sig.Sig.UpperBoundTySig;
import com.google.turbine.bytecode.sig.Sig.WildTySig;
+import com.google.turbine.bytecode.sig.SigParser;
+import com.google.turbine.model.Const;
+import com.google.turbine.model.Const.ArrayInitValue;
+import com.google.turbine.type.AnnoInfo;
import com.google.turbine.type.Type;
-import com.google.turbine.type.Type.ArrayTy;
-import com.google.turbine.type.Type.TyVar;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import java.util.function.Function;
import java.util.function.Supplier;
@@ -52,21 +65,21 @@ public class BytecodeBinder {
tyArgs.add(bindTy(arg, scope));
}
- classes.add(new Type.ClassTy.SimpleClassTy(sym, tyArgs.build(), ImmutableList.of()));
+ classes.add(Type.ClassTy.SimpleClassTy.create(sym, tyArgs.build(), ImmutableList.of()));
first = false;
}
- return new Type.ClassTy(classes);
+ return Type.ClassTy.create(classes);
}
private static Type wildTy(WildTySig sig, Function<String, TyVarSymbol> scope) {
switch (sig.boundKind()) {
case NONE:
- return new Type.WildUnboundedTy(ImmutableList.of());
+ return Type.WildUnboundedTy.create(ImmutableList.of());
case LOWER:
- return new Type.WildLowerBoundedTy(
+ return Type.WildLowerBoundedTy.create(
bindTy(((LowerBoundTySig) sig).bound(), scope), ImmutableList.of());
case UPPER:
- return new Type.WildUpperBoundedTy(
+ return Type.WildUpperBoundedTy.create(
bindTy(((UpperBoundTySig) sig).bound(), scope), ImmutableList.of());
default:
throw new AssertionError(sig.boundKind());
@@ -76,22 +89,110 @@ public class BytecodeBinder {
static Type bindTy(Sig.TySig sig, Function<String, TyVarSymbol> scope) {
switch (sig.kind()) {
case BASE_TY_SIG:
- return new Type.PrimTy(((Sig.BaseTySig) sig).type(), ImmutableList.of());
+ return Type.PrimTy.create(((Sig.BaseTySig) sig).type(), ImmutableList.of());
case CLASS_TY_SIG:
return bindClassTy((Sig.ClassTySig) sig, scope);
case TY_VAR_SIG:
- return new TyVar(scope.apply(((Sig.TyVarSig) sig).name()), ImmutableList.of());
+ return Type.TyVar.create(scope.apply(((Sig.TyVarSig) sig).name()), ImmutableList.of());
case ARRAY_TY_SIG:
return bindArrayTy((Sig.ArrayTySig) sig, scope);
case WILD_TY_SIG:
return wildTy((WildTySig) sig, scope);
+ case VOID_TY_SIG:
+ return Type.VOID;
default:
throw new AssertionError(sig.kind());
}
}
private static Type bindArrayTy(Sig.ArrayTySig arrayTySig, Function<String, TyVarSymbol> scope) {
- return new ArrayTy(bindTy(arrayTySig.elementType(), scope), ImmutableList.of());
+ return Type.ArrayTy.create(bindTy(arrayTySig.elementType(), scope), ImmutableList.of());
+ }
+
+ public static Const bindValue(Type type, ElementValue value) {
+ switch (value.kind()) {
+ case ENUM:
+ return bindEnumValue((EnumConstValue) value);
+ case CONST:
+ return bindConstValue(type, ((ConstValue) value).value());
+ case ARRAY:
+ return bindArrayValue(type, (ArrayValue) value);
+ case CLASS:
+ return new ClassValue(
+ bindTy(
+ new SigParser(((ConstClassValue) value).className()).parseType(),
+ x -> {
+ throw new IllegalStateException(x);
+ }));
+ case ANNOTATION:
+ return bindAnnotationValue(type, ((ElementValue.AnnotationValue) value).annotation());
+ }
+ throw new AssertionError(value.kind());
+ }
+
+ static AnnotationValue bindAnnotationValue(Type type, AnnotationInfo value) {
+ ClassSymbol sym = asClassSymbol(value.typeName());
+ ImmutableMap.Builder<String, Const> values = ImmutableMap.builder();
+ for (Map.Entry<String, ElementValue> e : value.elementValuePairs().entrySet()) {
+ values.put(e.getKey(), bindValue(type, e.getValue()));
+ }
+ return new AnnotationValue(sym, values.build());
+ }
+
+ static ImmutableList<AnnoInfo> bindAnnotations(List<AnnotationInfo> input) {
+ ImmutableList.Builder<AnnoInfo> result = ImmutableList.builder();
+ for (AnnotationInfo annotation : input) {
+ AnnotationValue anno = bindAnnotationValue(Type.VOID, annotation);
+ result.add(new AnnoInfo(null, anno.sym(), null, anno.values()));
+ }
+ return result.build();
+ }
+
+ private static ClassSymbol asClassSymbol(String s) {
+ return new ClassSymbol(s.substring(1, s.length() - 1));
+ }
+
+ private static Const bindArrayValue(Type type, ArrayValue value) {
+ ImmutableList.Builder<Const> elements = ImmutableList.builder();
+ for (ElementValue element : value.elements()) {
+ elements.add(bindValue(type, element));
+ }
+ return new ArrayInitValue(elements.build());
+ }
+
+ public static Const.Value bindConstValue(Type type, Const.Value value) {
+ if (type.tyKind() != Type.TyKind.PRIM_TY) {
+ return value;
+ }
+ // TODO(b/32626659): this is not bug-compatible with javac
+ switch (((Type.PrimTy) type).primkind()) {
+ case CHAR:
+ return new Const.CharValue(value.asChar().value());
+ case SHORT:
+ return new Const.ShortValue(value.asShort().value());
+ case INT:
+ return new Const.IntValue(value.asInteger().value());
+ case LONG:
+ return new Const.LongValue(value.asLong().value());
+ case FLOAT:
+ return new Const.FloatValue(value.asFloat().value());
+ case DOUBLE:
+ return new Const.DoubleValue(value.asDouble().value());
+ case BOOLEAN:
+ // boolean constants are encoded as integers
+ return new Const.BooleanValue(value.asInteger().value() != 0);
+ case BYTE:
+ return new Const.ByteValue(value.asByte().value());
+ case STRING:
+ case NULL:
+ return value;
+ }
+ throw new AssertionError(type);
+ }
+
+ private static Const bindEnumValue(EnumConstValue value) {
+ return new EnumConstantValue(
+ new FieldSymbol(asClassSymbol(value.typeName()), value.constName()));
}
/**
@@ -99,7 +200,7 @@ public class BytecodeBinder {
* version, and flags are populated, since the directives are not needed by turbine at compile
* time.
*/
- public static ModuleInfo bindModuleInfo(String path, Supplier<byte[]> bytes) throws IOException {
+ public static ModuleInfo bindModuleInfo(String path, Supplier<byte[]> bytes) {
ClassFile classFile = ClassReader.read(path, bytes.get());
ClassFile.ModuleInfo module = classFile.module();
return new ModuleInfo(
diff --git a/java/com/google/turbine/binder/bytecode/BytecodeBoundClass.java b/java/com/google/turbine/binder/bytecode/BytecodeBoundClass.java
index 36c191f..f21760b 100644
--- a/java/com/google/turbine/binder/bytecode/BytecodeBoundClass.java
+++ b/java/com/google/turbine/binder/bytecode/BytecodeBoundClass.java
@@ -40,16 +40,21 @@ import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue.ArrayVa
import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue.ConstClassValue;
import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue.EnumConstValue;
import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue.Kind;
+import com.google.turbine.bytecode.ClassFile.MethodInfo.ParameterInfo;
import com.google.turbine.bytecode.ClassReader;
import com.google.turbine.bytecode.sig.Sig;
import com.google.turbine.bytecode.sig.Sig.ClassSig;
+import com.google.turbine.bytecode.sig.Sig.ClassTySig;
+import com.google.turbine.bytecode.sig.Sig.TySig;
import com.google.turbine.bytecode.sig.SigParser;
import com.google.turbine.model.Const;
+import com.google.turbine.model.TurbineElementType;
import com.google.turbine.model.TurbineFlag;
import com.google.turbine.model.TurbineTyKind;
+import com.google.turbine.type.AnnoInfo;
import com.google.turbine.type.Type;
import com.google.turbine.type.Type.ClassTy;
-import java.lang.annotation.ElementType;
+import com.google.turbine.type.Type.IntersectionTy;
import java.lang.annotation.RetentionPolicy;
import java.util.Map;
import java.util.function.Function;
@@ -72,7 +77,7 @@ public class BytecodeBoundClass implements BoundClass, HeaderBoundClass, TypeBou
public BytecodeBoundClass(
ClassSymbol sym,
- final Supplier<byte[]> bytes,
+ Supplier<byte[]> bytes,
Env<ClassSymbol, BytecodeBoundClass> env,
String jarFile) {
this.sym = sym;
@@ -94,7 +99,7 @@ public class BytecodeBoundClass implements BoundClass, HeaderBoundClass, TypeBou
});
}
- final Supplier<TurbineTyKind> kind =
+ private final Supplier<TurbineTyKind> kind =
Suppliers.memoize(
new Supplier<TurbineTyKind>() {
@Override
@@ -118,7 +123,7 @@ public class BytecodeBoundClass implements BoundClass, HeaderBoundClass, TypeBou
return kind.get();
}
- final Supplier<ClassSymbol> owner =
+ private final Supplier<ClassSymbol> owner =
Suppliers.memoize(
new Supplier<ClassSymbol>() {
@Override
@@ -138,7 +143,7 @@ public class BytecodeBoundClass implements BoundClass, HeaderBoundClass, TypeBou
return owner.get();
}
- final Supplier<ImmutableMap<String, ClassSymbol>> children =
+ private final Supplier<ImmutableMap<String, ClassSymbol>> children =
Suppliers.memoize(
new Supplier<ImmutableMap<String, ClassSymbol>>() {
@Override
@@ -162,7 +167,7 @@ public class BytecodeBoundClass implements BoundClass, HeaderBoundClass, TypeBou
return children.get();
}
- final Supplier<Integer> access =
+ private final Supplier<Integer> access =
Suppliers.memoize(
new Supplier<Integer>() {
@Override
@@ -217,7 +222,7 @@ public class BytecodeBoundClass implements BoundClass, HeaderBoundClass, TypeBou
return tyParams.get();
}
- final Supplier<ClassSymbol> superclass =
+ private final Supplier<ClassSymbol> superclass =
Suppliers.memoize(
new Supplier<ClassSymbol>() {
@Override
@@ -235,7 +240,7 @@ public class BytecodeBoundClass implements BoundClass, HeaderBoundClass, TypeBou
return superclass.get();
}
- final Supplier<ImmutableList<ClassSymbol>> interfaces =
+ private final Supplier<ImmutableList<ClassSymbol>> interfaces =
Suppliers.memoize(
new Supplier<ImmutableList<ClassSymbol>>() {
@Override
@@ -253,7 +258,7 @@ public class BytecodeBoundClass implements BoundClass, HeaderBoundClass, TypeBou
return interfaces.get();
}
- Supplier<ClassTy> superClassType =
+ private final Supplier<ClassTy> superClassType =
Suppliers.memoize(
new Supplier<ClassTy>() {
@Override
@@ -274,7 +279,35 @@ public class BytecodeBoundClass implements BoundClass, HeaderBoundClass, TypeBou
return superClassType.get();
}
- Supplier<ImmutableMap<TyVarSymbol, TyVarInfo>> typeParameterTypes =
+ private final Supplier<ImmutableList<Type>> interfaceTypes =
+ Suppliers.memoize(
+ new Supplier<ImmutableList<Type>>() {
+ @Override
+ public ImmutableList<Type> get() {
+ if (interfaces().isEmpty()) {
+ return ImmutableList.of();
+ }
+ ImmutableList.Builder<Type> result = ImmutableList.builder();
+ if (sig.get() == null || sig.get().interfaces() == null) {
+ for (ClassSymbol sym : interfaces()) {
+ result.add(ClassTy.asNonParametricClassTy(sym));
+ }
+ } else {
+ Function<String, TyVarSymbol> scope = makeScope(env, sym, ImmutableMap.of());
+ for (ClassTySig classTySig : sig.get().interfaces()) {
+ result.add(BytecodeBinder.bindClassTy(classTySig, scope));
+ }
+ }
+ return result.build();
+ }
+ });
+
+ @Override
+ public ImmutableList<Type> interfaceTypes() {
+ return interfaceTypes.get();
+ }
+
+ private final Supplier<ImmutableMap<TyVarSymbol, TyVarInfo>> typeParameterTypes =
Suppliers.memoize(
new Supplier<ImmutableMap<TyVarSymbol, TyVarInfo>>() {
@Override
@@ -292,15 +325,14 @@ public class BytecodeBoundClass implements BoundClass, HeaderBoundClass, TypeBou
});
private static TyVarInfo bindTyParam(Sig.TyParamSig sig, Function<String, TyVarSymbol> scope) {
- Type superClassBound = null;
+ ImmutableList.Builder<Type> bounds = ImmutableList.builder();
if (sig.classBound() != null) {
- superClassBound = BytecodeBinder.bindTy(sig.classBound(), scope);
+ bounds.add(BytecodeBinder.bindTy(sig.classBound(), scope));
}
- ImmutableList.Builder<Type> interfaceBounds = ImmutableList.builder();
for (Sig.TySig t : sig.interfaceBounds()) {
- interfaceBounds.add(BytecodeBinder.bindTy(t, scope));
+ bounds.add(BytecodeBinder.bindTy(t, scope));
}
- return new TyVarInfo(superClassBound, interfaceBounds.build(), ImmutableList.of());
+ return new TyVarInfo(IntersectionTy.create(bounds.build()), ImmutableList.of());
}
@Override
@@ -316,29 +348,14 @@ public class BytecodeBoundClass implements BoundClass, HeaderBoundClass, TypeBou
ImmutableList.Builder<FieldInfo> fields = ImmutableList.builder();
for (ClassFile.FieldInfo cfi : classFile.get().fields()) {
FieldSymbol fieldSym = new FieldSymbol(sym, cfi.name());
- // we don't need a type here, the const value has all necessary information
- Type type = null;
+ Type type =
+ BytecodeBinder.bindTy(
+ new SigParser(cfi.descriptor()).parseType(),
+ makeScope(env, sym, ImmutableMap.of()));
int access = cfi.access();
Const.Value value = cfi.value();
if (value != null) {
- // TODO(b/32626659): this is not bug-compatible with javac
- switch (cfi.descriptor()) {
- case "Z":
- // boolean constants are encoded as integers
- value = new Const.BooleanValue(value.asInteger().value() != 0);
- break;
- case "C":
- value = new Const.CharValue(value.asChar().value());
- break;
- case "S":
- value = new Const.ShortValue(value.asShort().value());
- break;
- case "B":
- value = new Const.ByteValue(value.asByte().value());
- break;
- default:
- break;
- }
+ value = BytecodeBinder.bindConstValue(type, value);
}
fields.add(new FieldInfo(fieldSym, type, access, ImmutableList.of(), null, value));
}
@@ -351,15 +368,11 @@ public class BytecodeBoundClass implements BoundClass, HeaderBoundClass, TypeBou
return fields.get();
}
- Supplier<ImmutableList<MethodInfo>> methods =
+ private final Supplier<ImmutableList<MethodInfo>> methods =
Suppliers.memoize(
new Supplier<ImmutableList<MethodInfo>>() {
@Override
public ImmutableList<MethodInfo> get() {
- // we only need methods for annotation declarations
- if (kind() != TurbineTyKind.ANNOTATION) {
- return ImmutableList.of();
- }
ImmutableList.Builder<MethodInfo> methods = ImmutableList.builder();
for (ClassFile.MethodInfo m : classFile.get().methods()) {
methods.add(bindMethod(m));
@@ -372,9 +385,26 @@ public class BytecodeBoundClass implements BoundClass, HeaderBoundClass, TypeBou
MethodSymbol methodSymbol = new MethodSymbol(sym, m.name());
Sig.MethodSig sig = new SigParser(firstNonNull(m.signature(), m.descriptor())).parseMethodSig();
- verify(sig.tyParams().isEmpty());
+ ImmutableMap<String, TyVarSymbol> tyParams;
+ {
+ ImmutableMap.Builder<String, TyVarSymbol> result = ImmutableMap.builder();
+ for (Sig.TyParamSig p : sig.tyParams()) {
+ result.put(p.name(), new TyVarSymbol(methodSymbol, p.name()));
+ }
+ tyParams = result.build();
+ }
+
+ ImmutableMap<TyVarSymbol, TyVarInfo> tyParamTypes;
+ {
+ ImmutableMap.Builder<TyVarSymbol, TyVarInfo> tparams = ImmutableMap.builder();
+ Function<String, TyVarSymbol> scope = makeScope(env, sym, tyParams);
+ for (Sig.TyParamSig p : sig.tyParams()) {
+ tparams.put(tyParams.get(p.name()), bindTyParam(p, scope));
+ }
+ tyParamTypes = tparams.build();
+ }
- Function<String, TyVarSymbol> scope = makeScope(env, sym, ImmutableMap.of());
+ Function<String, TyVarSymbol> scope = makeScope(env, sym, tyParams);
Type ret = null;
if (sig.returnType() != null) {
@@ -382,23 +412,44 @@ public class BytecodeBoundClass implements BoundClass, HeaderBoundClass, TypeBou
}
ImmutableList.Builder<ParamInfo> formals = ImmutableList.builder();
+ int idx = 0;
for (Sig.TySig tySig : sig.params()) {
- formals.add(new ParamInfo(BytecodeBinder.bindTy(tySig, scope), null, ImmutableList.of(), 0));
+ String name = null;
+ int access = 0;
+ if (idx < m.parameters().size()) {
+ ParameterInfo paramInfo = m.parameters().get(idx);
+ name = paramInfo.name();
+ access = paramInfo.access();
+ }
+ ImmutableList<AnnoInfo> annotations =
+ (idx < m.parameterAnnotations().size())
+ ? BytecodeBinder.bindAnnotations(m.parameterAnnotations().get(idx))
+ : ImmutableList.of();
+ formals.add(new ParamInfo(BytecodeBinder.bindTy(tySig, scope), name, annotations, access));
+ idx++;
+ }
+
+ ImmutableList.Builder<Type> exceptions = ImmutableList.builder();
+ for (TySig e : sig.exceptions()) {
+ exceptions.add(BytecodeBinder.bindTy(e, scope));
}
- verify(sig.exceptions().isEmpty());
+ Const defaultValue =
+ m.defaultValue() != null ? BytecodeBinder.bindValue(ret, m.defaultValue()) : null;
+
+ ImmutableList<AnnoInfo> annotations = BytecodeBinder.bindAnnotations(m.annotations());
return new MethodInfo(
methodSymbol,
- ImmutableMap.of(),
+ tyParamTypes,
ret,
formals.build(),
- ImmutableList.of(),
+ exceptions.build(),
m.access(),
- null /*defaultValue*/,
- null /*decl*/,
- ImmutableList.of(),
- null);
+ defaultValue,
+ /* decl= */ null,
+ annotations,
+ /* receiver= */ null);
}
@Override
@@ -406,7 +457,7 @@ public class BytecodeBoundClass implements BoundClass, HeaderBoundClass, TypeBou
return methods.get();
}
- final Supplier<AnnotationMetadata> annotationMetadata =
+ private final Supplier<AnnotationMetadata> annotationMetadata =
Suppliers.memoize(
new Supplier<AnnotationMetadata>() {
@Override
@@ -415,7 +466,7 @@ public class BytecodeBoundClass implements BoundClass, HeaderBoundClass, TypeBou
return null;
}
RetentionPolicy retention = null;
- ImmutableSet<ElementType> target = null;
+ ImmutableSet<TurbineElementType> target = null;
ClassSymbol repeatable = null;
for (ClassFile.AnnotationInfo annotation : classFile.get().annotations()) {
switch (annotation.typeName()) {
@@ -448,8 +499,8 @@ public class BytecodeBoundClass implements BoundClass, HeaderBoundClass, TypeBou
return RetentionPolicy.valueOf(enumVal.constName());
}
- private static ImmutableSet<ElementType> bindTarget(AnnotationInfo annotation) {
- ImmutableSet.Builder<ElementType> result = ImmutableSet.builder();
+ private static ImmutableSet<TurbineElementType> bindTarget(AnnotationInfo annotation) {
+ ImmutableSet.Builder<TurbineElementType> result = ImmutableSet.builder();
ElementValue val = annotation.elementValuePairs().get("value");
switch (val.kind()) {
case ARRAY:
@@ -469,9 +520,9 @@ public class BytecodeBoundClass implements BoundClass, HeaderBoundClass, TypeBou
}
private static void bindTargetElement(
- ImmutableSet.Builder<ElementType> target, EnumConstValue enumVal) {
+ ImmutableSet.Builder<TurbineElementType> target, EnumConstValue enumVal) {
if (enumVal.typeName().equals("Ljava/lang/annotation/ElementType;")) {
- target.add(ElementType.valueOf(enumVal.constName()));
+ target.add(TurbineElementType.valueOf(enumVal.constName()));
}
}
@@ -492,6 +543,20 @@ public class BytecodeBoundClass implements BoundClass, HeaderBoundClass, TypeBou
return annotationMetadata.get();
}
+ private final Supplier<ImmutableList<AnnoInfo>> annotations =
+ Suppliers.memoize(
+ new Supplier<ImmutableList<AnnoInfo>>() {
+ @Override
+ public ImmutableList<AnnoInfo> get() {
+ return BytecodeBinder.bindAnnotations(classFile.get().annotations());
+ }
+ });
+
+ @Override
+ public ImmutableList<AnnoInfo> annotations() {
+ return annotations.get();
+ }
+
/**
* Create a scope for resolving type variable symbols declared in the class, and any enclosing
* instances.
diff --git a/java/com/google/turbine/binder/lookup/CanonicalSymbolResolver.java b/java/com/google/turbine/binder/lookup/CanonicalSymbolResolver.java
index 1e6eee1..1e33d5f 100644
--- a/java/com/google/turbine/binder/lookup/CanonicalSymbolResolver.java
+++ b/java/com/google/turbine/binder/lookup/CanonicalSymbolResolver.java
@@ -17,12 +17,13 @@
package com.google.turbine.binder.lookup;
import com.google.turbine.binder.sym.ClassSymbol;
+import com.google.turbine.tree.Tree;
/** Canonical type resolution. Breaks a circular dependency between binding and import handling. */
public interface CanonicalSymbolResolver extends ImportScope.ResolveFunction {
/** Resolves a single member type of the given symbol by canonical name. */
@Override
- ClassSymbol resolveOne(ClassSymbol sym, String bit);
+ ClassSymbol resolveOne(ClassSymbol sym, Tree.Ident bit);
/** Returns true if the given symbol is visible from the current package. */
boolean visible(ClassSymbol sym);
diff --git a/java/com/google/turbine/binder/lookup/ImportIndex.java b/java/com/google/turbine/binder/lookup/ImportIndex.java
index eb3ac8f..f28d905 100644
--- a/java/com/google/turbine/binder/lookup/ImportIndex.java
+++ b/java/com/google/turbine/binder/lookup/ImportIndex.java
@@ -24,10 +24,10 @@ import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.turbine.binder.sym.ClassSymbol;
-import com.google.turbine.diag.SourceFile;
-import com.google.turbine.diag.TurbineError;
import com.google.turbine.diag.TurbineError.ErrorKind;
+import com.google.turbine.diag.TurbineLog.TurbineLogWithSource;
import com.google.turbine.tree.Tree;
+import com.google.turbine.tree.Tree.Ident;
import com.google.turbine.tree.Tree.ImportDecl;
import java.util.HashMap;
import java.util.Map;
@@ -49,13 +49,13 @@ public class ImportIndex implements ImportScope {
*/
private final Map<String, Supplier<ImportScope>> thunks;
- public ImportIndex(ImmutableMap<String, Supplier<ImportScope>> thunks) {
+ public ImportIndex(TurbineLogWithSource log, ImmutableMap<String, Supplier<ImportScope>> thunks) {
this.thunks = thunks;
}
/** Creates an import index for the given top-level environment. */
public static ImportIndex create(
- SourceFile source,
+ TurbineLogWithSource log,
CanonicalSymbolResolver resolve,
final TopLevelIndex cpi,
ImmutableList<ImportDecl> imports) {
@@ -65,12 +65,12 @@ public class ImportIndex implements ImportScope {
continue;
}
thunks.put(
- getLast(i.type()),
+ getLast(i.type()).value(),
Suppliers.memoize(
new Supplier<ImportScope>() {
@Override
public ImportScope get() {
- return namedImport(source, cpi, i, resolve);
+ return namedImport(log, cpi, i, resolve);
}
}));
}
@@ -80,37 +80,32 @@ public class ImportIndex implements ImportScope {
if (!i.stat() || i.wild()) {
continue;
}
- String last = getLast(i.type());
- if (thunks.containsKey(last)) {
- continue;
- }
- thunks.put(
+ String last = getLast(i.type()).value();
+ thunks.putIfAbsent(
last,
Suppliers.memoize(
new Supplier<ImportScope>() {
@Override
public ImportScope get() {
- return staticNamedImport(cpi, i);
+ return staticNamedImport(log, cpi, i);
}
}));
}
- return new ImportIndex(ImmutableMap.copyOf(thunks));
+ return new ImportIndex(log, ImmutableMap.copyOf(thunks));
}
/** Fully resolve the canonical name of a non-static named import. */
private static ImportScope namedImport(
- SourceFile source, TopLevelIndex cpi, ImportDecl i, CanonicalSymbolResolver resolve) {
+ TurbineLogWithSource log, TopLevelIndex cpi, ImportDecl i, CanonicalSymbolResolver resolve) {
LookupResult result = cpi.scope().lookup(new LookupKey(i.type()));
if (result == null) {
- throw TurbineError.format(
- source,
- i.position(),
- ErrorKind.SYMBOL_NOT_FOUND,
- new ClassSymbol(Joiner.on('/').join(i.type())));
+ log.error(
+ i.position(), ErrorKind.SYMBOL_NOT_FOUND, new ClassSymbol(Joiner.on('/').join(i.type())));
+ return null;
}
ClassSymbol sym = (ClassSymbol) result.sym();
- for (String bit : result.remaining()) {
- sym = resolveNext(source, i.position(), resolve, sym, bit);
+ for (Tree.Ident bit : result.remaining()) {
+ sym = resolveNext(log, i.position(), resolve, sym, bit);
}
ClassSymbol resolved = sym;
return new ImportScope() {
@@ -122,18 +117,15 @@ public class ImportIndex implements ImportScope {
}
private static ClassSymbol resolveNext(
- SourceFile source,
+ TurbineLogWithSource log,
int position,
CanonicalSymbolResolver resolve,
ClassSymbol sym,
- String bit) {
+ Ident bit) {
ClassSymbol next = resolve.resolveOne(sym, bit);
if (next == null) {
- throw TurbineError.format(
- source,
- position,
- ErrorKind.SYMBOL_NOT_FOUND,
- new ClassSymbol(sym.binaryName() + '$' + bit));
+ log.error(
+ position, ErrorKind.SYMBOL_NOT_FOUND, new ClassSymbol(sym.binaryName() + '$' + bit));
}
return next;
}
@@ -145,16 +137,18 @@ public class ImportIndex implements ImportScope {
* hierarchy analysis is complete, so for now we resolve the base {@code java.util.HashMap} and
* defer the rest.
*/
- private static ImportScope staticNamedImport(TopLevelIndex cpi, ImportDecl i) {
+ private static ImportScope staticNamedImport(
+ TurbineLogWithSource log, TopLevelIndex cpi, ImportDecl i) {
LookupResult base = cpi.scope().lookup(new LookupKey(i.type()));
if (base == null) {
+ log.error(i.position(), ErrorKind.SYMBOL_NOT_FOUND, Joiner.on(".").join(i.type()));
return null;
}
return new ImportScope() {
@Override
public LookupResult lookup(LookupKey lookupKey, ResolveFunction resolve) {
ClassSymbol sym = (ClassSymbol) base.sym();
- for (String bit : base.remaining()) {
+ for (Tree.Ident bit : base.remaining()) {
sym = resolve.resolveOne(sym, bit);
if (sym == null) {
// Assume that static imports that don't resolve to types are non-type member imports,
@@ -169,7 +163,7 @@ public class ImportIndex implements ImportScope {
@Override
public LookupResult lookup(LookupKey lookup, ResolveFunction resolve) {
- Supplier<ImportScope> thunk = thunks.get(lookup.first());
+ Supplier<ImportScope> thunk = thunks.get(lookup.first().value());
if (thunk == null) {
return null;
}
diff --git a/java/com/google/turbine/binder/lookup/ImportScope.java b/java/com/google/turbine/binder/lookup/ImportScope.java
index 8b28cb3..2e6917e 100644
--- a/java/com/google/turbine/binder/lookup/ImportScope.java
+++ b/java/com/google/turbine/binder/lookup/ImportScope.java
@@ -17,6 +17,7 @@
package com.google.turbine.binder.lookup;
import com.google.turbine.binder.sym.ClassSymbol;
+import com.google.turbine.tree.Tree;
/**
* A scope for imports. Non-canonical imports depend on hierarchy analysis, so to break the cycle we
@@ -31,7 +32,7 @@ public interface ImportScope {
*/
@FunctionalInterface
interface ResolveFunction {
- ClassSymbol resolveOne(ClassSymbol base, String name);
+ ClassSymbol resolveOne(ClassSymbol base, Tree.Ident name);
}
/** See {@link Scope#lookup(LookupKey)}. */
diff --git a/java/com/google/turbine/binder/lookup/LookupKey.java b/java/com/google/turbine/binder/lookup/LookupKey.java
index 94e0838..1332fa1 100644
--- a/java/com/google/turbine/binder/lookup/LookupKey.java
+++ b/java/com/google/turbine/binder/lookup/LookupKey.java
@@ -18,6 +18,7 @@ package com.google.turbine.binder.lookup;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.Immutable;
+import com.google.turbine.tree.Tree.Ident;
import java.util.NoSuchElementException;
/**
@@ -26,14 +27,14 @@ import java.util.NoSuchElementException;
*/
@Immutable
public class LookupKey {
- private final ImmutableList<String> simpleNames;
+ private final ImmutableList<Ident> simpleNames;
- public LookupKey(Iterable<String> simpleNames) {
- this.simpleNames = ImmutableList.copyOf(simpleNames);
+ public LookupKey(ImmutableList<Ident> simpleNames) {
+ this.simpleNames = simpleNames;
}
/** The first simple name in the qualified type name. */
- public String first() {
+ public Ident first() {
return simpleNames.get(0);
}
@@ -62,7 +63,7 @@ public class LookupKey {
}
/** The simple names of the type. */
- public ImmutableList<String> simpleNames() {
+ public ImmutableList<Ident> simpleNames() {
return simpleNames;
}
}
diff --git a/java/com/google/turbine/binder/lookup/LookupResult.java b/java/com/google/turbine/binder/lookup/LookupResult.java
index 0529ecd..7e0f737 100644
--- a/java/com/google/turbine/binder/lookup/LookupResult.java
+++ b/java/com/google/turbine/binder/lookup/LookupResult.java
@@ -20,6 +20,7 @@ import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.Immutable;
import com.google.turbine.binder.sym.ClassSymbol;
import com.google.turbine.binder.sym.Symbol;
+import com.google.turbine.tree.Tree;
/**
* The result of a canonical type name lookup.
@@ -36,16 +37,15 @@ public class LookupResult {
}
/** The remaining nested type names. */
- public ImmutableList<String> remaining() {
+ public ImmutableList<Tree.Ident> remaining() {
return remaining;
}
private final Symbol sym;
- private final ImmutableList<String> remaining;
+ private final ImmutableList<Tree.Ident> remaining;
public LookupResult(Symbol sym, LookupKey remaining) {
this.sym = sym;
- this.remaining =
- remaining.hasNext() ? remaining.rest().simpleNames() : ImmutableList.<String>of();
+ this.remaining = remaining.hasNext() ? remaining.rest().simpleNames() : ImmutableList.of();
}
}
diff --git a/java/com/google/turbine/binder/lookup/MemberImportIndex.java b/java/com/google/turbine/binder/lookup/MemberImportIndex.java
index 45eefb5..a8ecc7a 100644
--- a/java/com/google/turbine/binder/lookup/MemberImportIndex.java
+++ b/java/com/google/turbine/binder/lookup/MemberImportIndex.java
@@ -25,6 +25,7 @@ import com.google.turbine.binder.sym.ClassSymbol;
import com.google.turbine.diag.SourceFile;
import com.google.turbine.diag.TurbineError;
import com.google.turbine.diag.TurbineError.ErrorKind;
+import com.google.turbine.tree.Tree;
import com.google.turbine.tree.Tree.ImportDecl;
import java.util.Iterator;
import java.util.LinkedHashMap;
@@ -59,7 +60,7 @@ public class MemberImportIndex {
return null;
}
ClassSymbol sym = (ClassSymbol) result.sym();
- for (String bit : result.remaining()) {
+ for (Tree.Ident bit : result.remaining()) {
sym = resolveNext(resolve, source, i.position(), sym, bit);
}
return sym;
@@ -67,7 +68,7 @@ public class MemberImportIndex {
}));
} else {
cache.put(
- getLast(i.type()),
+ getLast(i.type()).value(),
Suppliers.memoize(
new Supplier<ClassSymbol>() {
@Override
@@ -93,7 +94,7 @@ public class MemberImportIndex {
SourceFile source,
int position,
ClassSymbol sym,
- String bit) {
+ Tree.Ident bit) {
ClassSymbol next = resolve.resolveOne(sym, bit);
if (next == null) {
throw TurbineError.format(
diff --git a/java/com/google/turbine/binder/lookup/SimpleTopLevelIndex.java b/java/com/google/turbine/binder/lookup/SimpleTopLevelIndex.java
index 697ce61..99aa464 100644
--- a/java/com/google/turbine/binder/lookup/SimpleTopLevelIndex.java
+++ b/java/com/google/turbine/binder/lookup/SimpleTopLevelIndex.java
@@ -16,11 +16,9 @@
package com.google.turbine.binder.lookup;
-import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.turbine.binder.sym.ClassSymbol;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import javax.annotation.Nullable;
@@ -57,9 +55,8 @@ public class SimpleTopLevelIndex implements TopLevelIndex {
* @return {@code null} if an existing symbol with the same name has already been inserted.
*/
private Node insert(String name, ClassSymbol sym) {
- Node child;
- if (children.containsKey(name)) {
- child = children.get(name);
+ Node child = children.get(name);
+ if (child != null) {
if (child.sym != null) {
return null;
}
@@ -85,20 +82,26 @@ public class SimpleTopLevelIndex implements TopLevelIndex {
/** Inserts a {@link ClassSymbol} into the index, creating any needed packages. */
public boolean insert(ClassSymbol sym) {
- Iterator<String> it = Splitter.on('/').split(sym.binaryName()).iterator();
+ String binaryName = sym.binaryName();
+ int start = 0;
+ int end = binaryName.indexOf('/');
Node curr = root;
- while (it.hasNext()) {
- String simpleName = it.next();
- // if this is the last simple name in the qualified name of the top-level class being
- // inserted, we are creating a node for the class symbol
- ClassSymbol nodeSym = it.hasNext() ? null : sym;
- curr = curr.insert(simpleName, nodeSym);
+ while (end != -1) {
+ String simpleName = binaryName.substring(start, end);
+ curr = curr.insert(simpleName, null);
// If we've already inserted something with the current name (either a package or another
// symbol), bail out. When inserting elements from the classpath, this results in the
// expected first-match-wins semantics.
- if (curr == null || !Objects.equals(curr.sym, nodeSym)) {
+ if (curr == null) {
return false;
}
+ start = end + 1;
+ end = binaryName.indexOf('/', start);
+ }
+ String simpleName = binaryName.substring(start);
+ curr = curr.insert(simpleName, sym);
+ if (curr == null || !Objects.equals(curr.sym, sym)) {
+ return false;
}
return true;
}
@@ -132,7 +135,7 @@ public class SimpleTopLevelIndex implements TopLevelIndex {
public LookupResult lookup(LookupKey lookupKey) {
Node curr = root;
while (true) {
- curr = curr.lookup(lookupKey.first());
+ curr = curr.lookup(lookupKey.first().value());
if (curr == null) {
return null;
}
@@ -175,7 +178,7 @@ public class SimpleTopLevelIndex implements TopLevelIndex {
@Override
public LookupResult lookup(LookupKey lookupKey) {
- Node result = node.lookup(lookupKey.first());
+ Node result = node.lookup(lookupKey.first().value());
if (result != null && result.sym != null) {
return new LookupResult(result.sym, lookupKey);
}
diff --git a/java/com/google/turbine/binder/lookup/WildImportIndex.java b/java/com/google/turbine/binder/lookup/WildImportIndex.java
index 21e995d..043ccc5 100644
--- a/java/com/google/turbine/binder/lookup/WildImportIndex.java
+++ b/java/com/google/turbine/binder/lookup/WildImportIndex.java
@@ -20,6 +20,7 @@ import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableList;
import com.google.turbine.binder.sym.ClassSymbol;
+import com.google.turbine.tree.Tree;
import com.google.turbine.tree.Tree.ImportDecl;
/**
@@ -69,7 +70,11 @@ public class WildImportIndex implements ImportScope {
TopLevelIndex cpi,
ImportDecl i,
final CanonicalSymbolResolver importResolver) {
- Scope packageIndex = cpi.lookupPackage(i.type());
+ ImmutableList.Builder<String> flatNames = ImmutableList.builder();
+ for (Tree.Ident ident : i.type()) {
+ flatNames.add(ident.value());
+ }
+ Scope packageIndex = cpi.lookupPackage(flatNames.build());
if (packageIndex != null) {
// a wildcard import of a package
return new ImportScope() {
@@ -140,7 +145,7 @@ public class WildImportIndex implements ImportScope {
ResolveFunction resolve,
CanonicalSymbolResolver importResolver) {
ClassSymbol member = (ClassSymbol) result.sym();
- for (String bit : result.remaining()) {
+ for (Tree.Ident bit : result.remaining()) {
member = resolve.resolveOne(member, bit);
if (member == null) {
return null;
diff --git a/java/com/google/turbine/bytecode/ClassReader.java b/java/com/google/turbine/bytecode/ClassReader.java
index a9e2402..0070527 100644
--- a/java/com/google/turbine/bytecode/ClassReader.java
+++ b/java/com/google/turbine/bytecode/ClassReader.java
@@ -19,9 +19,13 @@ package com.google.turbine.bytecode;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.errorprone.annotations.CheckReturnValue;
+import com.google.turbine.bytecode.ClassFile.AnnotationInfo;
import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue;
+import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue.AnnotationValue;
import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue.ConstClassValue;
+import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue.ConstValue;
import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue.EnumConstValue;
+import com.google.turbine.bytecode.ClassFile.MethodInfo.ParameterInfo;
import com.google.turbine.bytecode.ClassFile.ModuleInfo;
import com.google.turbine.bytecode.ClassFile.ModuleInfo.ExportInfo;
import com.google.turbine.bytecode.ClassFile.ModuleInfo.OpenInfo;
@@ -29,7 +33,6 @@ import com.google.turbine.bytecode.ClassFile.ModuleInfo.ProvideInfo;
import com.google.turbine.bytecode.ClassFile.ModuleInfo.RequireInfo;
import com.google.turbine.bytecode.ClassFile.ModuleInfo.UseInfo;
import com.google.turbine.model.Const;
-import com.google.turbine.model.TurbineFlag;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -74,7 +77,7 @@ public class ClassReader {
}
int minorVersion = reader.u2();
int majorVersion = reader.u2();
- if (majorVersion < 45 || majorVersion > 53) {
+ if (majorVersion < 45) {
throw error("bad version: %d.%d", majorVersion, minorVersion);
}
ConstantPoolReader constantPool = ConstantPoolReader.readConstantPool(reader);
@@ -99,15 +102,16 @@ public class ClassReader {
String signature = null;
List<ClassFile.InnerClass> innerclasses = Collections.emptyList();
- List<ClassFile.AnnotationInfo> annotations = Collections.emptyList();
+ ImmutableList.Builder<ClassFile.AnnotationInfo> annotations = ImmutableList.builder();
ClassFile.ModuleInfo module = null;
int attributesCount = reader.u2();
for (int j = 0; j < attributesCount; j++) {
int attributeNameIndex = reader.u2();
String name = constantPool.utf8(attributeNameIndex);
switch (name) {
+ case "RuntimeInvisibleAnnotations":
case "RuntimeVisibleAnnotations":
- annotations = readAnnotations(constantPool, accessFlags);
+ readAnnotations(annotations, constantPool);
break;
case "Signature":
signature = readSignature(constantPool);
@@ -132,7 +136,7 @@ public class ClassReader {
interfaces,
methodinfos,
fieldinfos,
- annotations,
+ annotations.build(),
innerclasses,
ImmutableList.of(),
module);
@@ -175,22 +179,42 @@ public class ClassReader {
* <p>The only annotations that affect header compilation are {@link @Retention} and
* {@link @Target} on annotation declarations.
*/
- private List<ClassFile.AnnotationInfo> readAnnotations(
- ConstantPoolReader constantPool, int accessFlags) {
- List<ClassFile.AnnotationInfo> annotations = new ArrayList<>();
- if ((accessFlags & TurbineFlag.ACC_ANNOTATION) == 0) {
- reader.skip(reader.u4());
- return ImmutableList.of();
- }
+ private void readAnnotations(
+ ImmutableList.Builder<ClassFile.AnnotationInfo> annotations,
+ ConstantPoolReader constantPool) {
reader.u4(); // length
int numAnnotations = reader.u2();
for (int n = 0; n < numAnnotations; n++) {
- ClassFile.AnnotationInfo tmp = readAnnotation(constantPool);
- if (tmp != null) {
- annotations.add(tmp);
+ annotations.add(readAnnotation(constantPool));
+ }
+ }
+
+ /** Processes a JVMS 4.7.18 RuntimeVisibleParameterAnnotations attribute */
+ public void readParameterAnnotations(
+ List<ImmutableList.Builder<AnnotationInfo>> annotations, ConstantPoolReader constantPool) {
+ reader.u4(); // length
+ int numParameters = reader.u1();
+ while (annotations.size() < numParameters) {
+ annotations.add(ImmutableList.builder());
+ }
+ for (int i = 0; i < numParameters; i++) {
+ int numAnnotations = reader.u2();
+ for (int n = 0; n < numAnnotations; n++) {
+ annotations.get(i).add(readAnnotation(constantPool));
}
}
- return annotations;
+ }
+
+ /** Processes a JVMS 4.7.24 MethodParameters attribute. */
+ private void readMethodParameters(
+ ImmutableList.Builder<ParameterInfo> parameters, ConstantPoolReader constantPool) {
+ reader.u4(); // length
+ int numParameters = reader.u1();
+ for (int i = 0; i < numParameters; i++) {
+ String name = constantPool.utf8(reader.u2());
+ int access = reader.u2();
+ parameters.add(new ParameterInfo(name, access));
+ }
}
/** Processes a JVMS 4.7.25 Module attribute. */
@@ -278,36 +302,23 @@ public class ClassReader {
private ClassFile.AnnotationInfo readAnnotation(ConstantPoolReader constantPool) {
int typeIndex = reader.u2();
String annotationType = constantPool.utf8(typeIndex);
- boolean read;
- switch (annotationType) {
- case "Ljava/lang/annotation/Retention;":
- case "Ljava/lang/annotation/Target;":
- case "Ljava/lang/annotation/Repeatable;":
- read = true;
- break;
- default:
- read = false;
- break;
- }
int numElementValuePairs = reader.u2();
- ClassFile.AnnotationInfo result = null;
+ ImmutableMap.Builder<String, ElementValue> values = ImmutableMap.builder();
for (int e = 0; e < numElementValuePairs; e++) {
int elementNameIndex = reader.u2();
String key = constantPool.utf8(elementNameIndex);
- boolean value = read && key.equals("value");
- ElementValue tmp = readElementValue(constantPool, value);
- if (tmp != null) {
- result = new ClassFile.AnnotationInfo(annotationType, true, ImmutableMap.of(key, tmp));
- }
+ ElementValue value = readElementValue(constantPool);
+ values.put(key, value);
}
- return result;
+ return new ClassFile.AnnotationInfo(
+ annotationType,
+ // The runtimeVisible bit in AnnotationInfo is only used during lowering; earlier passes
+ // read the meta-annotations.
+ /* runtimeVisible= */ false,
+ values.build());
}
- /**
- * Extracts the value of an annotation declaration meta-annotation, or else skips over the element
- * value pair.
- */
- private ElementValue readElementValue(ConstantPoolReader constantPool, boolean value) {
+ private ElementValue readElementValue(ConstantPoolReader constantPool) {
int tag = reader.u1();
switch (tag) {
case 'B':
@@ -319,52 +330,38 @@ public class ClassReader {
case 'S':
case 'Z':
case 's':
- reader.u2(); // constValueIndex
- break;
+ {
+ int constValueIndex = reader.u2();
+ return new ConstValue(constantPool.constant(constValueIndex));
+ }
case 'e':
{
int typeNameIndex = reader.u2();
int constNameIndex = reader.u2();
- if (value) {
- String typeName = constantPool.utf8(typeNameIndex);
- switch (typeName) {
- case "Ljava/lang/annotation/RetentionPolicy;":
- case "Ljava/lang/annotation/ElementType;":
- String constName = constantPool.utf8(constNameIndex);
- return new EnumConstValue(typeName, constName);
- default:
- break;
- }
- }
- break;
+ String typeName = constantPool.utf8(typeNameIndex);
+ String constName = constantPool.utf8(constNameIndex);
+ return new EnumConstValue(typeName, constName);
}
case 'c':
- int classInfoIndex = reader.u2();
- String className = constantPool.utf8(classInfoIndex);
- return new ConstClassValue(className);
+ {
+ int classInfoIndex = reader.u2();
+ String className = constantPool.utf8(classInfoIndex);
+ return new ConstClassValue(className);
+ }
case '@':
- readAnnotation(constantPool);
- break;
+ return new AnnotationValue(readAnnotation(constantPool));
case '[':
{
int numValues = reader.u2();
- if (value) {
- ImmutableList.Builder<ElementValue> elements = ImmutableList.builder();
- for (int i = 0; i < numValues; i++) {
- elements.add(readElementValue(constantPool, true));
- }
- return new ElementValue.ArrayValue(elements.build());
- } else {
- for (int i = 0; i < numValues; i++) {
- readElementValue(constantPool, false);
- }
+ ImmutableList.Builder<ElementValue> elements = ImmutableList.builder();
+ for (int i = 0; i < numValues; i++) {
+ elements.add(readElementValue(constantPool));
}
- break;
+ return new ElementValue.ArrayValue(elements.build());
}
- default:
- throw error("bad tag value %c", tag);
+ default: // fall out
}
- return null;
+ throw new AssertionError(String.format("bad tag value %c", tag));
}
/** Reads JVMS 4.6 method_infos. */
@@ -380,6 +377,11 @@ public class ClassReader {
int attributesCount = reader.u2();
String signature = null;
ImmutableList<String> exceptions = ImmutableList.of();
+ ImmutableList.Builder<ClassFile.AnnotationInfo> annotations = ImmutableList.builder();
+ List<ImmutableList.Builder<ClassFile.AnnotationInfo>> parameterAnnotationsBuilder =
+ new ArrayList<>();
+ ImmutableList.Builder<ParameterInfo> parameters = ImmutableList.builder();
+ ElementValue defaultValue = null;
for (int j = 0; j < attributesCount; j++) {
String attributeName = constantPool.utf8(reader.u2());
switch (attributeName) {
@@ -389,11 +391,31 @@ public class ClassReader {
case "Signature":
signature = readSignature(constantPool);
break;
+ case "AnnotationDefault":
+ reader.u4(); // length
+ defaultValue = readElementValue(constantPool);
+ break;
+ case "RuntimeInvisibleAnnotations":
+ case "RuntimeVisibleAnnotations":
+ readAnnotations(annotations, constantPool);
+ break;
+ case "RuntimeInvisibleParameterAnnotations":
+ case "RuntimeVisibleParameterAnnotations":
+ readParameterAnnotations(parameterAnnotationsBuilder, constantPool);
+ break;
+ case "MethodParameters":
+ readMethodParameters(parameters, constantPool);
+ break;
default:
reader.skip(reader.u4());
break;
}
}
+ ImmutableList.Builder<ImmutableList<AnnotationInfo>> parameterAnnotations =
+ ImmutableList.builder();
+ for (ImmutableList.Builder<AnnotationInfo> x : parameterAnnotationsBuilder) {
+ parameterAnnotations.add(x.build());
+ }
methods.add(
new ClassFile.MethodInfo(
accessFlags,
@@ -401,11 +423,11 @@ public class ClassReader {
desc,
signature,
exceptions,
- null,
- ImmutableList.of(),
- ImmutableList.of(),
- ImmutableList.of(),
- ImmutableList.of()));
+ defaultValue,
+ annotations.build(),
+ parameterAnnotations.build(),
+ /* typeAnnotations= */ ImmutableList.of(),
+ parameters.build()));
}
return methods;
}
diff --git a/java/com/google/turbine/bytecode/ConstantPoolReader.java b/java/com/google/turbine/bytecode/ConstantPoolReader.java
index b6a2091..ffcb4c3 100644
--- a/java/com/google/turbine/bytecode/ConstantPoolReader.java
+++ b/java/com/google/turbine/bytecode/ConstantPoolReader.java
@@ -163,6 +163,8 @@ public class ConstantPoolReader {
return new Const.IntValue(reader.readInt());
case CONSTANT_STRING:
return new Const.StringValue(utf8(reader.readUnsignedShort()));
+ case CONSTANT_UTF8:
+ return new Const.StringValue(reader.readUTF());
default:
throw new AssertionError(String.format("bad tag: %x", tag));
}
diff --git a/java/com/google/turbine/bytecode/sig/SigParser.java b/java/com/google/turbine/bytecode/sig/SigParser.java
index 1db0dce..033fa18 100644
--- a/java/com/google/turbine/bytecode/sig/SigParser.java
+++ b/java/com/google/turbine/bytecode/sig/SigParser.java
@@ -145,7 +145,8 @@ public class SigParser {
return tyParams.build();
}
- private TySig parseType() {
+ /** Parses a type signature. */
+ public TySig parseType() {
switch (peek()) {
case 'Z':
eat();
diff --git a/java/com/google/turbine/deps/Dependencies.java b/java/com/google/turbine/deps/Dependencies.java
index a3c654e..f76efe7 100644
--- a/java/com/google/turbine/deps/Dependencies.java
+++ b/java/com/google/turbine/deps/Dependencies.java
@@ -16,7 +16,6 @@
package com.google.turbine.deps;
-import com.google.common.base.Optional;
import com.google.common.base.Predicates;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
@@ -40,6 +39,7 @@ import java.nio.file.Paths;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashSet;
+import java.util.Optional;
import java.util.Set;
/** Support for Bazel jdeps dependency output. */
diff --git a/java/com/google/turbine/diag/TurbineDiagnostic.java b/java/com/google/turbine/diag/TurbineDiagnostic.java
new file mode 100644
index 0000000..0404a8e
--- /dev/null
+++ b/java/com/google/turbine/diag/TurbineDiagnostic.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.turbine.diag;
+
+import static com.google.common.base.MoreObjects.firstNonNull;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.base.CharMatcher;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import com.google.turbine.binder.sym.ClassSymbol;
+import com.google.turbine.diag.TurbineError.ErrorKind;
+import java.util.Objects;
+
+/** A compilation error. */
+public class TurbineDiagnostic {
+
+ private final ErrorKind kind;
+ private final String diagnostic;
+ private final ImmutableList<Object> args;
+
+ private TurbineDiagnostic(ErrorKind kind, String diagnostic, ImmutableList<Object> args) {
+ this.kind = requireNonNull(kind);
+ this.diagnostic = requireNonNull(diagnostic);
+ this.args = requireNonNull(args);
+ }
+
+ /** The diagnostic kind. */
+ public ErrorKind kind() {
+ return kind;
+ }
+
+ /** The diagnostic message. */
+ public String diagnostic() {
+ return diagnostic;
+ }
+
+ /** The diagnostic arguments. */
+ public ImmutableList<Object> args() {
+ return args;
+ }
+
+ private static TurbineDiagnostic create(
+ ErrorKind kind, String diagnostic, ImmutableList<Object> args) {
+ switch (kind) {
+ case SYMBOL_NOT_FOUND:
+ {
+ checkArgument(
+ args.size() == 1 && getOnlyElement(args) instanceof ClassSymbol,
+ "diagnostic (%s) has invalid argument args %s",
+ diagnostic,
+ args);
+ break;
+ }
+ default: // fall out
+ }
+ return new TurbineDiagnostic(kind, diagnostic, args);
+ }
+
+ /**
+ * Formats a diagnostic.
+ *
+ * @param source the current source file
+ * @param kind the error kind
+ * @param args format args
+ */
+ public static TurbineDiagnostic format(SourceFile source, ErrorKind kind, Object... args) {
+ String path = firstNonNull(source.path(), "<>");
+ String message = kind.format(args);
+ String diagnostic = path + ": error: " + message.trim() + System.lineSeparator();
+ return create(kind, diagnostic, ImmutableList.copyOf(args));
+ }
+
+ /**
+ * Formats a diagnostic.
+ *
+ * @param position the diagnostic position
+ * @param kind the error kind
+ * @param args format args
+ */
+ public static TurbineDiagnostic format(
+ SourceFile source, int position, ErrorKind kind, Object... args) {
+ String path = firstNonNull(source.path(), "<>");
+ LineMap lineMap = LineMap.create(source.source());
+ int lineNumber = lineMap.lineNumber(position);
+ int column = lineMap.column(position);
+ String message = kind.format(args);
+
+ StringBuilder sb = new StringBuilder(path).append(":");
+ sb.append(lineNumber).append(": error: ");
+ sb.append(message.trim()).append(System.lineSeparator());
+ sb.append(CharMatcher.breakingWhitespace().trimTrailingFrom(lineMap.line(position)))
+ .append(System.lineSeparator());
+ sb.append(Strings.repeat(" ", column)).append('^');
+ String diagnostic = sb.toString();
+ return create(kind, diagnostic, ImmutableList.copyOf(args));
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(diagnostic, kind);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof TurbineDiagnostic)) {
+ return false;
+ }
+ TurbineDiagnostic that = (TurbineDiagnostic) obj;
+ return diagnostic.equals(that.diagnostic) && kind.equals(that.kind);
+ }
+}
diff --git a/java/com/google/turbine/diag/TurbineError.java b/java/com/google/turbine/diag/TurbineError.java
index cd7d9e1..e13eb44 100644
--- a/java/com/google/turbine/diag/TurbineError.java
+++ b/java/com/google/turbine/diag/TurbineError.java
@@ -16,14 +16,9 @@
package com.google.turbine.diag;
-import static com.google.common.base.MoreObjects.firstNonNull;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.collect.Iterables.getOnlyElement;
+import static java.util.stream.Collectors.joining;
-import com.google.common.base.CharMatcher;
-import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
-import com.google.turbine.binder.sym.ClassSymbol;
/** A compilation error. */
public class TurbineError extends Error {
@@ -33,6 +28,9 @@ public class TurbineError extends Error {
UNEXPECTED_INPUT("unexpected input: %c"),
UNEXPECTED_IDENTIFIER("unexpected identifier '%s'"),
UNEXPECTED_EOF("unexpected end of input"),
+ UNTERMINATED_STRING("unterminated string literal"),
+ UNTERMINATED_CHARACTER_LITERAL("unterminated char literal"),
+ EMPTY_CHARACTER_LITERAL("empty char literal"),
EXPECTED_TOKEN("expected token %s"),
INVALID_LITERAL("invalid literal: %s"),
UNEXPECTED_TYPE_PARAMETER("unexpected type parameter %s"),
@@ -68,10 +66,7 @@ public class TurbineError extends Error {
* @param args format args
*/
public static TurbineError format(SourceFile source, ErrorKind kind, Object... args) {
- String path = firstNonNull(source.path(), "<>");
- String message = kind.format(args);
- String diagnostic = path + ": error: " + message.trim() + System.lineSeparator();
- return new TurbineError(kind, diagnostic, ImmutableList.copyOf(args));
+ return new TurbineError(ImmutableList.of(TurbineDiagnostic.format(source, kind, args)));
}
/**
@@ -83,50 +78,18 @@ public class TurbineError extends Error {
*/
public static TurbineError format(
SourceFile source, int position, ErrorKind kind, Object... args) {
- String path = firstNonNull(source.path(), "<>");
- LineMap lineMap = LineMap.create(source.source());
- int lineNumber = lineMap.lineNumber(position);
- int column = lineMap.column(position);
- String message = kind.format(args);
-
- StringBuilder sb = new StringBuilder(path).append(":");
- sb.append(lineNumber).append(": error: ");
- sb.append(message.trim()).append(System.lineSeparator());
- sb.append(CharMatcher.breakingWhitespace().trimTrailingFrom(lineMap.line(position)))
- .append(System.lineSeparator());
- sb.append(Strings.repeat(" ", column)).append('^');
- String diagnostic = sb.toString();
- return new TurbineError(kind, diagnostic, ImmutableList.copyOf(args));
+ return new TurbineError(
+ ImmutableList.of(TurbineDiagnostic.format(source, position, kind, args)));
}
- private final ErrorKind kind;
- private final ImmutableList<Object> args;
-
- private TurbineError(ErrorKind kind, String diagnostic, ImmutableList<Object> args) {
- super(diagnostic);
- switch (kind) {
- case SYMBOL_NOT_FOUND:
- {
- checkArgument(
- args.size() == 1 && getOnlyElement(args) instanceof ClassSymbol,
- "diagnostic (%s) has invalid argument args %s",
- diagnostic,
- args);
- break;
- }
- default: // fall out
- }
- this.kind = kind;
- this.args = args;
- }
+ private final ImmutableList<TurbineDiagnostic> diagnostics;
- /** The diagnostic kind. */
- public ErrorKind kind() {
- return kind;
+ public TurbineError(ImmutableList<TurbineDiagnostic> diagnostics) {
+ super(diagnostics.stream().map(d -> d.diagnostic()).collect(joining("\n")));
+ this.diagnostics = diagnostics;
}
- /** The diagnostic arguments. */
- public ImmutableList<Object> args() {
- return args;
+ public ImmutableList<TurbineDiagnostic> diagnostics() {
+ return diagnostics;
}
}
diff --git a/java/com/google/turbine/diag/TurbineLog.java b/java/com/google/turbine/diag/TurbineLog.java
new file mode 100644
index 0000000..fd8fc38
--- /dev/null
+++ b/java/com/google/turbine/diag/TurbineLog.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.turbine.diag;
+
+import com.google.common.collect.ImmutableList;
+import com.google.turbine.diag.TurbineError.ErrorKind;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+/** A log that collects diagnostics. */
+public class TurbineLog {
+
+ private final Set<TurbineDiagnostic> errors = new LinkedHashSet<>();
+
+ public TurbineLogWithSource withSource(SourceFile source) {
+ return new TurbineLogWithSource(source);
+ }
+
+ public void maybeThrow() {
+ if (!errors.isEmpty()) {
+ throw new TurbineError(ImmutableList.copyOf(errors));
+ }
+ }
+
+ /** A log for a specific source file. */
+ public class TurbineLogWithSource {
+
+ private final SourceFile source;
+
+ private TurbineLogWithSource(SourceFile source) {
+ this.source = source;
+ }
+
+ public void error(ErrorKind kind, Object... args) {
+ errors.add(TurbineDiagnostic.format(source, kind, args));
+ }
+
+ public void error(int position, ErrorKind kind, Object... args) {
+ errors.add(TurbineDiagnostic.format(source, position, kind, args));
+ }
+ }
+}
diff --git a/java/com/google/turbine/lower/Lower.java b/java/com/google/turbine/lower/Lower.java
index 04f352e..99b5627 100644
--- a/java/com/google/turbine/lower/Lower.java
+++ b/java/com/google/turbine/lower/Lower.java
@@ -65,12 +65,14 @@ import com.google.turbine.diag.TurbineError;
import com.google.turbine.diag.TurbineError.ErrorKind;
import com.google.turbine.model.Const;
import com.google.turbine.model.TurbineFlag;
+import com.google.turbine.model.TurbineTyKind;
import com.google.turbine.model.TurbineVisibility;
import com.google.turbine.type.AnnoInfo;
import com.google.turbine.type.Type;
import com.google.turbine.type.Type.ArrayTy;
import com.google.turbine.type.Type.ClassTy;
import com.google.turbine.type.Type.ClassTy.SimpleClassTy;
+import com.google.turbine.type.Type.TyKind;
import com.google.turbine.type.Type.TyVar;
import com.google.turbine.type.Type.WildTy;
import com.google.turbine.types.Erasure;
@@ -236,7 +238,7 @@ public class Lower {
private byte[] lower(SourceTypeBoundClass info, ClassSymbol sym, Set<ClassSymbol> symbols) {
int access = classAccess(info);
String name = sig.descriptor(sym);
- String signature = sig.classSignature(info);
+ String signature = sig.classSignature(info, env);
String superName = info.superclass() != null ? sig.descriptor(info.superclass()) : null;
List<String> interfaces = new ArrayList<>();
for (ClassSymbol i : info.interfaces()) {
@@ -672,15 +674,12 @@ public class Lower {
TypePath.root(),
info));
}
- if (p.superClassBound() != null) {
- lowerTypeAnnotations(
- result,
- p.superClassBound(),
- boundTargetType,
- new TypeAnnotationInfo.TypeParameterBoundTarget(typeParameterIndex, 0));
- }
- int boundIndex = 1; // super class bound index is always 0; interface bounds start at 1
- for (Type i : p.interfaceBounds()) {
+ int boundIndex = 0;
+ for (Type i : p.bound().bounds()) {
+ if (boundIndex == 0 && isInterface(i, env)) {
+ // super class bound index is always 0; interface bounds start at 1
+ boundIndex++;
+ }
lowerTypeAnnotations(
result,
i,
@@ -691,6 +690,11 @@ public class Lower {
}
}
+ private boolean isInterface(Type type, Env<ClassSymbol, TypeBoundClass> env) {
+ return type.tyKind() == TyKind.CLASS_TY
+ && env.get(((ClassTy) type).sym()).kind() == TurbineTyKind.INTERFACE;
+ }
+
private void lowerTypeAnnotations(
Builder<TypeAnnotationInfo> result, Type type, TargetType targetType, Target target) {
new LowerTypeAnnotations(result, targetType, target)
@@ -781,7 +785,7 @@ public class Lower {
}
private void lowerClassTypeTypeAnnotations(ClassTy type, TypePath path) {
- for (SimpleClassTy simple : type.classes) {
+ for (SimpleClassTy simple : type.classes()) {
lowerTypeAnnotations(simple.annos(), path);
int idx = 0;
for (Type a : simple.targs()) {
diff --git a/java/com/google/turbine/lower/LowerSignature.java b/java/com/google/turbine/lower/LowerSignature.java
index 5fe3548..fe9b912 100644
--- a/java/com/google/turbine/lower/LowerSignature.java
+++ b/java/com/google/turbine/lower/LowerSignature.java
@@ -19,6 +19,7 @@ package com.google.turbine.lower;
import com.google.common.collect.ImmutableList;
import com.google.turbine.binder.bound.SourceTypeBoundClass;
import com.google.turbine.binder.bound.TypeBoundClass;
+import com.google.turbine.binder.bound.TypeBoundClass.TyVarInfo;
import com.google.turbine.binder.env.Env;
import com.google.turbine.binder.sym.ClassSymbol;
import com.google.turbine.binder.sym.TyVarSymbol;
@@ -32,11 +33,13 @@ import com.google.turbine.bytecode.sig.Sig.TySig;
import com.google.turbine.bytecode.sig.Sig.UpperBoundTySig;
import com.google.turbine.bytecode.sig.SigWriter;
import com.google.turbine.model.TurbineFlag;
+import com.google.turbine.model.TurbineTyKind;
import com.google.turbine.type.Type;
import com.google.turbine.type.Type.ArrayTy;
import com.google.turbine.type.Type.ClassTy;
import com.google.turbine.type.Type.ClassTy.SimpleClassTy;
import com.google.turbine.type.Type.PrimTy;
+import com.google.turbine.type.Type.TyKind;
import com.google.turbine.type.Type.TyVar;
import com.google.turbine.type.Type.WildTy;
import java.util.Iterator;
@@ -84,7 +87,7 @@ public class LowerSignature {
private ClassTySig classTySig(ClassTy t) {
classes.add(t.sym());
ImmutableList.Builder<SimpleClassTySig> classes = ImmutableList.builder();
- Iterator<SimpleClassTy> it = t.classes.iterator();
+ Iterator<SimpleClassTy> it = t.classes().iterator();
SimpleClassTy curr = it.next();
while (curr.targs().isEmpty() && it.hasNext()) {
curr = it.next();
@@ -141,7 +144,7 @@ public class LowerSignature {
if (!needsMethodSig(sym, env, method)) {
return null;
}
- ImmutableList<Sig.TyParamSig> typarams = tyParamSig(method.tyParams());
+ ImmutableList<Sig.TyParamSig> typarams = tyParamSig(method.tyParams(), env);
ImmutableList.Builder<Sig.TySig> fparams = ImmutableList.builder();
for (SourceTypeBoundClass.ParamInfo t : method.parameters()) {
if (t.synthetic()) {
@@ -203,19 +206,19 @@ public class LowerSignature {
* Produces a class signature attribute for a generic class, or {@code null} if the signature is
* unnecessary.
*/
- public String classSignature(SourceTypeBoundClass info) {
+ public String classSignature(SourceTypeBoundClass info, Env<ClassSymbol, TypeBoundClass> env) {
if (!classNeedsSig(info)) {
return null;
}
- ImmutableList<Sig.TyParamSig> typarams = tyParamSig(info.typeParameterTypes());
+ ImmutableList<Sig.TyParamSig> typarams = tyParamSig(info.typeParameterTypes(), env);
ClassTySig xtnd = null;
if (info.superClassType() != null) {
- xtnd = classTySig(info.superClassType());
+ xtnd = classTySig((ClassTy) info.superClassType());
}
ImmutableList.Builder<ClassTySig> impl = ImmutableList.builder();
- for (ClassTy i : info.interfaceTypes()) {
- impl.add(classTySig(i));
+ for (Type i : info.interfaceTypes()) {
+ impl.add(classTySig((ClassTy) i));
}
ClassSig sig = new ClassSig(typarams, xtnd, impl.build());
return SigWriter.classSig(sig);
@@ -235,7 +238,7 @@ public class LowerSignature {
if (ci.superClassType() != null && needsSig(ci.superClassType())) {
return true;
}
- for (ClassTy i : ci.interfaceTypes()) {
+ for (Type i : ci.interfaceTypes()) {
if (needsSig(i)) {
return true;
}
@@ -250,7 +253,7 @@ public class LowerSignature {
return false;
case CLASS_TY:
{
- for (SimpleClassTy s : ((ClassTy) ty).classes) {
+ for (SimpleClassTy s : ((ClassTy) ty).classes()) {
if (!s.targs().isEmpty()) {
return true;
}
@@ -267,31 +270,46 @@ public class LowerSignature {
}
private ImmutableList<Sig.TyParamSig> tyParamSig(
- Map<TyVarSymbol, SourceTypeBoundClass.TyVarInfo> px) {
+ Map<TyVarSymbol, TyVarInfo> px, Env<ClassSymbol, TypeBoundClass> env) {
ImmutableList.Builder<Sig.TyParamSig> result = ImmutableList.builder();
for (Map.Entry<TyVarSymbol, SourceTypeBoundClass.TyVarInfo> entry : px.entrySet()) {
- result.add(tyParamSig(entry.getKey(), entry.getValue()));
+ result.add(tyParamSig(entry.getKey(), entry.getValue(), env));
}
return result.build();
}
- private Sig.TyParamSig tyParamSig(TyVarSymbol sym, SourceTypeBoundClass.TyVarInfo info) {
+ private Sig.TyParamSig tyParamSig(
+ TyVarSymbol sym, SourceTypeBoundClass.TyVarInfo info, Env<ClassSymbol, TypeBoundClass> env) {
+
String identifier = sym.name();
Sig.TySig cbound = null;
- if (info.superClassBound() != null) {
- cbound = signature(info.superClassBound());
- } else if (info.interfaceBounds().isEmpty()) {
+ ImmutableList.Builder<Sig.TySig> ibounds = ImmutableList.builder();
+ if (info.bound().bounds().isEmpty()) {
cbound =
new ClassTySig(
"java/lang", ImmutableList.of(new SimpleClassTySig("Object", ImmutableList.of())));
- }
- ImmutableList.Builder<Sig.TySig> ibounds = ImmutableList.builder();
- for (Type i : info.interfaceBounds()) {
- ibounds.add(signature(i));
+ } else {
+ boolean first = true;
+ for (Type bound : info.bound().bounds()) {
+ TySig sig = signature(bound);
+ if (first) {
+ if (!isInterface(bound, env)) {
+ cbound = sig;
+ continue;
+ }
+ }
+ ibounds.add(sig);
+ first = false;
+ }
}
return new Sig.TyParamSig(identifier, cbound, ibounds.build());
}
+ private boolean isInterface(Type type, Env<ClassSymbol, TypeBoundClass> env) {
+ return type.tyKind() == TyKind.CLASS_TY
+ && env.get(((ClassTy) type).sym()).kind() == TurbineTyKind.INTERFACE;
+ }
+
public String descriptor(ClassSymbol sym) {
classes.add(sym);
return sym.binaryName();
diff --git a/java/com/google/turbine/main/Main.java b/java/com/google/turbine/main/Main.java
index 31a36c4..03a68ce 100644
--- a/java/com/google/turbine/main/Main.java
+++ b/java/com/google/turbine/main/Main.java
@@ -18,7 +18,6 @@ package com.google.turbine.main;
import static java.nio.charset.StandardCharsets.UTF_8;
-import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.hash.Hashing;
import com.google.turbine.binder.Binder;
@@ -30,6 +29,7 @@ import com.google.turbine.binder.JimageClassBinder;
import com.google.turbine.deps.Dependencies;
import com.google.turbine.deps.Transitive;
import com.google.turbine.diag.SourceFile;
+import com.google.turbine.diag.TurbineError;
import com.google.turbine.lower.Lower;
import com.google.turbine.lower.Lower.Lowered;
import com.google.turbine.options.TurbineOptions;
@@ -50,6 +50,7 @@ import java.time.ZoneId;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
+import java.util.Optional;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
@@ -70,7 +71,17 @@ public class Main {
static final Attributes.Name INJECTING_RULE_KIND = new Attributes.Name("Injecting-Rule-Kind");
public static void main(String[] args) throws IOException {
- compile(args);
+ boolean ok;
+ try {
+ ok = compile(args);
+ } catch (TurbineError | UsageException e) {
+ System.err.println(e.getMessage());
+ ok = false;
+ } catch (Throwable turbineCrash) {
+ turbineCrash.printStackTrace();
+ ok = false;
+ }
+ System.exit(ok ? 0 : 1);
}
public static boolean compile(String[] args) throws IOException {
@@ -79,9 +90,7 @@ public class Main {
}
public static boolean compile(TurbineOptions options) throws IOException {
- if (!options.processors().isEmpty()) {
- return false;
- }
+ usage(options);
ImmutableList<CompUnit> units = parseAll(options);
@@ -93,7 +102,7 @@ public class Main {
ClassPath classpath = ClassPathBinder.bindClasspath(toPaths(reducedClasspath));
BindingResult bound =
- Binder.bind(units, classpath, bootclasspath, /* moduleVersion=*/ Optional.absent());
+ Binder.bind(units, classpath, bootclasspath, /* moduleVersion=*/ Optional.empty());
// TODO(cushon): parallelize
Lowered lowered = Lower.lowerAll(bound.units(), bound.modules(), bound.classPathEnv());
@@ -113,10 +122,25 @@ public class Main {
return true;
}
+ private static void usage(TurbineOptions options) {
+ if (!options.processors().isEmpty()) {
+ throw new UsageException("--processors is not supported");
+ }
+ if (options.sources().isEmpty() && options.sourceJars().isEmpty()) {
+ throw new UsageException("no sources were provided");
+ }
+ if (options.help()) {
+ throw new UsageException();
+ }
+ if (!options.output().isPresent()) {
+ throw new UsageException("--output is required");
+ }
+ }
+
private static ClassPath bootclasspath(TurbineOptions options) throws IOException {
// if both --release and --bootclasspath are specified, --release wins
if (options.release().isPresent() && options.system().isPresent()) {
- throw new IllegalArgumentException("expected at most one of --release and --system");
+ throw new UsageException("expected at most one of --release and --system");
}
if (options.release().isPresent()) {
@@ -128,7 +152,7 @@ public class Main {
// ... otherwise, search ct.sym for a matching release
ClassPath bootclasspath = CtSymClassBinder.bind(release);
if (bootclasspath == null) {
- throw new IllegalArgumentException("not a supported release: " + release);
+ throw new UsageException("not a supported release: " + release);
}
return bootclasspath;
}
@@ -166,7 +190,7 @@ public class Main {
private static void writeOutput(
TurbineOptions options, Map<String, byte[]> lowered, Map<String, byte[]> transitive)
throws IOException {
- Path path = Paths.get(options.outputFile());
+ Path path = Paths.get(options.output().get());
try (OutputStream os = Files.newOutputStream(path);
BufferedOutputStream bos = new BufferedOutputStream(os, BUFFER_SIZE);
JarOutputStream jos = new JarOutputStream(bos)) {
diff --git a/java/com/google/turbine/main/UsageException.java b/java/com/google/turbine/main/UsageException.java
new file mode 100644
index 0000000..bd1ecba
--- /dev/null
+++ b/java/com/google/turbine/main/UsageException.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2018 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.turbine.main;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.base.Joiner;
+
+/** A command-line usage error. */
+class UsageException extends RuntimeException {
+
+ private static final String[] USAGE = {
+ "",
+ "Usage: turbine [options]",
+ "",
+ "Options:",
+ " --output",
+ " The jar output file.",
+ " --sources",
+ " The sources to compile.",
+ " --source_jars",
+ " jar archives of sources to compile.",
+ " --classpath",
+ " The compilation classpath.",
+ " --bootclasspath",
+ " The compilation bootclasspath.",
+ " --help",
+ " Print this usage statement.",
+ " @<filename>",
+ " Read options and filenames from file.",
+ "",
+ };
+
+ UsageException() {
+ super(buildMessage(null));
+ }
+
+ UsageException(String message) {
+ super(buildMessage(requireNonNull(message)));
+ }
+
+ private static String buildMessage(String message) {
+ StringBuilder builder = new StringBuilder();
+ if (message != null) {
+ builder.append(message).append('\n');
+ }
+ Joiner.on('\n').appendTo(builder, USAGE).append('\n');
+ return builder.toString();
+ }
+}
diff --git a/java/com/google/turbine/model/Const.java b/java/com/google/turbine/model/Const.java
index f683f38..6e41bd2 100644
--- a/java/com/google/turbine/model/Const.java
+++ b/java/com/google/turbine/model/Const.java
@@ -16,6 +16,7 @@
package com.google.turbine.model;
+import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
/**
@@ -24,6 +25,12 @@ import com.google.common.collect.ImmutableList;
*/
public abstract class Const {
+ @Override
+ public abstract int hashCode();
+
+ @Override
+ public abstract boolean equals(Object obj);
+
/** The constant kind. */
public abstract Kind kind();
@@ -36,6 +43,13 @@ public abstract class Const {
ANNOTATION
}
+ /** An invalid constant cast. */
+ public static class ConstCastError extends RuntimeException {
+ public ConstCastError(TurbineConstantTypeKind type, TurbineConstantTypeKind target) {
+ super(String.format("%s cannot be converted to %s", type, target));
+ }
+ }
+
/** Subtypes of {@link Const} for primitive and String literals. */
public abstract static class Value extends Const {
public abstract TurbineConstantTypeKind constantTypeKind();
@@ -46,39 +60,39 @@ public abstract class Const {
}
public IntValue asInteger() {
- throw new AssertionError(constantTypeKind());
+ throw new ConstCastError(constantTypeKind(), TurbineConstantTypeKind.INT);
}
public FloatValue asFloat() {
- throw new AssertionError(constantTypeKind());
+ throw new ConstCastError(constantTypeKind(), TurbineConstantTypeKind.FLOAT);
}
public DoubleValue asDouble() {
- throw new AssertionError(constantTypeKind());
+ throw new ConstCastError(constantTypeKind(), TurbineConstantTypeKind.DOUBLE);
}
public LongValue asLong() {
- throw new AssertionError(constantTypeKind());
+ throw new ConstCastError(constantTypeKind(), TurbineConstantTypeKind.LONG);
}
public BooleanValue asBoolean() {
- throw new AssertionError(constantTypeKind());
+ throw new ConstCastError(constantTypeKind(), TurbineConstantTypeKind.BOOLEAN);
}
public StringValue asString() {
- throw new AssertionError(constantTypeKind());
+ throw new ConstCastError(constantTypeKind(), TurbineConstantTypeKind.STRING);
}
public CharValue asChar() {
- throw new AssertionError(constantTypeKind());
+ throw new ConstCastError(constantTypeKind(), TurbineConstantTypeKind.CHAR);
}
public ShortValue asShort() {
- throw new AssertionError(constantTypeKind());
+ throw new ConstCastError(constantTypeKind(), TurbineConstantTypeKind.SHORT);
}
public ByteValue asByte() {
- throw new AssertionError(constantTypeKind());
+ throw new ConstCastError(constantTypeKind(), TurbineConstantTypeKind.BYTE);
}
}
@@ -113,6 +127,16 @@ public abstract class Const {
public StringValue asString() {
return new StringValue(String.valueOf(value));
}
+
+ @Override
+ public int hashCode() {
+ return Boolean.hashCode(value);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof BooleanValue && value == ((BooleanValue) obj).value();
+ }
}
/** An int literal value. */
@@ -177,6 +201,16 @@ public abstract class Const {
public StringValue asString() {
return new StringValue(String.valueOf(value));
}
+
+ @Override
+ public int hashCode() {
+ return Integer.hashCode(value);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof IntValue && value == ((IntValue) obj).value;
+ }
}
/** A long literal value. */
@@ -240,6 +274,16 @@ public abstract class Const {
public StringValue asString() {
return new StringValue(String.valueOf(value));
}
+
+ @Override
+ public int hashCode() {
+ return Long.hashCode(value);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof LongValue && value == ((LongValue) obj).value;
+ }
}
/** A char literal value. */
@@ -303,6 +347,16 @@ public abstract class Const {
public StringValue asString() {
return new StringValue(String.valueOf(value));
}
+
+ @Override
+ public int hashCode() {
+ return Character.hashCode(value);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof CharValue && value == ((CharValue) obj).value;
+ }
}
/** A float literal value. */
@@ -366,6 +420,16 @@ public abstract class Const {
public StringValue asString() {
return new StringValue(String.valueOf(value));
}
+
+ @Override
+ public int hashCode() {
+ return Float.hashCode(value);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof FloatValue && value == ((FloatValue) obj).value;
+ }
}
/** A double literal value. */
@@ -429,6 +493,16 @@ public abstract class Const {
public StringValue asString() {
return new StringValue(String.valueOf(value));
}
+
+ @Override
+ public int hashCode() {
+ return Double.hashCode(value);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof DoubleValue && value == ((DoubleValue) obj).value;
+ }
}
/** A String literal value. */
@@ -457,6 +531,16 @@ public abstract class Const {
public StringValue asString() {
return this;
}
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof StringValue && value.equals(((StringValue) obj).value);
+ }
}
/** A short literal value. */
@@ -520,6 +604,16 @@ public abstract class Const {
public StringValue asString() {
return new StringValue(String.valueOf(value));
}
+
+ @Override
+ public int hashCode() {
+ return Short.hashCode(value);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof ShortValue && value == ((ShortValue) obj).value;
+ }
}
/** A byte literal value. */
@@ -579,6 +673,21 @@ public abstract class Const {
public StringValue asString() {
return new StringValue(String.valueOf(value));
}
+
+ @Override
+ public int hashCode() {
+ return Byte.hashCode(value);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof ByteValue && value == ((ByteValue) obj).value;
+ }
+
+ @Override
+ public String toString() {
+ return String.valueOf(value);
+ }
}
/** A constant array literal (e.g. in an annotation). */
@@ -598,5 +707,20 @@ public abstract class Const {
public ImmutableList<Const> elements() {
return elements;
}
+
+ @Override
+ public int hashCode() {
+ return elements.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof ArrayInitValue && elements.equals(((ArrayInitValue) obj).elements);
+ }
+
+ @Override
+ public String toString() {
+ return "{" + Joiner.on(", ").join(elements) + "}";
+ }
}
}
diff --git a/java/com/google/turbine/model/TurbineElementType.java b/java/com/google/turbine/model/TurbineElementType.java
new file mode 100644
index 0000000..a68df3a
--- /dev/null
+++ b/java/com/google/turbine/model/TurbineElementType.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2018 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.turbine.model;
+
+/** Program locations where an annotation may appear. */
+public enum TurbineElementType {
+ ANNOTATION_TYPE,
+ CONSTRUCTOR,
+ FIELD,
+ LOCAL_VARIABLE,
+ METHOD,
+ MODULE,
+ PACKAGE,
+ PARAMETER,
+ TYPE,
+ TYPE_PARAMETER,
+ TYPE_USE
+}
diff --git a/java/com/google/turbine/options/TurbineOptions.java b/java/com/google/turbine/options/TurbineOptions.java
index 04458e6..3bc9755 100644
--- a/java/com/google/turbine/options/TurbineOptions.java
+++ b/java/com/google/turbine/options/TurbineOptions.java
@@ -18,15 +18,15 @@ package com.google.turbine.options;
import static com.google.common.base.Preconditions.checkNotNull;
-import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
+import java.util.Optional;
import javax.annotation.Nullable;
/** Header compilation options. */
public class TurbineOptions {
- private final String output;
+ private final Optional<String> output;
private final ImmutableList<String> classPath;
private final ImmutableSet<String> bootClassPath;
private final Optional<String> release;
@@ -41,15 +41,16 @@ public class TurbineOptions {
private final Optional<String> injectingRuleKind;
private final ImmutableList<String> depsArtifacts;
private final boolean javacFallback;
+ private final boolean help;
private final ImmutableList<String> javacOpts;
private final boolean shouldReduceClassPath;
private TurbineOptions(
- String output,
+ @Nullable String output,
ImmutableList<String> classPath,
ImmutableSet<String> bootClassPath,
- String release,
- String system,
+ @Nullable String release,
+ @Nullable String system,
ImmutableList<String> sources,
ImmutableList<String> processorPath,
ImmutableSet<String> processors,
@@ -60,23 +61,25 @@ public class TurbineOptions {
@Nullable String injectingRuleKind,
ImmutableList<String> depsArtifacts,
boolean javacFallback,
+ boolean help,
ImmutableList<String> javacOpts,
boolean shouldReduceClassPath) {
- this.output = checkNotNull(output, "output must not be null");
+ this.output = Optional.ofNullable(output);
this.classPath = checkNotNull(classPath, "classPath must not be null");
this.bootClassPath = checkNotNull(bootClassPath, "bootClassPath must not be null");
- this.release = Optional.fromNullable(release);
- this.system = Optional.fromNullable(system);
+ this.release = Optional.ofNullable(release);
+ this.system = Optional.ofNullable(system);
this.sources = checkNotNull(sources, "sources must not be null");
this.processorPath = checkNotNull(processorPath, "processorPath must not be null");
this.processors = checkNotNull(processors, "processors must not be null");
this.sourceJars = checkNotNull(sourceJars, "sourceJars must not be null");
- this.outputDeps = Optional.fromNullable(outputDeps);
+ this.outputDeps = Optional.ofNullable(outputDeps);
this.directJars = checkNotNull(directJars, "directJars must not be null");
- this.targetLabel = Optional.fromNullable(targetLabel);
- this.injectingRuleKind = Optional.fromNullable(injectingRuleKind);
+ this.targetLabel = Optional.ofNullable(targetLabel);
+ this.injectingRuleKind = Optional.ofNullable(injectingRuleKind);
this.depsArtifacts = checkNotNull(depsArtifacts, "depsArtifacts must not be null");
this.javacFallback = javacFallback;
+ this.help = help;
this.javacOpts = checkNotNull(javacOpts, "javacOpts must not be null");
this.shouldReduceClassPath = shouldReduceClassPath;
}
@@ -107,10 +110,22 @@ public class TurbineOptions {
}
/** The output jar. */
- public String outputFile() {
+ @Nullable
+ public Optional<String> output() {
return output;
}
+ /**
+ * The output jar.
+ *
+ * @deprecated use {@link #output} instead.
+ */
+ @Deprecated
+ @Nullable
+ public String outputFile() {
+ return output.orElse(null);
+ }
+
/** Paths to annotation processor artifacts. */
public ImmutableList<String> processorPath() {
return processorPath;
@@ -160,6 +175,11 @@ public class TurbineOptions {
return javacFallback;
}
+ /** Print usage information. */
+ public boolean help() {
+ return help;
+ }
+
/** Additional Java compiler flags. */
public ImmutableList<String> javacOpts() {
return javacOpts;
@@ -192,6 +212,7 @@ public class TurbineOptions {
@Nullable private String injectingRuleKind;
private final ImmutableList.Builder<String> depsArtifacts = ImmutableList.builder();
private boolean javacFallback = true;
+ private boolean help = false;
private final ImmutableList.Builder<String> javacOpts = ImmutableList.builder();
private boolean shouldReduceClassPath = true;
@@ -212,6 +233,7 @@ public class TurbineOptions {
injectingRuleKind,
depsArtifacts.build(),
javacFallback,
+ help,
javacOpts.build(),
shouldReduceClassPath);
}
@@ -291,6 +313,11 @@ public class TurbineOptions {
return this;
}
+ public Builder setHelp(boolean help) {
+ this.help = help;
+ return this;
+ }
+
public Builder addAllJavacOpts(Iterable<String> javacOpts) {
this.javacOpts.addAll(javacOpts);
return this;
diff --git a/java/com/google/turbine/options/TurbineOptionsParser.java b/java/com/google/turbine/options/TurbineOptionsParser.java
index f8fd8c3..2976285 100644
--- a/java/com/google/turbine/options/TurbineOptionsParser.java
+++ b/java/com/google/turbine/options/TurbineOptionsParser.java
@@ -116,6 +116,9 @@ public class TurbineOptionsParser {
case "--nojavac_fallback":
builder.setJavacFallback(false);
break;
+ case "--help":
+ builder.setHelp(true);
+ break;
default:
throw new IllegalArgumentException("unknown option: " + next);
}
diff --git a/java/com/google/turbine/parse/ConstExpressionParser.java b/java/com/google/turbine/parse/ConstExpressionParser.java
index 7b0f8c5..c6cb284 100644
--- a/java/com/google/turbine/parse/ConstExpressionParser.java
+++ b/java/com/google/turbine/parse/ConstExpressionParser.java
@@ -18,7 +18,6 @@ package com.google.turbine.parse;
import static com.google.common.collect.Iterables.getOnlyElement;
-import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.CheckReturnValue;
import com.google.turbine.diag.TurbineError;
@@ -29,7 +28,9 @@ import com.google.turbine.tree.Tree;
import com.google.turbine.tree.Tree.ClassLiteral;
import com.google.turbine.tree.Tree.ClassTy;
import com.google.turbine.tree.Tree.Expression;
+import com.google.turbine.tree.Tree.Ident;
import com.google.turbine.tree.TurbineOperatorKind;
+import java.util.Optional;
import javax.annotation.Nullable;
/** A parser for compile-time constant expressions. */
@@ -230,11 +231,10 @@ public class ConstExpressionParser {
}
}
- private static ClassTy asClassTy(int pos, ImmutableList<String> names) {
+ private static ClassTy asClassTy(int pos, ImmutableList<Tree.Ident> names) {
ClassTy cty = null;
- for (String bit : names) {
- cty =
- new ClassTy(pos, Optional.fromNullable(cty), bit, ImmutableList.of(), ImmutableList.of());
+ for (Tree.Ident bit : names) {
+ cty = new ClassTy(pos, Optional.ofNullable(cty), bit, ImmutableList.of(), ImmutableList.of());
}
return cty;
}
@@ -278,7 +278,7 @@ public class ConstExpressionParser {
/** Finish hex, decimal, octal, and binary integer literals (see JLS 3.10.1). */
private Tree.Expression finishLiteral(TurbineConstantTypeKind kind, boolean negate) {
- String text = lexer.stringValue();
+ String text = ident().value();
Const.Value value;
switch (kind) {
case INT:
@@ -422,8 +422,8 @@ public class ConstExpressionParser {
@Nullable
private Tree.Expression qualIdent() {
int pos = position;
- ImmutableList.Builder<String> bits = ImmutableList.builder();
- bits.add(lexer.stringValue());
+ ImmutableList.Builder<Ident> bits = ImmutableList.builder();
+ bits.add(ident());
eat();
if (token == Token.LBRACK) {
return finishClassLiteral(pos, asClassTy(pos, bits.build()));
@@ -432,7 +432,7 @@ public class ConstExpressionParser {
eat();
switch (token) {
case IDENT:
- bits.add(lexer.stringValue());
+ bits.add(ident());
break;
case CLASS:
// TODO(cushon): only allow in annotations?
@@ -446,6 +446,10 @@ public class ConstExpressionParser {
return new Tree.ConstVarName(pos, bits.build());
}
+ private Ident ident() {
+ return new Ident(lexer.position(), lexer.stringValue());
+ }
+
private Expression finishClassLiteral(int pos, Tree.Type type) {
while (token == Token.LBRACK) {
eat();
@@ -518,12 +522,15 @@ public class ConstExpressionParser {
if (!(term1 instanceof Tree.ConstVarName)) {
return null;
}
- ImmutableList<String> names = ((Tree.ConstVarName) term1).name();
+ ImmutableList<Ident> names = ((Tree.ConstVarName) term1).name();
if (names.size() > 1) {
return null;
}
- String name = getOnlyElement(names);
+ Ident name = getOnlyElement(names);
Tree.Expression rhs = expression(op.prec());
+ if (rhs == null) {
+ return null;
+ }
return new Tree.Assign(term1.position(), name, rhs);
}
@@ -560,7 +567,7 @@ public class ConstExpressionParser {
throw new AssertionError();
}
eat();
- ImmutableList<String> name = ((Tree.ConstVarName) qualIdent()).name();
+ ImmutableList<Ident> name = ((Tree.ConstVarName) qualIdent()).name();
ImmutableList.Builder<Tree.Expression> args = ImmutableList.builder();
if (token == Token.LPAREN) {
eat();
diff --git a/java/com/google/turbine/parse/Parser.java b/java/com/google/turbine/parse/Parser.java
index 3858619..ba76659 100644
--- a/java/com/google/turbine/parse/Parser.java
+++ b/java/com/google/turbine/parse/Parser.java
@@ -17,16 +17,12 @@
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.RPAREN;
-import static com.google.turbine.parse.Token.STATIC;
import static com.google.turbine.tree.TurbineModifier.PROTECTED;
import static com.google.turbine.tree.TurbineModifier.PUBLIC;
-import com.google.common.base.Joiner;
-import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.annotations.CheckReturnValue;
@@ -41,6 +37,7 @@ import com.google.turbine.tree.Tree.ArrTy;
import com.google.turbine.tree.Tree.ClassTy;
import com.google.turbine.tree.Tree.CompUnit;
import com.google.turbine.tree.Tree.Expression;
+import com.google.turbine.tree.Tree.Ident;
import com.google.turbine.tree.Tree.ImportDecl;
import com.google.turbine.tree.Tree.Kind;
import com.google.turbine.tree.Tree.MethDecl;
@@ -63,6 +60,7 @@ import java.util.ArrayDeque;
import java.util.Deque;
import java.util.EnumSet;
import java.util.List;
+import java.util.Optional;
import javax.annotation.Nullable;
/**
@@ -95,8 +93,8 @@ public class Parser {
// TODO(cushon): consider enforcing package, import, and declaration order
// and make it bug-compatible with javac:
// http://mail.openjdk.java.net/pipermail/compiler-dev/2013-August/006968.html
- Optional<PkgDecl> pkg = Optional.absent();
- Optional<ModDecl> mod = Optional.absent();
+ Optional<PkgDecl> pkg = Optional.empty();
+ Optional<ModDecl> mod = Optional.empty();
EnumSet<TurbineModifier> access = EnumSet.noneOf(TurbineModifier.class);
ImmutableList.Builder<ImportDecl> imports = ImmutableList.builder();
ImmutableList.Builder<TyDecl> decls = ImmutableList.builder();
@@ -184,14 +182,15 @@ public class Parser {
continue;
case IDENT:
{
- String ident = lexer.stringValue();
- if (access.isEmpty() && (ident.equals("module") || ident.equals("open"))) {
+ Ident ident = ident();
+ if (access.isEmpty()
+ && (ident.value().equals("module") || ident.value().equals("open"))) {
boolean open = false;
- if (ident.equals("open")) {
+ if (ident.value().equals("open")) {
ident = eatIdent();
open = true;
}
- if (!ident.equals("module")) {
+ if (!ident.value().equals("module")) {
throw error(token);
}
next();
@@ -215,7 +214,7 @@ public class Parser {
private TyDecl interfaceDeclaration(EnumSet<TurbineModifier> access, ImmutableList<Anno> annos) {
eat(Token.INTERFACE);
int pos = position;
- String name = eatIdent();
+ Ident name = eatIdent();
ImmutableList<TyParam> typarams;
if (token == Token.LT) {
typarams = typarams();
@@ -238,7 +237,7 @@ public class Parser {
annos,
name,
typarams,
- Optional.<ClassTy>absent(),
+ Optional.<ClassTy>empty(),
interfaces.build(),
members,
TurbineTyKind.INTERFACE);
@@ -247,7 +246,7 @@ public class Parser {
private TyDecl annotationDeclaration(EnumSet<TurbineModifier> access, ImmutableList<Anno> annos) {
eat(Token.INTERFACE);
int pos = position;
- String name = eatIdent();
+ Ident name = eatIdent();
eat(Token.LBRACE);
ImmutableList<Tree> members = classMembers();
eat(Token.RBRACE);
@@ -257,7 +256,7 @@ public class Parser {
annos,
name,
ImmutableList.<TyParam>of(),
- Optional.<ClassTy>absent(),
+ Optional.<ClassTy>empty(),
ImmutableList.<ClassTy>of(),
members,
TurbineTyKind.ANNOTATION);
@@ -266,7 +265,7 @@ public class Parser {
private TyDecl enumDeclaration(EnumSet<TurbineModifier> access, ImmutableList<Anno> annos) {
eat(Token.ENUM);
int pos = position;
- String name = eatIdent();
+ Ident name = eatIdent();
ImmutableList.Builder<ClassTy> interfaces = ImmutableList.builder();
if (token == Token.IMPLEMENTS) {
next();
@@ -284,18 +283,18 @@ public class Parser {
annos,
name,
ImmutableList.<TyParam>of(),
- Optional.<ClassTy>absent(),
+ Optional.<ClassTy>empty(),
interfaces.build(),
members,
TurbineTyKind.ENUM);
}
private String moduleName() {
- return Joiner.on('.').join(qualIdent());
+ return flatname('.', qualIdent());
}
private String packageName() {
- return Joiner.on('/').join(qualIdent());
+ return flatname('/', qualIdent());
}
private ModDecl moduleDeclaration(boolean open, ImmutableList<Anno> annos) {
@@ -340,6 +339,19 @@ public class Parser {
return new ModDecl(pos, annos, open, moduleName, directives.build());
}
+ private String flatname(char join, ImmutableList<Ident> idents) {
+ StringBuilder sb = new StringBuilder();
+ boolean first = true;
+ for (Ident ident : idents) {
+ if (!first) {
+ sb.append(join);
+ }
+ sb.append(ident.value());
+ first = false;
+ }
+ return sb.toString();
+ }
+
private ModRequires moduleRequires() {
int pos = position;
EnumSet<TurbineModifier> access = EnumSet.noneOf(TurbineModifier.class);
@@ -356,6 +368,7 @@ public class Parser {
}
break;
}
+
String moduleName = moduleName();
eat(Token.SEMI);
return new ModRequires(pos, ImmutableSet.copyOf(access), moduleName);
@@ -363,13 +376,14 @@ public class Parser {
private ModExports moduleExports() {
int pos = position;
+
String packageName = packageName();
ImmutableList.Builder<String> moduleNames = ImmutableList.builder();
if (lexer.stringValue().equals("to")) {
next();
do {
- String moduleName = moduleName();
- moduleNames.add(moduleName);
+
+ moduleNames.add(moduleName());
} while (maybe(Token.COMMA));
}
eat(Token.SEMI);
@@ -378,11 +392,13 @@ public class Parser {
private ModOpens moduleOpens() {
int pos = position;
+
String packageName = packageName();
ImmutableList.Builder<String> moduleNames = ImmutableList.builder();
if (lexer.stringValue().equals("to")) {
next();
do {
+
String moduleName = moduleName();
moduleNames.add(moduleName);
} while (maybe(Token.COMMA));
@@ -393,20 +409,20 @@ public class Parser {
private ModUses moduleUses() {
int pos = position;
- ImmutableList<String> uses = qualIdent();
+ ImmutableList<Ident> uses = qualIdent();
eat(Token.SEMI);
return new ModUses(pos, uses);
}
private ModProvides moduleProvides() {
int pos = position;
- ImmutableList<String> typeName = qualIdent();
- if (!eatIdent().equals("with")) {
+ ImmutableList<Ident> typeName = qualIdent();
+ if (!eatIdent().value().equals("with")) {
throw error(token);
}
- ImmutableList.Builder<ImmutableList<String>> implNames = ImmutableList.builder();
+ ImmutableList.Builder<ImmutableList<Ident>> implNames = ImmutableList.builder();
do {
- ImmutableList<String> implName = qualIdent();
+ ImmutableList<Ident> implName = qualIdent();
implNames.add(implName);
} while (maybe(Token.COMMA));
eat(Token.SEMI);
@@ -420,7 +436,7 @@ public class Parser {
TurbineModifier.ACC_ENUM,
TurbineModifier.FINAL);
- private ImmutableList<Tree> enumMembers(String enumName) {
+ private ImmutableList<Tree> enumMembers(Ident enumName) {
ImmutableList.Builder<Tree> result = ImmutableList.builder();
ImmutableList.Builder<Anno> annos = ImmutableList.builder();
OUTER:
@@ -428,7 +444,7 @@ public class Parser {
switch (token) {
case IDENT:
{
- String name = eatIdent();
+ Ident name = eatIdent();
if (token == Token.LPAREN) {
dropParens();
}
@@ -444,12 +460,12 @@ public class Parser {
annos.build(),
new ClassTy(
position,
- Optional.<ClassTy>absent(),
+ Optional.<ClassTy>empty(),
enumName,
ImmutableList.<Type>of(),
ImmutableList.of()),
name,
- Optional.<Expression>absent()));
+ Optional.<Expression>empty()));
annos = ImmutableList.builder();
break;
}
@@ -474,7 +490,7 @@ public class Parser {
private TyDecl classDeclaration(EnumSet<TurbineModifier> access, ImmutableList<Anno> annos) {
eat(Token.CLASS);
int pos = position;
- String name = eatIdent();
+ Ident name = eatIdent();
ImmutableList<TyParam> tyParams = ImmutableList.of();
if (token == Token.LT) {
tyParams = typarams();
@@ -500,7 +516,7 @@ public class Parser {
annos,
name,
tyParams,
- Optional.fromNullable(xtnds),
+ Optional.ofNullable(xtnds),
interfaces.build(),
members,
TurbineTyKind.CLASS);
@@ -624,7 +640,7 @@ public class Parser {
EnumSet<TurbineModifier> access, ImmutableList<Anno> annos) {
ImmutableList<TyParam> typaram = ImmutableList.of();
Type result;
- String name;
+ Ident name;
if (token == Token.LT) {
typaram = typarams();
@@ -660,7 +676,7 @@ public class Parser {
case IDENT:
{
int pos = position;
- String ident = eatIdent();
+ Ident ident = eatIdent();
switch (token) {
case LPAREN:
{
@@ -672,7 +688,7 @@ public class Parser {
result =
new ClassTy(
position,
- Optional.<ClassTy>absent(),
+ Optional.<ClassTy>empty(),
ident,
ImmutableList.<Type>of(),
ImmutableList.of());
@@ -686,7 +702,7 @@ public class Parser {
result =
new ClassTy(
position,
- Optional.<ClassTy>absent(),
+ Optional.<ClassTy>empty(),
ident,
ImmutableList.<Type>of(),
ImmutableList.of());
@@ -697,7 +713,7 @@ public class Parser {
{
result =
new ClassTy(
- position, Optional.<ClassTy>absent(), ident, tyargs(), ImmutableList.of());
+ position, Optional.<ClassTy>empty(), ident, tyargs(), ImmutableList.of());
result = maybeDims(maybeAnnos(), result);
break;
}
@@ -705,7 +721,7 @@ public class Parser {
result =
new ClassTy(
position,
- Optional.<ClassTy>absent(),
+ Optional.<ClassTy>empty(),
ident,
ImmutableList.<Type>of(),
ImmutableList.of());
@@ -764,12 +780,13 @@ public class Parser {
ImmutableList<Anno> annos,
ImmutableList<TyParam> typaram,
Type result,
- String name) {
+ Ident name) {
switch (token) {
case ASSIGN:
- case SEMI:
- case LBRACK:
+ case AT:
case COMMA:
+ case LBRACK:
+ case SEMI:
{
if (!typaram.isEmpty()) {
throw error(ErrorKind.UNEXPECTED_TYPE_PARAMETER, typaram);
@@ -788,7 +805,7 @@ public class Parser {
EnumSet<TurbineModifier> access,
ImmutableList<Anno> annos,
Type baseTy,
- String name) {
+ Ident name) {
ImmutableList.Builder<Tree> result = ImmutableList.builder();
VariableInitializerParser initializerParser = new VariableInitializerParser(token, lexer);
List<List<SavedToken>> bits = initializerParser.parseInitializers();
@@ -810,7 +827,7 @@ public class Parser {
if (init != null && init.kind() == Tree.Kind.ARRAY_INIT) {
init = null;
}
- result.add(new VarDecl(pos, access, annos, ty, name, Optional.fromNullable(init)));
+ result.add(new VarDecl(pos, access, annos, ty, name, Optional.ofNullable(init)));
}
eat(Token.SEMI);
return result.build();
@@ -822,7 +839,7 @@ public class Parser {
ImmutableList<Anno> annos,
ImmutableList<TyParam> typaram,
Type result,
- String name) {
+ Ident name) {
eat(Token.LPAREN);
ImmutableList.Builder<VarDecl> formals = ImmutableList.builder();
formalParams(formals, access);
@@ -863,18 +880,18 @@ public class Parser {
throw error(token);
}
if (result == null) {
- name = CTOR_NAME;
+ name = new Ident(position, CTOR_NAME);
}
return new MethDecl(
pos,
access,
annos,
typaram,
- Optional.<Tree>fromNullable(result),
+ Optional.<Tree>ofNullable(result),
name,
formals.build(),
exceptions.build(),
- Optional.fromNullable(defaultValue));
+ Optional.ofNullable(defaultValue));
}
/**
@@ -948,23 +965,24 @@ public class Parser {
}
// the parameter name is `this` for receiver parameters, and a qualified this expression
// for inner classes
- String name = identOrThis();
+ Ident name = identOrThis();
while (token == Token.DOT) {
eat(Token.DOT);
// Overwrite everything up to the terminal 'this' for inner classes; we don't need it
name = identOrThis();
}
ty = extraDims(ty);
- return new VarDecl(position, access, annos.build(), ty, name, Optional.<Expression>absent());
+ return new VarDecl(position, access, annos.build(), ty, name, Optional.<Expression>empty());
}
- private String identOrThis() {
+ private Ident identOrThis() {
switch (token) {
case IDENT:
return eatIdent();
case THIS:
+ int position = lexer.position();
eat(Token.THIS);
- return "this";
+ return new Ident(position, "this");
default:
throw error(token);
}
@@ -1016,7 +1034,7 @@ public class Parser {
OUTER:
while (true) {
ImmutableList<Anno> annotations = maybeAnnos();
- String name = eatIdent();
+ Ident name = eatIdent();
ImmutableList<Tree> bounds = ImmutableList.of();
if (token == Token.EXTENDS) {
next();
@@ -1059,12 +1077,12 @@ public class Parser {
if (typeAnnos == null) {
typeAnnos = maybeAnnos();
}
- String name = eatIdent();
+ Ident name = eatIdent();
ImmutableList<Type> tyargs = ImmutableList.of();
if (token == Token.LT) {
tyargs = tyargs();
}
- ty = new ClassTy(pos, Optional.fromNullable(ty), name, tyargs, typeAnnos);
+ ty = new ClassTy(pos, Optional.ofNullable(ty), name, tyargs, typeAnnos);
typeAnnos = null;
} while (maybe(Token.DOT));
return ty;
@@ -1085,25 +1103,25 @@ public class Parser {
next();
Type upper = referenceType(maybeAnnos());
acc.add(
- new WildTy(position, typeAnnos, Optional.of(upper), Optional.<Type>absent()));
+ new WildTy(position, typeAnnos, Optional.of(upper), Optional.<Type>empty()));
break;
case SUPER:
next();
Type lower = referenceType(maybeAnnos());
acc.add(
- new WildTy(position, typeAnnos, Optional.<Type>absent(), Optional.of(lower)));
+ new WildTy(position, typeAnnos, Optional.<Type>empty(), Optional.of(lower)));
break;
case COMMA:
acc.add(
new WildTy(
- position, typeAnnos, Optional.<Type>absent(), Optional.<Type>absent()));
+ position, typeAnnos, Optional.<Type>empty(), Optional.<Type>empty()));
continue OUTER;
case GT:
case GTGT:
case GTGTGT:
acc.add(
new WildTy(
- position, typeAnnos, Optional.<Type>absent(), Optional.<Type>absent()));
+ position, typeAnnos, Optional.<Type>empty(), Optional.<Type>empty()));
break OUTER;
default:
throw error(token);
@@ -1257,7 +1275,7 @@ public class Parser {
boolean stat = maybe(Token.STATIC);
int pos = position;
- ImmutableList.Builder<String> type = ImmutableList.builder();
+ ImmutableList.Builder<Ident> type = ImmutableList.builder();
type.add(eatIdent());
boolean wild = false;
OUTER:
@@ -1284,8 +1302,8 @@ public class Parser {
return result;
}
- private ImmutableList<String> qualIdent() {
- ImmutableList.Builder<String> name = ImmutableList.builder();
+ private ImmutableList<Ident> qualIdent() {
+ ImmutableList.Builder<Ident> name = ImmutableList.builder();
name.add(eatIdent());
while (maybe(Token.DOT)) {
name.add(eatIdent());
@@ -1295,7 +1313,7 @@ public class Parser {
private Anno annotation() {
int pos = position;
- ImmutableList<String> name = qualIdent();
+ ImmutableList<Ident> name = qualIdent();
ImmutableList.Builder<Expression> args = ImmutableList.builder();
if (token == Token.LPAREN) {
@@ -1318,10 +1336,16 @@ public class Parser {
return new Anno(pos, name, args.build());
}
- private String eatIdent() {
+ private Ident ident() {
+ int position = lexer.position();
String value = lexer.stringValue();
+ return new Ident(position, value);
+ }
+
+ private Ident eatIdent() {
+ Ident ident = ident();
eat(Token.IDENT);
- return value;
+ return ident;
}
private void eat(Token kind) {
diff --git a/java/com/google/turbine/parse/StreamLexer.java b/java/com/google/turbine/parse/StreamLexer.java
index 35fac45..74b0ce8 100644
--- a/java/com/google/turbine/parse/StreamLexer.java
+++ b/java/com/google/turbine/parse/StreamLexer.java
@@ -339,19 +339,23 @@ public class StreamLexer implements Lexer {
{
eat();
char value;
- if (ch == '\\') {
- eat();
- value = escape();
- } else {
- value = ch;
- eat();
+ switch (ch) {
+ case '\\':
+ eat();
+ value = escape();
+ break;
+ case '\'':
+ throw error(ErrorKind.EMPTY_CHARACTER_LITERAL);
+ default:
+ value = ch;
+ eat();
}
if (ch == '\'') {
saveValue(String.valueOf(value));
eat();
return Token.CHAR_LITERAL;
}
- throw error(ErrorKind.UNEXPECTED_INPUT, ch);
+ throw error(ErrorKind.UNTERMINATED_CHARACTER_LITERAL);
}
case '"':
@@ -370,6 +374,8 @@ public class StreamLexer implements Lexer {
saveValue(sb.toString());
eat();
return Token.STRING_LITERAL;
+ case '\n':
+ throw error(ErrorKind.UNTERMINATED_STRING);
case ASCII_SUB:
if (reader.done()) {
return Token.EOF;
diff --git a/java/com/google/turbine/tree/Pretty.java b/java/com/google/turbine/tree/Pretty.java
index 978be8d..2b9374e 100644
--- a/java/com/google/turbine/tree/Pretty.java
+++ b/java/com/google/turbine/tree/Pretty.java
@@ -22,6 +22,7 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.turbine.tree.Tree.Anno;
import com.google.turbine.tree.Tree.ClassLiteral;
+import com.google.turbine.tree.Tree.Ident;
import com.google.turbine.tree.Tree.ModDecl;
import com.google.turbine.tree.Tree.ModDirective;
import com.google.turbine.tree.Tree.ModExports;
@@ -80,6 +81,12 @@ public class Pretty implements Tree.Visitor<Void, Void> {
}
@Override
+ public Void visitIdent(Ident ident, Void input) {
+ sb.append(ident.value());
+ return null;
+ }
+
+ @Override
public Void visitWildTy(Tree.WildTy wildTy, Void input) {
printAnnos(wildTy.annos());
append('?');
@@ -124,7 +131,7 @@ public class Pretty implements Tree.Visitor<Void, Void> {
append('.');
}
printAnnos(classTy.annos());
- append(classTy.name());
+ append(classTy.name().value());
if (!classTy.tyargs().isEmpty()) {
append('<');
boolean first = true;
@@ -203,7 +210,7 @@ public class Pretty implements Tree.Visitor<Void, Void> {
@Override
public Void visitAssign(Tree.Assign assign, Void input) {
- append(assign.name()).append(" = ");
+ append(assign.name().value()).append(" = ");
assign.expr().accept(this, null);
return null;
}
@@ -280,7 +287,7 @@ public class Pretty implements Tree.Visitor<Void, Void> {
printAnnos(varDecl.annos());
printModifiers(varDecl.mods());
varDecl.ty().accept(this, null);
- append(' ').append(varDecl.name());
+ append(' ').append(varDecl.name().value());
if (varDecl.init().isPresent()) {
append(" = ");
varDecl.init().get().accept(this, null);
@@ -318,7 +325,7 @@ public class Pretty implements Tree.Visitor<Void, Void> {
methDecl.ret().get().accept(this, null);
append(' ');
}
- append(methDecl.name());
+ append(methDecl.name().value());
append('(');
boolean first = true;
for (Tree.VarDecl param : methDecl.params()) {
@@ -393,7 +400,7 @@ public class Pretty implements Tree.Visitor<Void, Void> {
append("@interface");
break;
}
- append(' ').append(tyDecl.name());
+ append(' ').append(tyDecl.name().value());
if (!tyDecl.typarams().isEmpty()) {
append('<');
boolean first = true;
@@ -431,7 +438,7 @@ public class Pretty implements Tree.Visitor<Void, Void> {
if (t instanceof Tree.VarDecl) {
Tree.VarDecl decl = (Tree.VarDecl) t;
if (decl.mods().contains(TurbineModifier.ACC_ENUM)) {
- append(decl.name()).append(',').append('\n');
+ append(decl.name().value()).append(',').append('\n');
continue;
}
}
@@ -503,7 +510,7 @@ public class Pretty implements Tree.Visitor<Void, Void> {
@Override
public Void visitTyParam(Tree.TyParam tyParam, Void input) {
printAnnos(tyParam.annos());
- append(tyParam.name());
+ append(tyParam.name().value());
if (!tyParam.bounds().isEmpty()) {
append(" extends ");
boolean first = true;
@@ -619,7 +626,7 @@ public class Pretty implements Tree.Visitor<Void, Void> {
append(" with").append('\n');
indent += 2;
boolean first = true;
- for (ImmutableList<String> implName : modProvides.implNames()) {
+ for (ImmutableList<Ident> implName : modProvides.implNames()) {
if (!first) {
append(',').append('\n');
}
diff --git a/java/com/google/turbine/tree/Tree.java b/java/com/google/turbine/tree/Tree.java
index a84c776..a20b106 100644
--- a/java/com/google/turbine/tree/Tree.java
+++ b/java/com/google/turbine/tree/Tree.java
@@ -16,13 +16,16 @@
package com.google.turbine.tree;
-import com.google.common.base.Optional;
+import static java.util.Objects.requireNonNull;
+
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
+import com.google.errorprone.annotations.Immutable;
import com.google.turbine.diag.SourceFile;
import com.google.turbine.model.Const;
import com.google.turbine.model.TurbineConstantTypeKind;
import com.google.turbine.model.TurbineTyKind;
+import java.util.Optional;
import java.util.Set;
/** An AST node. */
@@ -49,6 +52,7 @@ public abstract class Tree {
/** Tree kind. */
public enum Kind {
+ IDENT,
WILD_TY,
ARR_TY,
PRIM_TY,
@@ -80,6 +84,37 @@ public abstract class Tree {
MOD_PROVIDES
}
+ /** An identifier. */
+ @Immutable
+ public static class Ident extends Tree {
+
+ private final String value;
+
+ public Ident(int position, String value) {
+ super(position);
+ this.value = value;
+ }
+
+ @Override
+ public Kind kind() {
+ return Kind.IDENT;
+ }
+
+ @Override
+ public <I, O> O accept(Visitor<I, O> visitor, I input) {
+ return visitor.visitIdent(this, input);
+ }
+
+ public String value() {
+ return value;
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+ }
+
/** A type use. */
public abstract static class Type extends Tree {
private final ImmutableList<Anno> annos;
@@ -217,13 +252,13 @@ public abstract class Tree {
/** A class, enum, interface, or annotation {@link Type}. */
public static class ClassTy extends Type {
private final Optional<ClassTy> base;
- private final String name;
+ private final Ident name;
private final ImmutableList<Type> tyargs;
public ClassTy(
int position,
Optional<ClassTy> base,
- String name,
+ Ident name,
ImmutableList<Type> tyargs,
ImmutableList<Anno> annos) {
super(position, annos);
@@ -252,7 +287,7 @@ public abstract class Tree {
}
/** The simple name of the type. */
- public String name() {
+ public Ident name() {
return name;
}
@@ -390,9 +425,9 @@ public abstract class Tree {
/** A JLS 6.5.6.1 simple name that refers to a JSL 4.12.4 constant variable. */
public static class ConstVarName extends Expression {
- private final ImmutableList<String> name;
+ private final ImmutableList<Ident> name;
- public ConstVarName(int position, ImmutableList<String> name) {
+ public ConstVarName(int position, ImmutableList<Ident> name) {
super(position);
this.name = name;
}
@@ -407,7 +442,7 @@ public abstract class Tree {
return visitor.visitConstVarName(this, input);
}
- public ImmutableList<String> name() {
+ public ImmutableList<Ident> name() {
return name;
}
}
@@ -439,13 +474,13 @@ public abstract class Tree {
/** A JLS 15.26 assignment expression. */
public static class Assign extends Expression {
- private final String name;
+ private final Ident name;
private final Expression expr;
- public Assign(int position, String name, Expression expr) {
+ public Assign(int position, Ident name, Expression expr) {
super(position);
- this.name = name;
- this.expr = expr;
+ this.name = requireNonNull(name);
+ this.expr = requireNonNull(expr);
}
@Override
@@ -458,7 +493,7 @@ public abstract class Tree {
return visitor.visitAssign(this, input);
}
- public String name() {
+ public Ident name() {
return name;
}
@@ -583,11 +618,11 @@ public abstract class Tree {
/** A JLS 7.5 import declaration. */
public static class ImportDecl extends Tree {
- private final ImmutableList<String> type;
+ private final ImmutableList<Ident> type;
private final boolean stat;
private final boolean wild;
- public ImportDecl(int position, ImmutableList<String> type, boolean stat, boolean wild) {
+ public ImportDecl(int position, ImmutableList<Ident> type, boolean stat, boolean wild) {
super(position);
this.type = type;
this.stat = stat;
@@ -604,7 +639,7 @@ public abstract class Tree {
return visitor.visitImportDecl(this, input);
}
- public ImmutableList<String> type() {
+ public ImmutableList<Ident> type() {
return type;
}
@@ -624,7 +659,7 @@ public abstract class Tree {
private final ImmutableSet<TurbineModifier> mods;
private final ImmutableList<Anno> annos;
private final Tree ty;
- private final String name;
+ private final Ident name;
private final Optional<Expression> init;
public VarDecl(
@@ -632,7 +667,7 @@ public abstract class Tree {
Set<TurbineModifier> mods,
ImmutableList<Anno> annos,
Tree ty,
- String name,
+ Ident name,
Optional<Expression> init) {
super(position);
this.mods = ImmutableSet.copyOf(mods);
@@ -664,7 +699,7 @@ public abstract class Tree {
return ty;
}
- public String name() {
+ public Ident name() {
return name;
}
@@ -679,7 +714,7 @@ public abstract class Tree {
private final ImmutableList<Anno> annos;
private final ImmutableList<TyParam> typarams;
private final Optional<Tree> ret;
- private final String name;
+ private final Ident name;
private final ImmutableList<VarDecl> params;
private final ImmutableList<ClassTy> exntys;
private final Optional<Tree> defaultValue;
@@ -690,7 +725,7 @@ public abstract class Tree {
ImmutableList<Anno> annos,
ImmutableList<TyParam> typarams,
Optional<Tree> ret,
- String name,
+ Ident name,
ImmutableList<VarDecl> params,
ImmutableList<ClassTy> exntys,
Optional<Tree> defaultValue) {
@@ -731,7 +766,7 @@ public abstract class Tree {
return ret;
}
- public String name() {
+ public Ident name() {
return name;
}
@@ -750,10 +785,10 @@ public abstract class Tree {
/** A JLS 9.7 annotation. */
public static class Anno extends Tree {
- private final ImmutableList<String> name;
+ private final ImmutableList<Ident> name;
private final ImmutableList<Expression> args;
- public Anno(int position, ImmutableList<String> name, ImmutableList<Expression> args) {
+ public Anno(int position, ImmutableList<Ident> name, ImmutableList<Expression> args) {
super(position);
this.name = name;
this.args = args;
@@ -769,7 +804,7 @@ public abstract class Tree {
return visitor.visitAnno(this, input);
}
- public ImmutableList<String> name() {
+ public ImmutableList<Ident> name() {
return name;
}
@@ -811,7 +846,7 @@ public abstract class Tree {
public static class TyDecl extends Tree {
private final ImmutableSet<TurbineModifier> mods;
private final ImmutableList<Anno> annos;
- private final String name;
+ private final Ident name;
private final ImmutableList<TyParam> typarams;
private final Optional<ClassTy> xtnds;
private final ImmutableList<ClassTy> impls;
@@ -822,7 +857,7 @@ public abstract class Tree {
int position,
Set<TurbineModifier> mods,
ImmutableList<Anno> annos,
- String name,
+ Ident name,
ImmutableList<TyParam> typarams,
Optional<ClassTy> xtnds,
ImmutableList<ClassTy> impls,
@@ -857,7 +892,7 @@ public abstract class Tree {
return annos;
}
- public String name() {
+ public Ident name() {
return name;
}
@@ -884,12 +919,12 @@ public abstract class Tree {
/** A JLS 4.4. type variable declaration. */
public static class TyParam extends Tree {
- private final String name;
+ private final Ident name;
private final ImmutableList<Tree> bounds;
private final ImmutableList<Anno> annos;
public TyParam(
- int position, String name, ImmutableList<Tree> bounds, ImmutableList<Anno> annos) {
+ int position, Ident name, ImmutableList<Tree> bounds, ImmutableList<Anno> annos) {
super(position);
this.name = name;
this.bounds = bounds;
@@ -906,7 +941,7 @@ public abstract class Tree {
return visitor.visitTyParam(this, input);
}
- public String name() {
+ public Ident name() {
return name;
}
@@ -921,10 +956,10 @@ public abstract class Tree {
/** A JLS 7.4 package declaration. */
public static class PkgDecl extends Tree {
- private final ImmutableList<String> name;
+ private final ImmutableList<Ident> name;
private final ImmutableList<Anno> annos;
- public PkgDecl(int position, ImmutableList<String> name, ImmutableList<Anno> annos) {
+ public PkgDecl(int position, ImmutableList<Ident> name, ImmutableList<Anno> annos) {
super(position);
this.name = name;
this.annos = annos;
@@ -940,7 +975,7 @@ public abstract class Tree {
return visitor.visitPkgDecl(this, input);
}
- public ImmutableList<String> name() {
+ public ImmutableList<Ident> name() {
return name;
}
@@ -1127,14 +1162,14 @@ public abstract class Tree {
/** A JLS 7.7.3 module uses directive. */
public static class ModUses extends ModDirective {
- private final ImmutableList<String> typeName;
+ private final ImmutableList<Ident> typeName;
- public ModUses(int position, ImmutableList<String> typeName) {
+ public ModUses(int position, ImmutableList<Ident> typeName) {
super(position);
this.typeName = typeName;
}
- public ImmutableList<String> typeName() {
+ public ImmutableList<Ident> typeName() {
return typeName;
}
@@ -1157,23 +1192,23 @@ public abstract class Tree {
/** A JLS 7.7.4 module uses directive. */
public static class ModProvides extends ModDirective {
- private final ImmutableList<String> typeName;
- private final ImmutableList<ImmutableList<String>> implNames;
+ private final ImmutableList<Ident> typeName;
+ private final ImmutableList<ImmutableList<Ident>> implNames;
public ModProvides(
int position,
- ImmutableList<String> typeName,
- ImmutableList<ImmutableList<String>> implNames) {
+ ImmutableList<Ident> typeName,
+ ImmutableList<ImmutableList<Ident>> implNames) {
super(position);
this.typeName = typeName;
this.implNames = implNames;
}
- public ImmutableList<String> typeName() {
+ public ImmutableList<Ident> typeName() {
return typeName;
}
- public ImmutableList<ImmutableList<String>> implNames() {
+ public ImmutableList<ImmutableList<Ident>> implNames() {
return implNames;
}
@@ -1195,6 +1230,8 @@ public abstract class Tree {
/** A visitor for {@link Tree}s. */
public interface Visitor<I, O> {
+ O visitIdent(Ident ident, I input);
+
O visitWildTy(WildTy visitor, I input);
O visitArrTy(ArrTy arrTy, I input);
diff --git a/java/com/google/turbine/type/AnnoInfo.java b/java/com/google/turbine/type/AnnoInfo.java
index c564f48..9c907aa 100644
--- a/java/com/google/turbine/type/AnnoInfo.java
+++ b/java/com/google/turbine/type/AnnoInfo.java
@@ -16,8 +16,6 @@
package com.google.turbine.type;
-import static java.util.Objects.requireNonNull;
-
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.turbine.binder.sym.ClassSymbol;
@@ -26,6 +24,7 @@ import com.google.turbine.model.Const;
import com.google.turbine.tree.Tree;
import com.google.turbine.tree.Tree.Anno;
import com.google.turbine.tree.Tree.Expression;
+import java.util.Objects;
/** An annotation use. */
public class AnnoInfo {
@@ -37,7 +36,7 @@ public class AnnoInfo {
public AnnoInfo(
SourceFile source, ClassSymbol sym, Anno tree, ImmutableMap<String, Const> values) {
this.source = source;
- this.sym = requireNonNull(sym);
+ this.sym = sym;
this.tree = tree;
this.values = values;
}
@@ -70,4 +69,18 @@ public class AnnoInfo {
public AnnoInfo withValues(ImmutableMap<String, Const> values) {
return new AnnoInfo(source, sym, tree, values);
}
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(sym, values);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof AnnoInfo)) {
+ return false;
+ }
+ AnnoInfo that = (AnnoInfo) obj;
+ return sym.equals(that.sym) && values.equals(that.values);
+ }
}
diff --git a/java/com/google/turbine/type/Type.java b/java/com/google/turbine/type/Type.java
index 61a5bbe..3bf47d6 100644
--- a/java/com/google/turbine/type/Type.java
+++ b/java/com/google/turbine/type/Type.java
@@ -16,8 +16,8 @@
package com.google.turbine.type;
+import com.google.auto.value.AutoValue;
import com.google.common.base.Joiner;
-import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.turbine.binder.sym.ClassSymbol;
import com.google.turbine.binder.sym.TyVarSymbol;
@@ -44,7 +44,11 @@ public interface Type {
/** A type variable type. */
TY_VAR,
/** A wildcard type. */
- WILD_TY
+ WILD_TY,
+ /** An intersection type. */
+ INTERSECTION_TY,
+
+ ERROR_TY
}
/** The type kind. */
@@ -60,7 +64,8 @@ public interface Type {
};
/** A class type. */
- class ClassTy implements Type {
+ @AutoValue
+ abstract class ClassTy implements Type {
/**
* The {@link ClassTy} for {@code java.lang.Object}. There's nothing special about this
@@ -73,11 +78,10 @@ public interface Type {
/** Returns a {@link ClassTy} with no type arguments for the given {@link ClassSymbol}. */
public static ClassTy asNonParametricClassTy(ClassSymbol i) {
- return new ClassTy(
- Arrays.asList(new SimpleClassTy(i, ImmutableList.of(), ImmutableList.of())));
+ return create(Arrays.asList(SimpleClassTy.create(i, ImmutableList.of(), ImmutableList.of())));
}
- public final ImmutableList<SimpleClassTy> classes;
+ public abstract ImmutableList<SimpleClassTy> classes();
/**
* A class type. Qualified types are repesented as a list tuples, each of which contains a
@@ -85,8 +89,8 @@ public interface Type {
*
* @param classes components of a qualified class type, possibly with type arguments.
*/
- public ClassTy(Iterable<SimpleClassTy> classes) {
- this.classes = ImmutableList.copyOf(classes);
+ public static ClassTy create(Iterable<SimpleClassTy> classes) {
+ return new AutoValue_Type_ClassTy(ImmutableList.copyOf(classes));
}
@Override
@@ -96,23 +100,23 @@ public interface Type {
/** The class symbol. */
public ClassSymbol sym() {
- return classes.get(classes.size() - 1).sym;
+ return classes().get(classes().size() - 1).sym();
}
@Override
- public String toString() {
+ public final String toString() {
StringBuilder sb = new StringBuilder();
boolean first = true;
- for (SimpleClassTy c : classes) {
+ for (SimpleClassTy c : classes()) {
if (!first) {
sb.append('.');
- sb.append(c.sym.binaryName().substring(c.sym.binaryName().lastIndexOf('$') + 1));
+ sb.append(c.sym().binaryName().substring(c.sym().binaryName().lastIndexOf('$') + 1));
} else {
- sb.append(c.sym.binaryName());
+ sb.append(c.sym().binaryName());
}
- if (!c.targs.isEmpty()) {
+ if (!c.targs().isEmpty()) {
sb.append('<');
- Joiner.on(',').appendTo(sb, c.targs);
+ Joiner.on(',').appendTo(sb, c.targs());
sb.append('>');
}
first = false;
@@ -121,53 +125,35 @@ public interface Type {
}
/** One element of a qualified {@link ClassTy}. */
- public static class SimpleClassTy {
-
- private final ClassSymbol sym;
- private final ImmutableList<Type> targs;
- private final ImmutableList<AnnoInfo> annos;
+ @AutoValue
+ public abstract static class SimpleClassTy {
- public SimpleClassTy(
+ public static SimpleClassTy create(
ClassSymbol sym, ImmutableList<Type> targs, ImmutableList<AnnoInfo> annos) {
- Preconditions.checkNotNull(sym);
- Preconditions.checkNotNull(targs);
- this.sym = sym;
- this.targs = targs;
- this.annos = annos;
+ return new AutoValue_Type_ClassTy_SimpleClassTy(sym, targs, annos);
}
/** The class symbol of the element. */
- public ClassSymbol sym() {
- return sym;
- }
+ public abstract ClassSymbol sym();
/** The type arguments. */
- public ImmutableList<Type> targs() {
- return targs;
- }
+ public abstract ImmutableList<Type> targs();
/** The type annotations. */
- public ImmutableList<AnnoInfo> annos() {
- return annos;
- }
+ public abstract ImmutableList<AnnoInfo> annos();
}
}
/** An array type. */
- class ArrayTy implements Type {
-
- private final Type elem;
- private final ImmutableList<AnnoInfo> annos;
+ @AutoValue
+ abstract class ArrayTy implements Type {
- public ArrayTy(Type elem, ImmutableList<AnnoInfo> annos) {
- this.elem = elem;
- this.annos = annos;
+ public static ArrayTy create(Type elem, ImmutableList<AnnoInfo> annos) {
+ return new AutoValue_Type_ArrayTy(elem, annos);
}
/** The element type of the array. */
- public Type elementType() {
- return elem;
- }
+ public abstract Type elementType();
@Override
public TyKind tyKind() {
@@ -175,26 +161,19 @@ public interface Type {
}
/** The type annotations. */
- public ImmutableList<AnnoInfo> annos() {
- return annos;
- }
+ public abstract ImmutableList<AnnoInfo> annos();
}
/** A type variable. */
- class TyVar implements Type {
-
- private final TyVarSymbol sym;
- private final ImmutableList<AnnoInfo> annos;
+ @AutoValue
+ abstract class TyVar implements Type {
- public TyVar(TyVarSymbol sym, ImmutableList<AnnoInfo> annos) {
- this.sym = sym;
- this.annos = annos;
+ public static TyVar create(TyVarSymbol sym, ImmutableList<AnnoInfo> annos) {
+ return new AutoValue_Type_TyVar(sym, annos);
}
/** The type variable's symbol. */
- public TyVarSymbol sym() {
- return sym;
- }
+ public abstract TyVarSymbol sym();
@Override
public TyKind tyKind() {
@@ -202,31 +181,24 @@ public interface Type {
}
@Override
- public String toString() {
- return sym.owner() + "#" + sym.name();
+ public final String toString() {
+ return sym().owner() + "#" + sym().name();
}
/** The type annotations. */
- public ImmutableList<AnnoInfo> annos() {
- return annos;
- }
+ public abstract ImmutableList<AnnoInfo> annos();
}
/** A primitive type. */
- class PrimTy implements Type {
+ @AutoValue
+ abstract class PrimTy implements Type {
- private final TurbineConstantTypeKind primtkind;
- private final ImmutableList<AnnoInfo> annos;
-
- public PrimTy(TurbineConstantTypeKind tykind, ImmutableList<AnnoInfo> annos) {
- this.primtkind = tykind;
- this.annos = annos;
+ public static PrimTy create(TurbineConstantTypeKind tykind, ImmutableList<AnnoInfo> annos) {
+ return new AutoValue_Type_PrimTy(tykind, annos);
}
/** The primtive type kind. */
- public TurbineConstantTypeKind primkind() {
- return primtkind;
- }
+ public abstract TurbineConstantTypeKind primkind();
@Override
public TyKind tyKind() {
@@ -234,9 +206,7 @@ public interface Type {
}
/** The type annotations. */
- public ImmutableList<AnnoInfo> annos() {
- return annos;
- }
+ public abstract ImmutableList<AnnoInfo> annos();
}
/** A wildcard type, valid only inside (possibly nested) type arguments. */
@@ -262,26 +232,16 @@ public interface Type {
}
/** An upper-bounded wildcard type. */
- class WildUpperBoundedTy extends WildTy {
+ @AutoValue
+ abstract class WildUpperBoundedTy extends WildTy {
- public final Type bound;
- private final ImmutableList<AnnoInfo> annotations;
-
- public WildUpperBoundedTy(Type bound, ImmutableList<AnnoInfo> annotations) {
- this.bound = bound;
- this.annotations = annotations;
+ public static WildUpperBoundedTy create(Type bound, ImmutableList<AnnoInfo> annotations) {
+ return new AutoValue_Type_WildUpperBoundedTy(annotations, bound);
}
/** The upper bound. */
@Override
- public Type bound() {
- return bound;
- }
-
- @Override
- public ImmutableList<AnnoInfo> annotations() {
- return annotations;
- }
+ public abstract Type bound();
@Override
public BoundKind boundKind() {
@@ -290,40 +250,29 @@ public interface Type {
}
/** An lower-bounded wildcard type. */
- class WildLowerBoundedTy extends WildTy {
+ @AutoValue
+ abstract class WildLowerBoundedTy extends WildTy {
- public final Type bound;
- private final ImmutableList<AnnoInfo> annotations;
-
- public WildLowerBoundedTy(Type bound, ImmutableList<AnnoInfo> annotations) {
- this.bound = bound;
- this.annotations = annotations;
+ public static WildLowerBoundedTy create(Type bound, ImmutableList<AnnoInfo> annotations) {
+ return new AutoValue_Type_WildLowerBoundedTy(annotations, bound);
}
/** The lower bound. */
@Override
- public Type bound() {
- return bound;
- }
+ public abstract Type bound();
@Override
public BoundKind boundKind() {
return BoundKind.LOWER;
}
-
- @Override
- public ImmutableList<AnnoInfo> annotations() {
- return annotations;
- }
}
/** An unbounded wildcard type. */
- class WildUnboundedTy extends WildTy {
-
- private final ImmutableList<AnnoInfo> annotations;
+ @AutoValue
+ abstract class WildUnboundedTy extends WildTy {
- public WildUnboundedTy(ImmutableList<AnnoInfo> annotations) {
- this.annotations = annotations;
+ public static WildUnboundedTy create(ImmutableList<AnnoInfo> annotations) {
+ return new AutoValue_Type_WildUnboundedTy(annotations);
}
@Override
@@ -335,10 +284,34 @@ public interface Type {
public Type bound() {
throw new IllegalStateException();
}
+ }
+
+ /** An intersection type. */
+ @AutoValue
+ abstract class IntersectionTy implements Type {
+
+ public abstract ImmutableList<Type> bounds();
+
+ public static IntersectionTy create(ImmutableList<Type> bounds) {
+ return new AutoValue_Type_IntersectionTy(bounds);
+ }
+
+ @Override
+ public TyKind tyKind() {
+ return TyKind.INTERSECTION_TY;
+ }
+ }
+
+ /** An error type. */
+ @AutoValue
+ abstract class ErrorTy implements Type {
+ public static ErrorTy create() {
+ return new AutoValue_Type_ErrorTy();
+ }
@Override
- public ImmutableList<AnnoInfo> annotations() {
- return annotations;
+ public TyKind tyKind() {
+ return TyKind.ERROR_TY;
}
}
}
diff --git a/java/com/google/turbine/types/Canonicalize.java b/java/com/google/turbine/types/Canonicalize.java
index 98adf57..d3328b7 100644
--- a/java/com/google/turbine/types/Canonicalize.java
+++ b/java/com/google/turbine/types/Canonicalize.java
@@ -30,6 +30,7 @@ import com.google.turbine.type.Type;
import com.google.turbine.type.Type.ArrayTy;
import com.google.turbine.type.Type.ClassTy;
import com.google.turbine.type.Type.ClassTy.SimpleClassTy;
+import com.google.turbine.type.Type.IntersectionTy;
import com.google.turbine.type.Type.TyKind;
import com.google.turbine.type.Type.TyVar;
import com.google.turbine.type.Type.WildTy;
@@ -66,46 +67,72 @@ public class Canonicalize {
/** Canonicalizes the given type. */
public static Type canonicalize(
- SourceFile source, Env<ClassSymbol, TypeBoundClass> env, ClassSymbol base, Type type) {
+ SourceFile source,
+ int position,
+ Env<ClassSymbol, TypeBoundClass> env,
+ ClassSymbol sym,
+ Type type) {
+ return new Canonicalize(source, position, env).canonicalize(sym, type);
+ }
+
+ /** Canonicalize a qualified class type, excluding type arguments. */
+ public static ClassTy canonicalizeClassTy(
+ SourceFile source,
+ int position,
+ Env<ClassSymbol, TypeBoundClass> env,
+ ClassSymbol owner,
+ ClassTy classTy) {
+ return new Canonicalize(source, position, env).canonicalizeClassTy(owner, classTy);
+ }
+
+ private final SourceFile source;
+ private final int position;
+ private final Env<ClassSymbol, TypeBoundClass> env;
+
+ public Canonicalize(SourceFile source, int position, Env<ClassSymbol, TypeBoundClass> env) {
+ this.source = source;
+ this.position = position;
+ this.env = env;
+ }
+
+ private Type canonicalize(ClassSymbol base, Type type) {
switch (type.tyKind()) {
case PRIM_TY:
case VOID_TY:
case TY_VAR:
return type;
case WILD_TY:
- return canonicalizeWildTy(source, env, base, (WildTy) type);
+ return canonicalizeWildTy(base, (WildTy) type);
case ARRAY_TY:
{
Type.ArrayTy arrayTy = (Type.ArrayTy) type;
- return new Type.ArrayTy(
- canonicalize(source, env, base, arrayTy.elementType()), arrayTy.annos());
+ return Type.ArrayTy.create(canonicalize(base, arrayTy.elementType()), arrayTy.annos());
}
case CLASS_TY:
- return canonicalizeClassTy(source, env, base, (ClassTy) type);
+ return canonicalizeClassTy(base, (ClassTy) type);
+ case INTERSECTION_TY:
+ return canonicalizeIntersectionTy(base, (IntersectionTy) type);
default:
throw new AssertionError(type.tyKind());
}
}
- /** Canonicalize a qualified class type, excluding type arguments. */
- private static ClassTy canon(
- SourceFile source, Env<ClassSymbol, TypeBoundClass> env, ClassSymbol base, ClassTy ty) {
- if (isRaw(env, ty)) {
+ private ClassTy canon(ClassSymbol base, ClassTy ty) {
+ if (isRaw(ty)) {
return Erasure.eraseClassTy(ty);
}
// if the first name is a simple name resolved inside a nested class, add explicit qualifiers
// for the enclosing declarations
- Iterator<ClassTy.SimpleClassTy> it = ty.classes.iterator();
- Collection<ClassTy.SimpleClassTy> lexicalBase =
- lexicalBase(source, env, ty.classes.get(0).sym(), base);
+ Iterator<ClassTy.SimpleClassTy> it = ty.classes().iterator();
+ Collection<ClassTy.SimpleClassTy> lexicalBase = lexicalBase(ty.classes().get(0).sym(), base);
ClassTy canon =
!lexicalBase.isEmpty()
- ? new ClassTy(lexicalBase)
- : new ClassTy(Collections.singletonList(it.next()));
+ ? ClassTy.create(lexicalBase)
+ : ClassTy.create(Collections.singletonList(it.next()));
// canonicalize each additional simple name that appeared in source
while (it.hasNext()) {
- canon = canonOne(source, env, canon, it.next());
+ canon = canonOne(canon, it.next());
}
return canon;
}
@@ -113,9 +140,9 @@ public class Canonicalize {
/**
* Qualified type names cannot be partially raw; if any elements are raw erase the entire type.
*/
- private static boolean isRaw(Env<ClassSymbol, TypeBoundClass> env, ClassTy ty) {
- for (ClassTy.SimpleClassTy s : ty.classes.reverse()) {
- TypeBoundClass info = env.get(s.sym());
+ private boolean isRaw(ClassTy ty) {
+ for (ClassTy.SimpleClassTy s : ty.classes().reverse()) {
+ TypeBoundClass info = getInfo(s.sym());
if (s.targs().isEmpty() && !info.typeParameters().isEmpty()) {
return true;
}
@@ -127,50 +154,42 @@ public class Canonicalize {
}
/** Given a base symbol to canonicalize, find any implicit enclosing instances. */
- private static Collection<ClassTy.SimpleClassTy> lexicalBase(
- SourceFile source,
- Env<ClassSymbol, TypeBoundClass> env,
- ClassSymbol first,
- ClassSymbol owner) {
- if ((env.get(first).access() & TurbineFlag.ACC_STATIC) == TurbineFlag.ACC_STATIC) {
+ private Collection<ClassTy.SimpleClassTy> lexicalBase(ClassSymbol first, ClassSymbol owner) {
+
+ if ((getInfo(first).access() & TurbineFlag.ACC_STATIC) == TurbineFlag.ACC_STATIC) {
return Collections.emptyList();
}
- ClassSymbol canonOwner = env.get(first).owner();
+ ClassSymbol canonOwner = getInfo(first).owner();
Deque<ClassTy.SimpleClassTy> result = new ArrayDeque<>();
while (canonOwner != null && owner != null) {
- if (!isSubclass(env, owner, canonOwner)) {
- owner = env.get(owner).owner();
+ if (!isSubclass(owner, canonOwner)) {
+ owner = getInfo(owner).owner();
continue;
}
- result.addFirst(uninstantiated(env, owner));
- if ((env.get(owner).access() & TurbineFlag.ACC_STATIC) == TurbineFlag.ACC_STATIC) {
+ result.addFirst(uninstantiated(owner));
+ if ((getInfo(owner).access() & TurbineFlag.ACC_STATIC) == TurbineFlag.ACC_STATIC) {
break;
}
- TypeBoundClass info = env.get(canonOwner);
- if (info == null) {
- throw TurbineError.format(source, ErrorKind.CLASS_FILE_NOT_FOUND, canonOwner);
- }
- canonOwner = info.owner();
+ canonOwner = getInfo(canonOwner).owner();
}
return result;
}
- private static ClassTy.SimpleClassTy uninstantiated(
- Env<ClassSymbol, TypeBoundClass> env, ClassSymbol owner) {
+ private ClassTy.SimpleClassTy uninstantiated(ClassSymbol owner) {
ImmutableList.Builder<Type> targs = ImmutableList.builder();
- for (TyVarSymbol p : env.get(owner).typeParameterTypes().keySet()) {
- targs.add(new Type.TyVar(p, ImmutableList.of()));
+ for (TyVarSymbol p : getInfo(owner).typeParameterTypes().keySet()) {
+ targs.add(Type.TyVar.create(p, ImmutableList.of()));
}
- return new ClassTy.SimpleClassTy(owner, targs.build(), ImmutableList.of());
+ return ClassTy.SimpleClassTy.create(owner, targs.build(), ImmutableList.of());
}
// is s a subclass (not interface) of t?
- static boolean isSubclass(Env<ClassSymbol, TypeBoundClass> env, ClassSymbol s, ClassSymbol t) {
+ private boolean isSubclass(ClassSymbol s, ClassSymbol t) {
while (s != null) {
if (s.equals(t)) {
return true;
}
- s = env.get(s).superclass();
+ s = getInfo(s).superclass();
}
return false;
}
@@ -179,48 +198,44 @@ public class Canonicalize {
* Adds a simple class type to an existing canonical base class type, and canonicalizes the
* result.
*/
- private static ClassTy canonOne(
- SourceFile source, Env<ClassSymbol, TypeBoundClass> env, ClassTy base, SimpleClassTy ty) {
+ private ClassTy canonOne(ClassTy base, SimpleClassTy ty) {
// if the class is static, it has a trivial canonical qualifier with no type arguments
- if ((env.get(ty.sym()).access() & TurbineFlag.ACC_STATIC) == TurbineFlag.ACC_STATIC) {
- return new ClassTy(Collections.singletonList(ty));
+ if ((getInfo(ty.sym()).access() & TurbineFlag.ACC_STATIC) == TurbineFlag.ACC_STATIC) {
+ return ClassTy.create(ImmutableList.of(ty));
}
ImmutableList.Builder<ClassTy.SimpleClassTy> simples = ImmutableList.builder();
- ClassSymbol owner = env.get(ty.sym()).owner();
+ ClassSymbol owner = getInfo(ty.sym()).owner();
if (owner.equals(base.sym())) {
// if the canonical prefix is the owner the next symbol in the qualified name,
// the type is already in canonical form
- simples.addAll(base.classes);
+ simples.addAll(base.classes());
simples.add(ty);
- return new ClassTy(simples.build());
+ return ClassTy.create(simples.build());
}
// ... otherwise, find the supertype the class was inherited from
// and instantiate it as a member of the current class
ClassTy curr = base;
Map<TyVarSymbol, Type> mapping = new LinkedHashMap<>();
while (curr != null) {
- for (ClassTy.SimpleClassTy s : curr.classes) {
- addInstantiation(env, mapping, s);
+ for (ClassTy.SimpleClassTy s : curr.classes()) {
+ addInstantiation(mapping, s);
}
if (curr.sym().equals(owner)) {
- for (ClassTy.SimpleClassTy s : curr.classes) {
- simples.add(instantiate(env, mapping, s.sym()));
+ for (ClassTy.SimpleClassTy s : curr.classes()) {
+ simples.add(instantiate(mapping, s.sym()));
}
break;
}
- TypeBoundClass info = env.get(curr.sym());
- curr = canon(source, env, info.owner(), info.superClassType());
+ TypeBoundClass info = getInfo(curr.sym());
+ curr = canon(info.owner(), (ClassTy) info.superClassType());
}
simples.add(ty);
- return new ClassTy(simples.build());
+ return ClassTy.create(simples.build());
}
/** Add the type arguments of a simple class type to a type mapping. */
- static void addInstantiation(
- Env<ClassSymbol, TypeBoundClass> env,
- Map<TyVarSymbol, Type> mapping,
- ClassTy.SimpleClassTy simpleType) {
- Collection<TyVarSymbol> symbols = env.get(simpleType.sym()).typeParameters().values();
+ private void addInstantiation(Map<TyVarSymbol, Type> mapping, ClassTy.SimpleClassTy simpleType) {
+ Collection<TyVarSymbol> symbols = getInfo(simpleType.sym()).typeParameters().values();
if (simpleType.targs().isEmpty()) {
// the type is raw
for (TyVarSymbol sym : symbols) {
@@ -241,14 +256,12 @@ public class Canonicalize {
}
/** Instantiate a simple class type for the given symbol, and with the given type mapping. */
- static ClassTy.SimpleClassTy instantiate(
- Env<ClassSymbol, TypeBoundClass> env,
- Map<TyVarSymbol, Type> mapping,
- ClassSymbol classSymbol) {
+ private ClassTy.SimpleClassTy instantiate(
+ Map<TyVarSymbol, Type> mapping, ClassSymbol classSymbol) {
List<Type> args = new ArrayList<>();
- for (TyVarSymbol sym : env.get(classSymbol).typeParameterTypes().keySet()) {
+ for (TyVarSymbol sym : getInfo(classSymbol).typeParameterTypes().keySet()) {
if (!mapping.containsKey(sym)) {
- args.add(new Type.TyVar(sym, ImmutableList.of()));
+ args.add(Type.TyVar.create(sym, ImmutableList.of()));
continue;
}
Type arg = instantiate(mapping, mapping.get(sym));
@@ -259,11 +272,12 @@ public class Canonicalize {
}
args.add(arg);
}
- return new ClassTy.SimpleClassTy(classSymbol, ImmutableList.copyOf(args), ImmutableList.of());
+ return ClassTy.SimpleClassTy.create(
+ classSymbol, ImmutableList.copyOf(args), ImmutableList.of());
}
/** Instantiates a type argument using the given mapping. */
- private static Type instantiate(Map<TyVarSymbol, Type> mapping, Type type) {
+ private Type instantiate(Map<TyVarSymbol, Type> mapping, Type type) {
if (type == null) {
return null;
}
@@ -278,7 +292,7 @@ public class Canonicalize {
case ARRAY_TY:
ArrayTy arrayTy = (ArrayTy) type;
Type elem = instantiate(mapping, arrayTy.elementType());
- return new ArrayTy(elem, arrayTy.annos());
+ return ArrayTy.create(elem, arrayTy.annos());
case TY_VAR:
TyVar tyVar = (TyVar) type;
if (mapping.containsKey(tyVar.sym())) {
@@ -290,29 +304,31 @@ public class Canonicalize {
}
}
- private static Type instantiateWildTy(Map<TyVarSymbol, Type> mapping, WildTy type) {
+ private Type instantiateWildTy(Map<TyVarSymbol, Type> mapping, WildTy type) {
switch (type.boundKind()) {
case NONE:
return type;
case UPPER:
- return new Type.WildUpperBoundedTy(instantiate(mapping, type.bound()), type.annotations());
+ return Type.WildUpperBoundedTy.create(
+ instantiate(mapping, type.bound()), type.annotations());
case LOWER:
- return new Type.WildLowerBoundedTy(instantiate(mapping, type.bound()), type.annotations());
+ return Type.WildLowerBoundedTy.create(
+ instantiate(mapping, type.bound()), type.annotations());
default:
throw new AssertionError(type.boundKind());
}
}
- private static Type instantiateClassTy(Map<TyVarSymbol, Type> mapping, ClassTy type) {
+ private Type instantiateClassTy(Map<TyVarSymbol, Type> mapping, ClassTy type) {
ImmutableList.Builder<SimpleClassTy> simples = ImmutableList.builder();
- for (SimpleClassTy simple : type.classes) {
+ for (SimpleClassTy simple : type.classes()) {
ImmutableList.Builder<Type> args = ImmutableList.builder();
for (Type arg : simple.targs()) {
args.add(instantiate(mapping, arg));
}
- simples.add(new SimpleClassTy(simple.sym(), args.build(), simple.annos()));
+ simples.add(SimpleClassTy.create(simple.sym(), args.build(), simple.annos()));
}
- return new ClassTy(simples.build());
+ return ClassTy.create(simples.build());
}
/**
@@ -320,51 +336,56 @@ public class Canonicalize {
* reference, or else {@code null}.
*/
@Nullable
- private static TyVarSymbol tyVarSym(Type type) {
+ private TyVarSymbol tyVarSym(Type type) {
if (type.tyKind() == TyKind.TY_VAR) {
return ((TyVar) type).sym();
}
return null;
}
- public static ClassTy canonicalizeClassTy(
- SourceFile source, Env<ClassSymbol, TypeBoundClass> env, ClassSymbol base, ClassTy ty) {
+ private ClassTy canonicalizeClassTy(ClassSymbol base, ClassTy ty) {
// canonicalize type arguments first
ImmutableList.Builder<ClassTy.SimpleClassTy> args = ImmutableList.builder();
- for (ClassTy.SimpleClassTy s : ty.classes) {
- args.add(
- new ClassTy.SimpleClassTy(
- s.sym(), canonicalize(source, s.targs(), base, env), s.annos()));
+ for (ClassTy.SimpleClassTy s : ty.classes()) {
+ args.add(SimpleClassTy.create(s.sym(), canonicalize(s.targs(), base), s.annos()));
}
- ty = new ClassTy(args.build());
- return canon(source, env, base, ty);
+ ty = ClassTy.create(args.build());
+ return canon(base, ty);
}
- private static ImmutableList<Type> canonicalize(
- SourceFile source,
- ImmutableList<Type> targs,
- ClassSymbol base,
- Env<ClassSymbol, TypeBoundClass> env) {
+ private ImmutableList<Type> canonicalize(ImmutableList<Type> targs, ClassSymbol base) {
ImmutableList.Builder<Type> result = ImmutableList.builder();
for (Type a : targs) {
- result.add(canonicalize(source, env, base, a));
+ result.add(canonicalize(base, a));
}
return result.build();
}
- private static Type canonicalizeWildTy(
- SourceFile source, Env<ClassSymbol, TypeBoundClass> env, ClassSymbol base, WildTy type) {
+ private Type canonicalizeWildTy(ClassSymbol base, WildTy type) {
switch (type.boundKind()) {
case NONE:
return type;
case LOWER:
- return new Type.WildLowerBoundedTy(
- canonicalize(source, env, base, type.bound()), type.annotations());
+ return Type.WildLowerBoundedTy.create(canonicalize(base, type.bound()), type.annotations());
case UPPER:
- return new Type.WildUpperBoundedTy(
- canonicalize(source, env, base, type.bound()), type.annotations());
- default:
- throw new AssertionError(type.boundKind());
+ return Type.WildUpperBoundedTy.create(canonicalize(base, type.bound()), type.annotations());
+ }
+ throw new AssertionError(type.boundKind());
+ }
+
+ private Type canonicalizeIntersectionTy(ClassSymbol base, IntersectionTy type) {
+ ImmutableList.Builder<Type> bounds = ImmutableList.builder();
+ for (Type bound : type.bounds()) {
+ bounds.add(canonicalize(base, bound));
+ }
+ return IntersectionTy.create(bounds.build());
+ }
+
+ private TypeBoundClass getInfo(ClassSymbol canonOwner) {
+ TypeBoundClass info = env.get(canonOwner);
+ if (info == null) {
+ throw TurbineError.format(source, position, ErrorKind.CLASS_FILE_NOT_FOUND, canonOwner);
}
+ return info;
}
}
diff --git a/java/com/google/turbine/types/Erasure.java b/java/com/google/turbine/types/Erasure.java
index aa55673..e2c7d8f 100644
--- a/java/com/google/turbine/types/Erasure.java
+++ b/java/com/google/turbine/types/Erasure.java
@@ -19,8 +19,13 @@ package com.google.turbine.types;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.turbine.binder.bound.SourceTypeBoundClass;
+import com.google.turbine.binder.bound.TypeBoundClass.TyVarInfo;
import com.google.turbine.binder.sym.TyVarSymbol;
import com.google.turbine.type.Type;
+import com.google.turbine.type.Type.ArrayTy;
+import com.google.turbine.type.Type.ClassTy;
+import com.google.turbine.type.Type.ClassTy.SimpleClassTy;
+import com.google.turbine.type.Type.IntersectionTy;
import com.google.turbine.type.Type.TyVar;
/** Generic type erasure. */
@@ -36,37 +41,38 @@ public class Erasure {
return eraseArrayTy((Type.ArrayTy) ty, tenv);
case TY_VAR:
return eraseTyVar((TyVar) ty, tenv);
+ case INTERSECTION_TY:
+ return eraseIntersectionTy((Type.IntersectionTy) ty, tenv);
default:
throw new AssertionError(ty.tyKind());
}
}
+ private static Type eraseIntersectionTy(
+ IntersectionTy ty, Function<TyVarSymbol, TyVarInfo> tenv) {
+ return erase(ty.bounds().get(0), tenv);
+ }
+
private static Type eraseTyVar(
TyVar ty, Function<TyVarSymbol, SourceTypeBoundClass.TyVarInfo> tenv) {
SourceTypeBoundClass.TyVarInfo info = tenv.apply(ty.sym());
- if (info.superClassBound() != null) {
- return erase(info.superClassBound(), tenv);
- }
- if (!info.interfaceBounds().isEmpty()) {
- return erase(info.interfaceBounds().get(0), tenv);
- }
- return Type.ClassTy.OBJECT;
+ return erase(info.bound(), tenv);
}
private static Type.ArrayTy eraseArrayTy(
Type.ArrayTy ty, Function<TyVarSymbol, SourceTypeBoundClass.TyVarInfo> tenv) {
- return new Type.ArrayTy(erase(ty.elementType(), tenv), ty.annos());
+ return ArrayTy.create(erase(ty.elementType(), tenv), ty.annos());
}
public static Type.ClassTy eraseClassTy(Type.ClassTy ty) {
ImmutableList.Builder<Type.ClassTy.SimpleClassTy> classes = ImmutableList.builder();
- for (Type.ClassTy.SimpleClassTy c : ty.classes) {
+ for (Type.ClassTy.SimpleClassTy c : ty.classes()) {
if (c.targs().isEmpty()) {
classes.add(c);
} else {
- classes.add(new Type.ClassTy.SimpleClassTy(c.sym(), ImmutableList.of(), c.annos()));
+ classes.add(SimpleClassTy.create(c.sym(), ImmutableList.of(), c.annos()));
}
}
- return new Type.ClassTy(classes.build());
+ return ClassTy.create(classes.build());
}
}
diff --git a/javatests/com/google/turbine/binder/BinderErrorTest.java b/javatests/com/google/turbine/binder/BinderErrorTest.java
index 0f37537..f6fb317 100644
--- a/javatests/com/google/turbine/binder/BinderErrorTest.java
+++ b/javatests/com/google/turbine/binder/BinderErrorTest.java
@@ -21,13 +21,13 @@ import static com.google.turbine.testing.TestClassPaths.TURBINE_BOOTCLASSPATH;
import static org.junit.Assert.fail;
import com.google.common.base.Joiner;
-import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.turbine.diag.TurbineError;
import com.google.turbine.parse.Parser;
import com.google.turbine.tree.Tree.CompUnit;
import java.util.Arrays;
import java.util.Collections;
+import java.util.Optional;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -59,11 +59,10 @@ public class BinderErrorTest {
"class B extends A.NoSuch {",
"}",
},
- // TODO(cushon): we'd prefer the caret at NoSuch instead of A
{
"<>:4: error: symbol not found a.A$NoSuch", //
"class B extends A.NoSuch {",
- " ^",
+ " ^",
}
},
{
@@ -84,7 +83,7 @@ public class BinderErrorTest {
"@Anno(foo=100, bar=200) class Test {}",
},
{
- "<>:2: error: could not resolve foo", //
+ "<>:2: error: could not resolve element foo() in Anno", //
"@Anno(foo=100, bar=200) class Test {}",
" ^",
},
@@ -95,7 +94,7 @@ public class BinderErrorTest {
"@Anno(foo=100, bar=200) class Test {}",
},
{
- "<>:2: error: could not resolve bar", //
+ "<>:2: error: could not resolve element bar() in Anno", //
"@Anno(foo=100, bar=200) class Test {}",
" ^",
},
@@ -149,7 +148,10 @@ public class BinderErrorTest {
"<>:4: error: cycle in class hierarchy: p.OuterExtendsInner$Inner"
+ " -> p.OuterExtendsInner$Inner",
" public static class Inner extends Foo {}",
- " ^"
+ " ^",
+ "<>:4: error: could not resolve Foo",
+ " public static class Inner extends Foo {}",
+ " ^",
},
},
{
@@ -162,7 +164,10 @@ public class BinderErrorTest {
{
"<>:2: error: symbol not found java.lang.NoSuch", //
"import java.lang.NoSuch;",
- " ^"
+ " ^",
+ "<>:3: error: could not resolve NoSuch",
+ "public class Test extends NoSuch {",
+ " ^"
},
},
{
@@ -175,7 +180,10 @@ public class BinderErrorTest {
{
"<>:2: error: symbol not found java.util.List$NoSuch", //
"import java.util.List.NoSuch;",
- " ^"
+ " ^",
+ "<>:3: error: could not resolve NoSuch",
+ "public class Test extends NoSuch {",
+ " ^",
},
},
{
@@ -288,7 +296,7 @@ public class BinderErrorTest {
{
"<>:2: error: symbol not found java.lang.Deprecated$NoSuch", //
" @Deprecated.NoSuch int x;",
- " ^",
+ " ^",
},
},
{
@@ -403,6 +411,83 @@ public class BinderErrorTest {
" ^",
},
},
+ {
+ {
+ "class Cycle extends Cycle {", //
+ " NoSuch f;",
+ "}",
+ },
+ {
+ "<>:2: error: could not resolve NoSuch", //
+ " NoSuch f;",
+ " ^",
+ },
+ },
+ {
+ {
+ "@interface Anno { int foo() default 0; }", //
+ "@Anno(Foo.CONST)",
+ "class Foo {",
+ " static final int CONST = 42;",
+ "}",
+ },
+ {
+ "<>:2: error: could not resolve element value() in Anno", //
+ "@Anno(Foo.CONST)",
+ " ^",
+ },
+ },
+ {
+ {
+ "@interface Anno { int foo() default 0; }", //
+ "@Anno(foo = Foo.)",
+ "class Foo {}",
+ },
+ {
+ "<>:2: error: invalid annotation argument", //
+ "@Anno(foo = Foo.)",
+ " ^",
+ },
+ },
+ {
+ {
+ "import java.util.Map;", //
+ "class Foo {",
+ " Map.Entry.NoSuch<List> ys;",
+ "}",
+ },
+ {
+ "<>:3: error: symbol not found java.util.Map$Entry$NoSuch", //
+ " Map.Entry.NoSuch<List> ys;",
+ " ^",
+ },
+ },
+ {
+ {
+ "import java.util.List;", //
+ "class Foo {",
+ " NoSuch<List> xs;",
+ "}",
+ },
+ {
+ "<>:3: error: could not resolve NoSuch", //
+ " NoSuch<List> xs;",
+ " ^",
+ },
+ },
+ {
+ {
+ "import java.util.List;", //
+ "class Foo {",
+ " java.util.NoSuch<List> xs;",
+ "}",
+ },
+ {
+ "<>:3: error: could not resolve java.util.NoSuch", //
+ " java.util.NoSuch<List> xs;",
+ " ^",
+ },
+ },
};
return Arrays.asList((Object[][]) testCases);
}
@@ -422,9 +507,9 @@ public class BinderErrorTest {
ImmutableList.of(parseLines(source)),
ClassPathBinder.bindClasspath(Collections.emptyList()),
TURBINE_BOOTCLASSPATH,
- /* moduleVersion=*/ Optional.absent())
+ /* moduleVersion=*/ Optional.empty())
.units();
- fail();
+ fail(Joiner.on('\n').join(source));
} catch (TurbineError e) {
assertThat(e.getMessage()).isEqualTo(lines(expected));
}
diff --git a/javatests/com/google/turbine/binder/BinderTest.java b/javatests/com/google/turbine/binder/BinderTest.java
index 700baf0..8bf4cd3 100644
--- a/javatests/com/google/turbine/binder/BinderTest.java
+++ b/javatests/com/google/turbine/binder/BinderTest.java
@@ -16,29 +16,31 @@
package com.google.turbine.binder;
+import static com.google.common.collect.Iterables.getOnlyElement;
import static com.google.common.truth.Truth.assertThat;
import static com.google.turbine.testing.TestClassPaths.TURBINE_BOOTCLASSPATH;
import static org.junit.Assert.fail;
import com.google.common.base.Joiner;
-import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.turbine.binder.bound.SourceTypeBoundClass;
+import com.google.turbine.binder.bound.TypeBoundClass.FieldInfo;
import com.google.turbine.binder.sym.ClassSymbol;
import com.google.turbine.diag.TurbineError;
import com.google.turbine.lower.IntegrationTestSupport;
+import com.google.turbine.model.TurbineElementType;
import com.google.turbine.model.TurbineFlag;
import com.google.turbine.parse.Parser;
import com.google.turbine.tree.Tree;
import java.io.OutputStream;
-import java.lang.annotation.ElementType;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import org.junit.Rule;
@@ -76,7 +78,7 @@ public class BinderTest {
units,
ClassPathBinder.bindClasspath(Collections.emptyList()),
TURBINE_BOOTCLASSPATH,
- /* moduleVersion=*/ Optional.absent())
+ /* moduleVersion=*/ Optional.empty())
.units();
assertThat(bound.keySet())
@@ -122,7 +124,7 @@ public class BinderTest {
units,
ClassPathBinder.bindClasspath(Collections.emptyList()),
TURBINE_BOOTCLASSPATH,
- /* moduleVersion=*/ Optional.absent())
+ /* moduleVersion=*/ Optional.empty())
.units();
assertThat(bound.keySet())
@@ -162,7 +164,7 @@ public class BinderTest {
units,
ClassPathBinder.bindClasspath(Collections.emptyList()),
TURBINE_BOOTCLASSPATH,
- /* moduleVersion=*/ Optional.absent())
+ /* moduleVersion=*/ Optional.empty())
.units();
assertThat(bound.get(new ClassSymbol("other/Foo")).superclass())
@@ -192,7 +194,7 @@ public class BinderTest {
units,
ClassPathBinder.bindClasspath(Collections.emptyList()),
TURBINE_BOOTCLASSPATH,
- /* moduleVersion=*/ Optional.absent());
+ /* moduleVersion=*/ Optional.empty());
fail();
} catch (TurbineError e) {
assertThat(e.getMessage()).contains("cycle in class hierarchy: a.A -> b.B -> a.A");
@@ -213,7 +215,7 @@ public class BinderTest {
units,
ClassPathBinder.bindClasspath(Collections.emptyList()),
TURBINE_BOOTCLASSPATH,
- /* moduleVersion=*/ Optional.absent())
+ /* moduleVersion=*/ Optional.empty())
.units();
SourceTypeBoundClass a = bound.get(new ClassSymbol("com/test/Annotation"));
@@ -242,7 +244,7 @@ public class BinderTest {
units,
ClassPathBinder.bindClasspath(Collections.emptyList()),
TURBINE_BOOTCLASSPATH,
- /* moduleVersion=*/ Optional.absent())
+ /* moduleVersion=*/ Optional.empty())
.units();
SourceTypeBoundClass a = bound.get(new ClassSymbol("a/A"));
@@ -282,11 +284,39 @@ public class BinderTest {
units,
ClassPathBinder.bindClasspath(ImmutableList.of(libJar)),
TURBINE_BOOTCLASSPATH,
- /* moduleVersion=*/ Optional.absent())
+ /* moduleVersion=*/ Optional.empty())
.units();
SourceTypeBoundClass a = bound.get(new ClassSymbol("C$A"));
- assertThat(a.annotationMetadata().target()).containsExactly(ElementType.TYPE_USE);
+ assertThat(a.annotationMetadata().target()).containsExactly(TurbineElementType.TYPE_USE);
+ }
+
+ // Test that we don't crash on invalid constant field initializers.
+ // (Error reporting is deferred to javac.)
+ @Test
+ public void invalidConst() throws Exception {
+ List<Tree.CompUnit> units = new ArrayList<>();
+ units.add(
+ parseLines(
+ "package a;", //
+ "public class A {",
+ " public static final boolean b = true == 42;",
+ "}"));
+
+ ImmutableMap<ClassSymbol, SourceTypeBoundClass> bound =
+ Binder.bind(
+ units,
+ ClassPathBinder.bindClasspath(Collections.emptyList()),
+ TURBINE_BOOTCLASSPATH,
+ /* moduleVersion=*/ Optional.empty())
+ .units();
+
+ assertThat(bound.keySet()).containsExactly(new ClassSymbol("a/A"));
+
+ SourceTypeBoundClass a = bound.get(new ClassSymbol("a/A"));
+ FieldInfo f = getOnlyElement(a.fields());
+ assertThat(f.name()).isEqualTo("b");
+ assertThat(f.value()).isNull();
}
private Tree.CompUnit parseLines(String... lines) {
diff --git a/javatests/com/google/turbine/binder/ClassPathBinderTest.java b/javatests/com/google/turbine/binder/ClassPathBinderTest.java
index bd9bde3..0b063d4 100644
--- a/javatests/com/google/turbine/binder/ClassPathBinderTest.java
+++ b/javatests/com/google/turbine/binder/ClassPathBinderTest.java
@@ -16,6 +16,9 @@
package com.google.turbine.binder;
+import static com.google.common.collect.Iterables.getLast;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static com.google.common.collect.MoreCollectors.onlyElement;
import static com.google.common.truth.Truth.assertThat;
import static com.google.turbine.testing.TestClassPaths.TURBINE_BOOTCLASSPATH;
import static java.nio.charset.StandardCharsets.UTF_8;
@@ -24,20 +27,24 @@ import static org.junit.Assert.fail;
import com.google.common.base.VerifyException;
import com.google.common.collect.ImmutableList;
import com.google.common.io.ByteStreams;
-import com.google.turbine.binder.bound.HeaderBoundClass;
+import com.google.turbine.binder.bound.EnumConstantValue;
+import com.google.turbine.binder.bound.TypeBoundClass;
import com.google.turbine.binder.bytecode.BytecodeBoundClass;
import com.google.turbine.binder.env.Env;
import com.google.turbine.binder.lookup.LookupKey;
import com.google.turbine.binder.lookup.LookupResult;
import com.google.turbine.binder.lookup.Scope;
import com.google.turbine.binder.sym.ClassSymbol;
+import com.google.turbine.binder.sym.FieldSymbol;
import com.google.turbine.model.TurbineFlag;
import com.google.turbine.model.TurbineTyKind;
+import com.google.turbine.tree.Tree.Ident;
+import com.google.turbine.type.AnnoInfo;
+import com.google.turbine.type.Type.ClassTy;
import java.io.IOError;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.util.Arrays;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
@@ -54,11 +61,11 @@ public class ClassPathBinderTest {
Scope javaLang = TURBINE_BOOTCLASSPATH.index().lookupPackage(ImmutableList.of("java", "lang"));
- LookupResult result = javaLang.lookup(new LookupKey(Arrays.asList("String")));
+ LookupResult result = javaLang.lookup(new LookupKey(ImmutableList.of(new Ident(-1, "String"))));
assertThat(result.remaining()).isEmpty();
assertThat(result.sym()).isEqualTo(new ClassSymbol("java/lang/String"));
- result = javaLang.lookup(new LookupKey(Arrays.asList("Object")));
+ result = javaLang.lookup(new LookupKey(ImmutableList.of(new Ident(-1, "Object"))));
assertThat(result.remaining()).isEmpty();
assertThat(result.sym()).isEqualTo(new ClassSymbol("java/lang/Object"));
}
@@ -67,7 +74,7 @@ public class ClassPathBinderTest {
public void classPathClasses() throws IOException {
Env<ClassSymbol, BytecodeBoundClass> env = TURBINE_BOOTCLASSPATH.env();
- HeaderBoundClass c = env.get(new ClassSymbol("java/util/Map$Entry"));
+ TypeBoundClass c = env.get(new ClassSymbol("java/util/Map$Entry"));
assertThat(c.owner()).isEqualTo(new ClassSymbol("java/util/Map"));
assertThat(c.kind()).isEqualTo(TurbineTyKind.INTERFACE);
@@ -85,6 +92,39 @@ public class ClassPathBinderTest {
}
@Test
+ public void interfaces() {
+ Env<ClassSymbol, BytecodeBoundClass> env = TURBINE_BOOTCLASSPATH.env();
+
+ TypeBoundClass c = env.get(new ClassSymbol("java/lang/annotation/Retention"));
+ assertThat(c.interfaceTypes()).hasSize(1);
+ assertThat(((ClassTy) getOnlyElement(c.interfaceTypes())).sym())
+ .isEqualTo(new ClassSymbol("java/lang/annotation/Annotation"));
+
+ c = env.get(new ClassSymbol("java/util/ArrayList"));
+ ClassTy listInterface =
+ (ClassTy)
+ c.interfaceTypes().stream()
+ .filter(i -> ((ClassTy) i).sym().equals(new ClassSymbol("java/util/List")))
+ .collect(onlyElement());
+ assertThat(getLast(listInterface.classes()).targs()).hasSize(1);
+ }
+
+ @Test
+ public void annotations() {
+ Env<ClassSymbol, BytecodeBoundClass> env = TURBINE_BOOTCLASSPATH.env();
+ TypeBoundClass c = env.get(new ClassSymbol("java/lang/annotation/Retention"));
+
+ AnnoInfo anno =
+ c.annotations().stream()
+ .filter(a -> a.sym().equals(new ClassSymbol("java/lang/annotation/Retention")))
+ .collect(onlyElement());
+ assertThat(anno.values().keySet()).containsExactly("value");
+ assertThat(((EnumConstantValue) anno.values().get("value")).sym())
+ .isEqualTo(
+ new FieldSymbol(new ClassSymbol("java/lang/annotation/RetentionPolicy"), "RUNTIME"));
+ }
+
+ @Test
public void byteCodeBoundClassName() {
BytecodeBoundClass c =
new BytecodeBoundClass(
diff --git a/javatests/com/google/turbine/binder/JimageClassBinderTest.java b/javatests/com/google/turbine/binder/JimageClassBinderTest.java
index ffbbf87..bbcb245 100644
--- a/javatests/com/google/turbine/binder/JimageClassBinderTest.java
+++ b/javatests/com/google/turbine/binder/JimageClassBinderTest.java
@@ -16,6 +16,7 @@
package com.google.turbine.binder;
+import static com.google.common.collect.Iterables.getOnlyElement;
import static com.google.common.truth.Truth.assertThat;
import com.google.common.collect.ImmutableList;
@@ -23,6 +24,7 @@ import com.google.turbine.binder.bytecode.BytecodeBoundClass;
import com.google.turbine.binder.lookup.LookupKey;
import com.google.turbine.binder.lookup.LookupResult;
import com.google.turbine.binder.sym.ClassSymbol;
+import com.google.turbine.tree.Tree.Ident;
import java.io.IOException;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -49,7 +51,7 @@ public class JimageClassBinderTest {
binder
.index()
.lookupPackage(ImmutableList.of("java", "lang"))
- .lookup(new LookupKey(ImmutableList.of("Object")));
+ .lookup(new LookupKey(ImmutableList.of(new Ident(-1, "Object"))));
assertThat(((ClassSymbol) objectSym.sym()).binaryName()).isEqualTo("java/lang/Object");
assertThat(objectSym.remaining()).isEmpty();
@@ -57,16 +59,22 @@ public class JimageClassBinderTest {
binder
.index()
.lookupPackage(ImmutableList.of("java", "util"))
- .lookup(new LookupKey(ImmutableList.of("Map", "Entry")));
+ .lookup(new LookupKey(ImmutableList.of(new Ident(-1, "Map"), new Ident(-1, "Entry"))));
assertThat(((ClassSymbol) entrySym.sym()).binaryName()).isEqualTo("java/util/Map");
- assertThat(entrySym.remaining()).containsExactly("Entry");
+ assertThat(getOnlyElement(entrySym.remaining()).value()).isEqualTo("Entry");
entrySym =
binder
.index()
.scope()
- .lookup(new LookupKey(ImmutableList.of("java", "util", "Map", "Entry")));
+ .lookup(
+ new LookupKey(
+ ImmutableList.of(
+ new Ident(-1, "java"),
+ new Ident(-1, "util"),
+ new Ident(-1, "Map"),
+ new Ident(-1, "Entry"))));
assertThat(((ClassSymbol) entrySym.sym()).binaryName()).isEqualTo("java/util/Map");
- assertThat(entrySym.remaining()).containsExactly("Entry");
+ assertThat(getOnlyElement(entrySym.remaining()).value()).isEqualTo("Entry");
}
}
diff --git a/javatests/com/google/turbine/binder/bytecode/BytecodeBoundClassTest.java b/javatests/com/google/turbine/binder/bytecode/BytecodeBoundClassTest.java
new file mode 100644
index 0000000..4e3ec9a
--- /dev/null
+++ b/javatests/com/google/turbine/binder/bytecode/BytecodeBoundClassTest.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2018 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.turbine.binder.bytecode;
+
+import static com.google.common.collect.Iterables.getLast;
+import static com.google.common.collect.MoreCollectors.onlyElement;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.turbine.testing.TestClassPaths.TURBINE_BOOTCLASSPATH;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.io.ByteStreams;
+import com.google.turbine.binder.bound.ClassValue;
+import com.google.turbine.binder.bound.TypeBoundClass;
+import com.google.turbine.binder.bound.TypeBoundClass.MethodInfo;
+import com.google.turbine.binder.env.CompoundEnv;
+import com.google.turbine.binder.env.Env;
+import com.google.turbine.binder.env.SimpleEnv;
+import com.google.turbine.binder.sym.ClassSymbol;
+import com.google.turbine.type.Type;
+import com.google.turbine.type.Type.ClassTy;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Serializable;
+import java.io.UncheckedIOException;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class BytecodeBoundClassTest {
+
+ static class NoInterfaces {}
+
+ abstract static class RawInterfaces implements Serializable {}
+
+ abstract static class GenericInterfaces implements List<String> {}
+
+ @Test
+ public void interfaceTypes() {
+ TypeBoundClass noInterfaces = getBytecodeBoundClass(NoInterfaces.class);
+ TypeBoundClass rawInterfaces = getBytecodeBoundClass(RawInterfaces.class);
+ TypeBoundClass genericInterfaces = getBytecodeBoundClass(GenericInterfaces.class);
+
+ assertThat(noInterfaces.interfaceTypes()).isEmpty();
+
+ assertThat(rawInterfaces.interfaceTypes()).hasSize(1);
+ assertThat(((ClassTy) rawInterfaces.interfaceTypes().get(0)).sym())
+ .isEqualTo(new ClassSymbol("java/io/Serializable"));
+ assertThat(getLast(((ClassTy) rawInterfaces.interfaceTypes().get(0)).classes()).targs())
+ .isEmpty();
+
+ assertThat(genericInterfaces.interfaceTypes()).hasSize(1);
+ assertThat(((ClassTy) genericInterfaces.interfaceTypes().get(0)).sym())
+ .isEqualTo(new ClassSymbol("java/util/List"));
+ assertThat(getLast(((ClassTy) genericInterfaces.interfaceTypes().get(0)).classes()).targs())
+ .hasSize(1);
+ assertThat(
+ ((ClassTy)
+ getLast(((ClassTy) genericInterfaces.interfaceTypes().get(0)).classes())
+ .targs()
+ .get(0))
+ .sym())
+ .isEqualTo(new ClassSymbol("java/lang/String"));
+ }
+
+ static class HasMethod {
+ @Deprecated
+ <X, Y extends X, Z extends Throwable> X foo(@Deprecated X bar, Y baz) throws IOException, Z {
+ return null;
+ }
+ }
+
+ @Test
+ public void methodTypes() {
+ MethodInfo m =
+ getBytecodeBoundClass(HasMethod.class).methods().stream()
+ .filter(x -> x.name().equals("foo"))
+ .collect(onlyElement());
+
+ assertThat(m.tyParams()).hasSize(3);
+ assertThat(m.parameters().get(0).annotations()).hasSize(1);
+ assertThat(m.parameters().get(0).name()).isEqualTo("bar");
+ assertThat(m.exceptions()).hasSize(2);
+ }
+
+ @interface VoidAnno {
+ Class<?> a() default void.class;
+
+ Class<?> b() default int[].class;
+ }
+
+ @Test
+ public void voidAnno() {
+ BytecodeBoundClass c = getBytecodeBoundClass(VoidAnno.class);
+
+ assertThat(c.methods()).hasSize(2);
+ assertThat(((ClassValue) c.methods().get(0).defaultValue()).type().tyKind())
+ .isEqualTo(Type.TyKind.VOID_TY);
+ assertThat(((ClassValue) c.methods().get(1).defaultValue()).type().tyKind())
+ .isEqualTo(Type.TyKind.ARRAY_TY);
+ }
+
+ private static byte[] toByteArrayOrDie(InputStream is) {
+ try {
+ return ByteStreams.toByteArray(is);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ private BytecodeBoundClass getBytecodeBoundClass(
+ Env<ClassSymbol, BytecodeBoundClass> env, Class<?> clazz) {
+ String name = clazz.getName().replace('.', '/');
+ String path = "/" + name + ".class";
+ return new BytecodeBoundClass(
+ new ClassSymbol(name),
+ () -> toByteArrayOrDie(requireNonNull(getClass().getResourceAsStream(path), path)),
+ env,
+ "test.jar");
+ }
+
+ private BytecodeBoundClass getBytecodeBoundClass(Class<?> clazz) {
+ Env<ClassSymbol, BytecodeBoundClass> env = TURBINE_BOOTCLASSPATH.env();
+ env =
+ CompoundEnv.of(env)
+ .append(
+ new SimpleEnv<>(
+ ImmutableMap.of(
+ new ClassSymbol(BytecodeBoundClass.class.getName().replace('.', '/')),
+ getBytecodeBoundClass(env, BytecodeBoundClassTest.class))));
+ return getBytecodeBoundClass(env, clazz);
+ }
+}
diff --git a/javatests/com/google/turbine/binder/lookup/TopLevelIndexTest.java b/javatests/com/google/turbine/binder/lookup/TopLevelIndexTest.java
index 3dcf127..022e47c 100644
--- a/javatests/com/google/turbine/binder/lookup/TopLevelIndexTest.java
+++ b/javatests/com/google/turbine/binder/lookup/TopLevelIndexTest.java
@@ -16,11 +16,13 @@
package com.google.turbine.binder.lookup;
+import static com.google.common.collect.Iterables.getOnlyElement;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
import com.google.common.collect.ImmutableList;
import com.google.turbine.binder.sym.ClassSymbol;
+import com.google.turbine.tree.Tree.Ident;
import java.util.NoSuchElementException;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -36,13 +38,12 @@ public class TopLevelIndexTest {
ImmutableList.of(
new ClassSymbol("java/util/Map"),
new ClassSymbol("java/util/List"),
- new ClassSymbol("com/google/common/base/Optional")));
+ new ClassSymbol("java.util.Optional")));
}
@Test
public void simple() {
- LookupResult result =
- index.scope().lookup(new LookupKey(ImmutableList.of("java", "util", "Map")));
+ LookupResult result = index.scope().lookup(lookupKey(ImmutableList.of("java", "util", "Map")));
assertThat(result.sym()).isEqualTo(new ClassSymbol("java/util/Map"));
assertThat(result.remaining()).isEmpty();
}
@@ -50,14 +51,14 @@ public class TopLevelIndexTest {
@Test
public void nested() {
LookupResult result =
- index.scope().lookup(new LookupKey(ImmutableList.of("java", "util", "Map", "Entry")));
+ index.scope().lookup(lookupKey(ImmutableList.of("java", "util", "Map", "Entry")));
assertThat(result.sym()).isEqualTo(new ClassSymbol("java/util/Map"));
- assertThat(result.remaining()).containsExactly("Entry");
+ assertThat(getOnlyElement(result.remaining()).value()).isEqualTo("Entry");
}
@Test
public void empty() {
- assertThat(index.scope().lookup(new LookupKey(ImmutableList.of("java", "NoSuch", "Entry"))))
+ assertThat(index.scope().lookup(lookupKey(ImmutableList.of("java", "NoSuch", "Entry"))))
.isNull();
assertThat(index.lookupPackage(ImmutableList.of("java", "math"))).isNull();
assertThat(index.lookupPackage(ImmutableList.of("java", "util", "Map"))).isNull();
@@ -67,11 +68,11 @@ public class TopLevelIndexTest {
public void packageScope() {
Scope scope = index.lookupPackage(ImmutableList.of("java", "util"));
- assertThat(scope.lookup(new LookupKey(ImmutableList.of("Map"))).sym())
+ assertThat(scope.lookup(lookupKey(ImmutableList.of("Map"))).sym())
.isEqualTo(new ClassSymbol("java/util/Map"));
- assertThat(scope.lookup(new LookupKey(ImmutableList.of("List"))).sym())
+ assertThat(scope.lookup(lookupKey(ImmutableList.of("List"))).sym())
.isEqualTo(new ClassSymbol("java/util/List"));
- assertThat(scope.lookup(new LookupKey(ImmutableList.of("NoSuch")))).isNull();
+ assertThat(scope.lookup(lookupKey(ImmutableList.of("NoSuch")))).isNull();
}
@Test
@@ -82,7 +83,7 @@ public class TopLevelIndexTest {
SimpleTopLevelIndex.of(
ImmutableList.of(new ClassSymbol("java/Foo"), new ClassSymbol("java/Foo/Bar")));
- LookupResult result = index.scope().lookup(new LookupKey(ImmutableList.of("java", "Foo")));
+ LookupResult result = index.scope().lookup(lookupKey(ImmutableList.of("java", "Foo")));
assertThat(result.sym()).isEqualTo(new ClassSymbol("java/Foo"));
assertThat(result.remaining()).isEmpty();
}
@@ -92,11 +93,11 @@ public class TopLevelIndexTest {
SimpleTopLevelIndex.of(
ImmutableList.of(new ClassSymbol("java/Foo/Bar"), new ClassSymbol("java/Foo")));
- assertThat(index.scope().lookup(new LookupKey(ImmutableList.of("java", "Foo")))).isNull();
+ assertThat(index.scope().lookup(lookupKey(ImmutableList.of("java", "Foo")))).isNull();
LookupResult packageResult =
index
.lookupPackage(ImmutableList.of("java", "Foo"))
- .lookup(new LookupKey(ImmutableList.of("Bar")));
+ .lookup(lookupKey(ImmutableList.of("Bar")));
assertThat(packageResult.sym()).isEqualTo(new ClassSymbol("java/Foo/Bar"));
assertThat(packageResult.remaining()).isEmpty();
}
@@ -104,7 +105,7 @@ public class TopLevelIndexTest {
@Test
public void emptyLookup() {
- LookupKey key = new LookupKey(ImmutableList.of("java", "util", "List"));
+ LookupKey key = lookupKey(ImmutableList.of("java", "util", "List"));
key = key.rest();
key = key.rest();
try {
@@ -114,4 +115,12 @@ public class TopLevelIndexTest {
// expected
}
}
+
+ private LookupKey lookupKey(ImmutableList<String> names) {
+ ImmutableList.Builder<Ident> result = ImmutableList.builder();
+ for (String name : names) {
+ result.add(new Ident(-1, name));
+ }
+ return new LookupKey(result.build());
+ }
}
diff --git a/javatests/com/google/turbine/bytecode/ClassReaderTest.java b/javatests/com/google/turbine/bytecode/ClassReaderTest.java
index 5bce03d..dda29ac 100644
--- a/javatests/com/google/turbine/bytecode/ClassReaderTest.java
+++ b/javatests/com/google/turbine/bytecode/ClassReaderTest.java
@@ -133,7 +133,6 @@ public class ClassReaderTest {
assertThat(classFile.annotations()).hasSize(1);
ClassFile.AnnotationInfo annotation = Iterables.getOnlyElement(classFile.annotations());
assertThat(annotation.typeName()).isEqualTo("Ljava/lang/annotation/Retention;");
- assertThat(annotation.isRuntimeVisible()).isTrue();
assertThat(annotation.elementValuePairs()).hasSize(1);
assertThat(annotation.elementValuePairs()).containsKey("value");
ElementValue value = annotation.elementValuePairs().get("value");
diff --git a/javatests/com/google/turbine/bytecode/sig/SigIntegrationTest.java b/javatests/com/google/turbine/bytecode/sig/SigIntegrationTest.java
index 1c0d5c4..f3ab8e7 100644
--- a/javatests/com/google/turbine/bytecode/sig/SigIntegrationTest.java
+++ b/javatests/com/google/turbine/bytecode/sig/SigIntegrationTest.java
@@ -93,7 +93,7 @@ public class SigIntegrationTest {
try {
new ClassReader(Files.newInputStream(path))
.accept(
- new ClassVisitor(Opcodes.ASM6) {
+ new ClassVisitor(Opcodes.ASM7) {
@Override
public void visit(
int version,
diff --git a/javatests/com/google/turbine/deps/DependenciesTest.java b/javatests/com/google/turbine/deps/DependenciesTest.java
index 70377fb..4c2362f 100644
--- a/javatests/com/google/turbine/deps/DependenciesTest.java
+++ b/javatests/com/google/turbine/deps/DependenciesTest.java
@@ -19,7 +19,6 @@ package com.google.turbine.deps;
import static com.google.common.truth.Truth.assertThat;
import com.google.common.base.Joiner;
-import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
@@ -44,6 +43,7 @@ import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.stream.Collectors;
@@ -106,7 +106,7 @@ public class DependenciesTest {
units,
ClassPathBinder.bindClasspath(classpath),
TestClassPaths.TURBINE_BOOTCLASSPATH,
- /* moduleVersion=*/ Optional.absent());
+ /* moduleVersion=*/ Optional.empty());
Lowered lowered = Lower.lowerAll(bound.units(), bound.modules(), bound.classPathEnv());
diff --git a/javatests/com/google/turbine/lower/IntegrationTestSupport.java b/javatests/com/google/turbine/lower/IntegrationTestSupport.java
index 51b5a2e..c039241 100644
--- a/javatests/com/google/turbine/lower/IntegrationTestSupport.java
+++ b/javatests/com/google/turbine/lower/IntegrationTestSupport.java
@@ -23,7 +23,6 @@ import static java.util.stream.Collectors.toCollection;
import static java.util.stream.Collectors.toList;
import com.google.common.base.Joiner;
-import com.google.common.base.Optional;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.jimfs.Configuration;
@@ -60,6 +59,7 @@ import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaFileObject;
@@ -404,7 +404,7 @@ public class IntegrationTestSupport {
final Set<String> classes1 = classes;
new SignatureReader(signature)
.accept(
- new SignatureVisitor(Opcodes.ASM6) {
+ new SignatureVisitor(Opcodes.ASM7) {
private final Set<String> classes = classes1;
// class signatures may contain type arguments that contain class signatures
Deque<List<String>> pieces = new ArrayDeque<>();
@@ -431,7 +431,7 @@ public class IntegrationTestSupport {
static Map<String, byte[]> runTurbine(Map<String, String> input, ImmutableList<Path> classpath)
throws IOException {
return runTurbine(
- input, classpath, TURBINE_BOOTCLASSPATH, /* moduleVersion= */ Optional.absent());
+ input, classpath, TURBINE_BOOTCLASSPATH, /* moduleVersion= */ Optional.empty());
}
static Map<String, byte[]> runTurbine(
diff --git a/javatests/com/google/turbine/lower/LowerIntegrationTest.java b/javatests/com/google/turbine/lower/LowerIntegrationTest.java
index 6496756..f7e9c18 100644
--- a/javatests/com/google/turbine/lower/LowerIntegrationTest.java
+++ b/javatests/com/google/turbine/lower/LowerIntegrationTest.java
@@ -231,7 +231,7 @@ public class LowerIntegrationTest {
"import_wild_order.test",
"canon_recursive.test",
// TODO(cushon): crashes ASM, see:
- // http://forge.ow2.org/tracker/?func=detail&aid=317776&group_id=23&atid=100023
+ // https://gitlab.ow2.org/asm/asm/issues/317776
// "canon_array.test",
"java_lang_object.test",
"visible_package.test",
@@ -303,6 +303,11 @@ public class LowerIntegrationTest {
// TODO(cushon): support for source level 9 in integration tests
// "B74332665.test",
"memberimport.test",
+ "type_anno_c_array.test",
+ // https://bugs.openjdk.java.net/browse/JDK-8054064 ?
+ "shadow_inherited.test",
+ "static_final_boxed.test",
+ "anno_void.test",
};
List<Object[]> tests =
ImmutableList.copyOf(testCases).stream().map(x -> new Object[] {x}).collect(toList());
diff --git a/javatests/com/google/turbine/lower/LowerSignatureTest.java b/javatests/com/google/turbine/lower/LowerSignatureTest.java
index 59698e3..5ccbf01 100644
--- a/javatests/com/google/turbine/lower/LowerSignatureTest.java
+++ b/javatests/com/google/turbine/lower/LowerSignatureTest.java
@@ -25,6 +25,13 @@ import com.google.turbine.bytecode.sig.SigWriter;
import com.google.turbine.model.TurbineConstantTypeKind;
import com.google.turbine.type.Type;
import com.google.turbine.type.Type.ArrayTy;
+import com.google.turbine.type.Type.ClassTy;
+import com.google.turbine.type.Type.ClassTy.SimpleClassTy;
+import com.google.turbine.type.Type.PrimTy;
+import com.google.turbine.type.Type.TyVar;
+import com.google.turbine.type.Type.WildLowerBoundedTy;
+import com.google.turbine.type.Type.WildUnboundedTy;
+import com.google.turbine.type.Type.WildUpperBoundedTy;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -34,9 +41,9 @@ public class LowerSignatureTest {
@Test
public void simple() {
Type.ClassTy type =
- new Type.ClassTy(
+ ClassTy.create(
ImmutableList.of(
- new Type.ClassTy.SimpleClassTy(
+ SimpleClassTy.create(
new ClassSymbol("java/util/List"), ImmutableList.of(), ImmutableList.of())));
assertThat(SigWriter.type(new LowerSignature().signature(type))).isEqualTo("Ljava/util/List;");
}
@@ -47,13 +54,13 @@ public class LowerSignatureTest {
SigWriter.type(
new LowerSignature()
.signature(
- new Type.ClassTy(
+ ClassTy.create(
ImmutableList.of(
- new Type.ClassTy.SimpleClassTy(
+ SimpleClassTy.create(
new ClassSymbol("test/Outer"),
ImmutableList.of(),
ImmutableList.of()),
- new Type.ClassTy.SimpleClassTy(
+ SimpleClassTy.create(
new ClassSymbol("test/Outer$Inner"),
ImmutableList.of(),
ImmutableList.of()))))))
@@ -63,15 +70,15 @@ public class LowerSignatureTest {
@Test
public void genericEnclosing() {
Type.ClassTy type =
- new Type.ClassTy(
+ ClassTy.create(
ImmutableList.of(
- new Type.ClassTy.SimpleClassTy(
+ SimpleClassTy.create(
new ClassSymbol("test/Outer"),
- ImmutableList.of(Type.ClassTy.OBJECT),
+ ImmutableList.of(ClassTy.OBJECT),
ImmutableList.of()),
- new Type.ClassTy.SimpleClassTy(
+ SimpleClassTy.create(
new ClassSymbol("test/Outer$Inner"),
- ImmutableList.of(Type.ClassTy.OBJECT),
+ ImmutableList.of(ClassTy.OBJECT),
ImmutableList.of())));
assertThat(SigWriter.type(new LowerSignature().signature(type)))
.isEqualTo("Ltest/Outer<Ljava/lang/Object;>.Inner<Ljava/lang/Object;>;");
@@ -85,13 +92,13 @@ public class LowerSignatureTest {
SigWriter.type(
new LowerSignature()
.signature(
- new Type.ClassTy(
+ ClassTy.create(
ImmutableList.of(
- new Type.ClassTy.SimpleClassTy(
+ SimpleClassTy.create(
new ClassSymbol("Outer"),
ImmutableList.of(),
ImmutableList.of()),
- new Type.ClassTy.SimpleClassTy(
+ SimpleClassTy.create(
new ClassSymbol("Outer$Inner"),
ImmutableList.of(),
ImmutableList.of()))))))
@@ -104,16 +111,16 @@ public class LowerSignatureTest {
SigWriter.type(
new LowerSignature()
.signature(
- new Type.ClassTy(
+ ClassTy.create(
ImmutableList.of(
- new Type.ClassTy.SimpleClassTy(
+ SimpleClassTy.create(
new ClassSymbol("test/Test"),
ImmutableList.of(
- new Type.WildUnboundedTy(ImmutableList.of()),
- new Type.WildLowerBoundedTy(
- Type.ClassTy.OBJECT, ImmutableList.of()),
- new Type.WildUpperBoundedTy(
- Type.ClassTy.OBJECT, ImmutableList.of())),
+ WildUnboundedTy.create(ImmutableList.of()),
+ WildLowerBoundedTy.create(
+ ClassTy.OBJECT, ImmutableList.of()),
+ WildUpperBoundedTy.create(
+ ClassTy.OBJECT, ImmutableList.of())),
ImmutableList.of()))))))
.isEqualTo("Ltest/Test<*-Ljava/lang/Object;+Ljava/lang/Object;>;");
}
@@ -124,7 +131,7 @@ public class LowerSignatureTest {
SigWriter.type(
new LowerSignature()
.signature(
- new Type.TyVar(
+ TyVar.create(
new TyVarSymbol(ClassSymbol.OBJECT, "X"), ImmutableList.of()))))
.isEqualTo("TX;");
}
@@ -134,8 +141,7 @@ public class LowerSignatureTest {
assertThat(
SigWriter.type(
new LowerSignature()
- .signature(
- new Type.PrimTy(TurbineConstantTypeKind.BOOLEAN, ImmutableList.of()))))
+ .signature(PrimTy.create(TurbineConstantTypeKind.BOOLEAN, ImmutableList.of()))))
.isEqualTo("Z");
}
@@ -150,10 +156,10 @@ public class LowerSignatureTest {
SigWriter.type(
new LowerSignature()
.signature(
- new Type.ArrayTy(
- new ArrayTy(
- new ArrayTy(
- new Type.PrimTy(
+ ArrayTy.create(
+ ArrayTy.create(
+ ArrayTy.create(
+ PrimTy.create(
TurbineConstantTypeKind.BOOLEAN, ImmutableList.of()),
ImmutableList.of()),
ImmutableList.of()),
diff --git a/javatests/com/google/turbine/lower/LowerTest.java b/javatests/com/google/turbine/lower/LowerTest.java
index d97f46a..ef070f9 100644
--- a/javatests/com/google/turbine/lower/LowerTest.java
+++ b/javatests/com/google/turbine/lower/LowerTest.java
@@ -22,7 +22,6 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.fail;
import com.google.common.base.Joiner;
-import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.ByteStreams;
@@ -44,6 +43,11 @@ import com.google.turbine.model.TurbineTyKind;
import com.google.turbine.parse.Parser;
import com.google.turbine.testing.AsmUtils;
import com.google.turbine.type.Type;
+import com.google.turbine.type.Type.ClassTy;
+import com.google.turbine.type.Type.ClassTy.SimpleClassTy;
+import com.google.turbine.type.Type.IntersectionTy;
+import com.google.turbine.type.Type.PrimTy;
+import com.google.turbine.type.Type.TyVar;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
@@ -52,6 +56,7 @@ import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import org.junit.Rule;
@@ -75,14 +80,14 @@ public class LowerTest {
@Test
public void hello() throws Exception {
- ImmutableList<Type.ClassTy> interfaceTypes =
+ ImmutableList<Type> interfaceTypes =
ImmutableList.of(
- new Type.ClassTy(
+ ClassTy.create(
ImmutableList.of(
- new Type.ClassTy.SimpleClassTy(
+ SimpleClassTy.create(
new ClassSymbol("java/util/List"),
ImmutableList.of(
- new Type.TyVar(
+ TyVar.create(
new TyVarSymbol(new ClassSymbol("test/Test"), "V"),
ImmutableList.of())),
ImmutableList.of()))));
@@ -91,13 +96,14 @@ public class LowerTest {
ImmutableMap.of(
new TyVarSymbol(new ClassSymbol("test/Test"), "V"),
new SourceTypeBoundClass.TyVarInfo(
- new Type.ClassTy(
+ IntersectionTy.create(
ImmutableList.of(
- new Type.ClassTy.SimpleClassTy(
- new ClassSymbol("test/Test$Inner"),
- ImmutableList.of(),
- ImmutableList.of()))),
- ImmutableList.of(),
+ ClassTy.create(
+ ImmutableList.of(
+ SimpleClassTy.create(
+ new ClassSymbol("test/Test$Inner"),
+ ImmutableList.of(),
+ ImmutableList.of()))))),
ImmutableList.of()));
int access = TurbineFlag.ACC_SUPER | TurbineFlag.ACC_PUBLIC;
ImmutableList<SourceTypeBoundClass.MethodInfo> methods =
@@ -105,7 +111,7 @@ public class LowerTest {
new SourceTypeBoundClass.MethodInfo(
new MethodSymbol(new ClassSymbol("test/Test"), "f"),
ImmutableMap.of(),
- new Type.PrimTy(TurbineConstantTypeKind.INT, ImmutableList.of()),
+ PrimTy.create(TurbineConstantTypeKind.INT, ImmutableList.of()),
ImmutableList.of(),
ImmutableList.of(),
TurbineFlag.ACC_STATIC | TurbineFlag.ACC_PUBLIC,
@@ -118,34 +124,35 @@ public class LowerTest {
ImmutableMap.of(
new TyVarSymbol(new MethodSymbol(new ClassSymbol("test/Test"), "g"), "V"),
new SourceTypeBoundClass.TyVarInfo(
- null,
- ImmutableList.of(
- new Type.ClassTy(
- ImmutableList.of(
- new Type.ClassTy.SimpleClassTy(
- new ClassSymbol("java/lang/Runnable"),
- ImmutableList.of(),
- ImmutableList.of())))),
+ IntersectionTy.create(
+ ImmutableList.of(
+ ClassTy.create(
+ ImmutableList.of(
+ SimpleClassTy.create(
+ new ClassSymbol("java/lang/Runnable"),
+ ImmutableList.of(),
+ ImmutableList.of()))))),
ImmutableList.of()),
new TyVarSymbol(new MethodSymbol(new ClassSymbol("test/Test"), "g"), "E"),
new SourceTypeBoundClass.TyVarInfo(
- new Type.ClassTy(
+ IntersectionTy.create(
ImmutableList.of(
- new Type.ClassTy.SimpleClassTy(
- new ClassSymbol("java/lang/Error"),
- ImmutableList.of(),
- ImmutableList.of()))),
- ImmutableList.of(),
+ ClassTy.create(
+ ImmutableList.of(
+ SimpleClassTy.create(
+ new ClassSymbol("java/lang/Error"),
+ ImmutableList.of(),
+ ImmutableList.of()))))),
ImmutableList.of())),
Type.VOID,
ImmutableList.of(
new SourceTypeBoundClass.ParamInfo(
- new Type.PrimTy(TurbineConstantTypeKind.INT, ImmutableList.of()),
+ PrimTy.create(TurbineConstantTypeKind.INT, ImmutableList.of()),
"foo",
ImmutableList.of(),
0)),
ImmutableList.of(
- new Type.TyVar(
+ TyVar.create(
new TyVarSymbol(new MethodSymbol(new ClassSymbol("test/Test"), "g"), "E"),
ImmutableList.of())),
TurbineFlag.ACC_PUBLIC,
@@ -185,6 +192,7 @@ public class LowerTest {
null,
null,
ImmutableList.of(),
+ null,
null);
SourceTypeBoundClass i =
@@ -204,6 +212,7 @@ public class LowerTest {
null,
null,
ImmutableList.of(),
+ null,
null);
SimpleEnv.Builder<ClassSymbol, SourceTypeBoundClass> b = SimpleEnv.builder();
@@ -247,13 +256,13 @@ public class LowerTest {
"}"))),
ClassPathBinder.bindClasspath(ImmutableList.of()),
TURBINE_BOOTCLASSPATH,
- /* moduleVersion=*/ Optional.absent());
+ /* moduleVersion=*/ Optional.empty());
Map<String, byte[]> lowered =
Lower.lowerAll(bound.units(), bound.modules(), bound.classPathEnv()).bytes();
List<String> attributes = new ArrayList<>();
new ClassReader(lowered.get("Test$Inner$InnerMost"))
.accept(
- new ClassVisitor(Opcodes.ASM6) {
+ new ClassVisitor(Opcodes.ASM7) {
@Override
public void visitInnerClass(
String name, String outerName, String innerName, int access) {
@@ -325,17 +334,17 @@ public class LowerTest {
"}"))),
ClassPathBinder.bindClasspath(ImmutableList.of()),
TURBINE_BOOTCLASSPATH,
- /* moduleVersion=*/ Optional.absent());
+ /* moduleVersion=*/ Optional.empty());
Map<String, byte[]> lowered =
Lower.lowerAll(bound.units(), bound.modules(), bound.classPathEnv()).bytes();
TypePath[] path = new TypePath[1];
new ClassReader(lowered.get("Test"))
.accept(
- new ClassVisitor(Opcodes.ASM6) {
+ new ClassVisitor(Opcodes.ASM7) {
@Override
public FieldVisitor visitField(
int access, String name, String desc, String signature, Object value) {
- return new FieldVisitor(Opcodes.ASM6) {
+ return new FieldVisitor(Opcodes.ASM7) {
@Override
public AnnotationVisitor visitTypeAnnotation(
int typeRef, TypePath typePath, String desc, boolean visible) {
@@ -382,7 +391,7 @@ public class LowerTest {
Map<String, Object> values = new LinkedHashMap<>();
new ClassReader(actual.get("Test"))
.accept(
- new ClassVisitor(Opcodes.ASM6) {
+ new ClassVisitor(Opcodes.ASM7) {
@Override
public FieldVisitor visitField(
int access, String name, String desc, String signature, Object value) {
@@ -403,13 +412,13 @@ public class LowerTest {
ImmutableList.of(Parser.parse("@Deprecated class Test {}")),
ClassPathBinder.bindClasspath(ImmutableList.of()),
TURBINE_BOOTCLASSPATH,
- /* moduleVersion=*/ Optional.absent());
+ /* moduleVersion=*/ Optional.empty());
Map<String, byte[]> lowered =
Lower.lowerAll(bound.units(), bound.modules(), bound.classPathEnv()).bytes();
int[] acc = {0};
new ClassReader(lowered.get("Test"))
.accept(
- new ClassVisitor(Opcodes.ASM6) {
+ new ClassVisitor(Opcodes.ASM7) {
@Override
public void visit(
int version,
@@ -594,7 +603,10 @@ public class LowerTest {
} catch (TurbineError error) {
assertThat(error)
.hasMessageThat()
- .contains("Test.java: error: could not locate class file for A");
+ .contains(
+ "Test.java:3: error: could not locate class file for A\n"
+ + " I i;\n"
+ + " ^");
}
}
@@ -610,7 +622,7 @@ public class LowerTest {
int[] testAccess = {0};
new ClassReader(lowered.get("Test"))
.accept(
- new ClassVisitor(Opcodes.ASM6) {
+ new ClassVisitor(Opcodes.ASM7) {
@Override
public void visit(
int version,
diff --git a/javatests/com/google/turbine/lower/ModuleIntegrationTest.java b/javatests/com/google/turbine/lower/ModuleIntegrationTest.java
index d1bcb74..4067bd1 100644
--- a/javatests/com/google/turbine/lower/ModuleIntegrationTest.java
+++ b/javatests/com/google/turbine/lower/ModuleIntegrationTest.java
@@ -21,13 +21,14 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.stream.Collectors.toList;
import static org.junit.Assert.assertEquals;
-import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.io.ByteStreams;
+import com.google.turbine.binder.CtSymClassBinder;
import com.google.turbine.binder.JimageClassBinder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
+import java.util.Optional;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import org.junit.Rule;
@@ -94,7 +95,12 @@ public class ModuleIntegrationTest {
Map<String, byte[]> actual =
IntegrationTestSupport.runTurbine(
- input.sources, classpathJar, JimageClassBinder.bindDefault(), Optional.of("42"));
+ input.sources,
+ classpathJar,
+ Double.parseDouble(System.getProperty("java.class.version")) < 54
+ ? JimageClassBinder.bindDefault()
+ : CtSymClassBinder.bind("9"),
+ Optional.of("42"));
assertEquals(dump(expected), dump(actual));
}
diff --git a/javatests/com/google/turbine/lower/moduletestdata/classpath.test b/javatests/com/google/turbine/lower/moduletestdata/classpath.test
new file mode 100644
index 0000000..734ffea
--- /dev/null
+++ b/javatests/com/google/turbine/lower/moduletestdata/classpath.test
@@ -0,0 +1,7 @@
+%%% module-info.java %%%
+module one {}
+
+=== module-info.java ===
+module two {
+ requires one;
+} \ No newline at end of file
diff --git a/javatests/com/google/turbine/lower/moduletestdata/module-info.test b/javatests/com/google/turbine/lower/moduletestdata/module-info.test
new file mode 100644
index 0000000..cba828b
--- /dev/null
+++ b/javatests/com/google/turbine/lower/moduletestdata/module-info.test
@@ -0,0 +1,84 @@
+=== a/A.java ===
+package a;
+import static java.lang.annotation.ElementType.MODULE;
+import java.lang.annotation.Target;
+@Target(MODULE)
+public @interface A {
+ int[] value() default {};
+}
+
+=== a/B.java ===
+package a;
+import static java.lang.annotation.ElementType.MODULE;
+import java.lang.annotation.Target;
+@Target(MODULE)
+public @interface B {}
+
+=== com/google/Baz.java ===
+package com.google;
+public interface Baz {
+ public static int A = 42;
+ public static int B = 43;
+ public interface I {
+ public static final int C = 44;
+ }
+}
+
+=== com/google/Foo.java ===
+package com.google;
+public class Foo implements Baz.I {
+}
+
+=== com/google/Bar.java ===
+package com.google;
+public class Bar implements Baz.I {
+}
+
+=== com/google/p1/One.java ===
+package com.google.p1;
+public class One {}
+
+=== com/google/p2/Two.java ===
+package com.google.p2;
+public class Two {}
+
+=== com/google/p3/Three.java ===
+package com.google.p3;
+public class Three {}
+
+=== module-info.java ===
+
+import a.A;
+import a.B;
+import com.google.Foo;
+import com.google.Baz;
+import static com.google.Baz.A;
+
+@A({A, Baz.B, Baz.I.C})
+@B
+module com.google.m {
+ requires java.compiler;
+ requires transitive jdk.compiler;
+ requires static java.base;
+
+ exports com.google.p1;
+ exports com.google.p2 to
+ java.base;
+ exports com.google.p3 to
+ java.base,
+ java.compiler;
+
+ opens com.google.p1;
+ opens com.google.p2 to
+ java.base;
+ opens com.google.p3 to
+ java.base,
+ java.compiler;
+
+ uses Foo;
+ uses com.google.Bar;
+
+ provides com.google.Baz.I with
+ Foo,
+ com.google.Bar;
+}
diff --git a/javatests/com/google/turbine/lower/moduletestdata/multimodule.test b/javatests/com/google/turbine/lower/moduletestdata/multimodule.test
new file mode 100644
index 0000000..6c288b0
--- /dev/null
+++ b/javatests/com/google/turbine/lower/moduletestdata/multimodule.test
@@ -0,0 +1,13 @@
+%%% module-info.java %%%
+module one {}
+
+=== two/module-info.java ===
+module two {
+ requires one;
+}
+
+=== three/module-info.java ===
+module three {
+ requires one;
+ requires two;
+} \ No newline at end of file
diff --git a/javatests/com/google/turbine/lower/testdata/anno_void.test b/javatests/com/google/turbine/lower/testdata/anno_void.test
new file mode 100644
index 0000000..280302e
--- /dev/null
+++ b/javatests/com/google/turbine/lower/testdata/anno_void.test
@@ -0,0 +1,8 @@
+=== V.java ===
+@interface V {
+ Class<?> value() default void.class;
+}
+=== A.java ===
+@V()
+class A {
+} \ No newline at end of file
diff --git a/javatests/com/google/turbine/lower/testdata/golden/outer.txt b/javatests/com/google/turbine/lower/testdata/golden/outer.txt
index a7868b2..b6d541c 100644
--- a/javatests/com/google/turbine/lower/testdata/golden/outer.txt
+++ b/javatests/com/google/turbine/lower/testdata/golden/outer.txt
@@ -2,7 +2,7 @@
// access flags 0x21
// signature <V:Ltest/Test$Inner;>Ljava/lang/Object;Ljava/util/List<TV;>;
// declaration: test/Test<V extends test.Test$Inner> implements java.util.List<V>
-public class test/Test implements java/util/List {
+public class test/Test implements java/util/List {
// access flags 0xC
protected static INNERCLASS test/Test$Inner test/Test Inner
diff --git a/javatests/com/google/turbine/lower/testdata/shadow_inherited.test b/javatests/com/google/turbine/lower/testdata/shadow_inherited.test
new file mode 100644
index 0000000..9fbb478
--- /dev/null
+++ b/javatests/com/google/turbine/lower/testdata/shadow_inherited.test
@@ -0,0 +1,8 @@
+=== A.java ===
+class A {
+ class B {}
+}
+=== B.java ===
+class B extends A {
+ B b;
+} \ No newline at end of file
diff --git a/javatests/com/google/turbine/lower/testdata/static_final_boxed.test b/javatests/com/google/turbine/lower/testdata/static_final_boxed.test
new file mode 100644
index 0000000..6626483
--- /dev/null
+++ b/javatests/com/google/turbine/lower/testdata/static_final_boxed.test
@@ -0,0 +1,11 @@
+=== T.java ===
+class T {
+ public static final boolean Z = (Boolean) false;
+ public static final byte B = (Byte) (byte) 0;
+ public static final char C = (Character) (char) 0;
+ public static final short S = (Short) (short) 0;
+ public static final int I = (Integer) 0;
+ public static final long L = (Long) 0L;
+ public static final double D = (Double) 0d;
+ public static final float F = (Float) 0f;
+} \ No newline at end of file
diff --git a/javatests/com/google/turbine/lower/testdata/type_anno_c_array.test b/javatests/com/google/turbine/lower/testdata/type_anno_c_array.test
new file mode 100644
index 0000000..c8ac275
--- /dev/null
+++ b/javatests/com/google/turbine/lower/testdata/type_anno_c_array.test
@@ -0,0 +1,28 @@
+=== Test.java ===
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE_USE)
+@interface A {}
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE_USE)
+@interface B {}
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE_USE)
+@interface C {}
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE_USE)
+@interface D {}
+
+class Test {
+ static final int as @A [] = {};
+ static final int bs @A [] @B [] = {};
+ static final int @C [] cs @A [] @B [] = {};
+ static final int @C [] @D [] ds @A [] @B [] = {};
+}
diff --git a/javatests/com/google/turbine/main/MainTest.java b/javatests/com/google/turbine/main/MainTest.java
index 9307cb0..654a89b 100644
--- a/javatests/com/google/turbine/main/MainTest.java
+++ b/javatests/com/google/turbine/main/MainTest.java
@@ -229,4 +229,17 @@ public class MainTest {
assertThat(expected).hasMessageThat().contains("java.lang");
}
}
+
+ @Test
+ public void usage() throws IOException {
+ Path src = temporaryFolder.newFile("Test.java").toPath();
+ Files.write(src, "public class Test {}".getBytes(UTF_8));
+
+ try {
+ Main.compile(optionsWithBootclasspath().addSources(ImmutableList.of(src.toString())).build());
+ fail();
+ } catch (UsageException expected) {
+ assertThat(expected).hasMessageThat().contains("--output is required");
+ }
+ }
}
diff --git a/javatests/com/google/turbine/model/ConstTest.java b/javatests/com/google/turbine/model/ConstTest.java
new file mode 100644
index 0000000..7940124
--- /dev/null
+++ b/javatests/com/google/turbine/model/ConstTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2018 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.turbine.model;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.testing.EqualsTester;
+import com.google.turbine.binder.bound.AnnotationValue;
+import com.google.turbine.binder.bound.ClassValue;
+import com.google.turbine.binder.sym.ClassSymbol;
+import com.google.turbine.type.Type.ClassTy;
+import com.google.turbine.type.Type.PrimTy;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class ConstTest {
+ @Test
+ public void equalsTest() {
+ new EqualsTester()
+ .addEqualityGroup(new Const.BooleanValue(true), new Const.BooleanValue(true))
+ .addEqualityGroup(new Const.BooleanValue(false), new Const.BooleanValue(false))
+ .addEqualityGroup(new Const.IntValue(1), new Const.IntValue(1))
+ .addEqualityGroup(new Const.IntValue(2), new Const.IntValue(2))
+ .addEqualityGroup(new Const.LongValue(1), new Const.LongValue(1))
+ .addEqualityGroup(new Const.LongValue(2), new Const.LongValue(2))
+ .addEqualityGroup(new Const.CharValue('x'), new Const.CharValue('x'))
+ .addEqualityGroup(new Const.CharValue('y'), new Const.CharValue('y'))
+ .addEqualityGroup(new Const.FloatValue(1), new Const.FloatValue(1))
+ .addEqualityGroup(new Const.FloatValue(2), new Const.FloatValue(2))
+ .addEqualityGroup(new Const.DoubleValue(1), new Const.DoubleValue(1))
+ .addEqualityGroup(new Const.DoubleValue(2), new Const.DoubleValue(2))
+ .addEqualityGroup(new Const.StringValue("a"), new Const.StringValue("a"))
+ .addEqualityGroup(new Const.StringValue("b"), new Const.StringValue("b"))
+ .addEqualityGroup(new Const.ShortValue((short) 1), new Const.ShortValue((short) 1))
+ .addEqualityGroup(new Const.ShortValue((short) 2), new Const.ShortValue((short) 2))
+ .addEqualityGroup(new Const.ByteValue((byte) 1), new Const.ByteValue((byte) 1))
+ .addEqualityGroup(new Const.ByteValue((byte) 2), new Const.ByteValue((byte) 2))
+ .addEqualityGroup(
+ new Const.ArrayInitValue(
+ ImmutableList.of(new Const.IntValue(1), new Const.IntValue(2))),
+ new Const.ArrayInitValue(
+ ImmutableList.of(new Const.IntValue(1), new Const.IntValue(2))))
+ .addEqualityGroup(
+ new Const.ArrayInitValue(
+ ImmutableList.of(new Const.IntValue(3), new Const.IntValue(4))),
+ new Const.ArrayInitValue(
+ ImmutableList.of(new Const.IntValue(3), new Const.IntValue(4))))
+ .addEqualityGroup(
+ new AnnotationValue(
+ new ClassSymbol("test/Anno"), ImmutableMap.of("value", new Const.IntValue(3))),
+ new AnnotationValue(
+ new ClassSymbol("test/Anno"), ImmutableMap.of("value", new Const.IntValue(3))))
+ .addEqualityGroup(
+ new AnnotationValue(
+ new ClassSymbol("test/Anno"), ImmutableMap.of("value", new Const.IntValue(4))),
+ new AnnotationValue(
+ new ClassSymbol("test/Anno"), ImmutableMap.of("value", new Const.IntValue(4))))
+ .addEqualityGroup(
+ new ClassValue(ClassTy.asNonParametricClassTy(new ClassSymbol("test/Clazz"))),
+ new ClassValue(ClassTy.asNonParametricClassTy(new ClassSymbol("test/Clazz"))))
+ .addEqualityGroup(
+ new ClassValue(ClassTy.asNonParametricClassTy(new ClassSymbol("test/Other"))),
+ new ClassValue(ClassTy.asNonParametricClassTy(new ClassSymbol("test/Other"))))
+ .addEqualityGroup(
+ new ClassValue(PrimTy.create(TurbineConstantTypeKind.INT, ImmutableList.of())),
+ new ClassValue(PrimTy.create(TurbineConstantTypeKind.INT, ImmutableList.of())))
+ .testEquals();
+ }
+}
diff --git a/javatests/com/google/turbine/options/TurbineOptionsTest.java b/javatests/com/google/turbine/options/TurbineOptionsTest.java
index 36f9e20..5953bac 100644
--- a/javatests/com/google/turbine/options/TurbineOptionsTest.java
+++ b/javatests/com/google/turbine/options/TurbineOptionsTest.java
@@ -17,6 +17,7 @@
package com.google.turbine.options;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth8.assertThat;
import static org.junit.Assert.fail;
import com.google.common.collect.ImmutableList;
@@ -79,7 +80,7 @@ public class TurbineOptionsTest {
TurbineOptions options =
TurbineOptionsParser.parse(Iterables.concat(BASE_ARGS, Arrays.asList(lines)));
- assertThat(options.outputFile()).isEqualTo("out.jar");
+ assertThat(options.output()).hasValue("out.jar");
assertThat(options.sourceJars())
.containsExactly("sources1.srcjar", "sources2.srcjar")
.inOrder();
@@ -181,8 +182,8 @@ public class TurbineOptionsTest {
TurbineOptions options = TurbineOptionsParser.parse(Arrays.asList(lines));
- assertThat(options.targetLabel()).isAbsent();
- assertThat(options.injectingRuleKind()).isAbsent();
+ assertThat(options.targetLabel()).isEmpty();
+ assertThat(options.injectingRuleKind()).isEmpty();
}
@Test
@@ -222,13 +223,9 @@ public class TurbineOptionsTest {
}
@Test
- public void failIfMissingExpectedArgs() throws Exception {
- try {
- TurbineOptions.builder().build();
- fail();
- } catch (NullPointerException e) {
- assertThat(e).hasMessage("output must not be null");
- }
+ public void tolerateMissingOutput() throws Exception {
+ TurbineOptions options = TurbineOptions.builder().build();
+ assertThat(options.output()).isEmpty();
}
@Test
diff --git a/javatests/com/google/turbine/parse/ParseErrorTest.java b/javatests/com/google/turbine/parse/ParseErrorTest.java
index c728c8a..53864ef 100644
--- a/javatests/com/google/turbine/parse/ParseErrorTest.java
+++ b/javatests/com/google/turbine/parse/ParseErrorTest.java
@@ -154,6 +154,54 @@ public class ParseErrorTest {
}
}
+ @Test
+ public void unterminatedString() {
+ String input = "class T { String s = \"hello\nworld\"; }";
+ try {
+ Parser.parse(input);
+ fail("expected parsing to fail");
+ } catch (TurbineError e) {
+ assertThat(e.getMessage())
+ .isEqualTo(
+ lines(
+ "<>:1: error: unterminated string literal", //
+ "class T { String s = \"hello",
+ " ^"));
+ }
+ }
+
+ @Test
+ public void emptyChar() {
+ String input = "class T { char c = ''; }";
+ try {
+ Parser.parse(input);
+ fail("expected parsing to fail");
+ } catch (TurbineError e) {
+ assertThat(e.getMessage())
+ .isEqualTo(
+ lines(
+ "<>:1: error: empty char literal", //
+ "class T { char c = ''; }",
+ " ^"));
+ }
+ }
+
+ @Test
+ public void unterminatedChar() {
+ String input = "class T { char c = '; }";
+ try {
+ Parser.parse(input);
+ fail("expected parsing to fail");
+ } catch (TurbineError e) {
+ assertThat(e.getMessage())
+ .isEqualTo(
+ lines(
+ "<>:1: error: unterminated char literal", //
+ "class T { char c = '; }",
+ " ^"));
+ }
+ }
+
private static String lines(String... lines) {
return Joiner.on(System.lineSeparator()).join(lines);
}
diff --git a/pom.xml b/pom.xml
index 58bc5f4..46a5100 100644
--- a/pom.xml
+++ b/pom.xml
@@ -15,15 +15,16 @@
</description>
<properties>
- <javac.version>9-dev-r3297-4</javac.version>
- <asm.version>6.0</asm.version>
+ <asm.version>7.0</asm.version>
+ <javac.version>9+181-r4173-1</javac.version>
+ <guava.version>25.1-jre</guava.version>
</properties>
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
- <version>22.0</version>
+ <version>${guava.version}</version>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
@@ -64,15 +65,6 @@
<version>${javac.version}</version>
<scope>test</scope>
</dependency>
- <!-- required for javap task -->
- <dependency>
- <groupId>com.sun</groupId>
- <artifactId>tools</artifactId>
- <scope>system</scope>
- <optional>true</optional>
- <version>1.8</version>
- <systemPath>${java.home}/../lib/tools.jar</systemPath>
- </dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
@@ -82,7 +74,13 @@
<dependency>
<groupId>com.google.truth</groupId>
<artifactId>truth</artifactId>
- <version>0.36</version>
+ <version>0.42</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.truth.extensions</groupId>
+ <artifactId>truth-java8-extension</artifactId>
+ <version>0.42</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -91,6 +89,18 @@
<version>1.0</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava-testlib</artifactId>
+ <version>${guava.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.auto.value</groupId>
+ <artifactId>auto-value</artifactId>
+ <version>1.5.3</version>
+ <scope>provided</scope>
+ </dependency>
</dependencies>
<build>
@@ -101,6 +111,7 @@
<directory>javatests</directory>
<includes>
<include>**/testdata/**</include>
+ <include>**/moduletestdata/**</include>
</includes>
</testResource>
</testResources>
@@ -115,11 +126,14 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
- <version>3.1</version>
+ <version>3.6.2</version>
<configuration>
+ <fork>true</fork>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
+ <compilerArgument>-parameters</compilerArgument>
+ <testCompilerArgument>-parameters</testCompilerArgument>
</configuration>
</plugin>
<plugin>
@@ -147,10 +161,60 @@
<version>2.19.1</version>
<configuration>
<!-- set heap size to work around http://github.com/travis-ci/travis-ci/issues/3396 -->
- <!-- put javac.jar on bootclasspath when executing tests -->
- <argLine>-Xmx1024m -Xbootclasspath/p:${settings.localRepository}/com/google/errorprone/javac/${javac.version}/javac-${javac.version}.jar</argLine>
+ <argLine>-Xmx2g</argLine>
</configuration>
</plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-shade-plugin</artifactId>
+ <version>2.4.3</version>
+ <executions>
+ <execution>
+ <id>shade-all-deps</id>
+ <phase>package</phase>
+ <goals>
+ <goal>shade</goal>
+ </goals>
+ <configuration>
+ <shadedArtifactAttached>true</shadedArtifactAttached>
+ <shadedClassifierName>all-deps</shadedClassifierName>
+ <createDependencyReducedPom>false</createDependencyReducedPom>
+ <!-- http://stackoverflow.com/a/6743609 -->
+ <filters>
+ <filter>
+ <artifact>*:*</artifact>
+ <excludes>
+ <exclude>META-INF/*.SF</exclude>
+ <exclude>META-INF/*.DSA</exclude>
+ <exclude>META-INF/*.RSA</exclude>
+ </excludes>
+ </filter>
+ </filters>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
</plugins>
</build>
+ <profiles>
+ <profile>
+ <id>java-8</id>
+ <activation>
+ <jdk>1.8</jdk>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <!-- put javac.jar on bootclasspath when executing tests -->
+ <argLine>-Xbootclasspath/p:${settings.localRepository}/com/google/errorprone/javac/${javac.version}/javac-${javac.version}.jar</argLine>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
</project>