Update kotlin metadata library from 0.2.0 to 0.3.0

Bug: 206855609
Bug: 207397158
Change-Id: Iefad4c3e5435e8173bea4bce65e0593f93511785
diff --git a/build.gradle b/build.gradle
index 5220ac2..324c0e2 100644
--- a/build.gradle
+++ b/build.gradle
@@ -11,13 +11,6 @@
 import tasks.DownloadDependency
 import tasks.GetJarsFromConfiguration
 import utils.Utils
-import org.gradle.api.tasks.testing.logging.TestExceptionFormat
-import org.gradle.api.tasks.testing.logging.TestLogEvent
-import org.gradle.api.tasks.testing.TestOutputEvent
-
-import java.nio.charset.StandardCharsets
-import java.nio.file.Files
-import java.nio.file.StandardOpenOption
 
 buildscript {
     repositories {
@@ -53,7 +46,7 @@
     // The kotlin version is only here to specify the kotlin language level,
     // all kotlin compilations are done in tests.
     kotlinVersion = '1.3.72'
-    kotlinExtMetadataJVMVersion = '0.2.0'
+    kotlinExtMetadataJVMVersion = '0.3.0'
     smaliVersion = '2.2b4'
     errorproneVersion = '2.3.2'
     testngVersion = '6.10'
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 ef44b4b..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;
@@ -28,11 +30,64 @@
   public static final String NAME = "kotlin";
   public static final String PACKAGE_PREFIX = "L" + NAME + "/";
 
+  public final DexString kotlinJvmTypePrefix;
+
   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) {
@@ -41,6 +96,7 @@
     this.intrinsics = new Intrinsics();
     this.metadata = new Metadata();
     this.assertions = new _Assertions();
+    kotlinJvmTypePrefix = factory.createString("Lkotlin/jvm/");
   }
 
   public final class Functional {
@@ -67,10 +123,6 @@
     private Functional() {
     }
 
-    public final DexString kotlinStyleLambdaInstanceName = factory.createString("INSTANCE");
-
-    public final DexType functionBase =
-        factory.createType(PACKAGE_PREFIX + "jvm/internal/FunctionBase;");
     public final DexType lambdaType = factory.createType(PACKAGE_PREFIX + "jvm/internal/Lambda;");
 
     public final DexMethod lambdaInitializerMethod = factory.createMethod(
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationArgumentInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationArgumentInfo.java
index 883be66..6f34ad1 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationArgumentInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationArgumentInfo.java
@@ -29,10 +29,10 @@
       ImmutableMap.of();
 
   abstract boolean rewrite(
-      Consumer<KmAnnotationArgument<?>> consumer, AppView<?> appView, NamingLens namingLens);
+      Consumer<KmAnnotationArgument> consumer, AppView<?> appView, NamingLens namingLens);
 
   private static KotlinAnnotationArgumentInfo createArgument(
-      KmAnnotationArgument<?> arg, DexItemFactory factory) {
+      KmAnnotationArgument arg, DexItemFactory factory) {
     if (arg instanceof KClassValue) {
       return KotlinAnnotationClassValueInfo.create((KClassValue) arg, factory);
     } else if (arg instanceof EnumValue) {
@@ -47,7 +47,7 @@
   }
 
   static Map<String, KotlinAnnotationArgumentInfo> create(
-      Map<String, KmAnnotationArgument<?>> arguments, DexItemFactory factory) {
+      Map<String, KmAnnotationArgument> arguments, DexItemFactory factory) {
     if (arguments.isEmpty()) {
       return EMPTY_ARGUMENTS;
     }
@@ -59,14 +59,17 @@
   private static class KotlinAnnotationClassValueInfo extends KotlinAnnotationArgumentInfo {
 
     private final KotlinTypeReference value;
+    private final int arrayDimensionCount;
 
-    private KotlinAnnotationClassValueInfo(KotlinTypeReference value) {
+    private KotlinAnnotationClassValueInfo(KotlinTypeReference value, int arrayDimensionCount) {
       this.value = value;
+      this.arrayDimensionCount = arrayDimensionCount;
     }
 
     private static KotlinAnnotationClassValueInfo create(KClassValue arg, DexItemFactory factory) {
       return new KotlinAnnotationClassValueInfo(
-          KotlinTypeReference.fromBinaryName(arg.getValue(), factory));
+          KotlinTypeReference.fromBinaryName(arg.getClassName(), factory, arg.getClassName()),
+          arg.getArrayDimensionCount());
     }
 
     @Override
@@ -76,9 +79,9 @@
 
     @Override
     boolean rewrite(
-        Consumer<KmAnnotationArgument<?>> consumer, AppView<?> appView, NamingLens namingLens) {
+        Consumer<KmAnnotationArgument> consumer, AppView<?> appView, NamingLens namingLens) {
       return value.toRenamedBinaryNameOrDefault(
-          rewrittenValue -> consumer.accept(new KClassValue(rewrittenValue)),
+          rewrittenValue -> consumer.accept(new KClassValue(rewrittenValue, arrayDimensionCount)),
           appView,
           namingLens,
           ClassClassifiers.anyName);
@@ -97,7 +100,8 @@
 
     private static KotlinAnnotationEnumValueInfo create(EnumValue arg, DexItemFactory factory) {
       return new KotlinAnnotationEnumValueInfo(
-          KotlinTypeReference.fromBinaryName(arg.getEnumClassName(), factory),
+          KotlinTypeReference.fromBinaryName(
+              arg.getEnumClassName(), factory, arg.getEnumClassName()),
           arg.getEnumEntryName());
     }
 
@@ -108,7 +112,7 @@
 
     @Override
     boolean rewrite(
-        Consumer<KmAnnotationArgument<?>> consumer, AppView<?> appView, NamingLens namingLens) {
+        Consumer<KmAnnotationArgument> consumer, AppView<?> appView, NamingLens namingLens) {
       return enumClassName.toRenamedBinaryNameOrDefault(
           rewrittenEnumClassName ->
               consumer.accept(new EnumValue(rewrittenEnumClassName, enumEntryName)),
@@ -129,7 +133,7 @@
     private static KotlinAnnotationAnnotationValueInfo create(
         AnnotationValue arg, DexItemFactory factory) {
       return new KotlinAnnotationAnnotationValueInfo(
-          KotlinAnnotationInfo.create(arg.getValue(), factory));
+          KotlinAnnotationInfo.create(arg.getAnnotation(), factory));
     }
 
     @Override
@@ -139,7 +143,7 @@
 
     @Override
     boolean rewrite(
-        Consumer<KmAnnotationArgument<?>> consumer, AppView<?> appView, NamingLens namingLens) {
+        Consumer<KmAnnotationArgument> consumer, AppView<?> appView, NamingLens namingLens) {
       return value.rewrite(
           rewrittenAnnotation -> {
             if (rewrittenAnnotation != null) {
@@ -163,11 +167,11 @@
     }
 
     private static KotlinAnnotationArrayValueInfo create(ArrayValue arg, DexItemFactory factory) {
-      if (arg.getValue().isEmpty()) {
+      if (arg.getElements().isEmpty()) {
         return EMPTY;
       }
       ImmutableList.Builder<KotlinAnnotationArgumentInfo> builder = ImmutableList.builder();
-      for (KmAnnotationArgument<?> argument : arg.getValue()) {
+      for (KmAnnotationArgument argument : arg.getElements()) {
         builder.add(createArgument(argument, factory));
       }
       return new KotlinAnnotationArrayValueInfo(builder.build());
@@ -182,8 +186,8 @@
 
     @Override
     boolean rewrite(
-        Consumer<KmAnnotationArgument<?>> consumer, AppView<?> appView, NamingLens namingLens) {
-      List<KmAnnotationArgument<?>> rewrittenArguments = new ArrayList<>();
+        Consumer<KmAnnotationArgument> consumer, AppView<?> appView, NamingLens namingLens) {
+      List<KmAnnotationArgument> rewrittenArguments = new ArrayList<>();
       boolean rewritten = false;
       for (KotlinAnnotationArgumentInfo kotlinAnnotationArgumentInfo : value) {
         rewritten |=
@@ -203,13 +207,13 @@
 
   private static class KotlinAnnotationPrimitiveArgumentInfo extends KotlinAnnotationArgumentInfo {
 
-    private final KmAnnotationArgument<?> argument;
+    private final KmAnnotationArgument argument;
 
-    private KotlinAnnotationPrimitiveArgumentInfo(KmAnnotationArgument<?> argument) {
+    private KotlinAnnotationPrimitiveArgumentInfo(KmAnnotationArgument argument) {
       this.argument = argument;
     }
 
-    private static KotlinAnnotationPrimitiveArgumentInfo create(KmAnnotationArgument<?> argument) {
+    private static KotlinAnnotationPrimitiveArgumentInfo create(KmAnnotationArgument argument) {
       return new KotlinAnnotationPrimitiveArgumentInfo(argument);
     }
 
@@ -220,7 +224,7 @@
 
     @Override
     boolean rewrite(
-        Consumer<KmAnnotationArgument<?>> consumer, AppView<?> appView, NamingLens namingLens) {
+        Consumer<KmAnnotationArgument> consumer, AppView<?> appView, NamingLens namingLens) {
       consumer.accept(argument);
       return false;
     }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationInfo.java
index fd036d8..d21cfb1 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationInfo.java
@@ -34,7 +34,8 @@
 
   static KotlinAnnotationInfo create(KmAnnotation annotation, DexItemFactory factory) {
     return new KotlinAnnotationInfo(
-        KotlinTypeReference.fromBinaryName(annotation.getClassName(), factory),
+        KotlinTypeReference.fromBinaryName(
+            annotation.getClassName(), factory, annotation.getClassName()),
         KotlinAnnotationArgumentInfo.create(annotation.getArguments(), factory));
   }
 
@@ -63,7 +64,7 @@
                 return;
               }
               String classifier = DescriptorUtils.descriptorToKotlinClassifier(renamedDescriptor);
-              Map<String, KmAnnotationArgument<?>> rewrittenArguments = new LinkedHashMap<>();
+              Map<String, KmAnnotationArgument> rewrittenArguments = new LinkedHashMap<>();
               arguments.forEach(
                   (key, arg) ->
                       rewritten.or(
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java
index e440049..9e7d703 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java
@@ -16,6 +16,7 @@
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.utils.Box;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.Pair;
 import com.android.tools.r8.utils.Reporter;
@@ -37,6 +38,7 @@
 
   private final int flags;
   private final String name;
+  private final boolean nameCanBeSynthesizedFromClassOrAnonymousObjectOrigin;
   private final String moduleName;
   private final List<KotlinConstructorInfo> constructorsWithNoBacking;
   private final KotlinDeclarationContainerInfo declarationContainerInfo;
@@ -50,10 +52,16 @@
   private final String packageName;
   private final KotlinLocalDelegatedPropertyInfo localDelegatedProperties;
   private final int[] metadataVersion;
+  private final String inlineClassUnderlyingPropertyName;
+  private final KotlinTypeInfo inlineClassUnderlyingType;
+
+  // List of tracked assignments of kotlin metadata.
+  private final KotlinMetadataMembersTracker originalMembersWithKotlinInfo;
 
   private KotlinClassInfo(
       int flags,
       String name,
+      boolean nameCanBeSynthesizedFromClassOrAnonymousObjectOrigin,
       String moduleName,
       KotlinDeclarationContainerInfo declarationContainerInfo,
       List<KotlinTypeParameterInfo> typeParameters,
@@ -66,9 +74,14 @@
       KotlinTypeReference anonymousObjectOrigin,
       String packageName,
       KotlinLocalDelegatedPropertyInfo localDelegatedProperties,
-      int[] metadataVersion) {
+      int[] metadataVersion,
+      String inlineClassUnderlyingPropertyName,
+      KotlinTypeInfo inlineClassUnderlyingType,
+      KotlinMetadataMembersTracker originalMembersWithKotlinInfo) {
     this.flags = flags;
     this.name = name;
+    this.nameCanBeSynthesizedFromClassOrAnonymousObjectOrigin =
+        nameCanBeSynthesizedFromClassOrAnonymousObjectOrigin;
     this.moduleName = moduleName;
     this.declarationContainerInfo = declarationContainerInfo;
     this.typeParameters = typeParameters;
@@ -82,6 +95,9 @@
     this.packageName = packageName;
     this.localDelegatedProperties = localDelegatedProperties;
     this.metadataVersion = metadataVersion;
+    this.inlineClassUnderlyingPropertyName = inlineClassUnderlyingPropertyName;
+    this.inlineClassUnderlyingType = inlineClassUnderlyingType;
+    this.originalMembersWithKotlinInfo = originalMembersWithKotlinInfo;
   }
 
   public static KotlinClassInfo create(
@@ -107,6 +123,8 @@
     }
     ImmutableList.Builder<KotlinConstructorInfo> notBackedConstructors = ImmutableList.builder();
     int constructorIndex = 0;
+    KotlinMetadataMembersTracker originalMembersWithKotlinInfo =
+        new KotlinMetadataMembersTracker(appView);
     for (KmConstructor kmConstructor : kmClass.getConstructors()) {
       boolean readConstructorSignature =
           extensionInformation.hasJvmMethodSignatureExtensionForConstructor(constructorIndex++);
@@ -117,6 +135,7 @@
         DexEncodedMethod method = methodMap.get(signature.asString());
         if (method != null) {
           method.setKotlinMemberInfo(constructorInfo);
+          originalMembersWithKotlinInfo.add(method.getReference());
           continue;
         }
       }
@@ -125,11 +144,26 @@
     }
     KotlinDeclarationContainerInfo container =
         KotlinDeclarationContainerInfo.create(
-            kmClass, methodMap, fieldMap, factory, reporter, keepByteCode, extensionInformation);
+            kmClass,
+            methodMap,
+            fieldMap,
+            factory,
+            reporter,
+            keepByteCode,
+            extensionInformation,
+            originalMembersWithKotlinInfo);
     setCompanionObject(kmClass, hostClass, reporter);
+    KotlinTypeReference anonymousObjectOrigin = getAnonymousObjectOrigin(kmClass, factory);
+    boolean nameCanBeDeducedFromClassOrOrigin =
+        kmClass.name.equals(
+                KotlinMetadataUtils.getKotlinClassName(
+                    hostClass, hostClass.getType().toDescriptorString()))
+            || (anonymousObjectOrigin != null
+                && kmClass.name.equals(anonymousObjectOrigin.toKotlinClassifier(true)));
     return new KotlinClassInfo(
         kmClass.getFlags(),
         kmClass.name,
+        nameCanBeDeducedFromClassOrOrigin,
         JvmExtensionsKt.getModuleName(kmClass),
         container,
         KotlinTypeParameterInfo.create(kmClass.getTypeParameters(), factory, reporter),
@@ -139,18 +173,22 @@
         getNestedClasses(hostClass, kmClass.getNestedClasses(), factory),
         kmClass.getEnumEntries(),
         KotlinVersionRequirementInfo.create(kmClass.getVersionRequirements()),
-        getAnonymousObjectOrigin(kmClass, factory),
+        anonymousObjectOrigin,
         packageName,
         KotlinLocalDelegatedPropertyInfo.create(
             JvmExtensionsKt.getLocalDelegatedProperties(kmClass), factory, reporter),
-        metadataVersion);
+        metadataVersion,
+        kmClass.getInlineClassUnderlyingPropertyName(),
+        KotlinTypeInfo.create(kmClass.getInlineClassUnderlyingType(), factory, reporter),
+        originalMembersWithKotlinInfo);
   }
 
   private static KotlinTypeReference getAnonymousObjectOrigin(
       KmClass kmClass, DexItemFactory factory) {
     String anonymousObjectOriginName = JvmExtensionsKt.getAnonymousObjectOriginName(kmClass);
     if (anonymousObjectOriginName != null) {
-      return KotlinTypeReference.fromBinaryName(anonymousObjectOriginName, factory);
+      return KotlinTypeReference.fromBinaryName(
+          anonymousObjectOriginName, factory, anonymousObjectOriginName);
     }
     return null;
   }
@@ -161,7 +199,7 @@
     for (String nestedClass : nestedClasses) {
       String binaryName =
           clazz.type.toBinaryName() + DescriptorUtils.INNER_CLASS_SEPARATOR + nestedClass;
-      nestedTypes.add(KotlinTypeReference.fromBinaryName(binaryName, factory));
+      nestedTypes.add(KotlinTypeReference.fromBinaryName(binaryName, factory, nestedClass));
     }
     return nestedTypes.build();
   }
@@ -173,7 +211,7 @@
       String binaryName =
           sealedSubClass.replace(
               DescriptorUtils.JAVA_PACKAGE_SEPARATOR, DescriptorUtils.INNER_CLASS_SEPARATOR);
-      sealedTypes.add(KotlinTypeReference.fromBinaryName(binaryName, factory));
+      sealedTypes.add(KotlinTypeReference.fromBinaryName(binaryName, factory, sealedSubClass));
     }
     return sealedTypes.build();
   }
@@ -221,14 +259,29 @@
     // Set potentially renamed class name.
     DexString originalDescriptor = clazz.type.descriptor;
     DexString rewrittenDescriptor = namingLens.lookupDescriptor(clazz.type);
-    // If the original descriptor equals the rewritten descriptor, we pick the original name
-    // to preserve potential errors in the original name. As an example, the kotlin stdlib has
-    // name: .kotlin/collections/CollectionsKt___CollectionsKt$groupingBy$1, which seems incorrect.
     boolean rewritten = !originalDescriptor.equals(rewrittenDescriptor);
-    kmClass.setName(
-        !rewritten
-            ? this.name
-            : DescriptorUtils.getBinaryNameFromDescriptor(rewrittenDescriptor.toString()));
+    if (!nameCanBeSynthesizedFromClassOrAnonymousObjectOrigin) {
+      kmClass.setName(this.name);
+    } else {
+      String rewrittenName = null;
+      // When the class has an anonymousObjectOrigin and the name equals the identifier there, we
+      // keep the name tied to the anonymousObjectOrigin.
+      if (anonymousObjectOrigin != null
+          && name.equals(anonymousObjectOrigin.toKotlinClassifier(true))) {
+        Box<String> rewrittenOrigin = new Box<>();
+        anonymousObjectOrigin.toRenamedBinaryNameOrDefault(
+            rewrittenOrigin::set, appView, namingLens, null);
+        if (rewrittenOrigin.isSet()) {
+          rewrittenName = "." + rewrittenOrigin.get();
+        }
+      }
+      if (rewrittenName == null) {
+        rewrittenName =
+            KotlinMetadataUtils.getKotlinClassName(clazz, rewrittenDescriptor.toString());
+      }
+      kmClass.setName(rewrittenName);
+      rewritten |= !name.equals(rewrittenName);
+    }
     // Find a companion object.
     for (DexEncodedField field : clazz.fields()) {
       if (field.getKotlinInfo().isCompanion()) {
@@ -241,10 +294,12 @@
       rewritten |= constructorInfo.rewrite(kmClass, null, appView, namingLens);
     }
     // Find all constructors.
+    KotlinMetadataMembersTracker rewrittenReferences = new KotlinMetadataMembersTracker(appView);
     for (DexEncodedMethod method : clazz.methods()) {
       if (method.getKotlinInfo().isConstructor()) {
         KotlinConstructorInfo constructorInfo = method.getKotlinInfo().asConstructor();
         rewritten |= constructorInfo.rewrite(kmClass, method, appView, namingLens);
+        rewrittenReferences.add(method.getReference());
       }
     }
     // Rewrite functions, type-aliases and type-parameters.
@@ -255,7 +310,8 @@
             kmClass::visitTypeAlias,
             clazz,
             appView,
-            namingLens);
+            namingLens,
+            rewrittenReferences);
     // Rewrite type parameters.
     for (KotlinTypeParameterInfo typeParameter : typeParameters) {
       rewritten |= typeParameter.rewrite(kmClass::visitTypeParameter, appView, namingLens);
@@ -271,30 +327,31 @@
     }
     // Rewrite nested classes.
     for (KotlinTypeReference nestedClass : nestedClasses) {
-      rewritten |=
+      Box<String> nestedDescriptorBox = new Box<>();
+      boolean nestedClassRewritten =
           nestedClass.toRenamedBinaryNameOrDefault(
-              nestedDescriptor -> {
-                if (nestedDescriptor != null) {
-                  // If the class is a nested class, it should be on the form Foo.Bar$Baz, where Baz
-                  // is the
-                  // name we should record.
-                  int innerClassIndex =
-                      nestedDescriptor.lastIndexOf(DescriptorUtils.INNER_CLASS_SEPARATOR);
-                  kmClass.visitNestedClass(nestedDescriptor.substring(innerClassIndex + 1));
-                }
-              },
-              appView,
-              namingLens,
-              null);
+              nestedDescriptorBox::set, appView, namingLens, null);
+      if (nestedDescriptorBox.isSet()) {
+        if (nestedClassRewritten) {
+          // If the class is a nested class, it should be on the form Foo.Bar$Baz, where Baz
+          // is the name we should record.
+          String nestedDescriptor = nestedDescriptorBox.get();
+          int innerClassIndex = nestedDescriptor.lastIndexOf(DescriptorUtils.INNER_CLASS_SEPARATOR);
+          kmClass.visitNestedClass(nestedDescriptor.substring(innerClassIndex + 1));
+        } else {
+          kmClass.visitNestedClass(nestedClass.getOriginalName());
+        }
+      }
+      rewritten |= nestedClassRewritten;
     }
     // Rewrite sealed sub classes.
     for (KotlinTypeReference sealedSubClass : sealedSubClasses) {
       rewritten |=
           sealedSubClass.toRenamedBinaryNameOrDefault(
-              sealedDescriptor -> {
-                if (sealedDescriptor != null) {
+              sealedName -> {
+                if (sealedName != null) {
                   kmClass.visitSealedSubclass(
-                      sealedDescriptor.replace(
+                      sealedName.replace(
                           DescriptorUtils.INNER_CLASS_SEPARATOR,
                           DescriptorUtils.JAVA_PACKAGE_SEPARATOR));
                 }
@@ -306,6 +363,12 @@
     // TODO(b/154347404): Understand enum entries.
     kmClass.getEnumEntries().addAll(enumEntries);
     rewritten |= versionRequirements.rewrite(kmClass::visitVersionRequirement);
+    if (inlineClassUnderlyingPropertyName != null && inlineClassUnderlyingType != null) {
+      kmClass.setInlineClassUnderlyingPropertyName(inlineClassUnderlyingPropertyName);
+      rewritten |=
+          inlineClassUnderlyingType.rewrite(
+              kmClass::visitInlineClassUnderlyingType, appView, namingLens);
+    }
     JvmClassExtensionVisitor extensionVisitor =
         (JvmClassExtensionVisitor) kmClass.visitExtensions(JvmClassExtensionVisitor.TYPE);
     extensionVisitor.visitModuleName(moduleName);
@@ -327,7 +390,9 @@
     extensionVisitor.visitEnd();
     KotlinClassMetadata.Class.Writer writer = new KotlinClassMetadata.Class.Writer();
     kmClass.accept(writer);
-    return Pair.create(writer.write().getHeader(), rewritten);
+    return Pair.create(
+        writer.write().getHeader(),
+        rewritten || !originalMembersWithKotlinInfo.isEqual(rewrittenReferences, appView));
   }
 
   @Override
@@ -346,7 +411,7 @@
     declarationContainerInfo.trace(definitionSupplier);
     forEachApply(typeParameters, param -> param::trace, definitionSupplier);
     forEachApply(superTypes, type -> type::trace, definitionSupplier);
-    forEachApply(sealedSubClasses, sealed -> sealed::trace, definitionSupplier);
+    forEachApply(sealedSubClasses, sealedClass -> sealedClass::trace, definitionSupplier);
     forEachApply(nestedClasses, nested -> nested::trace, definitionSupplier);
     localDelegatedProperties.trace(definitionSupplier);
     // TODO(b/154347404): trace enum entries.
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
index bfabd6c..7f4c47d 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
@@ -33,6 +33,8 @@
 
 public final class KotlinClassMetadataReader {
 
+  private static final int SYNTHETIC_CLASS_KIND = 3;
+
   public static KotlinClassLevelInfo getKotlinInfo(
       DexClass clazz, AppView<?> appView, Consumer<DexEncodedMethod> keepByteCode) {
     DexAnnotation meta =
@@ -75,16 +77,25 @@
   public static boolean isLambda(AppView<?> appView, DexClass clazz) {
     DexItemFactory dexItemFactory = appView.dexItemFactory();
     Kotlin kotlin = dexItemFactory.kotlin;
+    Flavour flavour = getFlavour(clazz, kotlin);
+    if (flavour == Flavour.Unclassified) {
+      return false;
+    }
     DexAnnotation metadataAnnotation =
         clazz.annotations().getFirstMatching(dexItemFactory.kotlinMetadataType);
-    if (metadataAnnotation != null) {
-      KotlinClassMetadata kMetadata = toKotlinClassMetadata(kotlin, metadataAnnotation.annotation);
+    if (metadataAnnotation == null) {
+      return false;
+    }
+    Map<DexString, DexAnnotationElement> elementMap = toElementMap(metadataAnnotation.annotation);
+    if (getKind(kotlin, elementMap) == SYNTHETIC_CLASS_KIND) {
+      KotlinClassMetadata kMetadata = toKotlinClassMetadata(kotlin, elementMap);
       if (kMetadata instanceof SyntheticClass) {
-        SyntheticClass syntheticClass = (SyntheticClass) kMetadata;
-        return syntheticClass.isLambda()
-            && getFlavour(syntheticClass, clazz, kotlin) != Flavour.Unclassified;
+        return ((SyntheticClass) kMetadata).isLambda();
       }
     }
+    assert toKotlinClassMetadata(kotlin, elementMap) instanceof SyntheticClass
+            == (getKind(kotlin, elementMap) == SYNTHETIC_CLASS_KIND)
+        : "Synthetic class kinds should agree";
     return false;
   }
 
@@ -98,16 +109,21 @@
 
   public static KotlinClassMetadata toKotlinClassMetadata(
       Kotlin kotlin, DexEncodedAnnotation metadataAnnotation) {
+    return toKotlinClassMetadata(kotlin, toElementMap(metadataAnnotation));
+  }
+
+  private static Map<DexString, DexAnnotationElement> toElementMap(
+      DexEncodedAnnotation metadataAnnotation) {
     Map<DexString, DexAnnotationElement> elementMap = new IdentityHashMap<>();
     for (DexAnnotationElement element : metadataAnnotation.elements) {
       elementMap.put(element.name, element);
     }
+    return elementMap;
+  }
 
-    DexAnnotationElement kind = elementMap.get(kotlin.metadata.kind);
-    if (kind == null) {
-      throw new MetadataError("element 'k' is missing.");
-    }
-    Integer k = (Integer) kind.value.getBoxedValue();
+  private static KotlinClassMetadata toKotlinClassMetadata(
+      Kotlin kotlin, Map<DexString, DexAnnotationElement> elementMap) {
+    int k = getKind(kotlin, elementMap);
     DexAnnotationElement metadataVersion = elementMap.get(kotlin.metadata.metadataVersion);
     int[] mv = metadataVersion == null ? null : getUnboxedIntArray(metadataVersion.value, "mv");
     DexAnnotationElement bytecodeVersion = elementMap.get(kotlin.metadata.bytecodeVersion);
@@ -127,6 +143,14 @@
     return KotlinClassMetadata.read(header);
   }
 
+  private static int getKind(Kotlin kotlin, Map<DexString, DexAnnotationElement> elementMap) {
+    DexAnnotationElement kind = elementMap.get(kotlin.metadata.kind);
+    if (kind == null) {
+      throw new MetadataError("element 'k' is missing.");
+    }
+    return (Integer) kind.value.getBoxedValue();
+  }
+
   public static KotlinClassLevelInfo createKotlinInfo(
       Kotlin kotlin,
       DexClass clazz,
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java
index 5f5b696..9b2939e 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java
@@ -4,6 +4,8 @@
 
 package com.android.tools.r8.kotlin;
 
+import static com.android.tools.r8.kotlin.KotlinMetadataUtils.getKotlinLocalOrAnonymousNameFromDescriptor;
+
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexItemFactory;
@@ -68,13 +70,8 @@
     boolean rewrite(KmTypeVisitor visitor, AppView<?> appView, NamingLens namingLens) {
       return type.toRenamedDescriptorOrDefault(
           descriptor -> {
-            // For local or anonymous classes, the classifier is prefixed with '.' and inner classes
-            // are separated with '$'.
-            if (isLocalOrAnonymous) {
-              visitor.visitClass("." + DescriptorUtils.getBinaryNameFromDescriptor(descriptor));
-            } else {
-              visitor.visitClass(DescriptorUtils.descriptorToKotlinClassifier(descriptor));
-            }
+            visitor.visitClass(
+                getKotlinLocalOrAnonymousNameFromDescriptor(descriptor, isLocalOrAnonymous));
           },
           appView,
           namingLens,
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java
index e84f57a..9e79ee0 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java
@@ -56,7 +56,8 @@
       DexItemFactory factory,
       Reporter reporter,
       Consumer<DexEncodedMethod> keepByteCode,
-      KotlinJvmSignatureExtensionInformation extensionInformation) {
+      KotlinJvmSignatureExtensionInformation extensionInformation,
+      KotlinMetadataMembersTracker originalAssignmentTracker) {
     ImmutableList.Builder<KotlinFunctionInfo> notBackedFunctions = ImmutableList.builder();
     int functionCounter = 0;
     for (KmFunction kmFunction : container.getFunctions()) {
@@ -88,6 +89,7 @@
       }
       keepIfInline(kmFunction.getFlags(), method, keepByteCode);
       method.setKotlinMemberInfo(kotlinFunctionInfo);
+      originalAssignmentTracker.add(method.getReference());
     }
 
     ImmutableList.Builder<KotlinPropertyInfo> notBackedProperties = ImmutableList.builder();
@@ -102,6 +104,7 @@
         if (field != null) {
           hasBacking = true;
           field.setKotlinMemberInfo(kotlinPropertyInfo);
+          originalAssignmentTracker.add(field.getReference());
         }
       }
       if (propertyProcessor.getterSignature() != null) {
@@ -111,6 +114,7 @@
           hasBacking = true;
           keepIfAccessorInline(kmProperty.getGetterFlags(), method, keepByteCode);
           method.setKotlinMemberInfo(kotlinPropertyInfo);
+          originalAssignmentTracker.add(method.getReference());
         }
       }
       if (propertyProcessor.setterSignature() != null) {
@@ -120,6 +124,7 @@
           hasBacking = true;
           keepIfAccessorInline(kmProperty.getGetterFlags(), method, keepByteCode);
           method.setKotlinMemberInfo(kotlinPropertyInfo);
+          originalAssignmentTracker.add(method.getReference());
         }
       }
       if (!hasBacking) {
@@ -161,7 +166,8 @@
       KmVisitorProviders.KmTypeAliasVisitorProvider typeAliasProvider,
       DexClass clazz,
       AppView<?> appView,
-      NamingLens namingLens) {
+      NamingLens namingLens,
+      KotlinMetadataMembersTracker rewrittenMembersWithKotlinInfo) {
     // Type aliases only have a representation here, so we can generate them directly.
     boolean rewritten = false;
     for (KotlinTypeAliasInfo typeAlias : typeAliases) {
@@ -175,6 +181,7 @@
             .computeIfAbsent(
                 field.getKotlinInfo().asProperty(), ignored -> new KotlinPropertyGroup())
             .setBackingField(field);
+        rewrittenMembersWithKotlinInfo.add(field.getReference());
       }
     }
     for (DexEncodedMethod method : clazz.methods()) {
@@ -184,12 +191,14 @@
                 .getKotlinInfo()
                 .asFunction()
                 .rewrite(functionProvider, method, appView, namingLens);
+        rewrittenMembersWithKotlinInfo.add(method.getReference());
         continue;
       }
       KotlinPropertyInfo kotlinPropertyInfo = method.getKotlinInfo().asProperty();
       if (kotlinPropertyInfo == null) {
         continue;
       }
+      rewrittenMembersWithKotlinInfo.add(method.getReference());
       KotlinPropertyGroup kotlinPropertyGroup =
           properties.computeIfAbsent(kotlinPropertyInfo, ignored -> new KotlinPropertyGroup());
       if (method.getReference().proto.returnType == appView.dexItemFactory().voidType) {
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinFunctionInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinFunctionInfo.java
index e6a249c..5001c40 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinFunctionInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinFunctionInfo.java
@@ -106,7 +106,8 @@
       KmFunction kmFunction, DexItemFactory factory) {
     String lambdaClassOriginName = JvmExtensionsKt.getLambdaClassOriginName(kmFunction);
     if (lambdaClassOriginName != null) {
-      return KotlinTypeReference.fromBinaryName(lambdaClassOriginName, factory);
+      return KotlinTypeReference.fromBinaryName(
+          lambdaClassOriginName, factory, lambdaClassOriginName);
     }
     return null;
   }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataMembersTracker.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataMembersTracker.java
new file mode 100644
index 0000000..88691a9
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataMembersTracker.java
@@ -0,0 +1,65 @@
+// Copyright (c) 2021, 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.kotlin;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexMember;
+import com.android.tools.r8.graph.DexReference;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.utils.IterableUtils;
+import com.google.common.collect.Sets;
+import com.google.common.collect.Sets.SetView;
+import java.util.Set;
+
+public class KotlinMetadataMembersTracker {
+
+  private int count;
+  // Only used for asserting equality during local testing.
+  private final Set<DexMember<?, ?>> references;
+
+  public KotlinMetadataMembersTracker(AppView<?> appView) {
+    references = appView.options().testing.enableTestAssertions ? Sets.newIdentityHashSet() : null;
+  }
+
+  public void add(DexMember<?, ?> reference) {
+    count += 1;
+    if (references != null) {
+      references.add(reference);
+    }
+  }
+
+  public boolean isEqual(KotlinMetadataMembersTracker tracker, AppView<?> appView) {
+    if (count != tracker.count) {
+      return false;
+    }
+    if (references != null) {
+      assert tracker.references != null;
+      assert references.size() == tracker.references.size();
+      SetView<DexMember<?, ?>> diffComparedToRewritten =
+          Sets.difference(references, tracker.references);
+      if (!diffComparedToRewritten.isEmpty()) {
+        SetView<DexMember<?, ?>> diffComparedToOriginal =
+            Sets.difference(tracker.references, references);
+        // Known kotlin types may not exist directly in the way they are annotated in the metadata.
+        // As an example kotlin.Function2 exists in the metadata but the concrete type is
+        // kotlin.jvm.functions.Function2. As a result we may not rewrite metadata but the
+        // underlying types are changed.
+        diffComparedToRewritten.forEach(
+            diff -> {
+              DexReference rewrittenReference = appView.graphLens().lookupReference(diff);
+              assert diffComparedToOriginal.contains(rewrittenReference);
+              assert IterableUtils.findOrDefault(
+                      diff.getReferencedTypes(), type -> isKotlinJvmType(appView, type), null)
+                  != null;
+            });
+      }
+    }
+    return true;
+  }
+
+  private boolean isKotlinJvmType(AppView<?> appView, DexType type) {
+    return type.descriptor.startsWith(appView.dexItemFactory().kotlin.kotlinJvmTypePrefix);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataUtils.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataUtils.java
index 7eb45f6..2d6f39a 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataUtils.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataUtils.java
@@ -13,6 +13,7 @@
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.InnerClassAttribute;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.shaking.ProguardConfiguration;
 import com.android.tools.r8.shaking.ProguardConfigurationRule;
@@ -201,4 +202,27 @@
     // Check if the type is matched
     return proguardKeepRule.getClassNames().matches(factory.kotlinMetadataType);
   }
+
+  static String getKotlinClassName(DexClass clazz, String descriptor) {
+    InnerClassAttribute innerClassAttribute = clazz.getInnerClassAttributeForThisClass();
+    if (innerClassAttribute != null && innerClassAttribute.getOuter() != null) {
+      return DescriptorUtils.descriptorToKotlinClassifier(descriptor);
+    } else if (clazz.isLocalClass() || clazz.isAnonymousClass()) {
+      return getKotlinLocalOrAnonymousNameFromDescriptor(descriptor, true);
+    } else {
+      // We no longer have an innerclass relationship to maintain and we therefore return a binary
+      // name.
+      return DescriptorUtils.getBinaryNameFromDescriptor(descriptor);
+    }
+  }
+
+  static String getKotlinLocalOrAnonymousNameFromDescriptor(
+      String descriptor, boolean isLocalOrAnonymous) {
+    // For local or anonymous classes, the classifier is prefixed with '.' and inner classes
+    // are separated with '$'.
+    if (isLocalOrAnonymous) {
+      return "." + DescriptorUtils.getBinaryNameFromDescriptor(descriptor);
+    }
+    return DescriptorUtils.descriptorToKotlinClassifier(descriptor);
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataWriter.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataWriter.java
index fbfb3bb..ee9ea2c 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataWriter.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataWriter.java
@@ -325,6 +325,22 @@
                 appendKmType(nextIndent, sb, kmType);
               });
         });
+    if (kmClass.getInlineClassUnderlyingPropertyName() != null) {
+      appendKeyValue(
+          indent,
+          "inlineClassUnderlyingPropertyName",
+          sb,
+          kmClass.getInlineClassUnderlyingPropertyName());
+    }
+    if (kmClass.getInlineClassUnderlyingType() != null) {
+      appendKeyValue(
+          indent,
+          "inlineClassUnderlyingType",
+          sb,
+          nextIndent -> {
+            appendKmType(nextIndent, sb, kmClass.getInlineClassUnderlyingType());
+          });
+    }
     String companionObject = kmClass.getCompanionObject();
     appendKeyValue(
         indent, "enumEntries", sb, "[" + StringUtils.join(",", kmClass.getEnumEntries()) + "]");
@@ -769,7 +785,7 @@
               "arguments",
               sb,
               nextIndent -> {
-                Map<String, KmAnnotationArgument<?>> arguments = kmAnnotation.getArguments();
+                Map<String, KmAnnotationArgument> arguments = kmAnnotation.getArguments();
                 appendKmList(
                     nextIndent,
                     "{ key: String, value: KmAnnotationArgument<?> }",
@@ -795,9 +811,9 @@
   }
 
   private static void appendKmArgument(
-      String indent, StringBuilder sb, KmAnnotationArgument<?> annotationArgument) {
+      String indent, StringBuilder sb, KmAnnotationArgument annotationArgument) {
     if (annotationArgument instanceof KmAnnotationArgument.ArrayValue) {
-      List<KmAnnotationArgument<?>> value = ((ArrayValue) annotationArgument).getValue();
+      List<KmAnnotationArgument> value = ((ArrayValue) annotationArgument).getElements();
       appendKmList(
           indent,
           "ArrayValue",
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassFacadeInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassFacadeInfo.java
index 7088c7f..0545b20 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassFacadeInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassFacadeInfo.java
@@ -40,7 +40,7 @@
       DexItemFactory factory) {
     ImmutableList.Builder<KotlinTypeReference> builder = ImmutableList.builder();
     for (String partClassName : kmMultiFileClassFacade.getPartClassNames()) {
-      builder.add(KotlinTypeReference.fromBinaryName(partClassName, factory));
+      builder.add(KotlinTypeReference.fromBinaryName(partClassName, factory, partClassName));
     }
     return new KotlinMultiFileClassFacadeInfo(builder.build(), packageName, metadataVersion);
   }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinPackageInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinPackageInfo.java
index d28e7c3..fa483ae 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinPackageInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinPackageInfo.java
@@ -27,14 +27,17 @@
   private final String moduleName;
   private final KotlinDeclarationContainerInfo containerInfo;
   private final KotlinLocalDelegatedPropertyInfo localDelegatedProperties;
+  private final KotlinMetadataMembersTracker originalMembersWithKotlinInfo;
 
   private KotlinPackageInfo(
       String moduleName,
       KotlinDeclarationContainerInfo containerInfo,
-      KotlinLocalDelegatedPropertyInfo localDelegatedProperties) {
+      KotlinLocalDelegatedPropertyInfo localDelegatedProperties,
+      KotlinMetadataMembersTracker originalMembersWithKotlinInfo) {
     this.moduleName = moduleName;
     this.containerInfo = containerInfo;
     this.localDelegatedProperties = localDelegatedProperties;
+    this.originalMembersWithKotlinInfo = originalMembersWithKotlinInfo;
   }
 
   public static KotlinPackageInfo create(
@@ -51,6 +54,8 @@
     for (DexEncodedMethod method : clazz.methods()) {
       methodMap.put(toJvmMethodSignature(method.getReference()).asString(), method);
     }
+    KotlinMetadataMembersTracker originalMembersWithKotlinInfo =
+        new KotlinMetadataMembersTracker(appView);
     return new KotlinPackageInfo(
         JvmExtensionsKt.getModuleName(kmPackage),
         KotlinDeclarationContainerInfo.create(
@@ -60,14 +65,17 @@
             appView.dexItemFactory(),
             appView.reporter(),
             keepByteCode,
-            extensionInformation),
+            extensionInformation,
+            originalMembersWithKotlinInfo),
         KotlinLocalDelegatedPropertyInfo.create(
             JvmExtensionsKt.getLocalDelegatedProperties(kmPackage),
             appView.dexItemFactory(),
-            appView.reporter()));
+            appView.reporter()),
+        originalMembersWithKotlinInfo);
   }
 
   boolean rewrite(KmPackage kmPackage, DexClass clazz, AppView<?> appView, NamingLens namingLens) {
+    KotlinMetadataMembersTracker rewrittenReferences = new KotlinMetadataMembersTracker(appView);
     boolean rewritten =
         containerInfo.rewrite(
             kmPackage::visitFunction,
@@ -75,7 +83,8 @@
             kmPackage::visitTypeAlias,
             clazz,
             appView,
-            namingLens);
+            namingLens,
+            rewrittenReferences);
     JvmPackageExtensionVisitor extensionVisitor =
         (JvmPackageExtensionVisitor) kmPackage.visitExtensions(JvmPackageExtensionVisitor.TYPE);
     rewritten |=
@@ -83,7 +92,7 @@
             extensionVisitor::visitLocalDelegatedProperty, appView, namingLens);
     extensionVisitor.visitModuleName(moduleName);
     extensionVisitor.visitEnd();
-    return rewritten;
+    return rewritten || !originalMembersWithKotlinInfo.isEqual(rewrittenReferences, appView);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinSyntheticClassInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinSyntheticClassInfo.java
index 08e95b3..ee55f8b 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinSyntheticClassInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinSyntheticClassInfo.java
@@ -11,7 +11,6 @@
 import com.android.tools.r8.utils.Pair;
 import kotlinx.metadata.KmLambda;
 import kotlinx.metadata.jvm.KotlinClassHeader;
-import kotlinx.metadata.jvm.KotlinClassMetadata;
 import kotlinx.metadata.jvm.KotlinClassMetadata.SyntheticClass;
 import kotlinx.metadata.jvm.KotlinClassMetadata.SyntheticClass.Writer;
 
@@ -55,7 +54,7 @@
             ? KotlinLambdaInfo.create(
                 clazz, lambda, appView.dexItemFactory(), appView.reporter(), extensionInformation)
             : null,
-        getFlavour(syntheticClass, clazz, kotlin),
+        getFlavour(clazz, kotlin),
         packageName,
         metadataVersion);
   }
@@ -64,14 +63,6 @@
     return lambda != null && flavour != Flavour.Unclassified;
   }
 
-  public boolean isKotlinStyleLambda() {
-    return flavour == Flavour.KotlinStyleLambda;
-  }
-
-  public boolean isJavaStyleLambda() {
-    return flavour == Flavour.JavaStyleLambda;
-  }
-
   @Override
   public boolean isSyntheticClass() {
     return true;
@@ -112,23 +103,17 @@
     return metadataVersion;
   }
 
-  public static Flavour getFlavour(
-      KotlinClassMetadata.SyntheticClass metadata, DexClass clazz, Kotlin kotlin) {
-    // Returns KotlinStyleLambda if the given clazz is a Kotlin-style lambda:
-    //   a class that
-    //     1) is recognized as lambda in its Kotlin metadata;
-    //     2) directly extends kotlin.jvm.internal.Lambda
-    if (metadata.isLambda() && clazz.superType == kotlin.functional.lambdaType) {
+  public static Flavour getFlavour(DexClass clazz, Kotlin kotlin) {
+    // Returns KotlinStyleLambda if the given clazz has shape of a Kotlin-style lambda:
+    //   a class that directly extends kotlin.jvm.internal.Lambda
+    if (clazz.superType == kotlin.functional.lambdaType) {
       return Flavour.KotlinStyleLambda;
     }
-    // Returns JavaStyleLambda if the given clazz is a Java-style lambda:
+    // Returns JavaStyleLambda if the given clazz has shape of a Java-style lambda:
     //  a class that
-    //    1) is recognized as lambda in its Kotlin metadata;
-    //    2) doesn't extend any other class;
-    //    3) directly implements only one Java SAM.
-    if (metadata.isLambda()
-        && clazz.superType == kotlin.factory.objectType
-        && clazz.interfaces.size() == 1) {
+    //    1) doesn't extend any other class;
+    //    2) directly implements only one Java SAM.
+    if (clazz.superType == kotlin.factory.objectType && clazz.interfaces.size() == 1) {
       return Flavour.JavaStyleLambda;
     }
     return Flavour.Unclassified;
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 4d0d990..4fd93a0 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java
@@ -4,11 +4,14 @@
 
 package com.android.tools.r8.kotlin;
 
+import static com.android.tools.r8.kotlin.KotlinMetadataUtils.getKotlinLocalOrAnonymousNameFromDescriptor;
+
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 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;
@@ -22,28 +25,33 @@
 class KotlinTypeReference implements EnqueuerMetadataTraceable {
 
   private final DexType known;
-  private final String unknown;
+  private final String originalName;
 
-  private KotlinTypeReference(DexType known) {
+  private KotlinTypeReference(String originalName, DexType known) {
+    this.originalName = originalName;
     this.known = known;
-    this.unknown = null;
     assert known != null;
   }
 
-  private KotlinTypeReference(String unknown) {
+  private KotlinTypeReference(String originalName) {
     this.known = null;
-    this.unknown = unknown;
-    assert unknown != null;
+    this.originalName = originalName;
+    assert originalName != null;
   }
 
   public DexType getKnown() {
     return known;
   }
 
-  static KotlinTypeReference fromBinaryName(String binaryName, DexItemFactory factory) {
+  public String getOriginalName() {
+    return originalName;
+  }
+
+  static KotlinTypeReference fromBinaryName(
+      String binaryName, DexItemFactory factory, String originalName) {
     if (DescriptorUtils.isValidBinaryName(binaryName)) {
       return fromDescriptor(
-          DescriptorUtils.getDescriptorFromClassBinaryName(binaryName), factory, binaryName);
+          DescriptorUtils.getDescriptorFromClassBinaryName(binaryName), factory, originalName);
     }
     return new KotlinTypeReference(binaryName);
   }
@@ -53,12 +61,12 @@
   }
 
   static KotlinTypeReference fromDescriptor(
-      String descriptor, DexItemFactory factory, String unknownValue) {
+      String descriptor, DexItemFactory factory, String originalName) {
     if (DescriptorUtils.isDescriptor(descriptor)) {
       DexType type = factory.createType(descriptor);
-      return new KotlinTypeReference(type);
+      return new KotlinTypeReference(originalName, type);
     }
-    return new KotlinTypeReference(unknownValue);
+    return new KotlinTypeReference(originalName);
   }
 
   boolean toRenamedDescriptorOrDefault(
@@ -66,29 +74,44 @@
       AppView<?> appView,
       NamingLens namingLens,
       String defaultValue) {
-    if (unknown != null) {
-      rewrittenConsumer.accept(unknown);
+    if (known == null) {
+      rewrittenConsumer.accept(originalName);
       return false;
     }
-    assert known != null;
     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);
     return !known.toDescriptorString().equals(renamedString);
   }
 
+  String toKotlinClassifier(boolean isLocalOrAnonymous) {
+    if (known == null) {
+      return originalName;
+    }
+    return getKotlinLocalOrAnonymousNameFromDescriptor(
+        known.toDescriptorString(), isLocalOrAnonymous);
+  }
+
   boolean toRenamedBinaryNameOrDefault(
       Consumer<String> rewrittenConsumer,
       AppView<?> appView,
       NamingLens namingLens,
       String defaultValue) {
-    if (unknown != null) {
+    if (known == null) {
       // Unknown values are always on the input form, so we can just return it.
-      rewrittenConsumer.accept(unknown);
+      rewrittenConsumer.accept(originalName);
       return false;
     }
     return toRenamedDescriptorOrDefault(
@@ -126,7 +149,7 @@
 
   @Override
   public String toString() {
-    return known != null ? known.descriptor.toString() : unknown;
+    return known != null ? known.descriptor.toString() : originalName;
   }
 
   @Override
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 820f2a3..c602a1c 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -2171,7 +2171,7 @@
   }
 
   public static KotlinCompiler[] getKotlinCompilers() {
-    return new KotlinCompiler[] {getKotlinC_1_3_72(), getKotlinC_1_4_20(), getKotlinC_1_5_0_m2()};
+    return new KotlinCompiler[] {getKotlinC_1_4_20(), getKotlinC_1_5_0_m2()};
   }
 
   public static void disassemble(AndroidApp app, PrintStream ps) throws IOException {
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java
index cccbde4..9d53d71 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java
@@ -167,14 +167,14 @@
     assertEquals(
         DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB) + "/AnnoWithClassArr",
         annotation.getClassName());
-    Map<String, KmAnnotationArgument<?>> arguments = annotation.getArguments();
+    Map<String, KmAnnotationArgument> arguments = annotation.getArguments();
     assertEquals(1, arguments.size());
     ArrayValue classes = (ArrayValue) arguments.get("classes");
     assertEquals(
-        "KClassValue(value=" + foo.getFinalBinaryName() + ")",
-        classes.getValue().get(0).toString());
+        "KClassValue(className=" + foo.getFinalBinaryName() + ", arrayDimensionCount=0)",
+        classes.getElements().get(0).toString());
     assertEquals(
-        "KClassValue(value=" + bar.getFinalBinaryName() + ")",
-        classes.getValue().get(1).toString());
+        "KClassValue(className=" + bar.getFinalBinaryName() + ", arrayDimensionCount=0)",
+        classes.getElements().get(1).toString());
   }
 }
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteJvmStaticTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteJvmStaticTest.java
index 605b16c..7939805 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteJvmStaticTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteJvmStaticTest.java
@@ -94,6 +94,7 @@
             .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
             .addKeepAllClassesRule()
             .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
+            .addKeepAttributeInnerClassesAndEnclosingMethod()
             .compile()
             .inspect(this::inspect)
             .writeToZip();
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java
index 80578a3..370ab75 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java
@@ -78,6 +78,7 @@
         .addKeepAllClassesRule()
         .addKeepKotlinMetadata()
         .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
+        .addKeepAttributeInnerClassesAndEnclosingMethod()
         .allowDiagnosticWarningMessages()
         .compile()
         .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))