Fix annotation-context binding of constants in class files

The env of constant variables wasn't being set up to include constants
on the classpath when binding annotations. Instead, we can just read the
constant values directly from the bound fields if they're already there.

MOE_MIGRATED_REVID=136493292
diff --git a/java/com/google/turbine/binder/Binder.java b/java/com/google/turbine/binder/Binder.java
index 907da71..44e6e7a 100644
--- a/java/com/google/turbine/binder/Binder.java
+++ b/java/com/google/turbine/binder/Binder.java
@@ -68,7 +68,8 @@
 
     // change data to better represent source binding info
     Multimap<CompUnit, ClassSymbol> toplevels = LinkedHashMultimap.create();
-    SimpleEnv<SourceBoundClass> ienv = bindSourceBoundClasses(toplevels, units, tliBuilder);
+    SimpleEnv<ClassSymbol, SourceBoundClass> ienv =
+        bindSourceBoundClasses(toplevels, units, tliBuilder);
 
     ImmutableSet<ClassSymbol> syms = ienv.asMap().keySet();
 
@@ -82,7 +83,8 @@
 
     TopLevelIndex tli = tliBuilder.build();
 
-    SimpleEnv<PackageSourceBoundClass> psenv = bindPackages(ienv, tli, toplevels, classPathEnv);
+    SimpleEnv<ClassSymbol, PackageSourceBoundClass> psenv =
+        bindPackages(ienv, tli, toplevels, classPathEnv);
 
     Env<ClassSymbol, SourceHeaderBoundClass> henv = bindHierarchy(syms, psenv, classPathEnv);
 
@@ -105,11 +107,11 @@
   }
 
   /** Records enclosing declarations of member classes, and group classes by compilation unit. */
-  static SimpleEnv<SourceBoundClass> bindSourceBoundClasses(
+  static SimpleEnv<ClassSymbol, SourceBoundClass> bindSourceBoundClasses(
       Multimap<CompUnit, ClassSymbol> toplevels,
       List<CompUnit> units,
       TopLevelIndex.Builder tliBuilder) {
-    SimpleEnv.Builder<SourceBoundClass> envbuilder = SimpleEnv.builder();
+    SimpleEnv.Builder<ClassSymbol, SourceBoundClass> envbuilder = SimpleEnv.builder();
     for (CompUnit unit : units) {
       String packagename;
       if (unit.pkg().isPresent()) {
@@ -133,7 +135,7 @@
 
   /** Records member declarations within a top-level class. */
   private static ImmutableMap<String, ClassSymbol> bindSourceBoundClassMembers(
-      SimpleEnv.Builder<SourceBoundClass> env,
+      SimpleEnv.Builder<ClassSymbol, SourceBoundClass> env,
       ClassSymbol owner,
       ImmutableList<Tree> members,
       Multimap<CompUnit, ClassSymbol> toplevels,
@@ -154,13 +156,13 @@
   }
 
   /** Initializes scopes for compilation unit and package-level lookup. */
-  private static SimpleEnv<PackageSourceBoundClass> bindPackages(
+  private static SimpleEnv<ClassSymbol, PackageSourceBoundClass> bindPackages(
       Env<ClassSymbol, SourceBoundClass> ienv,
       TopLevelIndex tli,
       Multimap<CompUnit, ClassSymbol> classes,
       CompoundEnv<ClassSymbol, BytecodeBoundClass> classPathEnv) {
 
-    SimpleEnv.Builder<PackageSourceBoundClass> env = SimpleEnv.builder();
+    SimpleEnv.Builder<ClassSymbol, PackageSourceBoundClass> env = SimpleEnv.builder();
     Scope javaLang = verifyNotNull(tli.lookupPackage(ImmutableList.of("java", "lang")));
     CompoundScope topLevel = CompoundScope.base(tli).append(javaLang);
     for (Map.Entry<CompUnit, Collection<ClassSymbol>> entry : classes.asMap().entrySet()) {
@@ -185,7 +187,7 @@
   /** Binds the type hierarchy (superclasses and interfaces) for all classes in the compilation. */
   private static Env<ClassSymbol, SourceHeaderBoundClass> bindHierarchy(
       Iterable<ClassSymbol> syms,
-      final SimpleEnv<PackageSourceBoundClass> psenv,
+      final SimpleEnv<ClassSymbol, PackageSourceBoundClass> psenv,
       CompoundEnv<ClassSymbol, BytecodeBoundClass> classPathEnv) {
     ImmutableMap.Builder<
             ClassSymbol, LazyEnv.Completer<ClassSymbol, HeaderBoundClass, SourceHeaderBoundClass>>
@@ -208,7 +210,7 @@
       ImmutableSet<ClassSymbol> syms,
       Env<ClassSymbol, SourceHeaderBoundClass> shenv,
       Env<ClassSymbol, HeaderBoundClass> henv) {
-    SimpleEnv.Builder<SourceTypeBoundClass> builder = SimpleEnv.builder();
+    SimpleEnv.Builder<ClassSymbol, SourceTypeBoundClass> builder = SimpleEnv.builder();
     for (ClassSymbol sym : syms) {
       builder.putIfAbsent(sym, TypeBinder.bind(henv, sym, shenv.get(sym)));
     }
@@ -219,7 +221,7 @@
       ImmutableSet<ClassSymbol> syms,
       Env<ClassSymbol, SourceTypeBoundClass> stenv,
       Env<ClassSymbol, TypeBoundClass> tenv) {
-    SimpleEnv.Builder<SourceTypeBoundClass> builder = SimpleEnv.builder();
+    SimpleEnv.Builder<ClassSymbol, SourceTypeBoundClass> builder = SimpleEnv.builder();
     for (ClassSymbol sym : syms) {
       builder.putIfAbsent(sym, CanonicalTypeBinder.bind(sym, stenv.get(sym), tenv));
     }
@@ -268,26 +270,9 @@
     // lazily evaluated fields in the current compilation unit with
     // constant fields in the classpath (which don't require evaluation).
     Env<FieldSymbol, Const.Value> constenv =
-        new LazyEnv<>(
-            completers.build(),
-            CompoundEnv.<FieldSymbol, Const.Value>of(
-                new Env<FieldSymbol, Const.Value>() {
-                  @Override
-                  public Const.Value get(FieldSymbol sym1) {
-                    TypeBoundClass info1 = baseEnv.get(sym1.owner());
-                    if (info1 == null) {
-                      return null;
-                    }
-                    for (FieldInfo fi : info1.fields()) {
-                      if (fi.name().equals(sym1.name())) {
-                        return fi.value();
-                      }
-                    }
-                    throw new AssertionError(sym1);
-                  }
-                }));
+        new LazyEnv<>(completers.build(), SimpleEnv.<FieldSymbol, Const.Value>builder().build());
 
-    SimpleEnv.Builder<SourceTypeBoundClass> builder = SimpleEnv.builder();
+    SimpleEnv.Builder<ClassSymbol, SourceTypeBoundClass> builder = SimpleEnv.builder();
     for (ClassSymbol sym : syms) {
       builder.putIfAbsent(sym, new ConstBinder(constenv, sym, baseEnv, env.get(sym)).bind());
     }
diff --git a/java/com/google/turbine/binder/ConstEvaluator.java b/java/com/google/turbine/binder/ConstEvaluator.java
index 118b760..a6368a5 100644
--- a/java/com/google/turbine/binder/ConstEvaluator.java
+++ b/java/com/google/turbine/binder/ConstEvaluator.java
@@ -163,6 +163,9 @@
     if ((field.access() & TurbineFlag.ACC_ENUM) == TurbineFlag.ACC_ENUM) {
       return new Const.EnumConstantValue(field.sym());
     }
+    if (field.value() != null) {
+      return field.value();
+    }
     return values.get(field.sym());
   }
 
diff --git a/java/com/google/turbine/binder/env/LazyEnv.java b/java/com/google/turbine/binder/env/LazyEnv.java
index c33ab46..44d3c68 100644
--- a/java/com/google/turbine/binder/env/LazyEnv.java
+++ b/java/com/google/turbine/binder/env/LazyEnv.java
@@ -53,7 +53,7 @@
   /** An underlying env of already-computed {@code T}s that can be queried during completion. */
   private final Env<S, T> rec;
 
-  public LazyEnv(ImmutableMap<S, Completer<S, T, V>> completers, CompoundEnv<S, ? extends T> base) {
+  public LazyEnv(ImmutableMap<S, Completer<S, T, V>> completers, Env<S, ? extends T> base) {
     this.completers = completers;
     this.rec = CompoundEnv.<S, T>of(base).append(this);
   }
diff --git a/java/com/google/turbine/binder/env/SimpleEnv.java b/java/com/google/turbine/binder/env/SimpleEnv.java
index b9ee07b..07d2037 100644
--- a/java/com/google/turbine/binder/env/SimpleEnv.java
+++ b/java/com/google/turbine/binder/env/SimpleEnv.java
@@ -17,31 +17,31 @@
 package com.google.turbine.binder.env;
 
 import com.google.common.collect.ImmutableMap;
-import com.google.turbine.binder.sym.ClassSymbol;
+import com.google.turbine.binder.sym.Symbol;
 import java.util.LinkedHashMap;
 
 /** A simple {@link ImmutableMap}-backed {@link Env}. */
-public class SimpleEnv<V> implements Env<ClassSymbol, V> {
+public class SimpleEnv<K extends Symbol, V> implements Env<K, V> {
 
-  private final ImmutableMap<ClassSymbol, V> map;
+  private final ImmutableMap<K, V> map;
 
-  public SimpleEnv(ImmutableMap<ClassSymbol, V> map) {
+  public SimpleEnv(ImmutableMap<K, V> map) {
     this.map = map;
   }
 
-  public static <V> Builder<V> builder() {
+  public static <K extends Symbol, V> Builder<K, V> builder() {
     return new Builder<>();
   }
 
-  public ImmutableMap<ClassSymbol, V> asMap() {
+  public ImmutableMap<K, V> asMap() {
     return map;
   }
 
   /** A builder for {@link SimpleEnv}static. */
-  public static class Builder<V> {
-    private final LinkedHashMap<ClassSymbol, V> map = new LinkedHashMap<>();
+  public static class Builder<K extends Symbol, V> {
+    private final LinkedHashMap<K, V> map = new LinkedHashMap<>();
 
-    public boolean putIfAbsent(ClassSymbol sym, V v) {
+    public boolean putIfAbsent(K sym, V v) {
       if (map.containsKey(sym)) {
         return false;
       }
@@ -49,13 +49,13 @@
       return true;
     }
 
-    public SimpleEnv<V> build() {
+    public SimpleEnv<K, V> build() {
       return new SimpleEnv<>(ImmutableMap.copyOf(map));
     }
   }
 
   @Override
-  public V get(ClassSymbol sym) {
+  public V get(K sym) {
     return map.get(sym);
   }
 }
diff --git a/javatests/com/google/turbine/lower/LowerIntegrationTest.java b/javatests/com/google/turbine/lower/LowerIntegrationTest.java
index 4932e69..2310d38 100644
--- a/javatests/com/google/turbine/lower/LowerIntegrationTest.java
+++ b/javatests/com/google/turbine/lower/LowerIntegrationTest.java
@@ -217,6 +217,7 @@
       "wild3.test",
       "const_hiding.test",
       "interface_field.test",
+      "concat.test",
     };
     List<Object[]> tests =
         ImmutableList.copyOf(testCases).stream().map(x -> new Object[] {x}).collect(toList());
diff --git a/javatests/com/google/turbine/lower/LowerTest.java b/javatests/com/google/turbine/lower/LowerTest.java
index 317cb1d..74e87df 100644
--- a/javatests/com/google/turbine/lower/LowerTest.java
+++ b/javatests/com/google/turbine/lower/LowerTest.java
@@ -175,7 +175,7 @@
             ImmutableList.of(),
             null);
 
-    SimpleEnv.Builder<SourceTypeBoundClass> b = SimpleEnv.builder();
+    SimpleEnv.Builder<ClassSymbol, SourceTypeBoundClass> b = SimpleEnv.builder();
     b.putIfAbsent(new ClassSymbol("test/Test"), c);
     b.putIfAbsent(new ClassSymbol("test/Test$Inner"), i);
 
diff --git a/javatests/com/google/turbine/lower/testdata/concat.test b/javatests/com/google/turbine/lower/testdata/concat.test
new file mode 100644
index 0000000..7ba52a5
--- /dev/null
+++ b/javatests/com/google/turbine/lower/testdata/concat.test
@@ -0,0 +1,25 @@
+%%% Anno.java %%%
+public @interface Anno {
+  String[] bar() default {};
+  String[] foo() default {};
+}
+
+%%% A.java %%%
+import java.io.Serializable;
+public final class A implements Serializable {
+  public static final String X = "X";
+  public static final String Y = "Y" + X;
+}
+
+=== Test.java ===
+class Test {
+  @Anno(
+    foo ={
+      "a" + A.Y,
+    },
+    bar ={
+      "a" + A.Y,
+    }
+  )
+  int x;
+}