Don't evaluate constant values for boxed primitive fields

MOE_MIGRATED_REVID=139087738
diff --git a/java/com/google/turbine/binder/Binder.java b/java/com/google/turbine/binder/Binder.java
index d0161c8..9262a1f 100644
--- a/java/com/google/turbine/binder/Binder.java
+++ b/java/com/google/turbine/binder/Binder.java
@@ -57,6 +57,7 @@
 import com.google.turbine.tree.Tree.PkgDecl;
 import com.google.turbine.tree.Tree.TyDecl;
 import com.google.turbine.tree.TurbineModifier;
+import com.google.turbine.type.Type;
 import java.io.IOException;
 import java.nio.file.Path;
 import java.util.Collection;
@@ -275,14 +276,7 @@
     for (ClassSymbol sym : syms) {
       SourceTypeBoundClass info = env.get(sym);
       for (FieldInfo field : info.fields()) {
-        if ((field.access() & TurbineFlag.ACC_FINAL) == 0) {
-          continue;
-        }
-        if (field.decl() == null) {
-          continue;
-        }
-        final Optional<Tree.Expression> init = field.decl().init();
-        if (!init.isPresent()) {
+        if (!isConst(field)) {
           continue;
         }
         completers.put(
@@ -292,7 +286,7 @@
               public Const.Value complete(Env<FieldSymbol, Const.Value> env1, FieldSymbol k) {
                 try {
                   return new ConstEvaluator(sym, info, info.scope(), env1, baseEnv)
-                      .evalFieldInitializer(init.get(), field.type());
+                      .evalFieldInitializer(field.decl().init().get(), field.type());
                 } catch (LazyEnv.LazyBindingError e) {
                   // fields initializers are allowed to reference the field being initialized,
                   // but if they do they aren't constants
@@ -316,6 +310,31 @@
     return builder.build();
   }
 
+  static boolean isConst(FieldInfo field) {
+    if ((field.access() & TurbineFlag.ACC_FINAL) == 0) {
+      return false;
+    }
+    if (field.decl() == null) {
+      return false;
+    }
+    final Optional<Tree.Expression> init = field.decl().init();
+    if (!init.isPresent()) {
+      return false;
+    }
+    switch (field.type().tyKind()) {
+      case PRIM_TY:
+        break;
+      case CLASS_TY:
+        if (((Type.ClassTy) field.type()).sym().equals(ClassSymbol.STRING)) {
+          break;
+        }
+        // fall through
+      default:
+        return false;
+    }
+    return true;
+  }
+
   /**
    * Disambiguate annotations on field types and method return types that could be declaration or
    * type annotations.
diff --git a/javatests/com/google/turbine/lower/LowerIntegrationTest.java b/javatests/com/google/turbine/lower/LowerIntegrationTest.java
index c1859e5..fa48e5d 100644
--- a/javatests/com/google/turbine/lower/LowerIntegrationTest.java
+++ b/javatests/com/google/turbine/lower/LowerIntegrationTest.java
@@ -267,6 +267,7 @@
       "ctor_anno.test",
       "anno_const_coerce.test",
       "const_octal_underscore.test",
+      "const_boxed.test",
     };
     List<Object[]> tests =
         ImmutableList.copyOf(testCases).stream().map(x -> new Object[] {x}).collect(toList());
diff --git a/javatests/com/google/turbine/lower/testdata/const_boxed.test b/javatests/com/google/turbine/lower/testdata/const_boxed.test
new file mode 100644
index 0000000..830973b
--- /dev/null
+++ b/javatests/com/google/turbine/lower/testdata/const_boxed.test
@@ -0,0 +1,5 @@
+=== Test.java ===
+class Test {
+  static final Double A = 2.0;
+  static final String S = "" + A;
+}