Remove the boolean and byte distinction from array member types.

This CL also ensures that field member types are not conflated with those of
array instructions.

Bug: 109788783
Change-Id: I238d6b225d753c6f30db8a127017afb214c93bd2
diff --git a/src/main/java/com/android/tools/r8/cf/CfPrinter.java b/src/main/java/com/android/tools/r8/cf/CfPrinter.java
index 4378118..3866f5f 100644
--- a/src/main/java/com/android/tools/r8/cf/CfPrinter.java
+++ b/src/main/java/com/android/tools/r8/cf/CfPrinter.java
@@ -605,8 +605,7 @@
     switch (type) {
       case OBJECT:
         return 'a';
-      case BOOLEAN:
-      case BYTE:
+      case BOOLEAN_OR_BYTE:
         return 'b';
       case CHAR:
         return 'c';
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
index e77a59e..17dcff2 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
@@ -32,8 +32,7 @@
     switch (type) {
       case OBJECT:
         return Opcodes.AALOAD;
-      case BYTE:
-      case BOOLEAN:
+      case BOOLEAN_OR_BYTE:
         return Opcodes.BALOAD;
       case CHAR:
         return Opcodes.CALOAD;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
index ff76777..463d697 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
@@ -30,8 +30,7 @@
     switch (type) {
       case OBJECT:
         return Opcodes.AASTORE;
-      case BYTE:
-      case BOOLEAN:
+      case BOOLEAN_OR_BYTE:
         return Opcodes.BASTORE;
       case CHAR:
         return Opcodes.CASTORE;
diff --git a/src/main/java/com/android/tools/r8/code/AgetBoolean.java b/src/main/java/com/android/tools/r8/code/AgetBoolean.java
index c671af1..fc05007 100644
--- a/src/main/java/com/android/tools/r8/code/AgetBoolean.java
+++ b/src/main/java/com/android/tools/r8/code/AgetBoolean.java
@@ -37,7 +37,7 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addArrayGet(MemberType.BOOLEAN, AA, BB, CC);
+    builder.addArrayGet(MemberType.BOOLEAN_OR_BYTE, AA, BB, CC);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/code/AgetByte.java b/src/main/java/com/android/tools/r8/code/AgetByte.java
index abe1ac6..f7bc165 100644
--- a/src/main/java/com/android/tools/r8/code/AgetByte.java
+++ b/src/main/java/com/android/tools/r8/code/AgetByte.java
@@ -37,7 +37,7 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addArrayGet(MemberType.BYTE, AA, BB, CC);
+    builder.addArrayGet(MemberType.BOOLEAN_OR_BYTE, AA, BB, CC);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/code/AputBoolean.java b/src/main/java/com/android/tools/r8/code/AputBoolean.java
index f59bd90..ac64012 100644
--- a/src/main/java/com/android/tools/r8/code/AputBoolean.java
+++ b/src/main/java/com/android/tools/r8/code/AputBoolean.java
@@ -37,7 +37,7 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addArrayPut(MemberType.BOOLEAN, AA, BB, CC);
+    builder.addArrayPut(MemberType.BOOLEAN_OR_BYTE, AA, BB, CC);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/code/AputByte.java b/src/main/java/com/android/tools/r8/code/AputByte.java
index 5d522e0..1d439c6 100644
--- a/src/main/java/com/android/tools/r8/code/AputByte.java
+++ b/src/main/java/com/android/tools/r8/code/AputByte.java
@@ -37,7 +37,7 @@
 
   @Override
   public void buildIR(IRBuilder builder) {
-    builder.addArrayPut(MemberType.BYTE, AA, BB, CC);
+    builder.addArrayPut(MemberType.BOOLEAN_OR_BYTE, AA, BB, CC);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
index 5918964..2a10b2d 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
@@ -527,8 +527,7 @@
           return MemberType.OBJECT;
         case Opcodes.BALOAD:
         case Opcodes.BASTORE:
-          // TODO(b/109788783): Distinguish byte and boolean.
-          return MemberType.BOOLEAN;
+          return MemberType.BOOLEAN_OR_BYTE;
         case Opcodes.CALOAD:
         case Opcodes.CASTORE:
           return MemberType.CHAR;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/ArrayTypeLatticeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/ArrayTypeLatticeElement.java
index c631e11..5e16020 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/ArrayTypeLatticeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/ArrayTypeLatticeElement.java
@@ -57,7 +57,7 @@
     return nesting;
   }
 
-  TypeLatticeElement getArrayMemberTypeAsMemberType() {
+  public TypeLatticeElement getArrayMemberTypeAsMemberType() {
     return memberTypeLattice;
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/TypeLatticeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/TypeLatticeElement.java
index 94cd5e1..2dff5a9 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/TypeLatticeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/TypeLatticeElement.java
@@ -17,8 +17,8 @@
 public abstract class TypeLatticeElement {
   public static final BottomTypeLatticeElement BOTTOM = BottomTypeLatticeElement.getInstance();
   public static final TopTypeLatticeElement TOP = TopTypeLatticeElement.getInstance();
-  static final BooleanTypeLatticeElement BOOLEAN = BooleanTypeLatticeElement.getInstance();
-  static final ByteTypeLatticeElement BYTE = ByteTypeLatticeElement.getInstance();
+  public static final BooleanTypeLatticeElement BOOLEAN = BooleanTypeLatticeElement.getInstance();
+  public static final ByteTypeLatticeElement BYTE = ByteTypeLatticeElement.getInstance();
   static final ShortTypeLatticeElement SHORT = ShortTypeLatticeElement.getInstance();
   static final CharTypeLatticeElement CHAR = CharTypeLatticeElement.getInstance();
   public static final IntTypeLatticeElement INT = IntTypeLatticeElement.getInstance();
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java b/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java
index e082dcd..cf9994f 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java
@@ -80,11 +80,16 @@
       case OBJECT:
         instruction = new AgetObject(dest, array, index);
         break;
-      case BOOLEAN:
-        instruction = new AgetBoolean(dest, array, index);
-        break;
-      case BYTE:
-        instruction = new AgetByte(dest, array, index);
+      case BOOLEAN_OR_BYTE:
+        ArrayTypeLatticeElement arrayType = array().getTypeLattice().asArrayTypeLatticeElement();
+        if (arrayType != null
+            && arrayType.getArrayMemberTypeAsMemberType() == TypeLatticeElement.BOOLEAN) {
+          instruction = new AgetBoolean(dest, array, index);
+        } else {
+          assert array().getTypeLattice().isDefinitelyNull()
+              || arrayType.getArrayMemberTypeAsMemberType() == TypeLatticeElement.BYTE;
+          instruction = new AgetByte(dest, array, index);
+        }
         break;
       case CHAR:
         instruction = new AgetChar(dest, array, index);
@@ -190,8 +195,7 @@
             : arrayTypeLattice.getArrayMemberTypeAsValueType();
         assert valueType.isReference();
         return valueType;
-      case BOOLEAN:
-      case BYTE:
+      case BOOLEAN_OR_BYTE:
       case CHAR:
       case SHORT:
       case INT:
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java b/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java
index 82e65e5..b2b2f10 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java
@@ -17,6 +17,8 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.analysis.type.ArrayTypeLatticeElement;
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
 import com.android.tools.r8.ir.conversion.TypeConstraintResolver;
@@ -82,11 +84,16 @@
       case OBJECT:
         instruction = new AputObject(value, array, index);
         break;
-      case BOOLEAN:
-        instruction = new AputBoolean(value, array, index);
-        break;
-      case BYTE:
-        instruction = new AputByte(value, array, index);
+      case BOOLEAN_OR_BYTE:
+        ArrayTypeLatticeElement arrayType = array().getTypeLattice().asArrayTypeLatticeElement();
+        if (arrayType != null
+            && arrayType.getArrayMemberTypeAsMemberType() == TypeLatticeElement.BOOLEAN) {
+          instruction = new AputBoolean(value, array, index);
+        } else {
+          assert array().getTypeLattice().isDefinitelyNull()
+              || arrayType.getArrayMemberTypeAsMemberType() == TypeLatticeElement.BYTE;
+          instruction = new AputByte(value, array, index);
+        }
         break;
       case CHAR:
         instruction = new AputChar(value, array, index);
diff --git a/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java b/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
index fe5dac4..4810054 100644
--- a/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
@@ -16,7 +16,6 @@
 
 public abstract class FieldInstruction extends Instruction {
 
-  private MemberType type;
   private final DexField field;
 
   protected FieldInstruction(DexField field, Value dest, Value value) {
@@ -27,11 +26,10 @@
     super(dest, inValues);
     assert field != null;
     this.field = field;
-    this.type = MemberType.fromDexType(field.type);
   }
 
-  public MemberType getType() {
-    return type;
+  public FieldMemberType getType() {
+    return FieldMemberType.fromDexType(field.type);
   }
 
   public DexField getField() {
diff --git a/src/main/java/com/android/tools/r8/ir/code/FieldMemberType.java b/src/main/java/com/android/tools/r8/ir/code/FieldMemberType.java
new file mode 100644
index 0000000..3d2f9b0
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/code/FieldMemberType.java
@@ -0,0 +1,53 @@
+// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.code;
+
+import com.android.tools.r8.errors.InternalCompilerError;
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexType;
+
+public enum FieldMemberType {
+  OBJECT,
+  BOOLEAN,
+  BYTE,
+  CHAR,
+  SHORT,
+  INT,
+  FLOAT,
+  LONG,
+  DOUBLE;
+
+  public static FieldMemberType fromTypeDescriptorChar(char descriptor) {
+    switch (descriptor) {
+      case 'L':
+      case '[':
+        return FieldMemberType.OBJECT;
+      case 'Z':
+        return FieldMemberType.BOOLEAN;
+      case 'B':
+        return FieldMemberType.BYTE;
+      case 'S':
+        return FieldMemberType.SHORT;
+      case 'C':
+        return FieldMemberType.CHAR;
+      case 'I':
+        return FieldMemberType.INT;
+      case 'F':
+        return FieldMemberType.FLOAT;
+      case 'J':
+        return FieldMemberType.LONG;
+      case 'D':
+        return FieldMemberType.DOUBLE;
+      case 'V':
+        throw new InternalCompilerError("No member type for void type.");
+      default:
+        throw new Unreachable("Invalid descriptor char '" + descriptor + "'");
+    }
+  }
+
+  public static FieldMemberType fromDexType(DexType type) {
+    return fromTypeDescriptorChar((char) type.descriptor.content[0]);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java b/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java
index ca8cbfa..046aba5 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java
@@ -86,9 +86,6 @@
       case SHORT:
         instruction = new IgetShort(destRegister, objectRegister, field);
         break;
-      case INT_OR_FLOAT:
-      case LONG_OR_DOUBLE:
-        throw new Unreachable("Unexpected imprecise type: " + getType());
       default:
         throw new Unreachable("Unexpected type: " + getType());
     }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstancePut.java b/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
index 9cea0c0..fca35ba 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
@@ -83,9 +83,6 @@
       case SHORT:
         instruction = new IputShort(valueRegister, objectRegister, field);
         break;
-      case INT_OR_FLOAT:
-      case LONG_OR_DOUBLE:
-        throw new Unreachable("Unexpected imprecise type: " + getType());
       default:
         throw new Unreachable("Unexpected type: " + getType());
     }
diff --git a/src/main/java/com/android/tools/r8/ir/code/MemberType.java b/src/main/java/com/android/tools/r8/ir/code/MemberType.java
index a21a4e7..fe1048a 100644
--- a/src/main/java/com/android/tools/r8/ir/code/MemberType.java
+++ b/src/main/java/com/android/tools/r8/ir/code/MemberType.java
@@ -10,8 +10,7 @@
 
 public enum MemberType {
   OBJECT,
-  BOOLEAN,
-  BYTE,
+  BOOLEAN_OR_BYTE,
   CHAR,
   SHORT,
   INT,
@@ -79,9 +78,8 @@
       case '[':
         return MemberType.OBJECT;
       case 'Z':
-        return MemberType.BOOLEAN;
       case 'B':
-        return MemberType.BYTE;
+        return MemberType.BOOLEAN_OR_BYTE;
       case 'S':
         return MemberType.SHORT;
       case 'C':
diff --git a/src/main/java/com/android/tools/r8/ir/code/StaticGet.java b/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
index 6dbf723..4f8191f 100644
--- a/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
+++ b/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
@@ -78,9 +78,6 @@
       case SHORT:
         instruction = new SgetShort(dest, field);
         break;
-      case INT_OR_FLOAT:
-      case LONG_OR_DOUBLE:
-        throw new Unreachable("Unexpected imprecise type: " + getType());
       default:
         throw new Unreachable("Unexpected type: " + getType());
     }
diff --git a/src/main/java/com/android/tools/r8/ir/code/StaticPut.java b/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
index d8df7f1..a609206 100644
--- a/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
+++ b/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
@@ -75,9 +75,6 @@
       case SHORT:
         instruction = new SputShort(src, field);
         break;
-      case INT_OR_FLOAT:
-      case LONG_OR_DOUBLE:
-        throw new Unreachable("Unexpected imprecise type: " + getType());
       default:
         throw new Unreachable("Unexpected type: " + getType());
     }
diff --git a/src/main/java/com/android/tools/r8/ir/code/ValueType.java b/src/main/java/com/android/tools/r8/ir/code/ValueType.java
index e9e89aa..e3926c5 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ValueType.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ValueType.java
@@ -35,8 +35,7 @@
 
   public static ValueType fromMemberType(MemberType type) {
     switch (type) {
-      case BOOLEAN:
-      case BYTE:
+      case BOOLEAN_OR_BYTE:
       case CHAR:
       case SHORT:
       case INT:
diff --git a/src/main/java/com/android/tools/r8/ir/code/ValueTypeConstraint.java b/src/main/java/com/android/tools/r8/ir/code/ValueTypeConstraint.java
index 9c376fb..9ee7b0f 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ValueTypeConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ValueTypeConstraint.java
@@ -61,8 +61,7 @@
 
   public static ValueTypeConstraint fromMemberType(MemberType type) {
     switch (type) {
-      case BOOLEAN:
-      case BYTE:
+      case BOOLEAN_OR_BYTE:
       case CHAR:
       case SHORT:
       case INT:
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index bd7d27e..59d7a55 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -145,8 +145,7 @@
 
   private static TypeLatticeElement fromMemberType(MemberType type) {
     switch (type) {
-      case BOOLEAN:
-      case BYTE:
+      case BOOLEAN_OR_BYTE:
       case CHAR:
       case SHORT:
       case INT:
@@ -1005,7 +1004,6 @@
     Value in2 = readRegister(index, ValueTypeConstraint.INT);
     TypeLatticeElement typeLattice = fromMemberType(type);
     Value out = writeRegister(dest, typeLattice, ThrowingInfo.CAN_THROW);
-    out.setKnownToBeBoolean(type == MemberType.BOOLEAN);
     ArrayGet instruction = new ArrayGet(type, out, in1, in2);
     assert instruction.instructionTypeCanThrow();
     if (!type.isPrecise()) {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
index d7a55b7..591adeb 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
@@ -954,9 +954,8 @@
       case Type.OBJECT:
         return MemberType.OBJECT;
       case Type.BOOLEAN:
-        return MemberType.BOOLEAN;
       case Type.BYTE:
-        return MemberType.BYTE;
+        return MemberType.BOOLEAN_OR_BYTE;
       case Type.SHORT:
         return MemberType.SHORT;
       case Type.CHAR:
@@ -976,10 +975,6 @@
     }
   }
 
-  private MemberType memberType(String fieldDesc) {
-    return memberType(application.getAsmType(fieldDesc));
-  }
-
   private static NumericType numericType(Type type) {
     switch (type.getSort()) {
       case Type.BYTE:
diff --git a/src/test/java/com/android/tools/r8/R8RunExamplesTest.java b/src/test/java/com/android/tools/r8/R8RunExamplesTest.java
index 793df27..c9485e3 100644
--- a/src/test/java/com/android/tools/r8/R8RunExamplesTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunExamplesTest.java
@@ -156,10 +156,6 @@
   @Override
   protected Set<String> getFailingRunCfToDex() {
     return new ImmutableSet.Builder<String>()
-        // TODO(b/109788783): Implement byte/boolean distinction for array load/store.
-        .add("arrayaccess.ArrayAccess")
-        .add("barray.BArray")
-        .add("filledarray.FilledArray")
         .build();
   }