aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcushon <cushon@google.com>2018-04-09 14:12:12 -0700
committerLiam Miller-Cushon <cushon@google.com>2018-04-10 23:17:25 -0700
commitdb00737c711b291adf423c503284ce1dc01a13a6 (patch)
tree4f1e76610bca1ac1d1d38aef158c7247a820b261
parentbe7c38da06932677b2de0864f75444ac8d3d8e7c (diff)
downloadturbine-db00737c711b291adf423c503284ce1dc01a13a6.tar.gz
Improve diagnostics for missing enclosing classes
MOE_MIGRATED_REVID=192185656
-rw-r--r--java/com/google/turbine/binder/Binder.java13
-rw-r--r--java/com/google/turbine/binder/CanonicalTypeBinder.java55
-rw-r--r--java/com/google/turbine/binder/ModuleBinder.java10
-rw-r--r--java/com/google/turbine/binder/bound/SourceModuleInfo.java52
-rw-r--r--java/com/google/turbine/diag/TurbineError.java16
-rw-r--r--java/com/google/turbine/lower/Lower.java38
-rw-r--r--java/com/google/turbine/types/Canonicalize.java56
-rw-r--r--javatests/com/google/turbine/lower/LowerTest.java118
8 files changed, 293 insertions, 65 deletions
diff --git a/java/com/google/turbine/binder/Binder.java b/java/com/google/turbine/binder/Binder.java
index cbafdef..d4b151f 100644
--- a/java/com/google/turbine/binder/Binder.java
+++ b/java/com/google/turbine/binder/Binder.java
@@ -31,6 +31,7 @@ import com.google.turbine.binder.bound.PackageSourceBoundClass;
import com.google.turbine.binder.bound.PackageSourceBoundModule;
import com.google.turbine.binder.bound.SourceBoundClass;
import com.google.turbine.binder.bound.SourceHeaderBoundClass;
+import com.google.turbine.binder.bound.SourceModuleInfo;
import com.google.turbine.binder.bound.SourceTypeBoundClass;
import com.google.turbine.binder.bound.TypeBoundClass;
import com.google.turbine.binder.bound.TypeBoundClass.FieldInfo;
@@ -112,7 +113,7 @@ public class Binder {
canonicalizeTypes(
syms, tenv, CompoundEnv.<ClassSymbol, TypeBoundClass>of(classPathEnv).append(tenv));
- ImmutableList<ModuleInfo> boundModules =
+ ImmutableList<SourceModuleInfo> boundModules =
bindModules(
modules,
CompoundEnv.<ClassSymbol, TypeBoundClass>of(classPathEnv).append(tenv),
@@ -244,7 +245,7 @@ public class Binder {
return builder.build();
}
- private static ImmutableList<ModuleInfo> bindModules(
+ private static ImmutableList<SourceModuleInfo> bindModules(
SimpleEnv<ModuleSymbol, PackageSourceBoundModule> modules,
CompoundEnv<ClassSymbol, TypeBoundClass> env,
CompoundEnv<ModuleSymbol, ModuleInfo> moduleEnv,
@@ -274,7 +275,7 @@ public class Binder {
return null;
}
});
- ImmutableList.Builder<ModuleInfo> bound = ImmutableList.builder();
+ ImmutableList.Builder<SourceModuleInfo> bound = ImmutableList.builder();
for (PackageSourceBoundModule module : modules.asMap().values()) {
bound.add(ModuleBinder.bind(module, env, moduleEnv, moduleVersion));
}
@@ -378,12 +379,12 @@ public class Binder {
/** The result of binding: bound nodes for sources in the compilation, and the classpath. */
public static class BindingResult {
private final ImmutableMap<ClassSymbol, SourceTypeBoundClass> units;
- private final ImmutableList<ModuleInfo> modules;
+ private final ImmutableList<SourceModuleInfo> modules;
private final CompoundEnv<ClassSymbol, BytecodeBoundClass> classPathEnv;
public BindingResult(
ImmutableMap<ClassSymbol, SourceTypeBoundClass> units,
- ImmutableList<ModuleInfo> modules,
+ ImmutableList<SourceModuleInfo> modules,
CompoundEnv<ClassSymbol, BytecodeBoundClass> classPathEnv) {
this.units = units;
this.modules = modules;
@@ -395,7 +396,7 @@ public class Binder {
return units;
}
- public ImmutableList<ModuleInfo> modules() {
+ public ImmutableList<SourceModuleInfo> modules() {
return modules;
}
diff --git a/java/com/google/turbine/binder/CanonicalTypeBinder.java b/java/com/google/turbine/binder/CanonicalTypeBinder.java
index 2ff56a3..20db0d7 100644
--- a/java/com/google/turbine/binder/CanonicalTypeBinder.java
+++ b/java/com/google/turbine/binder/CanonicalTypeBinder.java
@@ -27,6 +27,7 @@ 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;
+import com.google.turbine.diag.SourceFile;
import com.google.turbine.type.Type;
import com.google.turbine.type.Type.ClassTy;
import com.google.turbine.types.Canonicalize;
@@ -41,16 +42,17 @@ public class CanonicalTypeBinder {
ClassSymbol sym, SourceTypeBoundClass base, Env<ClassSymbol, TypeBoundClass> env) {
ClassTy superClassType = null;
if (base.superClassType() != null) {
- superClassType = Canonicalize.canonicalizeClassTy(env, base.owner(), base.superClassType());
+ superClassType =
+ Canonicalize.canonicalizeClassTy(base.source(), env, base.owner(), base.superClassType());
}
ImmutableList.Builder<ClassTy> interfaceTypes = ImmutableList.builder();
for (ClassTy i : base.interfaceTypes()) {
- interfaceTypes.add(Canonicalize.canonicalizeClassTy(env, base.owner(), i));
+ interfaceTypes.add(Canonicalize.canonicalizeClassTy(base.source(), env, base.owner(), i));
}
ImmutableMap<TyVarSymbol, TyVarInfo> typParamTypes =
- typeParameters(env, sym, base.typeParameterTypes());
- ImmutableList<MethodInfo> methods = methods(env, sym, base.methods());
- ImmutableList<FieldInfo> fields = fields(env, sym, base.fields());
+ typeParameters(base.source(), env, sym, base.typeParameterTypes());
+ ImmutableList<MethodInfo> methods = methods(base.source(), env, sym, base.methods());
+ ImmutableList<FieldInfo> fields = fields(base.source(), env, sym, base.fields());
return new SourceTypeBoundClass(
interfaceTypes.build(),
superClassType,
@@ -71,13 +73,16 @@ public class CanonicalTypeBinder {
}
private static ImmutableList<FieldInfo> fields(
- Env<ClassSymbol, TypeBoundClass> env, ClassSymbol sym, ImmutableList<FieldInfo> fields) {
+ SourceFile source,
+ Env<ClassSymbol, TypeBoundClass> env,
+ ClassSymbol sym,
+ ImmutableList<FieldInfo> fields) {
ImmutableList.Builder<FieldInfo> result = ImmutableList.builder();
for (FieldInfo base : fields) {
result.add(
new FieldInfo(
base.sym(),
- Canonicalize.canonicalize(env, sym, base.type()),
+ Canonicalize.canonicalize(source, env, sym, base.type()),
base.access(),
base.annotations(),
base.decl(),
@@ -87,16 +92,19 @@ public class CanonicalTypeBinder {
}
private static ImmutableList<MethodInfo> methods(
- Env<ClassSymbol, TypeBoundClass> env, ClassSymbol sym, ImmutableList<MethodInfo> methods) {
+ SourceFile source,
+ Env<ClassSymbol, TypeBoundClass> env,
+ ClassSymbol sym,
+ ImmutableList<MethodInfo> methods) {
ImmutableList.Builder<MethodInfo> result = ImmutableList.builder();
for (MethodInfo base : methods) {
- ImmutableMap<TyVarSymbol, TyVarInfo> tps = typeParameters(env, sym, base.tyParams());
- Type ret = Canonicalize.canonicalize(env, sym, base.returnType());
+ ImmutableMap<TyVarSymbol, TyVarInfo> tps = typeParameters(source, env, sym, base.tyParams());
+ Type ret = Canonicalize.canonicalize(source, env, sym, base.returnType());
ImmutableList.Builder<ParamInfo> parameters = ImmutableList.builder();
for (ParamInfo parameter : base.parameters()) {
- parameters.add(param(env, sym, parameter));
+ parameters.add(param(source, env, sym, parameter));
}
- ImmutableList<Type> exceptions = canonicalizeList(env, sym, base.exceptions());
+ ImmutableList<Type> exceptions = canonicalizeList(source, env, sym, base.exceptions());
result.add(
new MethodInfo(
base.sym(),
@@ -108,40 +116,47 @@ public class CanonicalTypeBinder {
base.defaultValue(),
base.decl(),
base.annotations(),
- base.receiver() != null ? param(env, sym, base.receiver()) : null));
+ base.receiver() != null ? param(source, env, sym, base.receiver()) : null));
}
return result.build();
}
private static ParamInfo param(
- Env<ClassSymbol, TypeBoundClass> env, ClassSymbol sym, ParamInfo base) {
+ SourceFile source, Env<ClassSymbol, TypeBoundClass> env, ClassSymbol sym, ParamInfo base) {
return new ParamInfo(
- Canonicalize.canonicalize(env, sym, base.type()),
+ Canonicalize.canonicalize(source, env, sym, base.type()),
base.name(),
base.annotations(),
base.access());
}
private static ImmutableMap<TyVarSymbol, TyVarInfo> typeParameters(
- Env<ClassSymbol, TypeBoundClass> env, ClassSymbol sym, Map<TyVarSymbol, TyVarInfo> tps) {
+ SourceFile source,
+ 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(env, sym, info.superClassBound());
+ superClassBound = Canonicalize.canonicalize(source, env, sym, info.superClassBound());
}
- ImmutableList<Type> interfaceBounds = canonicalizeList(env, sym, info.interfaceBounds());
+ ImmutableList<Type> interfaceBounds =
+ canonicalizeList(source, env, sym, info.interfaceBounds());
result.put(e.getKey(), new TyVarInfo(superClassBound, interfaceBounds, info.annotations()));
}
return result.build();
}
private static ImmutableList<Type> canonicalizeList(
- Env<ClassSymbol, TypeBoundClass> env, ClassSymbol sym, ImmutableList<Type> types) {
+ SourceFile source,
+ Env<ClassSymbol, TypeBoundClass> env,
+ ClassSymbol sym,
+ ImmutableList<Type> types) {
ImmutableList.Builder<Type> result = ImmutableList.builder();
for (Type type : types) {
- result.add(Canonicalize.canonicalize(env, sym, type));
+ result.add(Canonicalize.canonicalize(source, env, sym, type));
}
return result.build();
}
diff --git a/java/com/google/turbine/binder/ModuleBinder.java b/java/com/google/turbine/binder/ModuleBinder.java
index 23c9624..2cf3d53 100644
--- a/java/com/google/turbine/binder/ModuleBinder.java
+++ b/java/com/google/turbine/binder/ModuleBinder.java
@@ -29,6 +29,7 @@ import com.google.turbine.binder.bound.ModuleInfo.ProvideInfo;
import com.google.turbine.binder.bound.ModuleInfo.RequireInfo;
import com.google.turbine.binder.bound.ModuleInfo.UseInfo;
import com.google.turbine.binder.bound.PackageSourceBoundModule;
+import com.google.turbine.binder.bound.SourceModuleInfo;
import com.google.turbine.binder.bound.TypeBoundClass;
import com.google.turbine.binder.env.CompoundEnv;
import com.google.turbine.binder.env.Env;
@@ -54,7 +55,7 @@ import com.google.turbine.type.AnnoInfo;
/** Binding pass for modules. */
public class ModuleBinder {
- public static ModuleInfo bind(
+ public static SourceModuleInfo bind(
PackageSourceBoundModule module,
CompoundEnv<ClassSymbol, TypeBoundClass> env,
Env<ModuleSymbol, ModuleInfo> moduleEnv,
@@ -80,7 +81,7 @@ public class ModuleBinder {
this.scope = module.scope().toScope(Resolve.resolveFunction(env, /* origin= */ null));
}
- private ModuleInfo bind() {
+ private SourceModuleInfo bind() {
// bind annotations; constant fields are already bound
ConstEvaluator constEvaluator =
new ConstEvaluator(
@@ -146,7 +147,7 @@ public class ModuleBinder {
.addAll(requires.build());
}
- return new ModuleInfo(
+ return new SourceModuleInfo(
module.module().moduleName(),
moduleVersion.orNull(),
flags,
@@ -155,7 +156,8 @@ public class ModuleBinder {
exports.build(),
opens.build(),
uses.build(),
- provides.build());
+ provides.build(),
+ module.source());
}
private RequireInfo bindRequires(ModRequires directive) {
diff --git a/java/com/google/turbine/binder/bound/SourceModuleInfo.java b/java/com/google/turbine/binder/bound/SourceModuleInfo.java
new file mode 100644
index 0000000..9ecca8b
--- /dev/null
+++ b/java/com/google/turbine/binder/bound/SourceModuleInfo.java
@@ -0,0 +1,52 @@
+/*
+ * 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.bound;
+
+import android.support.annotation.Nullable;
+import com.google.common.collect.ImmutableList;
+import com.google.turbine.binder.bound.ModuleInfo.ExportInfo;
+import com.google.turbine.binder.bound.ModuleInfo.OpenInfo;
+import com.google.turbine.binder.bound.ModuleInfo.ProvideInfo;
+import com.google.turbine.binder.bound.ModuleInfo.RequireInfo;
+import com.google.turbine.binder.bound.ModuleInfo.UseInfo;
+import com.google.turbine.diag.SourceFile;
+import com.google.turbine.type.AnnoInfo;
+
+/** A {@link ModuleInfo} that corresponds to a source file being compiled. */
+public class SourceModuleInfo extends ModuleInfo {
+
+ private final SourceFile source;
+
+ public SourceModuleInfo(
+ String name,
+ @Nullable String version,
+ int flags,
+ ImmutableList<AnnoInfo> annos,
+ ImmutableList<RequireInfo> requires,
+ ImmutableList<ExportInfo> exports,
+ ImmutableList<OpenInfo> opens,
+ ImmutableList<UseInfo> uses,
+ ImmutableList<ProvideInfo> provides,
+ SourceFile source) {
+ super(name, version, flags, annos, requires, exports, opens, uses, provides);
+ this.source = source;
+ }
+
+ public SourceFile source() {
+ return source;
+ }
+}
diff --git a/java/com/google/turbine/diag/TurbineError.java b/java/com/google/turbine/diag/TurbineError.java
index b8d6b65..8c75345 100644
--- a/java/com/google/turbine/diag/TurbineError.java
+++ b/java/com/google/turbine/diag/TurbineError.java
@@ -33,6 +33,7 @@ public class TurbineError extends Error {
INVALID_LITERAL("invalid literal: %s"),
UNEXPECTED_TYPE_PARAMETER("unexpected type parameter %s"),
SYMBOL_NOT_FOUND("symbol not found %s"),
+ CLASS_FILE_NOT_FOUND("could not locate class file for %s"),
TYPE_PARAMETER_QUALIFIER("type parameter used as type qualifier"),
UNEXPECTED_TOKEN("unexpected token: %s"),
INVALID_ANNOTATION_ARGUMENT("invalid annotation argument"),
@@ -58,7 +59,20 @@ public class TurbineError extends Error {
/**
* Formats a diagnostic.
*
- * @param source the source file
+ * @param source the current source file
+ * @param kind the error kind
+ * @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);
+ }
+
+ /**
+ * Formats a diagnostic.
+ *
* @param position the diagnostic position
* @param kind the error kind
* @param args format args
diff --git a/java/com/google/turbine/lower/Lower.java b/java/com/google/turbine/lower/Lower.java
index d8b464b..04f352e 100644
--- a/java/com/google/turbine/lower/Lower.java
+++ b/java/com/google/turbine/lower/Lower.java
@@ -27,12 +27,12 @@ import com.google.common.collect.ImmutableSet;
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.bound.ModuleInfo.ExportInfo;
import com.google.turbine.binder.bound.ModuleInfo.OpenInfo;
import com.google.turbine.binder.bound.ModuleInfo.ProvideInfo;
import com.google.turbine.binder.bound.ModuleInfo.RequireInfo;
import com.google.turbine.binder.bound.ModuleInfo.UseInfo;
+import com.google.turbine.binder.bound.SourceModuleInfo;
import com.google.turbine.binder.bound.SourceTypeBoundClass;
import com.google.turbine.binder.bound.TypeBoundClass;
import com.google.turbine.binder.bound.TypeBoundClass.FieldInfo;
@@ -60,6 +60,9 @@ import com.google.turbine.bytecode.sig.Sig;
import com.google.turbine.bytecode.sig.Sig.MethodSig;
import com.google.turbine.bytecode.sig.Sig.TySig;
import com.google.turbine.bytecode.sig.SigWriter;
+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.TurbineFlag;
import com.google.turbine.model.TurbineVisibility;
@@ -109,7 +112,7 @@ public class Lower {
/** Lowers all given classes to bytecode. */
public static Lowered lowerAll(
ImmutableMap<ClassSymbol, SourceTypeBoundClass> units,
- ImmutableList<ModuleInfo> modules,
+ ImmutableList<SourceModuleInfo> modules,
Env<ClassSymbol, BytecodeBoundClass> classpath) {
CompoundEnv<ClassSymbol, TypeBoundClass> env =
CompoundEnv.<ClassSymbol, TypeBoundClass>of(classpath).append(new SimpleEnv<>(units));
@@ -124,7 +127,7 @@ public class Lower {
} else {
// multi-module mode: the output module-info.class are in a directory corresponding to their
// package
- for (ModuleInfo module : modules) {
+ for (SourceModuleInfo module : modules) {
result.put(module.name().replace('.', '/') + "/module-info", lower(module, env, symbols));
}
}
@@ -141,7 +144,9 @@ public class Lower {
}
private static byte[] lower(
- ModuleInfo module, CompoundEnv<ClassSymbol, TypeBoundClass> env, Set<ClassSymbol> symbols) {
+ SourceModuleInfo module,
+ CompoundEnv<ClassSymbol, TypeBoundClass> env,
+ Set<ClassSymbol> symbols) {
return new Lower(env).lower(module, symbols);
}
@@ -152,7 +157,7 @@ public class Lower {
this.env = env;
}
- private byte[] lower(ModuleInfo module, Set<ClassSymbol> symbols) {
+ private byte[] lower(SourceModuleInfo module, Set<ClassSymbol> symbols) {
String name = "module-info";
ImmutableList<AnnotationInfo> annotations = lowerAnnotations(module.annos());
ClassFile.ModuleInfo moduleInfo = lowerModule(module);
@@ -161,7 +166,7 @@ public class Lower {
{
Set<ClassSymbol> all = new LinkedHashSet<>();
for (ClassSymbol sym : sig.classes) {
- addEnclosing(env, all, sym);
+ addEnclosing(module.source(), env, all, sym);
}
for (ClassSymbol innerSym : all) {
innerClasses.add(innerClass(env, innerSym));
@@ -185,7 +190,7 @@ public class Lower {
return ClassWriter.writeClass(classfile);
}
- private ClassFile.ModuleInfo lowerModule(ModuleInfo module) {
+ private ClassFile.ModuleInfo lowerModule(SourceModuleInfo module) {
ImmutableList.Builder<ClassFile.ModuleInfo.RequireInfo> requires = ImmutableList.builder();
for (RequireInfo require : module.requires()) {
requires.add(
@@ -258,7 +263,7 @@ public class Lower {
ImmutableList<AnnotationInfo> annotations = lowerAnnotations(info.annotations());
- ImmutableList<ClassFile.InnerClass> inners = collectInnerClasses(sym, info);
+ ImmutableList<ClassFile.InnerClass> inners = collectInnerClasses(info.source(), sym, info);
ImmutableList<TypeAnnotationInfo> typeAnnotations = classTypeAnnotations(info);
@@ -382,14 +387,14 @@ public class Lower {
/** Creates inner class attributes for all referenced inner classes. */
private ImmutableList<ClassFile.InnerClass> collectInnerClasses(
- ClassSymbol origin, SourceTypeBoundClass info) {
+ SourceFile source, ClassSymbol origin, SourceTypeBoundClass info) {
Set<ClassSymbol> all = new LinkedHashSet<>();
- addEnclosing(env, all, origin);
+ addEnclosing(source, env, all, origin);
for (ClassSymbol sym : info.children().values()) {
- addEnclosing(env, all, sym);
+ addEnclosing(source, env, all, sym);
}
for (ClassSymbol sym : sig.classes) {
- addEnclosing(env, all, sym);
+ addEnclosing(source, env, all, sym);
}
ImmutableList.Builder<ClassFile.InnerClass> inners = ImmutableList.builder();
for (ClassSymbol innerSym : all) {
@@ -406,14 +411,17 @@ public class Lower {
* classes' entries.
*/
private void addEnclosing(
- Env<ClassSymbol, TypeBoundClass> env, Set<ClassSymbol> all, ClassSymbol sym) {
+ SourceFile source,
+ Env<ClassSymbol, TypeBoundClass> env,
+ Set<ClassSymbol> all,
+ ClassSymbol sym) {
TypeBoundClass info = env.get(sym);
if (info == null) {
- throw new AssertionError(sym);
+ throw TurbineError.format(source, ErrorKind.CLASS_FILE_NOT_FOUND, sym);
}
ClassSymbol owner = env.get(sym).owner();
if (owner != null) {
- addEnclosing(env, all, owner);
+ addEnclosing(source, env, all, owner);
all.add(sym);
}
}
diff --git a/java/com/google/turbine/types/Canonicalize.java b/java/com/google/turbine/types/Canonicalize.java
index fc5d907..98adf57 100644
--- a/java/com/google/turbine/types/Canonicalize.java
+++ b/java/com/google/turbine/types/Canonicalize.java
@@ -22,6 +22,9 @@ import com.google.turbine.binder.bound.TypeBoundClass;
import com.google.turbine.binder.env.Env;
import com.google.turbine.binder.sym.ClassSymbol;
import com.google.turbine.binder.sym.TyVarSymbol;
+import com.google.turbine.diag.SourceFile;
+import com.google.turbine.diag.TurbineError;
+import com.google.turbine.diag.TurbineError.ErrorKind;
import com.google.turbine.model.TurbineFlag;
import com.google.turbine.type.Type;
import com.google.turbine.type.Type.ArrayTy;
@@ -63,35 +66,38 @@ public class Canonicalize {
/** Canonicalizes the given type. */
public static Type canonicalize(
- Env<ClassSymbol, TypeBoundClass> env, ClassSymbol base, Type type) {
+ SourceFile source, Env<ClassSymbol, TypeBoundClass> env, ClassSymbol base, Type type) {
switch (type.tyKind()) {
case PRIM_TY:
case VOID_TY:
case TY_VAR:
return type;
case WILD_TY:
- return canonicalizeWildTy(env, base, (WildTy) type);
+ return canonicalizeWildTy(source, env, base, (WildTy) type);
case ARRAY_TY:
{
Type.ArrayTy arrayTy = (Type.ArrayTy) type;
- return new Type.ArrayTy(canonicalize(env, base, arrayTy.elementType()), arrayTy.annos());
+ return new Type.ArrayTy(
+ canonicalize(source, env, base, arrayTy.elementType()), arrayTy.annos());
}
case CLASS_TY:
- return canonicalizeClassTy(env, base, (ClassTy) type);
+ return canonicalizeClassTy(source, env, base, (ClassTy) type);
default:
throw new AssertionError(type.tyKind());
}
}
/** Canonicalize a qualified class type, excluding type arguments. */
- private static ClassTy canon(Env<ClassSymbol, TypeBoundClass> env, ClassSymbol base, ClassTy ty) {
+ private static ClassTy canon(
+ SourceFile source, Env<ClassSymbol, TypeBoundClass> env, ClassSymbol base, ClassTy ty) {
if (isRaw(env, 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(env, ty.classes.get(0).sym(), base);
+ Collection<ClassTy.SimpleClassTy> lexicalBase =
+ lexicalBase(source, env, ty.classes.get(0).sym(), base);
ClassTy canon =
!lexicalBase.isEmpty()
? new ClassTy(lexicalBase)
@@ -99,7 +105,7 @@ public class Canonicalize {
// canonicalize each additional simple name that appeared in source
while (it.hasNext()) {
- canon = canonOne(env, canon, it.next());
+ canon = canonOne(source, env, canon, it.next());
}
return canon;
}
@@ -122,7 +128,10 @@ public class Canonicalize {
/** Given a base symbol to canonicalize, find any implicit enclosing instances. */
private static Collection<ClassTy.SimpleClassTy> lexicalBase(
- Env<ClassSymbol, TypeBoundClass> env, ClassSymbol first, ClassSymbol owner) {
+ SourceFile source,
+ Env<ClassSymbol, TypeBoundClass> env,
+ ClassSymbol first,
+ ClassSymbol owner) {
if ((env.get(first).access() & TurbineFlag.ACC_STATIC) == TurbineFlag.ACC_STATIC) {
return Collections.emptyList();
}
@@ -137,7 +146,11 @@ public class Canonicalize {
if ((env.get(owner).access() & TurbineFlag.ACC_STATIC) == TurbineFlag.ACC_STATIC) {
break;
}
- canonOwner = env.get(canonOwner).owner();
+ TypeBoundClass info = env.get(canonOwner);
+ if (info == null) {
+ throw TurbineError.format(source, ErrorKind.CLASS_FILE_NOT_FOUND, canonOwner);
+ }
+ canonOwner = info.owner();
}
return result;
}
@@ -167,7 +180,7 @@ public class Canonicalize {
* result.
*/
private static ClassTy canonOne(
- Env<ClassSymbol, TypeBoundClass> env, ClassTy base, ClassTy.SimpleClassTy ty) {
+ SourceFile source, Env<ClassSymbol, TypeBoundClass> env, 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));
@@ -196,7 +209,7 @@ public class Canonicalize {
break;
}
TypeBoundClass info = env.get(curr.sym());
- curr = canon(env, info.owner(), info.superClassType());
+ curr = canon(source, env, info.owner(), info.superClassType());
}
simples.add(ty);
return new ClassTy(simples.build());
@@ -315,36 +328,41 @@ public class Canonicalize {
}
public static ClassTy canonicalizeClassTy(
- Env<ClassSymbol, TypeBoundClass> env, ClassSymbol base, ClassTy ty) {
+ SourceFile source, Env<ClassSymbol, TypeBoundClass> env, 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(s.targs(), base, env), s.annos()));
+ args.add(
+ new ClassTy.SimpleClassTy(
+ s.sym(), canonicalize(source, s.targs(), base, env), s.annos()));
}
ty = new ClassTy(args.build());
- return canon(env, base, ty);
+ return canon(source, env, base, ty);
}
private static ImmutableList<Type> canonicalize(
- ImmutableList<Type> targs, ClassSymbol base, Env<ClassSymbol, TypeBoundClass> env) {
+ SourceFile source,
+ ImmutableList<Type> targs,
+ ClassSymbol base,
+ Env<ClassSymbol, TypeBoundClass> env) {
ImmutableList.Builder<Type> result = ImmutableList.builder();
for (Type a : targs) {
- result.add(canonicalize(env, base, a));
+ result.add(canonicalize(source, env, base, a));
}
return result.build();
}
private static Type canonicalizeWildTy(
- Env<ClassSymbol, TypeBoundClass> env, ClassSymbol base, WildTy type) {
+ SourceFile source, Env<ClassSymbol, TypeBoundClass> env, ClassSymbol base, WildTy type) {
switch (type.boundKind()) {
case NONE:
return type;
case LOWER:
return new Type.WildLowerBoundedTy(
- canonicalize(env, base, type.bound()), type.annotations());
+ canonicalize(source, env, base, type.bound()), type.annotations());
case UPPER:
return new Type.WildUpperBoundedTy(
- canonicalize(env, base, type.bound()), type.annotations());
+ canonicalize(source, env, base, type.bound()), type.annotations());
default:
throw new AssertionError(type.boundKind());
}
diff --git a/javatests/com/google/turbine/lower/LowerTest.java b/javatests/com/google/turbine/lower/LowerTest.java
index 6409d4d..86d4ce4 100644
--- a/javatests/com/google/turbine/lower/LowerTest.java
+++ b/javatests/com/google/turbine/lower/LowerTest.java
@@ -19,6 +19,7 @@ package com.google.turbine.lower;
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;
+import static org.junit.Assert.fail;
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
@@ -36,6 +37,7 @@ import com.google.turbine.binder.sym.MethodSymbol;
import com.google.turbine.binder.sym.TyVarSymbol;
import com.google.turbine.bytecode.ByteReader;
import com.google.turbine.bytecode.ConstantPoolReader;
+import com.google.turbine.diag.TurbineError;
import com.google.turbine.model.TurbineConstantTypeKind;
import com.google.turbine.model.TurbineFlag;
import com.google.turbine.model.TurbineTyKind;
@@ -480,6 +482,122 @@ public class LowerTest {
.isEqualTo(IntegrationTestSupport.dump(IntegrationTestSupport.canonicalize(expected)));
}
+ @Test
+ public void missingOuter() throws Exception {
+
+ Map<String, byte[]> lib =
+ IntegrationTestSupport.runJavac(
+ ImmutableMap.of(
+ "A.java",
+ lines(
+ "interface A {", //
+ " interface M {",
+ " interface I {}",
+ " } ",
+ "}"),
+ "B.java",
+ lines(
+ "interface B extends A {",
+ " interface BM extends M {",
+ " interface BI extends I {}",
+ " }",
+ "}")),
+ ImmutableList.of());
+
+ Path libJar = temporaryFolder.newFile("lib.jar").toPath();
+ try (OutputStream os = Files.newOutputStream(libJar);
+ JarOutputStream jos = new JarOutputStream(os)) {
+ jos.putNextEntry(new JarEntry("A$M.class"));
+ jos.write(lib.get("A$M"));
+ jos.putNextEntry(new JarEntry("A$M$I.class"));
+ jos.write(lib.get("A$M$I"));
+ jos.putNextEntry(new JarEntry("B.class"));
+ jos.write(lib.get("B"));
+ jos.putNextEntry(new JarEntry("B$BM.class"));
+ jos.write(lib.get("B$BM"));
+ jos.putNextEntry(new JarEntry("B$BM$BI.class"));
+ jos.write(lib.get("B$BM$BI"));
+ }
+
+ ImmutableMap<String, String> sources =
+ ImmutableMap.<String, String>builder()
+ .put(
+ "Test.java",
+ lines(
+ "public class Test extends B.BM {", //
+ " I i;",
+ "}"))
+ .build();
+
+ try {
+ IntegrationTestSupport.runTurbine(sources, ImmutableList.of(libJar));
+ fail();
+ } catch (TurbineError error) {
+ assertThat(error)
+ .hasMessageThat()
+ .contains("Test.java: error: could not locate class file for A");
+ }
+ }
+
+ @Test
+ public void missingOuter2() throws Exception {
+
+ Map<String, byte[]> lib =
+ IntegrationTestSupport.runJavac(
+ ImmutableMap.of(
+ "A.java",
+ lines(
+ "class A {", //
+ " class M { ",
+ " class I {} ",
+ " } ",
+ "}"),
+ "B.java",
+ lines(
+ "class B extends A { ",
+ " class BM extends M { ",
+ " class BI extends I {} ",
+ " } ",
+ "}")),
+ ImmutableList.of());
+
+ Path libJar = temporaryFolder.newFile("lib.jar").toPath();
+ try (OutputStream os = Files.newOutputStream(libJar);
+ JarOutputStream jos = new JarOutputStream(os)) {
+ jos.putNextEntry(new JarEntry("A$M.class"));
+ jos.write(lib.get("A$M"));
+ jos.putNextEntry(new JarEntry("A$M$I.class"));
+ jos.write(lib.get("A$M$I"));
+ jos.putNextEntry(new JarEntry("B.class"));
+ jos.write(lib.get("B"));
+ jos.putNextEntry(new JarEntry("B$BM.class"));
+ jos.write(lib.get("B$BM"));
+ jos.putNextEntry(new JarEntry("B$BM$BI.class"));
+ jos.write(lib.get("B$BM$BI"));
+ }
+
+ ImmutableMap<String, String> sources =
+ ImmutableMap.<String, String>builder()
+ .put(
+ "Test.java",
+ lines(
+ "public class Test extends B {", //
+ " class M extends BM {",
+ " I i;",
+ " }",
+ "}"))
+ .build();
+
+ try {
+ IntegrationTestSupport.runTurbine(sources, ImmutableList.of(libJar));
+ fail();
+ } catch (TurbineError error) {
+ assertThat(error)
+ .hasMessageThat()
+ .contains("Test.java: error: could not locate class file for A");
+ }
+ }
+
static String lines(String... lines) {
return Joiner.on("\n").join(lines);
}