Tolerate missing symbols when resolving fields

This mirrors existing logic for resolving simple names of types.

It's possible this could cause turbine to fail to resolve a compile-time
constant that was pruned from the reduced classpath, except the current
classpath reduction never prunes supertypes of any accessible types.
There is a single instance in the depot where a pre-compiled jar
references a supertype that doesn't exist, and triggers a crash here.

Longer-term, enabling strict deps enforcement of static members will
ensure that any classes we read constant fields from are direct deps.

If overly aggressive classpath pruning did cause a constant field to be
skipped, it would either happen in a context where a constant was
required (switch case, annotation value) and the error would be obvious,
or else a constant field might fail to be given a constant value.

MOE_MIGRATED_REVID=138703676
diff --git a/java/com/google/turbine/binder/Resolve.java b/java/com/google/turbine/binder/Resolve.java
index f54f1cd..7b9e490 100644
--- a/java/com/google/turbine/binder/Resolve.java
+++ b/java/com/google/turbine/binder/Resolve.java
@@ -106,6 +106,9 @@
   public static FieldInfo resolveField(
       Env<ClassSymbol, TypeBoundClass> env, ClassSymbol origin, ClassSymbol sym, String name) {
     TypeBoundClass info = env.get(sym);
+    if (info == null) {
+      return null;
+    }
     for (FieldInfo f : info.fields()) {
       if (f.name().equals(name)) {
         return f;
diff --git a/javatests/com/google/turbine/binder/BinderTest.java b/javatests/com/google/turbine/binder/BinderTest.java
index f389560..737b707 100644
--- a/javatests/com/google/turbine/binder/BinderTest.java
+++ b/javatests/com/google/turbine/binder/BinderTest.java
@@ -25,21 +25,32 @@
 import com.google.turbine.binder.bound.SourceTypeBoundClass;
 import com.google.turbine.binder.env.LazyEnv;
 import com.google.turbine.binder.sym.ClassSymbol;
+import com.google.turbine.lower.IntegrationTestSupport;
 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.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
 @RunWith(JUnit4.class)
 public class BinderTest {
 
+  @Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder();
+
   private static final ImmutableList<Path> BOOTCLASSPATH =
       ImmutableList.of(Paths.get(System.getProperty("java.home")).resolve("lib/rt.jar"));
 
@@ -236,6 +247,42 @@
         .isEqualTo(new ClassSymbol("lib/Lib$Inner"));
   }
 
+  @Test
+  public void incompleteClasspath() throws Exception {
+
+    Map<String, byte[]> lib =
+        IntegrationTestSupport.runJavac(
+            ImmutableMap.of(
+                "A.java", "class A {}",
+                "B.java", "class B extends A {}"),
+            ImmutableList.of(),
+            BOOTCLASSPATH);
+
+    // create a jar containing only B
+    Path libJar = temporaryFolder.newFile("lib.jar").toPath();
+    try (OutputStream os = Files.newOutputStream(libJar);
+        JarOutputStream jos = new JarOutputStream(os)) {
+      jos.putNextEntry(new JarEntry("B.class"));
+      jos.write(lib.get("B"));
+    }
+
+    List<Tree.CompUnit> units = new ArrayList<>();
+    units.add(
+        parseLines(
+            "import java.lang.annotation.Target;",
+            "import java.lang.annotation.ElementType;",
+            "public class C implements B {",
+            "  @Target(ElementType.TYPE_USE)",
+            "  @interface A {};",
+            "}"));
+
+    ImmutableMap<ClassSymbol, SourceTypeBoundClass> bound =
+        Binder.bind(units, ImmutableList.of(libJar), BOOTCLASSPATH).units();
+
+    SourceTypeBoundClass a = bound.get(new ClassSymbol("C$A"));
+    assertThat(a.annotationMetadata().target()).containsExactly(ElementType.TYPE_USE);
+  }
+
   private Tree.CompUnit parseLines(String... lines) {
     return Parser.parse(Joiner.on('\n').join(lines));
   }