[Metadata] Keep special kotlin types for reflect and kotlinc

Bug: 196179629
Change-Id: I1b09d5b1f0f809cfe556e2771a11cc03e84b1671
diff --git a/src/main/java/com/android/tools/r8/kotlin/Kotlin.java b/src/main/java/com/android/tools/r8/kotlin/Kotlin.java
index 2bbd2b3..9470367 100644
--- a/src/main/java/com/android/tools/r8/kotlin/Kotlin.java
+++ b/src/main/java/com/android/tools/r8/kotlin/Kotlin.java
@@ -9,8 +9,10 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
+import com.google.common.collect.ImmutableSet;
 import it.unimi.dsi.fastutil.objects.Object2IntArrayMap;
 import it.unimi.dsi.fastutil.objects.Object2IntMap;
+import java.util.Set;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
@@ -33,8 +35,59 @@
   public static final class ClassClassifiers {
 
     public static final String arrayBinaryName = NAME + "/Array";
+    public static final String arrayDescriptor = PACKAGE_PREFIX + "Array;";
     public static final String anyDescriptor = PACKAGE_PREFIX + "Any;";
+    public static final String unitDescriptor = PACKAGE_PREFIX + "Unit;";
+    public static final String booleanDescriptor = PACKAGE_PREFIX + "Boolean";
+    public static final String charDescriptor = PACKAGE_PREFIX + "Char";
+    public static final String byteDescriptor = PACKAGE_PREFIX + "Byte";
+    public static final String uByteDescriptor = PACKAGE_PREFIX + "UByte";
+    public static final String shortDescriptor = PACKAGE_PREFIX + "Short;";
+    public static final String uShortDescriptor = PACKAGE_PREFIX + "UShort;";
+    public static final String intDescriptor = PACKAGE_PREFIX + "Int;";
+    public static final String uIntDescriptor = PACKAGE_PREFIX + "UInt;";
+    public static final String floatDescriptor = PACKAGE_PREFIX + "Float;";
+    public static final String longDescriptor = PACKAGE_PREFIX + "Long;";
+    public static final String uLongDescriptor = PACKAGE_PREFIX + "ULong;";
+    public static final String doubleDescriptor = PACKAGE_PREFIX + "Double;";
+    public static final String functionDescriptor = PACKAGE_PREFIX + "Function;";
+    public static final String kFunctionDescriptor = PACKAGE_PREFIX + "KFunction;";
     public static final String anyName = NAME + "/Any";
+
+    public static final Set<String> kotlinPrimitivesDescriptors =
+        ImmutableSet.<String>builder()
+            .add(booleanDescriptor)
+            .add(charDescriptor)
+            .add(byteDescriptor)
+            .add(uByteDescriptor)
+            .add(shortDescriptor)
+            .add(uShortDescriptor)
+            .add(intDescriptor)
+            .add(uIntDescriptor)
+            .add(floatDescriptor)
+            .add(longDescriptor)
+            .add(uLongDescriptor)
+            .add(doubleDescriptor)
+            .build();
+
+    // Kotlin static known types is a possible not complete collection of descriptors that kotlinc
+    // and kotlin reflect know and expect the existence of.
+    public static final Set<String> kotlinStaticallyKnownTypes;
+
+    static {
+      ImmutableSet.Builder<String> builder = ImmutableSet.builder();
+      kotlinPrimitivesDescriptors.forEach(
+          primitive -> {
+            builder.add(primitive);
+            builder.add(primitive.substring(0, primitive.length() - 1) + "Array;");
+          });
+      builder.add(unitDescriptor);
+      builder.add(anyDescriptor);
+      builder.add(arrayDescriptor);
+      builder.add(functionDescriptor);
+      builder.add(kFunctionDescriptor);
+      kotlinStaticallyKnownTypes = builder.build();
+    }
   }
 
   public Kotlin(DexItemFactory factory) {
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java
index 8cea528..4fd93a0 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java
@@ -11,6 +11,7 @@
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.kotlin.Kotlin.ClassClassifiers;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.DescriptorUtils;
@@ -79,8 +80,16 @@
     }
     DexType rewrittenType = toRewrittenTypeOrNull(appView, known);
     if (rewrittenType == null) {
-      rewrittenConsumer.accept(defaultValue);
-      return true;
+      String knownDescriptor = known.toDescriptorString();
+      // Static known kotlin types can be pruned without rewriting to Any since the types are known
+      // by kotlinc and kotlin reflect.
+      if (ClassClassifiers.kotlinStaticallyKnownTypes.contains(knownDescriptor)) {
+        rewrittenConsumer.accept(knownDescriptor);
+        return false;
+      } else {
+        rewrittenConsumer.accept(defaultValue);
+        return true;
+      }
     }
     String renamedString = namingLens.lookupDescriptor(rewrittenType).toString();
     rewrittenConsumer.accept(renamedString);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteUnitPrimitiveTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteUnitPrimitiveTest.java
index 66760d1..fafb083 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteUnitPrimitiveTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteUnitPrimitiveTest.java
@@ -10,7 +10,6 @@
 import static com.android.tools.r8.ToolHelper.getKotlinReflectJar;
 import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertNull;
@@ -18,6 +17,7 @@
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.kotlin.KotlinMetadataWriter;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.StringUtils;
@@ -128,9 +128,7 @@
             getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc), libJar)
         .addClasspath(main)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
-        // TODO(b/196179629): Should not fail.
-        .assertFailureWithErrorThatMatches(
-            containsString("Could not compute caller for function: public final fun testUnit()"));
+        .assertSuccessWithOutput(EXPECTED);
   }
 
   private void inspect(CodeInspector inspector) throws IOException {
@@ -150,10 +148,11 @@
       KotlinClassHeader rewrittenHeader = rewrittenMetadata.getHeader();
       TestCase.assertEquals(originalHeader.getKind(), rewrittenHeader.getKind());
       TestCase.assertEquals(originalHeader.getPackageName(), rewrittenHeader.getPackageName());
-      // TODO(b/196179629): There should not be any rewriting of the data since the return type
-      //  should not change. Therefore we should be able to assert everything to be equal.
-      Assert.assertNotEquals(originalHeader.getData1(), rewrittenHeader.getData1());
-      Assert.assertNotEquals(originalHeader.getData2(), rewrittenHeader.getData2());
+      Assert.assertArrayEquals(originalHeader.getData1(), rewrittenHeader.getData1());
+      Assert.assertArrayEquals(originalHeader.getData2(), rewrittenHeader.getData2());
+      String expected = KotlinMetadataWriter.kotlinMetadataToString("", originalMetadata);
+      String actual = KotlinMetadataWriter.kotlinMetadataToString("", rewrittenMetadata);
+      TestCase.assertEquals(expected, actual);
     }
   }
 }