Version 2.1.41

Backport kotlin metadata modeling and tests

This will sync the treatment of kotlin metadata between our main
development branch and the beta release branch.

The back port includes content from the following CL's:
CL: https://r8-review.googlesource.com/52084
CL: https://r8-review.googlesource.com/52094

Manually edited Enqueuer to pass in pruned types and re-added missing
overrides for KotlinMetadataDefinitionSupplier.

Besides the back ports above the following clean cherry-pick is:

Cherry pick: Reland "Move rewriting of Kotlin Metadata out of minifiers"
CL: https://r8-review.googlesource.com/52095

Bug: 158766557
Change-Id: I1636245a9da9ca938dce02cabe44b40243ebacb1
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index c3ad10a..951b795 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -51,6 +51,7 @@
 import com.android.tools.r8.ir.optimize.enums.EnumValueInfoMapCollector;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
 import com.android.tools.r8.jar.CfApplicationWriter;
+import com.android.tools.r8.kotlin.KotlinMetadataRewriter;
 import com.android.tools.r8.kotlin.KotlinMetadataUtils;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.naming.Minifier;
@@ -806,6 +807,10 @@
         namingLens = NamingLens.getIdentityLens();
       }
 
+      timing.begin("MinifyKotlinMetadata");
+      new KotlinMetadataRewriter(appView, namingLens).run(executorService);
+      timing.end();
+
       timing.begin("Line number remapping");
       // When line number optimization is turned off the identity mapping for line numbers is
       // used. We still run the line number optimizer to collect line numbers and inline frame
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 8778485..04e1817 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
 
   // This field is accessed from release scripts using simple pattern matching.
   // Therefore, changing this field could break our release scripts.
-  public static final String LABEL = "2.1.40";
+  public static final String LABEL = "2.1.41";
 
   private Version() {
   }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KmVisitorProviders.java b/src/main/java/com/android/tools/r8/kotlin/KmVisitorProviders.java
index 84d6e82..65bdeec 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KmVisitorProviders.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KmVisitorProviders.java
@@ -5,6 +5,11 @@
 package com.android.tools.r8.kotlin;
 
 import kotlinx.metadata.KmAnnotation;
+import kotlinx.metadata.KmContractVisitor;
+import kotlinx.metadata.KmEffectExpressionVisitor;
+import kotlinx.metadata.KmEffectInvocationKind;
+import kotlinx.metadata.KmEffectType;
+import kotlinx.metadata.KmEffectVisitor;
 import kotlinx.metadata.KmFunctionVisitor;
 import kotlinx.metadata.KmLambdaVisitor;
 import kotlinx.metadata.KmPropertyVisitor;
@@ -13,6 +18,7 @@
 import kotlinx.metadata.KmTypeVisitor;
 import kotlinx.metadata.KmValueParameterVisitor;
 import kotlinx.metadata.KmVariance;
+import kotlinx.metadata.KmVersionRequirementVisitor;
 
 /**
  * The reason for having these visitor providers is to make the separation of concern a bit easier
@@ -101,4 +107,28 @@
 
     KmTypeVisitor get(int flags, String typeFlexibilityId);
   }
+
+  @FunctionalInterface
+  public interface KmVersionRequirementVisitorProvider {
+
+    KmVersionRequirementVisitor get();
+  }
+
+  @FunctionalInterface
+  public interface KmContractVisitorProvider {
+
+    KmContractVisitor get();
+  }
+
+  @FunctionalInterface
+  public interface KmEffectVisitorProvider {
+
+    KmEffectVisitor get(KmEffectType type, KmEffectInvocationKind effectInvocationKind);
+  }
+
+  @FunctionalInterface
+  public interface KmEffectExpressionVisitorProvider {
+
+    KmEffectExpressionVisitor get();
+  }
 }
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 602165c..ef44b4b 100644
--- a/src/main/java/com/android/tools/r8/kotlin/Kotlin.java
+++ b/src/main/java/com/android/tools/r8/kotlin/Kotlin.java
@@ -9,11 +9,8 @@
 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.ImmutableList;
-import com.google.common.collect.ImmutableMap;
 import it.unimi.dsi.fastutil.objects.Object2IntArrayMap;
 import it.unimi.dsi.fastutil.objects.Object2IntMap;
-import java.util.Map;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
@@ -21,17 +18,6 @@
 /** Class provides basic information about symbols related to Kotlin support. */
 public final class Kotlin {
 
-  // Simply "kotlin", but to avoid being renamed by Shadow.relocate in build.gradle.
-  public static final String NAME = String.join("", ImmutableList.of("k", "o", "t", "l", "i", "n"));
-
-  // Simply "Lkotlin/", but to avoid being renamed by Shadow.relocate in build.gradle.
-  private static final String KOTLIN =
-      String.join("", ImmutableList.of("L", "k", "o", "t", "l", "i", "n", "/"));
-
-  static String addKotlinPrefix(String str) {
-    return KOTLIN + str;
-  }
-
   public final DexItemFactory factory;
 
   public final Functional functional;
@@ -39,82 +25,22 @@
   public final Metadata metadata;
   public final _Assertions assertions;
 
+  public static final String NAME = "kotlin";
+  public static final String PACKAGE_PREFIX = "L" + NAME + "/";
+
   public static final class ClassClassifiers {
 
     public static final String arrayBinaryName = NAME + "/Array";
+    public static final String anyDescriptor = PACKAGE_PREFIX + "Any;";
     public static final String anyName = NAME + "/Any";
   }
 
-  // Mappings from JVM types to Kotlin types (of type DexType)
-  final Map<DexType, DexType> knownTypeConversion;
-
   public Kotlin(DexItemFactory factory) {
     this.factory = factory;
-
     this.functional = new Functional();
     this.intrinsics = new Intrinsics();
     this.metadata = new Metadata();
     this.assertions = new _Assertions();
-
-    // See {@link org.jetbrains.kotlin.metadata.jvm.deserialization.ClassMapperLite}
-    this.knownTypeConversion =
-        ImmutableMap.<DexType, DexType>builder()
-            // https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/index.html
-            // Boxed primitives and arrays
-            .put(factory.booleanType, factory.createType(addKotlinPrefix("Boolean;")))
-            .put(factory.boxedBooleanType, factory.createType(addKotlinPrefix("Boolean;")))
-            .put(factory.booleanArrayType, factory.createType(addKotlinPrefix("BooleanArray;")))
-            .put(factory.byteType, factory.createType(addKotlinPrefix("Byte;")))
-            .put(factory.byteArrayType, factory.createType(addKotlinPrefix("ByteArray;")))
-            .put(factory.charType, factory.createType(addKotlinPrefix("Char;")))
-            .put(factory.charArrayType, factory.createType(addKotlinPrefix("CharArray;")))
-            .put(factory.shortType, factory.createType(addKotlinPrefix("Short;")))
-            .put(factory.shortArrayType, factory.createType(addKotlinPrefix("ShortArray;")))
-            .put(factory.intType, factory.createType(addKotlinPrefix("Int;")))
-            .put(factory.boxedIntType, factory.createType(addKotlinPrefix("Int;")))
-            .put(factory.intArrayType, factory.createType(addKotlinPrefix("IntArray;")))
-            .put(factory.longType, factory.createType(addKotlinPrefix("Long;")))
-            .put(factory.longArrayType, factory.createType(addKotlinPrefix("LongArray;")))
-            .put(factory.floatType, factory.createType(addKotlinPrefix("Float;")))
-            .put(factory.floatArrayType, factory.createType(addKotlinPrefix("FloatArray;")))
-            .put(factory.doubleType, factory.createType(addKotlinPrefix("Double;")))
-            .put(factory.doubleArrayType, factory.createType(addKotlinPrefix("DoubleArray;")))
-            // Other intrinsics
-            .put(factory.voidType, factory.createType(addKotlinPrefix("Unit;")))
-            .put(factory.objectType, factory.createType(addKotlinPrefix("Any;")))
-            .put(factory.boxedVoidType, factory.createType(addKotlinPrefix("Nothing;")))
-            .put(factory.stringType, factory.createType(addKotlinPrefix("String;")))
-            .put(factory.charSequenceType, factory.createType(addKotlinPrefix("CharSequence;")))
-            .put(factory.throwableType, factory.createType(addKotlinPrefix("Throwable;")))
-            .put(factory.cloneableType, factory.createType(addKotlinPrefix("Cloneable;")))
-            .put(factory.boxedNumberType, factory.createType(addKotlinPrefix("Number;")))
-            .put(factory.comparableType, factory.createType(addKotlinPrefix("Comparable;")))
-            .put(factory.enumType, factory.createType(addKotlinPrefix("Enum;")))
-            // Collections
-            .put(factory.iteratorType, factory.createType(addKotlinPrefix("collections/Iterator;")))
-            .put(
-                factory.collectionType,
-                factory.createType(addKotlinPrefix("collections/Collection;")))
-            .put(factory.listType, factory.createType(addKotlinPrefix("collections/List;")))
-            .put(factory.setType, factory.createType(addKotlinPrefix("collections/Set;")))
-            .put(factory.mapType, factory.createType(addKotlinPrefix("collections/Map;")))
-            .put(
-                factory.listIteratorType,
-                factory.createType(addKotlinPrefix("collections/ListIterator;")))
-            .put(factory.iterableType, factory.createType(addKotlinPrefix("collections/Iterable;")))
-            .put(
-                factory.mapEntryType, factory.createType(addKotlinPrefix("collections/Map$Entry;")))
-            // .../jvm/functions/FunctionN -> .../FunctionN
-            .putAll(
-                IntStream.rangeClosed(0, 22)
-                    .boxed()
-                    .collect(
-                        Collectors.toMap(
-                            i ->
-                                factory.createType(
-                                    addKotlinPrefix("jvm/functions/Function" + i + ";")),
-                            i -> factory.createType(addKotlinPrefix("Function" + i + ";")))))
-            .build();
   }
 
   public final class Functional {
@@ -128,12 +54,15 @@
     //   > "Error: A JNI error has occurred, please check your installation and try again"
     //
     // This implementation just ignores lambdas with arity > 22.
-    private final Object2IntMap<DexType> functions = new Object2IntArrayMap<>(
-        IntStream.rangeClosed(0, 22).boxed().collect(
-            Collectors.toMap(
-                i -> factory.createType(addKotlinPrefix("jvm/functions/Function") + i + ";"),
-                Function.identity()))
-    );
+    private final Object2IntMap<DexType> functions =
+        new Object2IntArrayMap<>(
+            IntStream.rangeClosed(0, 22)
+                .boxed()
+                .collect(
+                    Collectors.toMap(
+                        i ->
+                            factory.createType(PACKAGE_PREFIX + "jvm/functions/Function" + i + ";"),
+                        Function.identity())));
 
     private Functional() {
     }
@@ -141,8 +70,8 @@
     public final DexString kotlinStyleLambdaInstanceName = factory.createString("INSTANCE");
 
     public final DexType functionBase =
-        factory.createType(addKotlinPrefix("jvm/internal/FunctionBase;"));
-    public final DexType lambdaType = factory.createType(addKotlinPrefix("jvm/internal/Lambda;"));
+        factory.createType(PACKAGE_PREFIX + "jvm/internal/FunctionBase;");
+    public final DexType lambdaType = factory.createType(PACKAGE_PREFIX + "jvm/internal/Lambda;");
 
     public final DexMethod lambdaInitializerMethod = factory.createMethod(
         lambdaType,
@@ -172,7 +101,7 @@
   }
 
   public final class _Assertions {
-    public final DexType type = factory.createType(addKotlinPrefix("_Assertions;"));
+    public final DexType type = factory.createType(PACKAGE_PREFIX + "_Assertions;");
     public final DexString enabledFieldName = factory.createString("ENABLED");
     public final DexField enabledField =
         factory.createField(type, factory.booleanType, enabledFieldName);
@@ -180,7 +109,7 @@
 
   // kotlin.jvm.internal.Intrinsics class
   public final class Intrinsics {
-    public final DexType type = factory.createType(addKotlinPrefix("jvm/internal/Intrinsics;"));
+    public final DexType type = factory.createType(PACKAGE_PREFIX + "jvm/internal/Intrinsics;");
     public final DexMethod throwParameterIsNullException = factory.createMethod(type,
         factory.createProto(factory.voidType, factory.stringType), "throwParameterIsNullException");
     public final DexMethod checkParameterIsNotNull = factory.createMethod(type,
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationArgumentInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationArgumentInfo.java
new file mode 100644
index 0000000..953766c
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationArgumentInfo.java
@@ -0,0 +1,208 @@
+// Copyright (c) 2020, 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.DexDefinitionSupplier;
+import com.android.tools.r8.graph.DexItemFactory;
+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.Box;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import kotlinx.metadata.KmAnnotation;
+import kotlinx.metadata.KmAnnotationArgument;
+import kotlinx.metadata.KmAnnotationArgument.AnnotationValue;
+import kotlinx.metadata.KmAnnotationArgument.ArrayValue;
+import kotlinx.metadata.KmAnnotationArgument.EnumValue;
+import kotlinx.metadata.KmAnnotationArgument.KClassValue;
+
+abstract class KotlinAnnotationArgumentInfo implements EnqueuerMetadataTraceable {
+
+  private static final Map<String, KotlinAnnotationArgumentInfo> EMPTY_ARGUMENTS =
+      ImmutableMap.of();
+
+  abstract KmAnnotationArgument<?> rewrite(AppView<?> appView, NamingLens namingLens);
+
+  private static KotlinAnnotationArgumentInfo createArgument(
+      KmAnnotationArgument<?> arg, DexItemFactory factory) {
+    if (arg instanceof KClassValue) {
+      return KotlinAnnotationClassValueInfo.create((KClassValue) arg, factory);
+    } else if (arg instanceof EnumValue) {
+      return KotlinAnnotationEnumValueInfo.create((EnumValue) arg, factory);
+    } else if (arg instanceof AnnotationValue) {
+      return KotlinAnnotationAnnotationValueInfo.create((AnnotationValue) arg, factory);
+    } else if (arg instanceof ArrayValue) {
+      return KotlinAnnotationArrayValueInfo.create((ArrayValue) arg, factory);
+    } else {
+      return KotlinAnnotationPrimitiveArgumentInfo.create(arg);
+    }
+  }
+
+  static Map<String, KotlinAnnotationArgumentInfo> create(
+      Map<String, KmAnnotationArgument<?>> arguments, DexItemFactory factory) {
+    if (arguments.isEmpty()) {
+      return EMPTY_ARGUMENTS;
+    }
+    LinkedHashMap<String, KotlinAnnotationArgumentInfo> modeled = new LinkedHashMap<>();
+    arguments.forEach((key, arg) -> modeled.put(key, createArgument(arg, factory)));
+    return modeled;
+  }
+
+  private static class KotlinAnnotationClassValueInfo extends KotlinAnnotationArgumentInfo {
+
+    private final KotlinTypeReference value;
+
+    private KotlinAnnotationClassValueInfo(KotlinTypeReference value) {
+      this.value = value;
+    }
+
+    private static KotlinAnnotationClassValueInfo create(KClassValue arg, DexItemFactory factory) {
+      return new KotlinAnnotationClassValueInfo(
+          KotlinTypeReference.fromBinaryName(arg.getValue(), factory));
+    }
+
+    @Override
+    public void trace(DexDefinitionSupplier definitionSupplier) {
+      value.trace(definitionSupplier);
+    }
+
+    @Override
+    KmAnnotationArgument<?> rewrite(AppView<?> appView, NamingLens namingLens) {
+      return new KClassValue(
+          value.toRenamedBinaryNameOrDefault(appView, namingLens, ClassClassifiers.anyName));
+    }
+  }
+
+  private static class KotlinAnnotationEnumValueInfo extends KotlinAnnotationArgumentInfo {
+
+    private final KotlinTypeReference enumClassName;
+    private final String enumEntryName;
+
+    private KotlinAnnotationEnumValueInfo(KotlinTypeReference enumClassName, String enumEntryName) {
+      this.enumClassName = enumClassName;
+      this.enumEntryName = enumEntryName;
+    }
+
+    private static KotlinAnnotationEnumValueInfo create(EnumValue arg, DexItemFactory factory) {
+      return new KotlinAnnotationEnumValueInfo(
+          KotlinTypeReference.fromBinaryName(arg.getEnumClassName(), factory),
+          arg.getEnumEntryName());
+    }
+
+    @Override
+    public void trace(DexDefinitionSupplier definitionSupplier) {
+      enumClassName.trace(definitionSupplier);
+    }
+
+    @Override
+    KmAnnotationArgument<?> rewrite(AppView<?> appView, NamingLens namingLens) {
+      return new EnumValue(
+          enumClassName.toRenamedBinaryNameOrDefault(appView, namingLens, ClassClassifiers.anyName),
+          enumEntryName);
+    }
+  }
+
+  private static class KotlinAnnotationAnnotationValueInfo extends KotlinAnnotationArgumentInfo {
+
+    private final KotlinAnnotationInfo value;
+
+    private KotlinAnnotationAnnotationValueInfo(KotlinAnnotationInfo value) {
+      this.value = value;
+    }
+
+    private static KotlinAnnotationAnnotationValueInfo create(
+        AnnotationValue arg, DexItemFactory factory) {
+      return new KotlinAnnotationAnnotationValueInfo(
+          KotlinAnnotationInfo.create(arg.getValue(), factory));
+    }
+
+    @Override
+    public void trace(DexDefinitionSupplier definitionSupplier) {
+      value.trace(definitionSupplier);
+    }
+
+    @Override
+    KmAnnotationArgument<?> rewrite(AppView<?> appView, NamingLens namingLens) {
+      Box<KmAnnotation> rewrittenAnnotation = new Box<>();
+      value.rewrite(rewrittenAnnotation::set, appView, namingLens);
+      if (rewrittenAnnotation.isSet()) {
+        return new AnnotationValue(rewrittenAnnotation.get());
+      }
+      return null;
+    }
+  }
+
+  private static class KotlinAnnotationArrayValueInfo extends KotlinAnnotationArgumentInfo {
+
+    private static final KotlinAnnotationArrayValueInfo EMPTY =
+        new KotlinAnnotationArrayValueInfo(ImmutableList.of());
+
+    private final List<KotlinAnnotationArgumentInfo> value;
+
+    private KotlinAnnotationArrayValueInfo(List<KotlinAnnotationArgumentInfo> value) {
+      this.value = value;
+    }
+
+    private static KotlinAnnotationArrayValueInfo create(ArrayValue arg, DexItemFactory factory) {
+      if (arg.getValue().isEmpty()) {
+        return EMPTY;
+      }
+      ImmutableList.Builder<KotlinAnnotationArgumentInfo> builder = ImmutableList.builder();
+      for (KmAnnotationArgument<?> argument : arg.getValue()) {
+        builder.add(createArgument(argument, factory));
+      }
+      return new KotlinAnnotationArrayValueInfo(builder.build());
+    }
+
+    @Override
+    public void trace(DexDefinitionSupplier definitionSupplier) {
+      for (KotlinAnnotationArgumentInfo kotlinAnnotationArgumentInfo : value) {
+        kotlinAnnotationArgumentInfo.trace(definitionSupplier);
+      }
+    }
+
+    @Override
+    KmAnnotationArgument<?> rewrite(AppView<?> appView, NamingLens namingLens) {
+      List<KmAnnotationArgument<?>> rewrittenArguments = new ArrayList<>();
+      for (KotlinAnnotationArgumentInfo kotlinAnnotationArgumentInfo : value) {
+        KmAnnotationArgument<?> rewrittenArg =
+            kotlinAnnotationArgumentInfo.rewrite(appView, namingLens);
+        if (rewrittenArg != null) {
+          rewrittenArguments.add(rewrittenArg);
+        }
+      }
+      return new ArrayValue(rewrittenArguments);
+    }
+  }
+
+  private static class KotlinAnnotationPrimitiveArgumentInfo extends KotlinAnnotationArgumentInfo {
+
+    private final KmAnnotationArgument<?> argument;
+
+    private KotlinAnnotationPrimitiveArgumentInfo(KmAnnotationArgument<?> argument) {
+      this.argument = argument;
+    }
+
+    private static KotlinAnnotationPrimitiveArgumentInfo create(KmAnnotationArgument<?> argument) {
+      return new KotlinAnnotationPrimitiveArgumentInfo(argument);
+    }
+
+    @Override
+    public void trace(DexDefinitionSupplier definitionSupplier) {
+      // Nothing to trace
+    }
+
+    @Override
+    KmAnnotationArgument<?> rewrite(AppView<?> appView, NamingLens namingLens) {
+      return argument;
+    }
+  }
+}
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 a4bc5b0..45adb46 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationInfo.java
@@ -4,65 +4,75 @@
 
 package com.android.tools.r8.kotlin;
 
-import static com.android.tools.r8.kotlin.KotlinMetadataUtils.referenceTypeFromBinaryName;
-
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexDefinitionSupplier;
-import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.naming.NamingLens;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.google.common.collect.ImmutableList;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import kotlinx.metadata.KmAnnotation;
 import kotlinx.metadata.KmAnnotationArgument;
 
 // Holds information about a KmAnnotation
-public class KotlinAnnotationInfo {
+public class KotlinAnnotationInfo implements EnqueuerMetadataTraceable {
 
   private static final List<KotlinAnnotationInfo> EMPTY_ANNOTATIONS = ImmutableList.of();
 
-  private final DexType annotationType;
-  // TODO(b/155053894): Model KmAnnotationArgument.
-  private final Map<String, KmAnnotationArgument<?>> arguments;
+  private final KotlinTypeReference annotationType;
+  private final Map<String, KotlinAnnotationArgumentInfo> arguments;
 
   private KotlinAnnotationInfo(
-      DexType annotationType, Map<String, KmAnnotationArgument<?>> arguments) {
+      KotlinTypeReference annotationType, Map<String, KotlinAnnotationArgumentInfo> arguments) {
     this.annotationType = annotationType;
     this.arguments = arguments;
   }
 
-  private static KotlinAnnotationInfo create(
-      KmAnnotation annotation, DexDefinitionSupplier definitionSupplier) {
+  static KotlinAnnotationInfo create(KmAnnotation annotation, DexItemFactory factory) {
     return new KotlinAnnotationInfo(
-        referenceTypeFromBinaryName(annotation.getClassName(), definitionSupplier),
-        annotation.getArguments());
+        KotlinTypeReference.fromBinaryName(annotation.getClassName(), factory),
+        KotlinAnnotationArgumentInfo.create(annotation.getArguments(), factory));
   }
 
-  static List<KotlinAnnotationInfo> create(
-      List<KmAnnotation> annotations, DexDefinitionSupplier definitionSupplier) {
+  static List<KotlinAnnotationInfo> create(List<KmAnnotation> annotations, DexItemFactory factory) {
     if (annotations.isEmpty()) {
       return EMPTY_ANNOTATIONS;
     }
     ImmutableList.Builder<KotlinAnnotationInfo> builder = ImmutableList.builder();
     for (KmAnnotation annotation : annotations) {
-      builder.add(create(annotation, definitionSupplier));
+      builder.add(create(annotation, factory));
     }
     return builder.build();
   }
 
   public void rewrite(
       KmVisitorProviders.KmAnnotationVisitorProvider visitorProvider,
-      AppView<AppInfoWithLiveness> appView,
+      AppView<?> appView,
       NamingLens namingLens) {
-    if (appView.appInfo().wasPruned(annotationType)) {
+    String renamedDescriptor =
+        annotationType.toRenamedDescriptorOrDefault(appView, namingLens, null);
+    if (renamedDescriptor == null) {
+      // The type has been pruned
       return;
     }
-    DexString descriptor = namingLens.lookupDescriptor(annotationType);
-    String classifier = DescriptorUtils.descriptorToKotlinClassifier(descriptor.toString());
-    KmAnnotation annotation = new KmAnnotation(classifier, arguments);
-    visitorProvider.get(annotation);
+    String classifier = DescriptorUtils.descriptorToKotlinClassifier(renamedDescriptor);
+    Map<String, KmAnnotationArgument<?>> rewrittenArguments = new LinkedHashMap<>();
+    arguments.forEach(
+        (key, arg) -> {
+          KmAnnotationArgument<?> rewrittenArg = arg.rewrite(appView, namingLens);
+          if (rewrittenArg != null) {
+            rewrittenArguments.put(key, rewrittenArg);
+          }
+        });
+    visitorProvider.get(new KmAnnotation(classifier, rewrittenArguments));
+  }
+
+  @Override
+  public void trace(DexDefinitionSupplier definitionSupplier) {
+    annotationType.trace(definitionSupplier);
+    arguments.forEach((ignored, arg) -> arg.trace(definitionSupplier));
   }
 }
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 b507093..24947bf 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java
@@ -4,19 +4,18 @@
 
 package com.android.tools.r8.kotlin;
 
-import static com.android.tools.r8.kotlin.KotlinMetadataUtils.referenceTypeFromBinaryName;
 import static com.android.tools.r8.kotlin.KotlinMetadataUtils.toJvmFieldSignature;
 import static com.android.tools.r8.kotlin.KotlinMetadataUtils.toJvmMethodSignature;
+import static com.android.tools.r8.utils.FunctionUtils.forEachApply;
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.naming.NamingLens;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.Reporter;
 import com.google.common.collect.ImmutableList;
@@ -27,6 +26,7 @@
 import kotlinx.metadata.KmClass;
 import kotlinx.metadata.KmConstructor;
 import kotlinx.metadata.KmType;
+import kotlinx.metadata.jvm.JvmClassExtensionVisitor;
 import kotlinx.metadata.jvm.JvmExtensionsKt;
 import kotlinx.metadata.jvm.JvmMethodSignature;
 import kotlinx.metadata.jvm.KotlinClassHeader;
@@ -41,14 +41,15 @@
   private final KotlinDeclarationContainerInfo declarationContainerInfo;
   private final List<KotlinTypeParameterInfo> typeParameters;
   private final List<KotlinTypeInfo> superTypes;
-  private final List<DexType> sealedSubClasses;
-  private final List<DexType> nestedClasses;
-  // TODO(b/154347404): Understand enum entries.
+  private final List<KotlinTypeReference> sealedSubClasses;
+  private final List<KotlinTypeReference> nestedClasses;
   private final List<String> enumEntries;
-  private final DexType anonymousObjectOrigin;
+  private final KotlinVersionRequirementInfo versionRequirements;
+  private final KotlinTypeReference anonymousObjectOrigin;
   private final String packageName;
+  private final KotlinLocalDelegatedPropertyInfo localDelegatedProperties;
 
-  public KotlinClassInfo(
+  private KotlinClassInfo(
       int flags,
       String name,
       String moduleName,
@@ -56,11 +57,13 @@
       List<KotlinTypeParameterInfo> typeParameters,
       List<KotlinConstructorInfo> constructorsWithNoBacking,
       List<KotlinTypeInfo> superTypes,
-      List<DexType> sealedSubClasses,
-      List<DexType> nestedClasses,
+      List<KotlinTypeReference> sealedSubClasses,
+      List<KotlinTypeReference> nestedClasses,
       List<String> enumEntries,
-      DexType anonymousObjectOrigin,
-      String packageName) {
+      KotlinVersionRequirementInfo versionRequirements,
+      KotlinTypeReference anonymousObjectOrigin,
+      String packageName,
+      KotlinLocalDelegatedPropertyInfo localDelegatedProperties) {
     this.flags = flags;
     this.name = name;
     this.moduleName = moduleName;
@@ -71,15 +74,17 @@
     this.sealedSubClasses = sealedSubClasses;
     this.nestedClasses = nestedClasses;
     this.enumEntries = enumEntries;
+    this.versionRequirements = versionRequirements;
     this.anonymousObjectOrigin = anonymousObjectOrigin;
     this.packageName = packageName;
+    this.localDelegatedProperties = localDelegatedProperties;
   }
 
   public static KotlinClassInfo create(
       KmClass kmClass,
       String packageName,
       DexClass hostClass,
-      DexDefinitionSupplier definitionSupplier,
+      DexItemFactory factory,
       Reporter reporter,
       Consumer<DexEncodedMethod> keepByteCode) {
     Map<String, DexEncodedField> fieldMap = new HashMap<>();
@@ -93,7 +98,7 @@
     ImmutableList.Builder<KotlinConstructorInfo> notBackedConstructors = ImmutableList.builder();
     for (KmConstructor kmConstructor : kmClass.getConstructors()) {
       KotlinConstructorInfo constructorInfo =
-          KotlinConstructorInfo.create(kmConstructor, definitionSupplier, reporter);
+          KotlinConstructorInfo.create(kmConstructor, factory, reporter);
       JvmMethodSignature signature = JvmExtensionsKt.getSignature(kmConstructor);
       if (signature != null) {
         DexEncodedMethod method = methodMap.get(signature.asString());
@@ -107,60 +112,63 @@
     }
     KotlinDeclarationContainerInfo container =
         KotlinDeclarationContainerInfo.create(
-            kmClass, methodMap, fieldMap, definitionSupplier, reporter, keepByteCode);
+            kmClass, methodMap, fieldMap, factory, reporter, keepByteCode);
     setCompanionObject(kmClass, hostClass, reporter);
     return new KotlinClassInfo(
         kmClass.getFlags(),
         kmClass.name,
         JvmExtensionsKt.getModuleName(kmClass),
         container,
-        KotlinTypeParameterInfo.create(kmClass.getTypeParameters(), definitionSupplier, reporter),
+        KotlinTypeParameterInfo.create(kmClass.getTypeParameters(), factory, reporter),
         notBackedConstructors.build(),
-        getSuperTypes(kmClass.getSupertypes(), definitionSupplier, reporter),
-        getSealedSubClasses(hostClass, kmClass.getSealedSubclasses(), definitionSupplier),
-        getNestedClasses(hostClass, kmClass.getNestedClasses(), definitionSupplier),
+        getSuperTypes(kmClass.getSupertypes(), factory, reporter),
+        getSealedSubClasses(kmClass.getSealedSubclasses(), factory),
+        getNestedClasses(hostClass, kmClass.getNestedClasses(), factory),
         kmClass.getEnumEntries(),
-        getAnonymousObjectOrigin(kmClass, definitionSupplier),
-        packageName);
+        KotlinVersionRequirementInfo.create(kmClass.getVersionRequirements()),
+        getAnonymousObjectOrigin(kmClass, factory),
+        packageName,
+        KotlinLocalDelegatedPropertyInfo.create(
+            JvmExtensionsKt.getLocalDelegatedProperties(kmClass), factory, reporter));
   }
 
-  private static DexType getAnonymousObjectOrigin(
-      KmClass kmClass, DexDefinitionSupplier definitionSupplier) {
+  private static KotlinTypeReference getAnonymousObjectOrigin(
+      KmClass kmClass, DexItemFactory factory) {
     String anonymousObjectOriginName = JvmExtensionsKt.getAnonymousObjectOriginName(kmClass);
     if (anonymousObjectOriginName != null) {
-      return referenceTypeFromBinaryName(anonymousObjectOriginName, definitionSupplier);
+      return KotlinTypeReference.fromBinaryName(anonymousObjectOriginName, factory);
     }
     return null;
   }
 
-  private static List<DexType> getNestedClasses(
-      DexClass clazz, List<String> nestedClasses, DexDefinitionSupplier definitionSupplier) {
-    ImmutableList.Builder<DexType> nestedTypes = ImmutableList.builder();
+  private static List<KotlinTypeReference> getNestedClasses(
+      DexClass clazz, List<String> nestedClasses, DexItemFactory factory) {
+    ImmutableList.Builder<KotlinTypeReference> nestedTypes = ImmutableList.builder();
     for (String nestedClass : nestedClasses) {
       String binaryName =
           clazz.type.toBinaryName() + DescriptorUtils.INNER_CLASS_SEPARATOR + nestedClass;
-      nestedTypes.add(referenceTypeFromBinaryName(binaryName, definitionSupplier));
+      nestedTypes.add(KotlinTypeReference.fromBinaryName(binaryName, factory));
     }
     return nestedTypes.build();
   }
 
-  private static List<DexType> getSealedSubClasses(
-      DexClass clazz, List<String> sealedSubclasses, DexDefinitionSupplier definitionSupplier) {
-    ImmutableList.Builder<DexType> sealedTypes = ImmutableList.builder();
+  private static List<KotlinTypeReference> getSealedSubClasses(
+      List<String> sealedSubclasses, DexItemFactory factory) {
+    ImmutableList.Builder<KotlinTypeReference> sealedTypes = ImmutableList.builder();
     for (String sealedSubClass : sealedSubclasses) {
       String binaryName =
           sealedSubClass.replace(
               DescriptorUtils.JAVA_PACKAGE_SEPARATOR, DescriptorUtils.INNER_CLASS_SEPARATOR);
-      sealedTypes.add(referenceTypeFromBinaryName(binaryName, definitionSupplier));
+      sealedTypes.add(KotlinTypeReference.fromBinaryName(binaryName, factory));
     }
     return sealedTypes.build();
   }
 
   private static List<KotlinTypeInfo> getSuperTypes(
-      List<KmType> superTypes, DexDefinitionSupplier definitionSupplier, Reporter reporter) {
+      List<KmType> superTypes, DexItemFactory factory, Reporter reporter) {
     ImmutableList.Builder<KotlinTypeInfo> superTypeInfos = ImmutableList.builder();
     for (KmType superType : superTypes) {
-      superTypeInfos.add(KotlinTypeInfo.create(superType, definitionSupplier, reporter));
+      superTypeInfos.add(KotlinTypeInfo.create(superType, factory, reporter));
     }
     return superTypeInfos.build();
   }
@@ -191,8 +199,7 @@
   }
 
   @Override
-  public KotlinClassHeader rewrite(
-      DexClass clazz, AppView<AppInfoWithLiveness> appView, NamingLens namingLens) {
+  public KotlinClassHeader rewrite(DexClass clazz, AppView<?> appView, NamingLens namingLens) {
     KmClass kmClass = new KmClass();
     // TODO(b/154348683): Set flags.
     kmClass.setFlags(flags);
@@ -205,7 +212,7 @@
     kmClass.setName(
         originalDescriptor.equals(rewrittenDescriptor)
             ? this.name
-            : KotlinMetadataUtils.kotlinNameFromDescriptor(rewrittenDescriptor));
+            : DescriptorUtils.getBinaryNameFromDescriptor(rewrittenDescriptor.toString()));
     // Find a companion object.
     for (DexEncodedField field : clazz.fields()) {
       if (field.getKotlinMemberInfo().isCompanion()) {
@@ -240,36 +247,41 @@
       superType.rewrite(kmClass::visitSupertype, appView, namingLens);
     }
     // Rewrite nested classes.
-    for (DexType nestedClass : nestedClasses) {
-      if (appView.appInfo().isNonProgramTypeOrLiveProgramType(nestedClass)) {
-        String descriptor =
-            KotlinMetadataUtils.kotlinNameFromDescriptor(namingLens.lookupDescriptor(nestedClass));
+    for (KotlinTypeReference nestedClass : nestedClasses) {
+      String nestedDescriptor = nestedClass.toRenamedBinaryNameOrDefault(appView, namingLens, null);
+      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 = descriptor.lastIndexOf(DescriptorUtils.INNER_CLASS_SEPARATOR);
-        kmClass.visitNestedClass(descriptor.substring(innerClassIndex + 1));
+        int innerClassIndex = nestedDescriptor.lastIndexOf(DescriptorUtils.INNER_CLASS_SEPARATOR);
+        kmClass.visitNestedClass(nestedDescriptor.substring(innerClassIndex + 1));
       }
     }
     // Rewrite sealed sub classes.
-    for (DexType sealedSubClass : sealedSubClasses) {
-      if (appView.appInfo().isNonProgramTypeOrLiveProgramType(sealedSubClass)) {
-        String descriptor =
-            KotlinMetadataUtils.kotlinNameFromDescriptor(
-                namingLens.lookupDescriptor(sealedSubClass));
+    for (KotlinTypeReference sealedSubClass : sealedSubClasses) {
+      String sealedDescriptor =
+          sealedSubClass.toRenamedBinaryNameOrDefault(appView, namingLens, null);
+      if (sealedDescriptor != null) {
         kmClass.visitSealedSubclass(
-            descriptor.replace(
+            sealedDescriptor.replace(
                 DescriptorUtils.INNER_CLASS_SEPARATOR, DescriptorUtils.JAVA_PACKAGE_SEPARATOR));
       }
     }
     // TODO(b/154347404): Understand enum entries.
     kmClass.getEnumEntries().addAll(enumEntries);
-
-    JvmExtensionsKt.setModuleName(kmClass, moduleName);
+    versionRequirements.rewrite(kmClass::visitVersionRequirement);
+    JvmClassExtensionVisitor extensionVisitor =
+        (JvmClassExtensionVisitor) kmClass.visitExtensions(JvmClassExtensionVisitor.TYPE);
+    extensionVisitor.visitModuleName(moduleName);
     if (anonymousObjectOrigin != null) {
-      JvmExtensionsKt.setAnonymousObjectOriginName(
-          kmClass, KotlinMetadataUtils.kotlinNameFromDescriptor(anonymousObjectOrigin.descriptor));
+      String renamedAnon =
+          anonymousObjectOrigin.toRenamedBinaryNameOrDefault(appView, namingLens, null);
+      if (renamedAnon != null) {
+        extensionVisitor.visitAnonymousObjectOriginName(renamedAnon);
+      }
     }
-
+    localDelegatedProperties.rewrite(
+        extensionVisitor::visitLocalDelegatedProperty, appView, namingLens);
+    extensionVisitor.visitEnd();
     KotlinClassMetadata.Class.Writer writer = new KotlinClassMetadata.Class.Writer();
     kmClass.accept(writer);
     return writer.write().getHeader();
@@ -279,4 +291,19 @@
   public String getPackageName() {
     return packageName;
   }
+
+  @Override
+  public void trace(DexDefinitionSupplier definitionSupplier) {
+    forEachApply(constructorsWithNoBacking, constructor -> constructor::trace, definitionSupplier);
+    declarationContainerInfo.trace(definitionSupplier);
+    forEachApply(typeParameters, param -> param::trace, definitionSupplier);
+    forEachApply(superTypes, type -> type::trace, definitionSupplier);
+    forEachApply(sealedSubClasses, sealed -> sealed::trace, definitionSupplier);
+    forEachApply(nestedClasses, nested -> nested::trace, definitionSupplier);
+    localDelegatedProperties.trace(definitionSupplier);
+    // TODO(b/154347404): trace enum entries.
+    if (anonymousObjectOrigin != null) {
+      anonymousObjectOrigin.trace(definitionSupplier);
+    }
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClassLevelInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClassLevelInfo.java
index f9662ef..fdb326e 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassLevelInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassLevelInfo.java
@@ -7,10 +7,14 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.naming.NamingLens;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import kotlinx.metadata.jvm.KotlinClassHeader;
 
-public interface KotlinClassLevelInfo {
+public interface KotlinClassLevelInfo extends EnqueuerMetadataTraceable {
+
+  default boolean isNoKotlinInformation() {
+    return false;
+  }
 
   default boolean isClass() {
     return false;
@@ -52,8 +56,7 @@
     return null;
   }
 
-  KotlinClassHeader rewrite(
-      DexClass clazz, AppView<AppInfoWithLiveness> appView, NamingLens namingLens);
+  KotlinClassHeader rewrite(DexClass clazz, AppView<?> appView, NamingLens namingLens);
 
   String getPackageName();
 }
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 5fe02b2..2171a00 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
@@ -12,6 +12,7 @@
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexEncodedAnnotation;
 import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexValue;
 import com.android.tools.r8.graph.DexValue.DexValueArray;
@@ -31,22 +32,18 @@
   public static KotlinClassLevelInfo getKotlinInfo(
       Kotlin kotlin,
       DexClass clazz,
-      DexDefinitionSupplier definitionSupplier,
+      DexItemFactory factory,
       Reporter reporter,
       boolean onlyProcessLambda,
       Consumer<DexEncodedMethod> keepByteCode) {
-    DexAnnotation meta =
-        clazz
-            .annotations()
-            .getFirstMatching(definitionSupplier.dexItemFactory().kotlinMetadataType);
+    DexAnnotation meta = clazz.annotations().getFirstMatching(factory.kotlinMetadataType);
     if (meta != null) {
       try {
         KotlinClassMetadata kMetadata = toKotlinClassMetadata(kotlin, meta.annotation);
         if (onlyProcessLambda && kMetadata.getHeader().getKind() != KOTLIN_METADATA_KIND_LAMBDA) {
           return NO_KOTLIN_INFO;
         }
-        return createKotlinInfo(
-            kotlin, clazz, kMetadata, definitionSupplier, reporter, keepByteCode);
+        return createKotlinInfo(kotlin, clazz, kMetadata, factory, reporter, keepByteCode);
       } catch (ClassCastException | InconsistentKotlinMetadataException | MetadataError e) {
         reporter.info(
             new StringDiagnostic(
@@ -68,6 +65,14 @@
     return NO_KOTLIN_INFO;
   }
 
+  public static boolean hasKotlinClassMetadataAnnotation(
+      DexClass clazz, DexDefinitionSupplier definitionSupplier) {
+    return clazz
+            .annotations()
+            .getFirstMatching(definitionSupplier.dexItemFactory().kotlinMetadataType)
+        != null;
+  }
+
   public static KotlinClassMetadata toKotlinClassMetadata(
       Kotlin kotlin, DexEncodedAnnotation metadataAnnotation) {
     Map<DexString, DexAnnotationElement> elementMap = new IdentityHashMap<>();
@@ -103,7 +108,7 @@
       Kotlin kotlin,
       DexClass clazz,
       KotlinClassMetadata kMetadata,
-      DexDefinitionSupplier definitionSupplier,
+      DexItemFactory factory,
       Reporter reporter,
       Consumer<DexEncodedMethod> keepByteCode) {
     String packageName = kMetadata.getHeader().getPackageName();
@@ -112,7 +117,7 @@
           ((KotlinClassMetadata.Class) kMetadata).toKmClass(),
           packageName,
           clazz,
-          definitionSupplier,
+          factory,
           reporter,
           keepByteCode);
     } else if (kMetadata instanceof KotlinClassMetadata.FileFacade) {
@@ -121,20 +126,20 @@
           (KotlinClassMetadata.FileFacade) kMetadata,
           packageName,
           clazz,
-          definitionSupplier,
+          factory,
           reporter,
           keepByteCode);
     } else if (kMetadata instanceof KotlinClassMetadata.MultiFileClassFacade) {
       // multi-file class with the same @JvmName.
       return KotlinMultiFileClassFacadeInfo.create(
-          (KotlinClassMetadata.MultiFileClassFacade) kMetadata, packageName, definitionSupplier);
+          (KotlinClassMetadata.MultiFileClassFacade) kMetadata, packageName, factory);
     } else if (kMetadata instanceof KotlinClassMetadata.MultiFileClassPart) {
       // A single file, which is part of multi-file class.
       return KotlinMultiFileClassPartInfo.create(
           (KotlinClassMetadata.MultiFileClassPart) kMetadata,
           packageName,
           clazz,
-          definitionSupplier,
+          factory,
           reporter,
           keepByteCode);
     } else if (kMetadata instanceof KotlinClassMetadata.SyntheticClass) {
@@ -143,7 +148,7 @@
           packageName,
           clazz,
           kotlin,
-          definitionSupplier,
+          factory,
           reporter);
     } else {
       throw new MetadataError("unsupported 'k' value: " + kMetadata.getHeader().getKind());
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 d6ff5b4..c80ed32 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java
@@ -4,15 +4,12 @@
 
 package com.android.tools.r8.kotlin;
 
-import static com.android.tools.r8.kotlin.KotlinMetadataUtils.referenceTypeFromDescriptor;
-
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexDefinitionSupplier;
-import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.kotlin.Kotlin.ClassClassifiers;
 import com.android.tools.r8.naming.NamingLens;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.Reporter;
 import kotlinx.metadata.KmClassifier;
@@ -20,10 +17,10 @@
 import kotlinx.metadata.KmClassifier.TypeParameter;
 import kotlinx.metadata.KmTypeVisitor;
 
-public abstract class KotlinClassifierInfo {
+public abstract class KotlinClassifierInfo implements EnqueuerMetadataTraceable {
 
   public static KotlinClassifierInfo create(
-      KmClassifier classifier, DexDefinitionSupplier definitionSupplier, Reporter reporter) {
+      KmClassifier classifier, DexItemFactory factory, Reporter reporter) {
     if (classifier instanceof KmClassifier.Class) {
       String originalTypeName = ((KmClassifier.Class) classifier).getName();
       // If this name starts with '.', it represents a local class or an anonymous object. This is
@@ -35,7 +32,7 @@
               isLocalOrAnonymous ? originalTypeName.substring(1) : originalTypeName);
       if (DescriptorUtils.isClassDescriptor(descriptor)) {
         return new KotlinClassClassifierInfo(
-            referenceTypeFromDescriptor(descriptor, definitionSupplier), isLocalOrAnonymous);
+            KotlinTypeReference.fromDescriptor(descriptor, factory), isLocalOrAnonymous);
       } else {
         return new KotlinUnknownClassClassifierInfo(originalTypeName);
       }
@@ -49,36 +46,35 @@
     }
   }
 
-  abstract void rewrite(
-      KmTypeVisitor visitor, AppView<AppInfoWithLiveness> appView, NamingLens namingLens);
+  abstract void rewrite(KmTypeVisitor visitor, AppView<?> appView, NamingLens namingLens);
 
   public static class KotlinClassClassifierInfo extends KotlinClassifierInfo {
 
-    private final DexType type;
+    private final KotlinTypeReference type;
     private final boolean isLocalOrAnonymous;
 
-    private KotlinClassClassifierInfo(DexType type, boolean isLocalOrAnonymous) {
+    private KotlinClassClassifierInfo(KotlinTypeReference type, boolean isLocalOrAnonymous) {
       this.type = type;
       this.isLocalOrAnonymous = isLocalOrAnonymous;
     }
 
     @Override
-    void rewrite(
-        KmTypeVisitor visitor, AppView<AppInfoWithLiveness> appView, NamingLens namingLens) {
-      if (appView.appInfo().wasPruned(type)) {
-        visitor.visitClass(ClassClassifiers.anyName);
-        return;
-      }
-      DexString descriptor = namingLens.lookupDescriptor(type);
+    void rewrite(KmTypeVisitor visitor, AppView<?> appView, NamingLens namingLens) {
+      String descriptor =
+          type.toRenamedDescriptorOrDefault(appView, namingLens, ClassClassifiers.anyDescriptor);
       // For local or anonymous classes, the classifier is prefixed with '.' and inner classes are
       // separated with '$'.
       if (isLocalOrAnonymous) {
-        visitor.visitClass(
-            "." + DescriptorUtils.getBinaryNameFromDescriptor(descriptor.toString()));
+        visitor.visitClass("." + DescriptorUtils.getBinaryNameFromDescriptor(descriptor));
       } else {
-        visitor.visitClass(DescriptorUtils.descriptorToKotlinClassifier(descriptor.toString()));
+        visitor.visitClass(DescriptorUtils.descriptorToKotlinClassifier(descriptor));
       }
     }
+
+    @Override
+    public void trace(DexDefinitionSupplier definitionSupplier) {
+      type.trace(definitionSupplier);
+    }
   }
 
   public static class KotlinTypeParameterClassifierInfo extends KotlinClassifierInfo {
@@ -90,10 +86,14 @@
     }
 
     @Override
-    void rewrite(
-        KmTypeVisitor visitor, AppView<AppInfoWithLiveness> appView, NamingLens namingLens) {
+    void rewrite(KmTypeVisitor visitor, AppView<?> appView, NamingLens namingLens) {
       visitor.visitTypeParameter(typeId);
     }
+
+    @Override
+    public void trace(DexDefinitionSupplier definitionSupplier) {
+      // Intentionally empty.
+    }
   }
 
   public static class KotlinTypeAliasClassifierInfo extends KotlinClassifierInfo {
@@ -105,10 +105,14 @@
     }
 
     @Override
-    void rewrite(
-        KmTypeVisitor visitor, AppView<AppInfoWithLiveness> appView, NamingLens namingLens) {
+    void rewrite(KmTypeVisitor visitor, AppView<?> appView, NamingLens namingLens) {
       visitor.visitTypeAlias(typeAlias);
     }
+
+    @Override
+    public void trace(DexDefinitionSupplier definitionSupplier) {
+      // Intentionally empty.
+    }
   }
 
   public static class KotlinUnknownClassClassifierInfo extends KotlinClassifierInfo {
@@ -119,10 +123,14 @@
     }
 
     @Override
-    void rewrite(
-        KmTypeVisitor visitor, AppView<AppInfoWithLiveness> appView, NamingLens namingLens) {
+    void rewrite(KmTypeVisitor visitor, AppView<?> appView, NamingLens namingLens) {
       visitor.visitClass(classifier);
     }
+
+    @Override
+    public void trace(DexDefinitionSupplier definitionSupplier) {
+      // Intentionally empty.
+    }
   }
 
   public static class KotlinUnknownClassifierInfo extends KotlinClassifierInfo {
@@ -133,9 +141,13 @@
     }
 
     @Override
-    void rewrite(
-        KmTypeVisitor visitor, AppView<AppInfoWithLiveness> appView, NamingLens namingLens) {
+    void rewrite(KmTypeVisitor visitor, AppView<?> appView, NamingLens namingLens) {
       visitor.visitTypeAlias(classifier);
     }
+
+    @Override
+    public void trace(DexDefinitionSupplier definitionSupplier) {
+      // Intentionally empty.
+    }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinCompanionInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinCompanionInfo.java
index 2f97b4f..1e19f1a 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinCompanionInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinCompanionInfo.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.kotlin;
 
+import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.naming.NamingLens;
@@ -27,4 +28,9 @@
     String finalName = dexString.toString();
     visitor.visitCompanionObject(finalName);
   }
+
+  @Override
+  public void trace(DexDefinitionSupplier definitionSupplier) {
+    // Do nothing.
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinConstructorInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinConstructorInfo.java
index 6f9f366..2e4ee98 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinConstructorInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinConstructorInfo.java
@@ -4,11 +4,13 @@
 
 package com.android.tools.r8.kotlin;
 
+import static com.android.tools.r8.utils.FunctionUtils.forEachApply;
+
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.naming.NamingLens;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.Reporter;
 import java.util.List;
 import kotlinx.metadata.KmClass;
@@ -21,34 +23,34 @@
   // Information from original KmValueParameter(s) if available.
   private final int flags;
   // Information about the value parameters.
-  private final List<KotlinValueParameterInfo> valueParameterInfos;
+  private final List<KotlinValueParameterInfo> valueParameters;
+  // Information about version requirements.
+  private final KotlinVersionRequirementInfo versionRequirements;
   // Information about the signature.
   private final KotlinJvmMethodSignatureInfo signature;
 
   private KotlinConstructorInfo(
       int flags,
-      List<KotlinValueParameterInfo> valueParameterInfos,
+      List<KotlinValueParameterInfo> valueParameters,
+      KotlinVersionRequirementInfo versionRequirements,
       KotlinJvmMethodSignatureInfo signature) {
     this.flags = flags;
-    this.valueParameterInfos = valueParameterInfos;
+    this.valueParameters = valueParameters;
+    this.versionRequirements = versionRequirements;
     this.signature = signature;
   }
 
   public static KotlinConstructorInfo create(
-      KmConstructor kmConstructor, DexDefinitionSupplier definitionSupplier, Reporter reporter) {
+      KmConstructor kmConstructor, DexItemFactory factory, Reporter reporter) {
     return new KotlinConstructorInfo(
         kmConstructor.getFlags(),
-        KotlinValueParameterInfo.create(
-            kmConstructor.getValueParameters(), definitionSupplier, reporter),
-        KotlinJvmMethodSignatureInfo.create(
-            JvmExtensionsKt.getSignature(kmConstructor), definitionSupplier));
+        KotlinValueParameterInfo.create(kmConstructor.getValueParameters(), factory, reporter),
+        KotlinVersionRequirementInfo.create(kmConstructor.getVersionRequirements()),
+        KotlinJvmMethodSignatureInfo.create(JvmExtensionsKt.getSignature(kmConstructor), factory));
   }
 
   public void rewrite(
-      KmClass kmClass,
-      DexEncodedMethod method,
-      AppView<AppInfoWithLiveness> appView,
-      NamingLens namingLens) {
+      KmClass kmClass, DexEncodedMethod method, AppView<?> appView, NamingLens namingLens) {
     // Note that JvmExtensionsKt.setSignature does not have an overload for KmConstructorVisitor,
     // thus we rely on creating the KmConstructor manually.
     // TODO(b/154348683): Check for special flags to pass in.
@@ -56,9 +58,10 @@
     if (signature != null) {
       JvmExtensionsKt.setSignature(kmConstructor, signature.rewrite(method, appView, namingLens));
     }
-    for (KotlinValueParameterInfo valueParameterInfo : valueParameterInfos) {
+    for (KotlinValueParameterInfo valueParameterInfo : valueParameters) {
       valueParameterInfo.rewrite(kmConstructor::visitValueParameter, appView, namingLens);
     }
+    versionRequirements.rewrite(kmConstructor::visitVersionRequirement);
     kmClass.getConstructors().add(kmConstructor);
   }
 
@@ -71,4 +74,12 @@
   public KotlinConstructorInfo asConstructor() {
     return this;
   }
+
+  @Override
+  public void trace(DexDefinitionSupplier definitionSupplier) {
+    forEachApply(valueParameters, param -> param::trace, definitionSupplier);
+    if (signature != null) {
+      signature.trace(definitionSupplier);
+    }
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinContractInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinContractInfo.java
new file mode 100644
index 0000000..fd0d60d
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinContractInfo.java
@@ -0,0 +1,65 @@
+// Copyright (c) 2020, 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 static com.android.tools.r8.utils.FunctionUtils.forEachApply;
+
+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.naming.NamingLens;
+import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
+import com.android.tools.r8.utils.Reporter;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import kotlinx.metadata.KmContract;
+import kotlinx.metadata.KmContractVisitor;
+import kotlinx.metadata.KmEffect;
+
+public class KotlinContractInfo implements EnqueuerMetadataTraceable {
+
+  private static final KotlinContractInfo NO_EFFECT = new KotlinContractInfo(ImmutableList.of());
+
+  private final List<KotlinEffectInfo> effects;
+
+  private KotlinContractInfo(List<KotlinEffectInfo> effects) {
+    this.effects = effects;
+  }
+
+  static KotlinContractInfo create(
+      KmContract kmContract, DexItemFactory factory, Reporter reporter) {
+    if (kmContract == null) {
+      return NO_EFFECT;
+    }
+    List<KmEffect> effects = kmContract.getEffects();
+    if (effects.isEmpty()) {
+      return NO_EFFECT;
+    }
+    ImmutableList.Builder<KotlinEffectInfo> builder = ImmutableList.builder();
+    for (KmEffect effect : effects) {
+      builder.add(KotlinEffectInfo.create(effect, factory, reporter));
+    }
+    return new KotlinContractInfo(builder.build());
+  }
+
+  @Override
+  public void trace(DexDefinitionSupplier definitionSupplier) {
+    forEachApply(effects, effect -> effect::trace, definitionSupplier);
+  }
+
+  public void rewrite(
+      KmVisitorProviders.KmContractVisitorProvider visitorProvider,
+      AppView<?> appView,
+      NamingLens namingLens) {
+    if (this == NO_EFFECT) {
+      return;
+    }
+    KmContractVisitor kmContractVisitor = visitorProvider.get();
+    for (KotlinEffectInfo effect : effects) {
+      effect.rewrite(kmContractVisitor::visitEffect, appView, namingLens);
+    }
+    kmContractVisitor.visitEnd();
+  }
+}
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 cd349ab..79b4173 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java
@@ -5,15 +5,17 @@
 package com.android.tools.r8.kotlin;
 
 import static com.android.tools.r8.kotlin.KotlinMetadataUtils.isValidMethodDescriptor;
+import static com.android.tools.r8.utils.FunctionUtils.forEachApply;
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.kotlin.KotlinMetadataUtils.KmPropertyProcessor;
 import com.android.tools.r8.naming.NamingLens;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.Reporter;
 import com.google.common.collect.ImmutableList;
 import java.util.IdentityHashMap;
@@ -29,7 +31,7 @@
 import kotlinx.metadata.jvm.JvmMethodSignature;
 
 // Holds information about KmDeclarationContainer
-public class KotlinDeclarationContainerInfo {
+public class KotlinDeclarationContainerInfo implements EnqueuerMetadataTraceable {
 
   private final List<KotlinTypeAliasInfo> typeAliases;
   // The functions in notBackedFunctions are KmFunctions where we could not find a representative.
@@ -51,7 +53,7 @@
       KmDeclarationContainer container,
       Map<String, DexEncodedMethod> methodSignatureMap,
       Map<String, DexEncodedField> fieldSignatureMap,
-      DexDefinitionSupplier definitionSupplier,
+      DexItemFactory factory,
       Reporter reporter,
       Consumer<DexEncodedMethod> keepByteCode) {
     ImmutableList.Builder<KotlinFunctionInfo> notBackedFunctions = ImmutableList.builder();
@@ -62,7 +64,7 @@
         continue;
       }
       KotlinFunctionInfo kotlinFunctionInfo =
-          KotlinFunctionInfo.create(kmFunction, definitionSupplier, reporter);
+          KotlinFunctionInfo.create(kmFunction, factory, reporter);
       DexEncodedMethod method = methodSignatureMap.get(signature.asString());
       if (method == null) {
         notBackedFunctions.add(kotlinFunctionInfo);
@@ -85,7 +87,7 @@
     ImmutableList.Builder<KotlinPropertyInfo> notBackedProperties = ImmutableList.builder();
     for (KmProperty kmProperty : container.getProperties()) {
       KotlinPropertyInfo kotlinPropertyInfo =
-          KotlinPropertyInfo.create(kmProperty, definitionSupplier, reporter);
+          KotlinPropertyInfo.create(kmProperty, factory, reporter);
       KmPropertyProcessor propertyProcessor = new KmPropertyProcessor(kmProperty);
       boolean hasBacking = false;
       if (propertyProcessor.fieldSignature() != null) {
@@ -119,7 +121,7 @@
       }
     }
     return new KotlinDeclarationContainerInfo(
-        getTypeAliases(container.getTypeAliases(), definitionSupplier, reporter),
+        getTypeAliases(container.getTypeAliases(), factory, reporter),
         notBackedFunctions.build(),
         notBackedProperties.build());
   }
@@ -139,10 +141,10 @@
   }
 
   private static List<KotlinTypeAliasInfo> getTypeAliases(
-      List<KmTypeAlias> aliases, DexDefinitionSupplier definitionSupplier, Reporter reporter) {
+      List<KmTypeAlias> aliases, DexItemFactory factory, Reporter reporter) {
     ImmutableList.Builder<KotlinTypeAliasInfo> builder = ImmutableList.builder();
     for (KmTypeAlias alias : aliases) {
-      builder.add(KotlinTypeAliasInfo.create(alias, definitionSupplier, reporter));
+      builder.add(KotlinTypeAliasInfo.create(alias, factory, reporter));
     }
     return builder.build();
   }
@@ -152,7 +154,7 @@
       KmVisitorProviders.KmPropertyVisitorProvider propertyProvider,
       KmVisitorProviders.KmTypeAliasVisitorProvider typeAliasProvider,
       DexClass clazz,
-      AppView<AppInfoWithLiveness> appView,
+      AppView<?> appView,
       NamingLens namingLens) {
     // Type aliases only have a representation here, so we can generate them directly.
     for (KotlinTypeAliasInfo typeAlias : typeAliases) {
@@ -208,6 +210,13 @@
     }
   }
 
+  @Override
+  public void trace(DexDefinitionSupplier definitionSupplier) {
+    forEachApply(typeAliases, alias -> alias::trace, definitionSupplier);
+    forEachApply(functionsWithNoBacking, function -> function::trace, definitionSupplier);
+    forEachApply(propertiesWithNoBacking, property -> property::trace, definitionSupplier);
+  }
+
   public static class KotlinPropertyGroup {
 
     private DexEncodedField backingField = null;
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinEffectExpressionInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinEffectExpressionInfo.java
new file mode 100644
index 0000000..d6664d1
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinEffectExpressionInfo.java
@@ -0,0 +1,109 @@
+// Copyright (c) 2020, 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 static com.android.tools.r8.utils.FunctionUtils.forEachApply;
+
+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.kotlin.KmVisitorProviders.KmEffectExpressionVisitorProvider;
+import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
+import com.android.tools.r8.utils.Reporter;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import kotlinx.metadata.KmConstantValue;
+import kotlinx.metadata.KmEffectExpression;
+import kotlinx.metadata.KmEffectExpressionVisitor;
+
+public class KotlinEffectExpressionInfo implements EnqueuerMetadataTraceable {
+
+  private static final List<KotlinEffectExpressionInfo> NO_EXPRESSIONS = ImmutableList.of();
+  private static final KotlinEffectExpressionInfo NO_EXPRESSION =
+      new KotlinEffectExpressionInfo(0, 0, null, null, NO_EXPRESSIONS, NO_EXPRESSIONS);
+
+  private final int flags;
+  private final Integer parameterIndex;
+  private final KmConstantValue constantValue;
+  private final KotlinTypeInfo isInstanceType;
+  private final List<KotlinEffectExpressionInfo> andArguments;
+  private final List<KotlinEffectExpressionInfo> orArguments;
+
+  private KotlinEffectExpressionInfo(
+      int flags,
+      Integer parameterIndex,
+      KmConstantValue constantValue,
+      KotlinTypeInfo isInstanceType,
+      List<KotlinEffectExpressionInfo> andArguments,
+      List<KotlinEffectExpressionInfo> orArguments) {
+    this.flags = flags;
+    this.parameterIndex = parameterIndex;
+    this.constantValue = constantValue;
+    this.isInstanceType = isInstanceType;
+    this.andArguments = andArguments;
+    this.orArguments = orArguments;
+  }
+
+  static KotlinEffectExpressionInfo create(
+      KmEffectExpression effectExpression, DexItemFactory factory, Reporter reporter) {
+    if (effectExpression == null) {
+      return NO_EXPRESSION;
+    }
+    return new KotlinEffectExpressionInfo(
+        effectExpression.getFlags(),
+        effectExpression.getParameterIndex(),
+        effectExpression.getConstantValue(),
+        KotlinTypeInfo.create(effectExpression.isInstanceType(), factory, reporter),
+        create(effectExpression.getAndArguments(), factory, reporter),
+        create(effectExpression.getOrArguments(), factory, reporter));
+  }
+
+  static List<KotlinEffectExpressionInfo> create(
+      List<KmEffectExpression> effectExpressions, DexItemFactory factory, Reporter reporter) {
+    if (effectExpressions.isEmpty()) {
+      return NO_EXPRESSIONS;
+    }
+    ImmutableList.Builder<KotlinEffectExpressionInfo> builder = ImmutableList.builder();
+    for (KmEffectExpression effectExpression : effectExpressions) {
+      builder.add(create(effectExpression, factory, reporter));
+    }
+    return builder.build();
+  }
+
+  @Override
+  public void trace(DexDefinitionSupplier definitionSupplier) {
+    if (this == NO_EXPRESSION) {
+      return;
+    }
+    if (isInstanceType != null) {
+      isInstanceType.trace(definitionSupplier);
+    }
+    forEachApply(andArguments, arg -> arg::trace, definitionSupplier);
+    forEachApply(orArguments, arg -> arg::trace, definitionSupplier);
+  }
+
+  public void rewrite(
+      KmEffectExpressionVisitorProvider provider, AppView<?> appView, NamingLens namingLens) {
+    if (this == NO_EXPRESSION) {
+      return;
+    }
+    KmEffectExpressionVisitor visitor = provider.get();
+    visitor.visit(flags, parameterIndex);
+    if (constantValue != null) {
+      visitor.visitConstantValue(constantValue.getValue());
+    }
+    if (isInstanceType != null) {
+      isInstanceType.rewrite(visitor::visitIsInstanceType, appView, namingLens);
+    }
+    for (KotlinEffectExpressionInfo andArgument : andArguments) {
+      andArgument.rewrite(visitor::visitAndArgument, appView, namingLens);
+    }
+    for (KotlinEffectExpressionInfo orArgument : orArguments) {
+      orArgument.rewrite(visitor::visitAndArgument, appView, namingLens);
+    }
+    visitor.visitEnd();
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinEffectInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinEffectInfo.java
new file mode 100644
index 0000000..3b1c748
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinEffectInfo.java
@@ -0,0 +1,62 @@
+// Copyright (c) 2020, 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 static com.android.tools.r8.utils.FunctionUtils.forEachApply;
+
+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.kotlin.KmVisitorProviders.KmEffectVisitorProvider;
+import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
+import com.android.tools.r8.utils.Reporter;
+import java.util.List;
+import kotlinx.metadata.KmEffect;
+import kotlinx.metadata.KmEffectInvocationKind;
+import kotlinx.metadata.KmEffectType;
+import kotlinx.metadata.KmEffectVisitor;
+
+public class KotlinEffectInfo implements EnqueuerMetadataTraceable {
+
+  private final KmEffectType type;
+  private final KmEffectInvocationKind invocationKind;
+  private final List<KotlinEffectExpressionInfo> constructorArguments;
+  private final KotlinEffectExpressionInfo conclusion;
+
+  public KotlinEffectInfo(
+      KmEffectType type,
+      KmEffectInvocationKind invocationKind,
+      List<KotlinEffectExpressionInfo> constructorArguments,
+      KotlinEffectExpressionInfo conclusion) {
+    this.type = type;
+    this.invocationKind = invocationKind;
+    this.constructorArguments = constructorArguments;
+    this.conclusion = conclusion;
+  }
+
+  static KotlinEffectInfo create(KmEffect effect, DexItemFactory factory, Reporter reporter) {
+    return new KotlinEffectInfo(
+        effect.getType(),
+        effect.getInvocationKind(),
+        KotlinEffectExpressionInfo.create(effect.getConstructorArguments(), factory, reporter),
+        KotlinEffectExpressionInfo.create(effect.getConclusion(), factory, reporter));
+  }
+
+  @Override
+  public void trace(DexDefinitionSupplier definitionSupplier) {
+    forEachApply(constructorArguments, arg -> arg::trace, definitionSupplier);
+    conclusion.trace(definitionSupplier);
+  }
+
+  void rewrite(KmEffectVisitorProvider visitorProvider, AppView<?> appView, NamingLens namingLens) {
+    KmEffectVisitor kmEffectVisitor = visitorProvider.get(type, invocationKind);
+    conclusion.rewrite(kmEffectVisitor::visitConclusionOfConditionalEffect, appView, namingLens);
+    for (KotlinEffectExpressionInfo constructorArgument : constructorArguments) {
+      constructorArgument.rewrite(kmEffectVisitor::visitConstructorArgument, appView, namingLens);
+    }
+    kmEffectVisitor.visitEnd();
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinFieldLevelInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinFieldLevelInfo.java
index 7df7afb..8d9d468 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinFieldLevelInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinFieldLevelInfo.java
@@ -4,7 +4,9 @@
 
 package com.android.tools.r8.kotlin;
 
-public interface KotlinFieldLevelInfo {
+import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
+
+public interface KotlinFieldLevelInfo extends EnqueuerMetadataTraceable {
 
   default boolean isCompanion() {
     return false;
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinFileFacadeInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinFileFacadeInfo.java
index c31df8c..886281f 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinFileFacadeInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinFileFacadeInfo.java
@@ -8,8 +8,8 @@
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.naming.NamingLens;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.Reporter;
 import java.util.function.Consumer;
 import kotlinx.metadata.KmPackage;
@@ -32,12 +32,12 @@
       FileFacade kmFileFacade,
       String packageName,
       DexClass clazz,
-      DexDefinitionSupplier definitionSupplier,
+      DexItemFactory factory,
       Reporter reporter,
       Consumer<DexEncodedMethod> keepByteCode) {
     return new KotlinFileFacadeInfo(
         KotlinPackageInfo.create(
-            kmFileFacade.toKmPackage(), clazz, definitionSupplier, reporter, keepByteCode),
+            kmFileFacade.toKmPackage(), clazz, factory, reporter, keepByteCode),
         packageName);
   }
 
@@ -52,8 +52,7 @@
   }
 
   @Override
-  public KotlinClassHeader rewrite(
-      DexClass clazz, AppView<AppInfoWithLiveness> appView, NamingLens namingLens) {
+  public KotlinClassHeader rewrite(DexClass clazz, AppView<?> appView, NamingLens namingLens) {
     KotlinClassMetadata.FileFacade.Writer writer = new KotlinClassMetadata.FileFacade.Writer();
     KmPackage kmPackage = new KmPackage();
     packageInfo.rewrite(kmPackage, clazz, appView, namingLens);
@@ -65,4 +64,9 @@
   public String getPackageName() {
     return packageName;
   }
+
+  @Override
+  public void trace(DexDefinitionSupplier definitionSupplier) {
+    packageInfo.trace(definitionSupplier);
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinFlexibleTypeUpperBoundInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinFlexibleTypeUpperBoundInfo.java
index c8c8836..91413c7 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinFlexibleTypeUpperBoundInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinFlexibleTypeUpperBoundInfo.java
@@ -6,8 +6,8 @@
 
 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.naming.NamingLens;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.Reporter;
 import java.util.List;
 import kotlinx.metadata.KmFlexibleTypeUpperBound;
@@ -45,28 +45,26 @@
   }
 
   static KotlinFlexibleTypeUpperBoundInfo create(
-      KmFlexibleTypeUpperBound flexibleTypeUpperBound,
-      DexDefinitionSupplier definitionSupplier,
-      Reporter reporter) {
+      KmFlexibleTypeUpperBound flexibleTypeUpperBound, DexItemFactory factory, Reporter reporter) {
     if (flexibleTypeUpperBound == null) {
       return NO_FLEXIBLE_UPPER_BOUND;
     }
     KmType kmType = flexibleTypeUpperBound.getType();
     return new KotlinFlexibleTypeUpperBoundInfo(
         kmType.getFlags(),
-        KotlinClassifierInfo.create(kmType.classifier, definitionSupplier, reporter),
-        KotlinTypeInfo.create(kmType.getAbbreviatedType(), definitionSupplier, reporter),
-        KotlinTypeInfo.create(kmType.getOuterType(), definitionSupplier, reporter),
-        getArguments(kmType.getArguments(), definitionSupplier, reporter),
-        KotlinAnnotationInfo.create(JvmExtensionsKt.getAnnotations(kmType), definitionSupplier),
+        KotlinClassifierInfo.create(kmType.classifier, factory, reporter),
+        KotlinTypeInfo.create(kmType.getAbbreviatedType(), factory, reporter),
+        KotlinTypeInfo.create(kmType.getOuterType(), factory, reporter),
+        getArguments(kmType.getArguments(), factory, reporter),
+        KotlinAnnotationInfo.create(JvmExtensionsKt.getAnnotations(kmType), factory),
         KotlinFlexibleTypeUpperBoundInfo.create(
-            kmType.getFlexibleTypeUpperBound(), definitionSupplier, reporter),
+            kmType.getFlexibleTypeUpperBound(), factory, reporter),
         flexibleTypeUpperBound.getTypeFlexibilityId());
   }
 
   public void rewrite(
       KmVisitorProviders.KmFlexibleUpperBoundVisitorProvider visitorProvider,
-      AppView<AppInfoWithLiveness> appView,
+      AppView<?> appView,
       NamingLens namingLens) {
     if (this == NO_FLEXIBLE_UPPER_BOUND) {
       // Nothing to do.
@@ -74,4 +72,12 @@
     }
     super.rewrite(flags -> visitorProvider.get(flags, typeFlexibilityId), appView, namingLens);
   }
+
+  @Override
+  public void trace(DexDefinitionSupplier definitionSupplier) {
+    if (this == NO_FLEXIBLE_UPPER_BOUND) {
+      return;
+    }
+    super.trace(definitionSupplier);
+  }
 }
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 58b07cb..f5ce062 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinFunctionInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinFunctionInfo.java
@@ -4,14 +4,13 @@
 
 package com.android.tools.r8.kotlin;
 
-import static com.android.tools.r8.kotlin.KotlinMetadataUtils.referenceTypeFromBinaryName;
+import static com.android.tools.r8.utils.FunctionUtils.forEachApply;
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.naming.NamingLens;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.Reporter;
 import java.util.List;
 import kotlinx.metadata.KmFunction;
@@ -36,7 +35,13 @@
   // Information about the signature
   private final KotlinJvmMethodSignatureInfo signature;
   // Information about the lambdaClassOrigin.
-  private final DexType lambdaClassOrigin;
+  private final KotlinTypeReference lambdaClassOrigin;
+  // Information about version requirements.
+  private final KotlinVersionRequirementInfo versionRequirements;
+  // Kotlin contract information.
+  private final KotlinContractInfo contract;
+  // A value describing if any of the parameters are crossinline.
+  private final boolean crossInlineParameter;
 
   private KotlinFunctionInfo(
       int flags,
@@ -46,7 +51,10 @@
       List<KotlinValueParameterInfo> valueParameters,
       List<KotlinTypeParameterInfo> typeParameters,
       KotlinJvmMethodSignatureInfo signature,
-      DexType lambdaClassOrigin) {
+      KotlinTypeReference lambdaClassOrigin,
+      KotlinVersionRequirementInfo versionRequirements,
+      KotlinContractInfo contract,
+      boolean crossInlineParameter) {
     this.flags = flags;
     this.name = name;
     this.returnType = returnType;
@@ -55,29 +63,45 @@
     this.typeParameters = typeParameters;
     this.signature = signature;
     this.lambdaClassOrigin = lambdaClassOrigin;
+    this.versionRequirements = versionRequirements;
+    this.contract = contract;
+    this.crossInlineParameter = crossInlineParameter;
+  }
+
+  public boolean hasCrossInlineParameter() {
+    return crossInlineParameter;
   }
 
   static KotlinFunctionInfo create(
-      KmFunction kmFunction, DexDefinitionSupplier definitionSupplier, Reporter reporter) {
+      KmFunction kmFunction, DexItemFactory factory, Reporter reporter) {
+    boolean isCrossInline = false;
+    List<KotlinValueParameterInfo> valueParameters =
+        KotlinValueParameterInfo.create(kmFunction.getValueParameters(), factory, reporter);
+    for (KotlinValueParameterInfo valueParameter : valueParameters) {
+      if (valueParameter.isCrossInline()) {
+        isCrossInline = true;
+        break;
+      }
+    }
     return new KotlinFunctionInfo(
         kmFunction.getFlags(),
         kmFunction.getName(),
-        KotlinTypeInfo.create(kmFunction.getReturnType(), definitionSupplier, reporter),
-        KotlinTypeInfo.create(kmFunction.getReceiverParameterType(), definitionSupplier, reporter),
-        KotlinValueParameterInfo.create(
-            kmFunction.getValueParameters(), definitionSupplier, reporter),
-        KotlinTypeParameterInfo.create(
-            kmFunction.getTypeParameters(), definitionSupplier, reporter),
-        KotlinJvmMethodSignatureInfo.create(
-            JvmExtensionsKt.getSignature(kmFunction), definitionSupplier),
-        getlambdaClassOrigin(kmFunction, definitionSupplier));
+        KotlinTypeInfo.create(kmFunction.getReturnType(), factory, reporter),
+        KotlinTypeInfo.create(kmFunction.getReceiverParameterType(), factory, reporter),
+        valueParameters,
+        KotlinTypeParameterInfo.create(kmFunction.getTypeParameters(), factory, reporter),
+        KotlinJvmMethodSignatureInfo.create(JvmExtensionsKt.getSignature(kmFunction), factory),
+        getlambdaClassOrigin(kmFunction, factory),
+        KotlinVersionRequirementInfo.create(kmFunction.getVersionRequirements()),
+        KotlinContractInfo.create(kmFunction.getContract(), factory, reporter),
+        isCrossInline);
   }
 
-  private static DexType getlambdaClassOrigin(
-      KmFunction kmFunction, DexDefinitionSupplier definitionSupplier) {
+  private static KotlinTypeReference getlambdaClassOrigin(
+      KmFunction kmFunction, DexItemFactory factory) {
     String lambdaClassOriginName = JvmExtensionsKt.getLambdaClassOriginName(kmFunction);
     if (lambdaClassOriginName != null) {
-      return referenceTypeFromBinaryName(lambdaClassOriginName, definitionSupplier);
+      return KotlinTypeReference.fromBinaryName(lambdaClassOriginName, factory);
     }
     return null;
   }
@@ -85,7 +109,7 @@
   public void rewrite(
       KmVisitorProviders.KmFunctionVisitorProvider visitorProvider,
       DexEncodedMethod method,
-      AppView<AppInfoWithLiveness> appView,
+      AppView<?> appView,
       NamingLens namingLens) {
     // TODO(b/154348683): Check method for flags to pass in.
     String finalName = this.name;
@@ -108,15 +132,20 @@
     if (receiverParameterType != null) {
       receiverParameterType.rewrite(kmFunction::visitReceiverParameterType, appView, namingLens);
     }
+    versionRequirements.rewrite(kmFunction::visitVersionRequirement);
     JvmFunctionExtensionVisitor extensionVisitor =
         (JvmFunctionExtensionVisitor) kmFunction.visitExtensions(JvmFunctionExtensionVisitor.TYPE);
     if (signature != null && extensionVisitor != null) {
       extensionVisitor.visit(signature.rewrite(method, appView, namingLens));
     }
     if (lambdaClassOrigin != null && extensionVisitor != null) {
-      extensionVisitor.visitLambdaClassOriginName(
-          KotlinMetadataUtils.kotlinNameFromDescriptor(lambdaClassOrigin.descriptor));
+      String lambdaClassOriginName =
+          lambdaClassOrigin.toRenamedBinaryNameOrDefault(appView, namingLens, null);
+      if (lambdaClassOriginName != null) {
+        extensionVisitor.visitLambdaClassOriginName(lambdaClassOriginName);
+      }
     }
+    contract.rewrite(kmFunction::visitContract, appView, namingLens);
   }
 
   @Override
@@ -132,4 +161,25 @@
   public boolean isExtensionFunction() {
     return receiverParameterType != null;
   }
+
+  public KotlinJvmMethodSignatureInfo getSignature() {
+    return signature;
+  }
+
+  @Override
+  public void trace(DexDefinitionSupplier definitionSupplier) {
+    forEachApply(valueParameters, param -> param::trace, definitionSupplier);
+    returnType.trace(definitionSupplier);
+    if (receiverParameterType != null) {
+      receiverParameterType.trace(definitionSupplier);
+    }
+    forEachApply(typeParameters, param -> param::trace, definitionSupplier);
+    if (signature != null) {
+      signature.trace(definitionSupplier);
+    }
+    if (lambdaClassOrigin != null) {
+      lambdaClassOrigin.trace(definitionSupplier);
+    }
+    contract.trace(definitionSupplier);
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinJvmFieldSignatureInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinJvmFieldSignatureInfo.java
index 69c0442..974e4a8 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinJvmFieldSignatureInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinJvmFieldSignatureInfo.java
@@ -4,43 +4,40 @@
 
 package com.android.tools.r8.kotlin;
 
-import static com.android.tools.r8.kotlin.KotlinMetadataUtils.referenceTypeFromDescriptor;
-import static com.android.tools.r8.kotlin.KotlinMetadataUtils.toRenamedDescriptorOrDefault;
-
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.naming.NamingLens;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import kotlinx.metadata.jvm.JvmFieldSignature;
 
 /**
  * The JvmSignature for a method or property does not always correspond to the actual signature, see
  * b/154201250. We therefore need to model the signature as well.
  */
-public class KotlinJvmFieldSignatureInfo {
+public class KotlinJvmFieldSignatureInfo implements EnqueuerMetadataTraceable {
 
-  private final DexType type;
+  private final KotlinTypeReference type;
   private final String name;
 
-  private KotlinJvmFieldSignatureInfo(String name, DexType type) {
+  private KotlinJvmFieldSignatureInfo(String name, KotlinTypeReference type) {
     this.name = name;
     this.type = type;
   }
 
   public static KotlinJvmFieldSignatureInfo create(
-      JvmFieldSignature fieldSignature, DexDefinitionSupplier definitionSupplier) {
+      JvmFieldSignature fieldSignature, DexItemFactory factory) {
     if (fieldSignature == null) {
       return null;
     }
     return new KotlinJvmFieldSignatureInfo(
         fieldSignature.getName(),
-        referenceTypeFromDescriptor(fieldSignature.getDesc(), definitionSupplier));
+        KotlinTypeReference.fromDescriptor(fieldSignature.getDesc(), factory));
   }
 
   public JvmFieldSignature rewrite(
-      DexEncodedField field, AppView<AppInfoWithLiveness> appView, NamingLens namingLens) {
+      DexEncodedField field, AppView<?> appView, NamingLens namingLens) {
     String finalName = name;
     if (field != null) {
       String fieldName = field.field.name.toString();
@@ -51,6 +48,11 @@
     }
     String defValue = appView.dexItemFactory().objectType.toDescriptorString();
     return new JvmFieldSignature(
-        finalName, toRenamedDescriptorOrDefault(type, appView, namingLens, defValue));
+        finalName, type.toRenamedDescriptorOrDefault(appView, namingLens, defValue));
+  }
+
+  @Override
+  public void trace(DexDefinitionSupplier definitionSupplier) {
+    type.trace(definitionSupplier);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinJvmMethodSignatureInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinJvmMethodSignatureInfo.java
index d9d5c9d..2469a54 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinJvmMethodSignatureInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinJvmMethodSignatureInfo.java
@@ -4,15 +4,14 @@
 
 package com.android.tools.r8.kotlin;
 
-import static com.android.tools.r8.kotlin.KotlinMetadataUtils.referenceTypeFromDescriptor;
-import static com.android.tools.r8.kotlin.KotlinMetadataUtils.toRenamedDescriptorOrDefault;
+import static com.android.tools.r8.utils.FunctionUtils.forEachApply;
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.naming.NamingLens;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.google.common.collect.ImmutableList;
 import java.util.List;
@@ -22,43 +21,62 @@
  * The JvmSignature for a method or property does not always correspond to the actual signature, see
  * b/154201250. We therefore need to model the signature as well.
  */
-public class KotlinJvmMethodSignatureInfo {
+public class KotlinJvmMethodSignatureInfo implements EnqueuerMetadataTraceable {
 
-  private static final List<DexType> EMPTY_PARAMETERS_LIST = ImmutableList.of();
+  private static final List<KotlinTypeReference> EMPTY_PARAMETERS_LIST = ImmutableList.of();
 
   private final String name;
-  private final DexType returnType;
-  private final List<DexType> parameters;
+  private final KotlinTypeReference returnType;
+  private final List<KotlinTypeReference> parameters;
+  private final String invalidDescriptor;
 
-  private KotlinJvmMethodSignatureInfo(String name, DexType returnType, List<DexType> parameters) {
+  private KotlinJvmMethodSignatureInfo(
+      String name, KotlinTypeReference returnType, List<KotlinTypeReference> parameters) {
     this.name = name;
     this.returnType = returnType;
     this.parameters = parameters;
+    this.invalidDescriptor = null;
+  }
+
+  private KotlinJvmMethodSignatureInfo(String name, String invalidDescriptor) {
+    this.name = name;
+    this.invalidDescriptor = invalidDescriptor;
+    this.parameters = EMPTY_PARAMETERS_LIST;
+    this.returnType = null;
   }
 
   public static KotlinJvmMethodSignatureInfo create(
-      JvmMethodSignature methodSignature, DexDefinitionSupplier definitionSupplier) {
+      JvmMethodSignature methodSignature, DexItemFactory factory) {
     if (methodSignature == null) {
       return null;
     }
     String kotlinDescriptor = methodSignature.getDesc();
+    if (!KotlinMetadataUtils.isValidMethodDescriptor(kotlinDescriptor)) {
+      // If the method descriptor is invalid, keep it as invalid.
+      return new KotlinJvmMethodSignatureInfo(methodSignature.getName(), kotlinDescriptor);
+    }
     String returnTypeDescriptor = DescriptorUtils.getReturnTypeDescriptor(kotlinDescriptor);
-    DexType returnType = referenceTypeFromDescriptor(returnTypeDescriptor, definitionSupplier);
+    KotlinTypeReference returnType =
+        KotlinTypeReference.fromDescriptor(returnTypeDescriptor, factory);
     String[] descriptors = DescriptorUtils.getArgumentTypeDescriptors(kotlinDescriptor);
     if (descriptors.length == 0) {
       return new KotlinJvmMethodSignatureInfo(
           methodSignature.getName(), returnType, EMPTY_PARAMETERS_LIST);
     }
-    ImmutableList.Builder<DexType> parameters = ImmutableList.builder();
+    ImmutableList.Builder<KotlinTypeReference> parameters = ImmutableList.builder();
     for (String descriptor : descriptors) {
-      parameters.add(referenceTypeFromDescriptor(descriptor, definitionSupplier));
+      parameters.add(KotlinTypeReference.fromDescriptor(descriptor, factory));
     }
     return new KotlinJvmMethodSignatureInfo(
         methodSignature.getName(), returnType, parameters.build());
   }
 
   public JvmMethodSignature rewrite(
-      DexEncodedMethod method, AppView<AppInfoWithLiveness> appView, NamingLens namingLens) {
+      DexEncodedMethod method, AppView<?> appView, NamingLens namingLens) {
+    if (invalidDescriptor != null) {
+      return new JvmMethodSignature(name, invalidDescriptor);
+    }
+    assert returnType != null;
     String finalName = name;
     if (method != null) {
       String methodName = method.method.name.toString();
@@ -70,11 +88,38 @@
     StringBuilder descBuilder = new StringBuilder();
     descBuilder.append("(");
     String defValue = appView.dexItemFactory().objectType.toDescriptorString();
-    for (DexType parameter : parameters) {
-      descBuilder.append(toRenamedDescriptorOrDefault(parameter, appView, namingLens, defValue));
+    for (KotlinTypeReference parameter : parameters) {
+      descBuilder.append(parameter.toRenamedDescriptorOrDefault(appView, namingLens, defValue));
     }
     descBuilder.append(")");
-    descBuilder.append(toRenamedDescriptorOrDefault(returnType, appView, namingLens, defValue));
+    descBuilder.append(returnType.toRenamedDescriptorOrDefault(appView, namingLens, defValue));
     return new JvmMethodSignature(finalName, descBuilder.toString());
   }
+
+  @Override
+  public String toString() {
+    if (invalidDescriptor != null) {
+      return name + "(" + invalidDescriptor + ")";
+    }
+    assert returnType != null;
+    StringBuilder descBuilder = new StringBuilder();
+    descBuilder.append(name);
+    descBuilder.append("(");
+    for (KotlinTypeReference parameter : parameters) {
+      descBuilder.append(parameter.toString());
+    }
+    descBuilder.append(")");
+    descBuilder.append(returnType.toString());
+    return descBuilder.toString();
+  }
+
+  @Override
+  public void trace(DexDefinitionSupplier definitionSupplier) {
+    if (invalidDescriptor != null) {
+      return;
+    }
+    assert returnType != null;
+    returnType.trace(definitionSupplier);
+    forEachApply(parameters, param -> param::trace, definitionSupplier);
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinLambdaInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinLambdaInfo.java
index d25f105..cc215d5 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinLambdaInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinLambdaInfo.java
@@ -10,62 +10,75 @@
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.naming.NamingLens;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.Reporter;
 import kotlinx.metadata.KmLambda;
-import kotlinx.metadata.KmLambdaVisitor;
 import kotlinx.metadata.jvm.JvmExtensionsKt;
 import kotlinx.metadata.jvm.JvmMethodSignature;
 
 // Holds information about a KmLambda
-public class KotlinLambdaInfo {
+public class KotlinLambdaInfo implements EnqueuerMetadataTraceable {
 
   private final KotlinFunctionInfo function;
+  private final boolean hasBacking;
 
-  private KotlinLambdaInfo(KotlinFunctionInfo function) {
+  private KotlinLambdaInfo(KotlinFunctionInfo function, boolean hasBacking) {
     this.function = function;
+    this.hasBacking = hasBacking;
   }
 
   static KotlinLambdaInfo create(
-      DexClass clazz,
-      KmLambda lambda,
-      DexDefinitionSupplier definitionSupplier,
-      Reporter reporter) {
+      DexClass clazz, KmLambda lambda, DexItemFactory factory, Reporter reporter) {
     if (lambda == null) {
       assert false;
       return null;
     }
+    KotlinFunctionInfo kotlinFunctionInfo =
+        KotlinFunctionInfo.create(lambda.function, factory, reporter);
     JvmMethodSignature signature = JvmExtensionsKt.getSignature(lambda.function);
-    if (signature == null) {
-      assert false;
-      return null;
-    }
-    for (DexEncodedMethod method : clazz.methods()) {
-      if (toJvmMethodSignature(method.method).asString().equals(signature.asString())) {
-        KotlinFunctionInfo kotlinFunctionInfo =
-            KotlinFunctionInfo.create(lambda.function, definitionSupplier, reporter);
-        method.setKotlinMemberInfo(kotlinFunctionInfo);
-        return new KotlinLambdaInfo(kotlinFunctionInfo);
+    if (signature != null) {
+      for (DexEncodedMethod method : clazz.methods()) {
+        if (toJvmMethodSignature(method.method).asString().equals(signature.asString())) {
+          method.setKotlinMemberInfo(kotlinFunctionInfo);
+          return new KotlinLambdaInfo(kotlinFunctionInfo, true);
+        }
       }
     }
-    // TODO(b/155536535): Resolve this assert for NestTreeShakeJarVerificationTest.
-    // assert false;
-    return null;
+    return new KotlinLambdaInfo(kotlinFunctionInfo, false);
   }
 
   boolean rewrite(
       KmVisitorProviders.KmLambdaVisitorProvider visitorProvider,
       DexClass clazz,
-      AppView<AppInfoWithLiveness> appView,
+      AppView<?> appView,
       NamingLens namingLens) {
+    if (!hasBacking) {
+      function.rewrite(visitorProvider.get()::visitFunction, null, appView, namingLens);
+      return true;
+    }
+    DexEncodedMethod backing = null;
     for (DexEncodedMethod method : clazz.methods()) {
       if (method.getKotlinMemberInfo() == function) {
-        KmLambdaVisitor kmLambdaVisitor = visitorProvider.get();
-        function.rewrite(kmLambdaVisitor::visitFunction, method, appView, namingLens);
-        return true;
+        backing = method;
+        break;
       }
     }
-    return false;
+    if (backing == null) {
+      appView
+          .options()
+          .reporter
+          .info(
+              KotlinMetadataDiagnostic.lambdaBackingNotFound(clazz.type, function.getSignature()));
+      return false;
+    }
+    function.rewrite(visitorProvider.get()::visitFunction, backing, appView, namingLens);
+    return true;
+  }
+
+  @Override
+  public void trace(DexDefinitionSupplier definitionSupplier) {
+    function.trace(definitionSupplier);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinLocalDelegatedPropertyInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinLocalDelegatedPropertyInfo.java
new file mode 100644
index 0000000..fca17cf
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinLocalDelegatedPropertyInfo.java
@@ -0,0 +1,61 @@
+// Copyright (c) 2020, 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 static com.android.tools.r8.utils.FunctionUtils.forEachApply;
+
+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.kotlin.KmVisitorProviders.KmPropertyVisitorProvider;
+import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
+import com.android.tools.r8.utils.Reporter;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import kotlinx.metadata.KmProperty;
+
+public class KotlinLocalDelegatedPropertyInfo implements EnqueuerMetadataTraceable {
+
+  private static final KotlinLocalDelegatedPropertyInfo EMPTY_DELEGATED_PROPERTIES =
+      new KotlinLocalDelegatedPropertyInfo(ImmutableList.of());
+
+  private final List<KotlinPropertyInfo> propertyInfos;
+
+  private KotlinLocalDelegatedPropertyInfo(List<KotlinPropertyInfo> propertyInfos) {
+    this.propertyInfos = propertyInfos;
+  }
+
+  static KotlinLocalDelegatedPropertyInfo create(
+      List<KmProperty> kmProperties, DexItemFactory factory, Reporter reporter) {
+    if (kmProperties == null || kmProperties.size() == 0) {
+      return EMPTY_DELEGATED_PROPERTIES;
+    }
+    ImmutableList.Builder<KotlinPropertyInfo> builder = ImmutableList.builder();
+    for (KmProperty kmProperty : kmProperties) {
+      KotlinPropertyInfo kotlinPropertyInfo =
+          KotlinPropertyInfo.create(kmProperty, factory, reporter);
+      // For ordinary properties, we place these on the fields and methods, but these are hooked in,
+      // and do not have any jvm signatures:
+      assert kotlinPropertyInfo.getFieldSignature() == null;
+      assert kotlinPropertyInfo.getGetterSignature() == null;
+      assert kotlinPropertyInfo.getSetterSignature() == null;
+      builder.add(kotlinPropertyInfo);
+    }
+    return new KotlinLocalDelegatedPropertyInfo(builder.build());
+  }
+
+  @Override
+  public void trace(DexDefinitionSupplier definitionSupplier) {
+    forEachApply(propertyInfos, prop -> prop::trace, definitionSupplier);
+  }
+
+  public void rewrite(
+      KmPropertyVisitorProvider visitorProvider, AppView<?> appView, NamingLens namingLens) {
+    for (KotlinPropertyInfo propertyInfo : propertyInfos) {
+      propertyInfo.rewrite(visitorProvider, null, null, null, appView, namingLens);
+    }
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataDiagnostic.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataDiagnostic.java
index 83947d7..3415e13 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataDiagnostic.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataDiagnostic.java
@@ -73,4 +73,18 @@
             + StringUtils.LINE_SEPARATOR
             + StringUtils.stacktraceAsString(t));
   }
+
+  static KotlinMetadataDiagnostic lambdaBackingNotFound(
+      DexType type, KotlinJvmMethodSignatureInfo signatureInfo) {
+    return new KotlinMetadataDiagnostic(
+        Origin.unknown(),
+        Position.UNKNOWN,
+        "The lambda function "
+            + signatureInfo.toString()
+            + " could no longer be found in "
+            + type.toSourceString()
+            + " . The method is most likely pruned and would require a specific keep rule to keep"
+            + " alive. As a result, the metadata information regarding the lambda structure has"
+            + " been discarded.");
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java
index 28928ef..254255e 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java
@@ -4,11 +4,24 @@
 
 package com.android.tools.r8.kotlin;
 
+import static com.android.tools.r8.kotlin.KotlinClassMetadataReader.hasKotlinClassMetadataAnnotation;
+import static com.android.tools.r8.kotlin.KotlinMetadataUtils.NO_KOTLIN_INFO;
+import static com.android.tools.r8.utils.FunctionUtils.forEachApply;
+
+import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexDefinition;
 import com.android.tools.r8.graph.DexDefinitionSupplier;
+import com.android.tools.r8.graph.DexEncodedField;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexReference;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.EnclosingMethodAttribute;
 import com.android.tools.r8.graph.analysis.EnqueuerAnalysis;
 import com.android.tools.r8.shaking.Enqueuer;
 import com.google.common.collect.Sets;
@@ -18,12 +31,11 @@
 
   private final AppView<?> appView;
   private final DexDefinitionSupplier definitionSupplier;
-  private final Set<DexMethod> keepByteCodeFunctions = Sets.newIdentityHashSet();
 
   public KotlinMetadataEnqueuerExtension(
-      AppView<?> appView, DexDefinitionSupplier definitionSupplier) {
+      AppView<?> appView, DexDefinitionSupplier definitionSupplier, Set<DexType> prunedTypes) {
     this.appView = appView;
-    this.definitionSupplier = definitionSupplier;
+    this.definitionSupplier = new KotlinMetadataDefinitionSupplier(definitionSupplier, prunedTypes);
   }
 
   @Override
@@ -31,23 +43,120 @@
     DexType kotlinMetadataType = appView.dexItemFactory().kotlinMetadataType;
     DexClass kotlinMetadataClass =
         appView.appInfo().definitionForWithoutExistenceAssert(kotlinMetadataType);
-    // We will process kotlin.Metadata even if the type is not present in the program, as long as
-    // the annotation will be in the output
+    // In the first round of tree shaking build up all metadata such that it can be traced later.
     boolean keepMetadata =
-        enqueuer.isPinned(kotlinMetadataType)
-            || enqueuer.isMissing(kotlinMetadataType)
-            || (kotlinMetadataClass != null && kotlinMetadataClass.isNotProgramClass());
+        kotlinMetadataClass == null
+            || kotlinMetadataClass.isNotProgramClass()
+            || enqueuer.isPinned(kotlinMetadataType);
+    if (enqueuer.getMode().isInitialTreeShaking()) {
+      Set<DexMethod> keepByteCodeFunctions = Sets.newIdentityHashSet();
+      Set<DexProgramClass> localOrAnonymousClasses = Sets.newIdentityHashSet();
+      enqueuer.forAllLiveClasses(
+          clazz -> {
+            boolean onlyProcessLambdas = !keepMetadata || !enqueuer.isPinned(clazz.type);
+            assert clazz.getKotlinInfo().isNoKotlinInformation();
+            clazz.setKotlinInfo(
+                KotlinClassMetadataReader.getKotlinInfo(
+                    appView.dexItemFactory().kotlin,
+                    clazz,
+                    definitionSupplier.dexItemFactory(),
+                    appView.options().reporter,
+                    onlyProcessLambdas,
+                    method -> keepByteCodeFunctions.add(method.method)));
+            if (clazz.getEnclosingMethod() != null
+                && clazz.getEnclosingMethod().getEnclosingMethod() != null) {
+              localOrAnonymousClasses.add(clazz);
+            }
+          });
+      appView.setCfByteCodePassThrough(keepByteCodeFunctions);
+      for (DexProgramClass localOrAnonymousClass : localOrAnonymousClasses) {
+        EnclosingMethodAttribute enclosingAttribute = localOrAnonymousClass.getEnclosingMethod();
+        DexClass holder =
+            definitionSupplier.definitionForHolder(enclosingAttribute.getEnclosingMethod());
+        if (holder == null) {
+          continue;
+        }
+        DexEncodedMethod method = holder.lookupMethod(enclosingAttribute.getEnclosingMethod());
+        // If we cannot lookup the method, the conservative choice is keep the byte code.
+        if (method == null
+            || (method.getKotlinMemberInfo().isFunction()
+                && method.getKotlinMemberInfo().asFunction().hasCrossInlineParameter())) {
+          localOrAnonymousClass.forEachProgramMethod(
+              m -> keepByteCodeFunctions.add(m.getReference()));
+        }
+      }
+    } else {
+      assert verifyKotlinMetadataModeledForAllClasses(enqueuer, keepMetadata);
+    }
+    // Trace through the modeled kotlin metadata.
     enqueuer.forAllLiveClasses(
         clazz -> {
-          clazz.setKotlinInfo(
-              KotlinClassMetadataReader.getKotlinInfo(
-                  appView.dexItemFactory().kotlin,
-                  clazz,
-                  definitionSupplier,
-                  appView.options().reporter,
-                  !keepMetadata || !enqueuer.isPinned(clazz.type),
-                  method -> keepByteCodeFunctions.add(method.method)));
+          clazz.getKotlinInfo().trace(definitionSupplier);
+          forEachApply(
+              clazz.methods(), method -> method.getKotlinMemberInfo()::trace, definitionSupplier);
+          forEachApply(
+              clazz.fields(), field -> field.getKotlinMemberInfo()::trace, definitionSupplier);
         });
-    appView.setCfByteCodePassThrough(keepByteCodeFunctions);
+  }
+
+  private boolean verifyKotlinMetadataModeledForAllClasses(
+      Enqueuer enqueuer, boolean keepMetadata) {
+    enqueuer.forAllLiveClasses(
+        clazz -> {
+          // Trace through class and member definitions
+          assert !hasKotlinClassMetadataAnnotation(clazz, definitionSupplier)
+              || !keepMetadata
+              || !enqueuer.isPinned(clazz.type)
+              || clazz.getKotlinInfo() != NO_KOTLIN_INFO;
+        });
+    return true;
+  }
+
+  public static class KotlinMetadataDefinitionSupplier implements DexDefinitionSupplier {
+
+    private final DexDefinitionSupplier baseSupplier;
+    private final Set<DexType> prunedTypes;
+
+    private KotlinMetadataDefinitionSupplier(
+        DexDefinitionSupplier baseSupplier, Set<DexType> prunedTypes) {
+      this.baseSupplier = baseSupplier;
+      this.prunedTypes = prunedTypes;
+    }
+
+    @Override
+    public DexDefinition definitionFor(DexReference reference) {
+      throw new Unreachable("Should not be called");
+    }
+
+    @Override
+    public DexEncodedField definitionFor(DexField field) {
+      throw new Unreachable("Should not be called");
+    }
+
+    @Override
+    public DexEncodedMethod definitionFor(DexMethod method) {
+      throw new Unreachable("Should not be called");
+    }
+
+    @Override
+    public DexClass definitionFor(DexType type) {
+      // TODO(b/157700128) Metadata cannot at this point keep anything alive. Therefore, if a type
+      //  has been pruned it may still be referenced, so we do an early check here to ensure it will
+      //  not end up as. Ideally, those types should be removed by a pass on the modeled data.
+      if (prunedTypes != null && prunedTypes.contains(type)) {
+        return null;
+      }
+      return baseSupplier.definitionFor(type);
+    }
+
+    @Override
+    public DexProgramClass definitionForProgramType(DexType type) {
+      throw new Unreachable("Should not be called");
+    }
+
+    @Override
+    public DexItemFactory dexItemFactory() {
+      return baseSupplier.dexItemFactory();
+    }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
index ce0ba80..d709ea4 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
@@ -16,7 +16,6 @@
 import com.android.tools.r8.graph.DexValue.DexValueInt;
 import com.android.tools.r8.graph.DexValue.DexValueString;
 import com.android.tools.r8.naming.NamingLens;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.ThreadUtils;
 import java.util.ArrayList;
 import java.util.List;
@@ -26,12 +25,12 @@
 
 public class KotlinMetadataRewriter {
 
-  private final AppView<AppInfoWithLiveness> appView;
+  private final AppView<?> appView;
   private final NamingLens lens;
   private final DexItemFactory factory;
   private final Kotlin kotlin;
 
-  public KotlinMetadataRewriter(AppView<AppInfoWithLiveness> appView, NamingLens lens) {
+  public KotlinMetadataRewriter(AppView<?> appView, NamingLens lens) {
     this.appView = appView;
     this.lens = lens;
     this.factory = appView.dexItemFactory();
@@ -54,7 +53,8 @@
           }
           if (oldMeta == null
               || kotlinInfo == NO_KOTLIN_INFO
-              || !appView.appInfo().isPinned(clazz.type)) {
+              || (appView.appInfo().hasLiveness()
+                  && !appView.withLiveness().appInfo().isPinned(clazz.type))) {
             // Remove @Metadata in DexAnnotation when there is no kotlin info and the type is not
             // missing.
             if (oldMeta != null) {
@@ -83,27 +83,33 @@
       KotlinClassHeader header, String packageName) {
     List<DexAnnotationElement> elements = new ArrayList<>();
     elements.add(
-        new DexAnnotationElement(kotlin.metadata.kind, DexValueInt.create(header.getKind())));
-    elements.add(
         new DexAnnotationElement(
             kotlin.metadata.metadataVersion, createIntArray(header.getMetadataVersion())));
     elements.add(
         new DexAnnotationElement(
             kotlin.metadata.bytecodeVersion, createIntArray(header.getBytecodeVersion())));
     elements.add(
+        new DexAnnotationElement(kotlin.metadata.kind, DexValueInt.create(header.getKind())));
+    elements.add(
         new DexAnnotationElement(kotlin.metadata.data1, createStringArray(header.getData1())));
     elements.add(
         new DexAnnotationElement(kotlin.metadata.data2, createStringArray(header.getData2())));
-    elements.add(
-        new DexAnnotationElement(
-            kotlin.metadata.extraString,
-            new DexValueString(factory.createString(header.getExtraString()))));
-    elements.add(
-        new DexAnnotationElement(
-            kotlin.metadata.packageName, new DexValueString(factory.createString(packageName))));
-    elements.add(
-        new DexAnnotationElement(
-            kotlin.metadata.extraInt, DexValueInt.create(header.getExtraInt())));
+    if (packageName != null && !packageName.isEmpty()) {
+      elements.add(
+          new DexAnnotationElement(
+              kotlin.metadata.packageName, new DexValueString(factory.createString(packageName))));
+    }
+    if (!header.getExtraString().isEmpty()) {
+      elements.add(
+          new DexAnnotationElement(
+              kotlin.metadata.extraString,
+              new DexValueString(factory.createString(header.getExtraString()))));
+    }
+    if (header.getExtraInt() != 0) {
+      elements.add(
+          new DexAnnotationElement(
+              kotlin.metadata.extraInt, DexValueInt.create(header.getExtraInt())));
+    }
     DexEncodedAnnotation encodedAnnotation =
         new DexEncodedAnnotation(
             factory.kotlinMetadataType, elements.toArray(DexAnnotationElement.EMPTY_ARRAY));
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 1f21451..6ef7a0d 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataUtils.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataUtils.java
@@ -12,10 +12,8 @@
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.naming.NamingLens;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.shaking.ProguardConfiguration;
 import com.android.tools.r8.shaking.ProguardConfigurationRule;
 import com.android.tools.r8.shaking.ProguardKeepRule;
@@ -50,8 +48,7 @@
     }
 
     @Override
-    public KotlinClassHeader rewrite(
-        DexClass clazz, AppView<AppInfoWithLiveness> appView, NamingLens namingLens) {
+    public KotlinClassHeader rewrite(DexClass clazz, AppView<?> appView, NamingLens namingLens) {
       throw new Unreachable("Should never be called");
     }
 
@@ -59,6 +56,16 @@
     public String getPackageName() {
       throw new Unreachable("Should never be called");
     }
+
+    @Override
+    public boolean isNoKotlinInformation() {
+      return true;
+    }
+
+    @Override
+    public void trace(DexDefinitionSupplier definitionSupplier) {
+      // No information needed to trace.
+    }
   }
 
   static JvmFieldSignature toJvmFieldSignature(DexField field) {
@@ -137,41 +144,6 @@
     }
   }
 
-  static String toRenamedDescriptorOrDefault(
-      DexType type,
-      AppView<AppInfoWithLiveness> appView,
-      NamingLens namingLens,
-      String defaultValue) {
-    if (appView.appInfo().wasPruned(type)) {
-      return defaultValue;
-    }
-    DexString descriptor = namingLens.lookupDescriptor(type);
-    if (descriptor != null) {
-      return descriptor.toString();
-    }
-    return defaultValue;
-  }
-
-  static String kotlinNameFromDescriptor(DexString descriptor) {
-    return DescriptorUtils.getBinaryNameFromDescriptor(descriptor.toString());
-  }
-
-  static DexType referenceTypeFromBinaryName(
-      String binaryName, DexDefinitionSupplier definitionSupplier) {
-    return referenceTypeFromDescriptor(
-        DescriptorUtils.getDescriptorFromClassBinaryName(binaryName), definitionSupplier);
-  }
-
-  static DexType referenceTypeFromDescriptor(
-      String descriptor, DexDefinitionSupplier definitionSupplier) {
-    DexType type = definitionSupplier.dexItemFactory().createType(descriptor);
-    // Lookup the definition, ignoring the result. This populates the sets in the Enqueuer.
-    if (type.isClassType()) {
-      definitionSupplier.definitionFor(type);
-    }
-    return type;
-  }
-
   public static boolean mayProcessKotlinMetadata(AppView<?> appView) {
     // This can run before we have determined the pinned items, because we may need to load the
     // stack-map table on input. This is therefore a conservative guess on kotlin.Metadata is kept.
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 fa21f81..1a51644 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataWriter.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataWriter.java
@@ -11,6 +11,7 @@
 import com.android.tools.r8.utils.Action;
 import com.android.tools.r8.utils.StringUtils;
 import java.io.PrintStream;
+import java.util.Collection;
 import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
@@ -20,9 +21,13 @@
 import kotlinx.metadata.InconsistentKotlinMetadataException;
 import kotlinx.metadata.KmAnnotation;
 import kotlinx.metadata.KmAnnotationArgument;
+import kotlinx.metadata.KmAnnotationArgument.ArrayValue;
 import kotlinx.metadata.KmClass;
 import kotlinx.metadata.KmConstructor;
+import kotlinx.metadata.KmContract;
 import kotlinx.metadata.KmDeclarationContainer;
+import kotlinx.metadata.KmEffect;
+import kotlinx.metadata.KmEffectExpression;
 import kotlinx.metadata.KmFlexibleTypeUpperBound;
 import kotlinx.metadata.KmFunction;
 import kotlinx.metadata.KmLambda;
@@ -33,6 +38,7 @@
 import kotlinx.metadata.KmTypeParameter;
 import kotlinx.metadata.KmTypeProjection;
 import kotlinx.metadata.KmValueParameter;
+import kotlinx.metadata.KmVersionRequirement;
 import kotlinx.metadata.jvm.JvmExtensionsKt;
 import kotlinx.metadata.jvm.JvmFieldSignature;
 import kotlinx.metadata.jvm.JvmMethodSignature;
@@ -173,7 +179,7 @@
       String indent,
       String typeDescription,
       StringBuilder sb,
-      List<T> items,
+      Collection<T> items,
       BiConsumer<String, T> appendItem) {
     if (items.isEmpty()) {
       sb.append(typeDescription).append("[]");
@@ -351,6 +357,7 @@
                 appendKmProperty(nextNextIndent, sb, kmProperty);
               });
         });
+    appendKmVersionRequirement(indent, sb, kmClass.getVersionRequirements());
     appendKeyValue(
         indent,
         "constructors",
@@ -389,6 +396,7 @@
           JvmMethodSignature signature = JvmExtensionsKt.getSignature(constructor);
           appendKeyValue(
               newIndent, "signature", sb, signature != null ? signature.asString() : "null");
+          appendKmVersionRequirement(newIndent, sb, constructor.getVersionRequirements());
         });
   }
 
@@ -420,6 +428,19 @@
               "valueParameters",
               sb,
               nextIndent -> appendValueParameters(nextIndent, sb, function.getValueParameters()));
+          appendKmVersionRequirement(newIndent, sb, function.getVersionRequirements());
+          KmContract contract = function.getContract();
+          if (contract == null) {
+            appendKeyValue(newIndent, "contract", sb, "null");
+          } else {
+            appendKeyValue(
+                newIndent,
+                "contract",
+                sb,
+                nextIndent -> {
+                  appendKmContract(nextIndent, sb, contract);
+                });
+          }
           JvmMethodSignature signature = JvmExtensionsKt.getSignature(function);
           appendKeyValue(
               newIndent, "signature", sb, signature != null ? signature.asString() : "null");
@@ -461,6 +482,7 @@
               "setterParameter",
               sb,
               nextIndent -> appendValueParameter(nextIndent, sb, kmProperty.getSetterParameter()));
+          appendKmVersionRequirement(newIndent, sb, kmProperty.getVersionRequirements());
           appendKeyValue(newIndent, "jvmFlags", sb, JvmExtensionsKt.getJvmFlags(kmProperty) + "");
           JvmFieldSignature fieldSignature = JvmExtensionsKt.getFieldSignature(kmProperty);
           appendKeyValue(
@@ -730,6 +752,7 @@
               nextIndent -> {
                 appendKmType(nextIndent, sb, kmTypeAlias.underlyingType);
               });
+          appendKmVersionRequirement(newIndent, sb, kmTypeAlias.getVersionRequirements());
         });
   }
 
@@ -747,9 +770,202 @@
               sb,
               nextIndent -> {
                 Map<String, KmAnnotationArgument<?>> arguments = kmAnnotation.getArguments();
-                for (String key : arguments.keySet()) {
-                  appendKeyValue(nextIndent, key, sb, arguments.get(key).toString());
-                }
+                appendKmList(
+                    nextIndent,
+                    "{ key: String, value: KmAnnotationArgument<?> }",
+                    sb,
+                    arguments.keySet(),
+                    (nextNextIndent, key) -> {
+                      appendKmSection(
+                          nextNextIndent,
+                          "",
+                          sb,
+                          nextNextNextIndent -> {
+                            appendKeyValue(
+                                nextNextNextIndent,
+                                key,
+                                sb,
+                                nextNextNextNextIndent -> {
+                                  appendKmArgument(nextNextNextIndent, sb, arguments.get(key));
+                                });
+                          });
+                    });
+              });
+        });
+  }
+
+  private static void appendKmArgument(
+      String indent, StringBuilder sb, KmAnnotationArgument<?> annotationArgument) {
+    if (annotationArgument instanceof KmAnnotationArgument.ArrayValue) {
+      List<KmAnnotationArgument<?>> value = ((ArrayValue) annotationArgument).getValue();
+      appendKmList(
+          indent,
+          "ArrayValue",
+          sb,
+          value,
+          (newIndent, annoArg) -> {
+            appendKmArgument(newIndent, sb, annoArg);
+          });
+    } else {
+      sb.append(annotationArgument.toString());
+    }
+  }
+
+  private static void appendKmVersionRequirement(
+      String indent, StringBuilder sb, List<KmVersionRequirement> kmVersionRequirements) {
+    appendKeyValue(
+        indent,
+        "versionRequirements",
+        sb,
+        newIndent -> {
+          appendKmList(
+              newIndent,
+              "KmVersionRequirement",
+              sb,
+              kmVersionRequirements,
+              (nextIndent, kmVersionRequirement) -> {
+                appendKmSection(
+                    nextIndent,
+                    "KmVersionRequirement",
+                    sb,
+                    nextNextIndent -> {
+                      appendKeyValue(nextNextIndent, "kind", sb, kmVersionRequirement.kind.name());
+                      appendKeyValue(
+                          nextNextIndent, "level", sb, kmVersionRequirement.level.name());
+                      appendKeyValue(
+                          nextNextIndent,
+                          "errorCode",
+                          sb,
+                          kmVersionRequirement.getErrorCode() == null
+                              ? "null"
+                              : kmVersionRequirement.getErrorCode().toString());
+                      appendKeyValue(
+                          nextNextIndent, "message", sb, kmVersionRequirement.getMessage());
+                      appendKeyValue(
+                          nextNextIndent,
+                          "version",
+                          sb,
+                          kmVersionRequirement.getVersion().toString());
+                    });
+              });
+        });
+  }
+
+  private static void appendKmContract(String indent, StringBuilder sb, KmContract contract) {
+    appendKmSection(
+        indent,
+        "KmContract",
+        sb,
+        newIndent -> {
+          appendKeyValue(
+              newIndent,
+              "effects",
+              sb,
+              nextIndent ->
+                  appendKmList(
+                      nextIndent,
+                      "KmEffect",
+                      sb,
+                      contract.getEffects(),
+                      (nextNextIndent, effect) -> appendKmEffect(nextNextIndent, sb, effect)));
+        });
+  }
+
+  private static void appendKmEffect(String indent, StringBuilder sb, KmEffect effect) {
+    appendKmSection(
+        indent,
+        "KmEffect",
+        sb,
+        newIndent -> {
+          appendKeyValue(newIndent, "type", sb, effect.getType().toString());
+          appendKeyValue(
+              newIndent,
+              "invocationKind",
+              sb,
+              effect.getInvocationKind() == null ? "null" : effect.getInvocationKind().toString());
+          appendKeyValue(
+              newIndent,
+              "constructorArguments",
+              sb,
+              nextIndent -> {
+                appendKmList(
+                    nextIndent,
+                    "KmEffectExpression",
+                    sb,
+                    effect.getConstructorArguments(),
+                    (nextNextIndent, expression) -> {
+                      appendKmEffectExpression(nextNextIndent, sb, expression);
+                    });
+              });
+          KmEffectExpression conclusion = effect.getConclusion();
+          if (conclusion == null) {
+            appendKeyValue(newIndent, "conclusion", sb, "null");
+          } else {
+            appendKeyValue(
+                newIndent,
+                "conclusion",
+                sb,
+                nextIndent -> appendKmEffectExpression(nextIndent, sb, conclusion));
+          }
+        });
+  }
+
+  private static void appendKmEffectExpression(
+      String indent, StringBuilder sb, KmEffectExpression expression) {
+    appendKmSection(
+        indent,
+        "KmEffectExpression",
+        sb,
+        newIndent -> {
+          appendKeyValue(newIndent, "flags", sb, expression.getFlags() + "");
+          appendKeyValue(
+              newIndent,
+              "foo",
+              sb,
+              expression.getParameterIndex() == null
+                  ? "null"
+                  : expression.getParameterIndex() + "");
+          appendKeyValue(
+              newIndent,
+              "constantValue",
+              sb,
+              expression.getConstantValue() == null
+                  ? "null"
+                  : expression.getConstantValue().toString());
+          appendKeyValue(
+              newIndent,
+              "isInstanceType",
+              sb,
+              nextIndent -> {
+                appendKmType(nextIndent, sb, expression.isInstanceType());
+              });
+          appendKeyValue(
+              newIndent,
+              "andArguments",
+              sb,
+              nextIndent -> {
+                appendKmList(
+                    nextIndent,
+                    "KmEffectExpression",
+                    sb,
+                    expression.getAndArguments(),
+                    (nextNextIndent, expr) -> {
+                      appendKmEffectExpression(nextNextIndent, sb, expr);
+                    });
+              });
+          appendKeyValue(
+              newIndent,
+              "orArguments",
+              sb,
+              nextIndent -> {
+                appendKmList(
+                    nextIndent,
+                    "KmEffectExpression",
+                    sb,
+                    expression.getOrArguments(),
+                    (nextNextIndent, expr) -> {
+                      appendKmEffectExpression(nextNextIndent, sb, expr);
+                    });
               });
         });
   }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMethodLevelInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMethodLevelInfo.java
index 604374e..a02cb0a 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMethodLevelInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMethodLevelInfo.java
@@ -4,7 +4,9 @@
 
 package com.android.tools.r8.kotlin;
 
-public interface KotlinMethodLevelInfo {
+import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
+
+public interface KotlinMethodLevelInfo extends EnqueuerMetadataTraceable {
 
   default boolean isConstructor() {
     return false;
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 3baea9c..34c5248 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassFacadeInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassFacadeInfo.java
@@ -4,14 +4,13 @@
 
 package com.android.tools.r8.kotlin;
 
+import static com.android.tools.r8.utils.FunctionUtils.forEachApply;
+
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexDefinitionSupplier;
-import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.naming.NamingLens;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.DescriptorUtils;
 import com.google.common.collect.ImmutableList;
 import java.util.ArrayList;
 import java.util.List;
@@ -22,23 +21,20 @@
 // Holds information about Metadata.MultiFileClassFace
 public class KotlinMultiFileClassFacadeInfo implements KotlinClassLevelInfo {
 
-  private final List<DexType> partClassNames;
+  private final List<KotlinTypeReference> partClassNames;
   private final String packageName;
 
-  private KotlinMultiFileClassFacadeInfo(List<DexType> partClassNames, String packageName) {
+  private KotlinMultiFileClassFacadeInfo(
+      List<KotlinTypeReference> partClassNames, String packageName) {
     this.partClassNames = partClassNames;
     this.packageName = packageName;
   }
 
   static KotlinMultiFileClassFacadeInfo create(
-      MultiFileClassFacade kmMultiFileClassFacade,
-      String packageName,
-      DexDefinitionSupplier definitionSupplier) {
-    ImmutableList.Builder<DexType> builder = ImmutableList.builder();
+      MultiFileClassFacade kmMultiFileClassFacade, String packageName, DexItemFactory factory) {
+    ImmutableList.Builder<KotlinTypeReference> builder = ImmutableList.builder();
     for (String partClassName : kmMultiFileClassFacade.getPartClassNames()) {
-      String descriptor = DescriptorUtils.getDescriptorFromClassBinaryName(partClassName);
-      DexType type = definitionSupplier.dexItemFactory().createType(descriptor);
-      builder.add(type);
+      builder.add(KotlinTypeReference.fromBinaryName(partClassName, factory));
     }
     return new KotlinMultiFileClassFacadeInfo(builder.build(), packageName);
   }
@@ -54,16 +50,14 @@
   }
 
   @Override
-  public KotlinClassHeader rewrite(
-      DexClass clazz, AppView<AppInfoWithLiveness> appView, NamingLens namingLens) {
+  public KotlinClassHeader rewrite(DexClass clazz, AppView<?> appView, NamingLens namingLens) {
     KotlinClassMetadata.MultiFileClassFacade.Writer writer =
         new KotlinClassMetadata.MultiFileClassFacade.Writer();
     List<String> partClassNameStrings = new ArrayList<>(partClassNames.size());
-    for (DexType partClassName : partClassNames) {
-      if (appView.appInfo().isNonProgramTypeOrLiveProgramType(partClassName)) {
-        DexString descriptor = namingLens.lookupDescriptor(partClassName);
-        String classifier = DescriptorUtils.descriptorToKotlinClassifier(descriptor.toString());
-        partClassNameStrings.add(classifier);
+    for (KotlinTypeReference partClassName : partClassNames) {
+      String binaryName = partClassName.toRenamedBinaryNameOrDefault(appView, namingLens, null);
+      if (binaryName != null) {
+        partClassNameStrings.add(binaryName);
       }
     }
     return writer.write(partClassNameStrings).getHeader();
@@ -73,4 +67,9 @@
   public String getPackageName() {
     return packageName;
   }
+
+  @Override
+  public void trace(DexDefinitionSupplier definitionSupplier) {
+    forEachApply(partClassNames, type -> type::trace, definitionSupplier);
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassPartInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassPartInfo.java
index d4ec800..ca97d0b 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassPartInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassPartInfo.java
@@ -8,8 +8,8 @@
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.naming.NamingLens;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.Reporter;
 import java.util.function.Consumer;
 import kotlinx.metadata.KmPackage;
@@ -20,6 +20,7 @@
 // Holds information about Metadata.MultiFileClassPartInfo
 public class KotlinMultiFileClassPartInfo implements KotlinClassLevelInfo {
 
+  // TODO(b/157630779): Maybe model facadeClassName.
   private final String facadeClassName;
   private final KotlinPackageInfo packageInfo;
   private final String packageName;
@@ -35,13 +36,12 @@
       MultiFileClassPart classPart,
       String packageName,
       DexClass clazz,
-      DexDefinitionSupplier definitionSupplier,
+      DexItemFactory factory,
       Reporter reporter,
       Consumer<DexEncodedMethod> keepByteCode) {
     return new KotlinMultiFileClassPartInfo(
         classPart.getFacadeClassName(),
-        KotlinPackageInfo.create(
-            classPart.toKmPackage(), clazz, definitionSupplier, reporter, keepByteCode),
+        KotlinPackageInfo.create(classPart.toKmPackage(), clazz, factory, reporter, keepByteCode),
         packageName);
   }
 
@@ -56,8 +56,7 @@
   }
 
   @Override
-  public KotlinClassHeader rewrite(
-      DexClass clazz, AppView<AppInfoWithLiveness> appView, NamingLens namingLens) {
+  public KotlinClassHeader rewrite(DexClass clazz, AppView<?> appView, NamingLens namingLens) {
     KotlinClassMetadata.MultiFileClassPart.Writer writer =
         new KotlinClassMetadata.MultiFileClassPart.Writer();
     KmPackage kmPackage = new KmPackage();
@@ -70,4 +69,9 @@
   public String getPackageName() {
     return packageName;
   }
+
+  @Override
+  public void trace(DexDefinitionSupplier definitionSupplier) {
+    packageInfo.trace(definitionSupplier);
+  }
 }
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 d98e109..1ac03db 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinPackageInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinPackageInfo.java
@@ -12,30 +12,37 @@
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.naming.NamingLens;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.Reporter;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.function.Consumer;
 import kotlinx.metadata.KmPackage;
 import kotlinx.metadata.jvm.JvmExtensionsKt;
+import kotlinx.metadata.jvm.JvmPackageExtensionVisitor;
 
 // Holds information about a KmPackage object.
-public class KotlinPackageInfo {
+public class KotlinPackageInfo implements EnqueuerMetadataTraceable {
 
   private final String moduleName;
   private final KotlinDeclarationContainerInfo containerInfo;
+  private final KotlinLocalDelegatedPropertyInfo localDelegatedProperties;
 
-  private KotlinPackageInfo(String moduleName, KotlinDeclarationContainerInfo containerInfo) {
+  private KotlinPackageInfo(
+      String moduleName,
+      KotlinDeclarationContainerInfo containerInfo,
+      KotlinLocalDelegatedPropertyInfo localDelegatedProperties) {
     this.moduleName = moduleName;
     this.containerInfo = containerInfo;
+    this.localDelegatedProperties = localDelegatedProperties;
   }
 
   public static KotlinPackageInfo create(
       KmPackage kmPackage,
       DexClass clazz,
-      DexDefinitionSupplier definitionSupplier,
+      DexItemFactory factory,
       Reporter reporter,
       Consumer<DexEncodedMethod> keepByteCode) {
     Map<String, DexEncodedField> fieldMap = new HashMap<>();
@@ -49,14 +56,13 @@
     return new KotlinPackageInfo(
         JvmExtensionsKt.getModuleName(kmPackage),
         KotlinDeclarationContainerInfo.create(
-            kmPackage, methodMap, fieldMap, definitionSupplier, reporter, keepByteCode));
+            kmPackage, methodMap, fieldMap, factory, reporter, keepByteCode),
+        KotlinLocalDelegatedPropertyInfo.create(
+            JvmExtensionsKt.getLocalDelegatedProperties(kmPackage), factory, reporter));
   }
 
   public void rewrite(
-      KmPackage kmPackage,
-      DexClass clazz,
-      AppView<AppInfoWithLiveness> appView,
-      NamingLens namingLens) {
+      KmPackage kmPackage, DexClass clazz, AppView<?> appView, NamingLens namingLens) {
     containerInfo.rewrite(
         kmPackage::visitFunction,
         kmPackage::visitProperty,
@@ -64,6 +70,17 @@
         clazz,
         appView,
         namingLens);
-    JvmExtensionsKt.setModuleName(kmPackage, moduleName);
+    JvmPackageExtensionVisitor extensionVisitor =
+        (JvmPackageExtensionVisitor) kmPackage.visitExtensions(JvmPackageExtensionVisitor.TYPE);
+    localDelegatedProperties.rewrite(
+        extensionVisitor::visitLocalDelegatedProperty, appView, namingLens);
+    extensionVisitor.visitModuleName(moduleName);
+    extensionVisitor.visitEnd();
+  }
+
+  @Override
+  public void trace(DexDefinitionSupplier definitionSupplier) {
+    containerInfo.trace(definitionSupplier);
+    localDelegatedProperties.trace(definitionSupplier);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinPropertyInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinPropertyInfo.java
index 802428a..6fceb06 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinPropertyInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinPropertyInfo.java
@@ -4,12 +4,14 @@
 
 package com.android.tools.r8.kotlin;
 
+import static com.android.tools.r8.utils.FunctionUtils.forEachApply;
+
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.naming.NamingLens;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.Reporter;
 import java.util.List;
 import kotlinx.metadata.KmProperty;
@@ -41,6 +43,8 @@
 
   private final List<KotlinTypeParameterInfo> typeParameters;
 
+  private final KotlinVersionRequirementInfo versionRequirements;
+
   private final int jvmFlags;
 
   private final KotlinJvmFieldSignatureInfo fieldSignature;
@@ -60,6 +64,7 @@
       KotlinTypeInfo receiverParameterType,
       KotlinValueParameterInfo setterParameter,
       List<KotlinTypeParameterInfo> typeParameters,
+      KotlinVersionRequirementInfo versionRequirements,
       int jvmFlags,
       KotlinJvmFieldSignatureInfo fieldSignature,
       KotlinJvmMethodSignatureInfo getterSignature,
@@ -73,6 +78,7 @@
     this.receiverParameterType = receiverParameterType;
     this.setterParameter = setterParameter;
     this.typeParameters = typeParameters;
+    this.versionRequirements = versionRequirements;
     this.jvmFlags = jvmFlags;
     this.fieldSignature = fieldSignature;
     this.getterSignature = getterSignature;
@@ -81,27 +87,25 @@
   }
 
   public static KotlinPropertyInfo create(
-      KmProperty kmProperty, DexDefinitionSupplier definitionSupplier, Reporter reporter) {
+      KmProperty kmProperty, DexItemFactory factory, Reporter reporter) {
     return new KotlinPropertyInfo(
         kmProperty.getFlags(),
         kmProperty.getGetterFlags(),
         kmProperty.getSetterFlags(),
         kmProperty.getName(),
-        KotlinTypeInfo.create(kmProperty.getReturnType(), definitionSupplier, reporter),
-        KotlinTypeInfo.create(kmProperty.getReceiverParameterType(), definitionSupplier, reporter),
-        KotlinValueParameterInfo.create(
-            kmProperty.getSetterParameter(), definitionSupplier, reporter),
-        KotlinTypeParameterInfo.create(
-            kmProperty.getTypeParameters(), definitionSupplier, reporter),
+        KotlinTypeInfo.create(kmProperty.getReturnType(), factory, reporter),
+        KotlinTypeInfo.create(kmProperty.getReceiverParameterType(), factory, reporter),
+        KotlinValueParameterInfo.create(kmProperty.getSetterParameter(), factory, reporter),
+        KotlinTypeParameterInfo.create(kmProperty.getTypeParameters(), factory, reporter),
+        KotlinVersionRequirementInfo.create(kmProperty.getVersionRequirements()),
         JvmExtensionsKt.getJvmFlags(kmProperty),
-        KotlinJvmFieldSignatureInfo.create(
-            JvmExtensionsKt.getFieldSignature(kmProperty), definitionSupplier),
+        KotlinJvmFieldSignatureInfo.create(JvmExtensionsKt.getFieldSignature(kmProperty), factory),
         KotlinJvmMethodSignatureInfo.create(
-            JvmExtensionsKt.getGetterSignature(kmProperty), definitionSupplier),
+            JvmExtensionsKt.getGetterSignature(kmProperty), factory),
         KotlinJvmMethodSignatureInfo.create(
-            JvmExtensionsKt.getSetterSignature(kmProperty), definitionSupplier),
+            JvmExtensionsKt.getSetterSignature(kmProperty), factory),
         KotlinJvmMethodSignatureInfo.create(
-            JvmExtensionsKt.getSyntheticMethodForAnnotations(kmProperty), definitionSupplier));
+            JvmExtensionsKt.getSyntheticMethodForAnnotations(kmProperty), factory));
   }
 
   @Override
@@ -124,12 +128,24 @@
     return this;
   }
 
+  public KotlinJvmFieldSignatureInfo getFieldSignature() {
+    return fieldSignature;
+  }
+
+  public KotlinJvmMethodSignatureInfo getGetterSignature() {
+    return getterSignature;
+  }
+
+  public KotlinJvmMethodSignatureInfo getSetterSignature() {
+    return setterSignature;
+  }
+
   void rewrite(
       KmVisitorProviders.KmPropertyVisitorProvider visitorProvider,
       DexEncodedField field,
       DexEncodedMethod getter,
       DexEncodedMethod setter,
-      AppView<AppInfoWithLiveness> appView,
+      AppView<?> appView,
       NamingLens namingLens) {
     // TODO(b/154348683): Flags again.
     KmPropertyVisitor kmProperty = visitorProvider.get(flags, name, getterFlags, setterFlags);
@@ -146,6 +162,7 @@
     for (KotlinTypeParameterInfo typeParameter : typeParameters) {
       typeParameter.rewrite(kmProperty::visitTypeParameter, appView, namingLens);
     }
+    versionRequirements.rewrite(kmProperty::visitVersionRequirement);
     JvmPropertyExtensionVisitor extensionVisitor =
         (JvmPropertyExtensionVisitor) kmProperty.visitExtensions(JvmPropertyExtensionVisitor.TYPE);
     if (extensionVisitor != null) {
@@ -160,4 +177,30 @@
       }
     }
   }
+
+  @Override
+  public void trace(DexDefinitionSupplier definitionSupplier) {
+    if (returnType != null) {
+      returnType.trace(definitionSupplier);
+    }
+    if (receiverParameterType != null) {
+      receiverParameterType.trace(definitionSupplier);
+    }
+    if (setterParameter != null) {
+      setterParameter.trace(definitionSupplier);
+    }
+    forEachApply(typeParameters, param -> param::trace, definitionSupplier);
+    if (fieldSignature != null) {
+      fieldSignature.trace(definitionSupplier);
+    }
+    if (getterSignature != null) {
+      getterSignature.trace(definitionSupplier);
+    }
+    if (setterSignature != null) {
+      setterSignature.trace(definitionSupplier);
+    }
+    if (syntheticMethodForAnnotations != null) {
+      syntheticMethodForAnnotations.trace(definitionSupplier);
+    }
+  }
 }
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 38933b5..79054f4 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinSyntheticClassInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinSyntheticClassInfo.java
@@ -7,8 +7,8 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexDefinitionSupplier;
+import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.naming.NamingLens;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.Reporter;
 import kotlinx.metadata.KmLambda;
 import kotlinx.metadata.jvm.KotlinClassHeader;
@@ -41,7 +41,7 @@
       String packageName,
       DexClass clazz,
       Kotlin kotlin,
-      DexDefinitionSupplier definitionSupplier,
+      DexItemFactory factory,
       Reporter reporter) {
     KmLambda lambda = null;
     if (syntheticClass.isLambda()) {
@@ -49,9 +49,7 @@
       assert lambda != null;
     }
     return new KotlinSyntheticClassInfo(
-        lambda != null
-            ? KotlinLambdaInfo.create(clazz, lambda, definitionSupplier, reporter)
-            : null,
+        lambda != null ? KotlinLambdaInfo.create(clazz, lambda, factory, reporter) : null,
         getFlavour(syntheticClass, clazz, kotlin),
         packageName);
   }
@@ -79,8 +77,7 @@
   }
 
   @Override
-  public KotlinClassHeader rewrite(
-      DexClass clazz, AppView<AppInfoWithLiveness> appView, NamingLens namingLens) {
+  public KotlinClassHeader rewrite(DexClass clazz, AppView<?> appView, NamingLens namingLens) {
     Writer writer = new Writer();
     if (lambda != null) {
       KmLambda kmLambda = new KmLambda();
@@ -92,6 +89,13 @@
   }
 
   @Override
+  public void trace(DexDefinitionSupplier definitionSupplier) {
+    if (lambda != null) {
+      lambda.trace(definitionSupplier);
+    }
+  }
+
+  @Override
   public String getPackageName() {
     return packageName;
   }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeAliasInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeAliasInfo.java
index b4b5354..3ecbc2c 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeAliasInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeAliasInfo.java
@@ -4,17 +4,20 @@
 
 package com.android.tools.r8.kotlin;
 
+import static com.android.tools.r8.utils.FunctionUtils.forEachApply;
+
 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.naming.NamingLens;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.Reporter;
 import java.util.List;
 import kotlinx.metadata.KmTypeAlias;
 import kotlinx.metadata.KmTypeAliasVisitor;
 
 // Holds information about KmTypeAlias
-public class KotlinTypeAliasInfo {
+public class KotlinTypeAliasInfo implements EnqueuerMetadataTraceable {
 
   private final int flags;
   private final String name;
@@ -22,6 +25,7 @@
   private final KotlinTypeInfo expandedType;
   private final List<KotlinTypeParameterInfo> typeParameters;
   private final List<KotlinAnnotationInfo> annotations;
+  private final KotlinVersionRequirementInfo versionRequirements;
 
   private KotlinTypeAliasInfo(
       int flags,
@@ -29,7 +33,8 @@
       KotlinTypeInfo underlyingType,
       KotlinTypeInfo expandedType,
       List<KotlinTypeParameterInfo> typeParameters,
-      List<KotlinAnnotationInfo> annotations) {
+      List<KotlinAnnotationInfo> annotations,
+      KotlinVersionRequirementInfo versionRequirements) {
     this.flags = flags;
     this.name = name;
     assert underlyingType != null;
@@ -38,22 +43,24 @@
     this.expandedType = expandedType;
     this.typeParameters = typeParameters;
     this.annotations = annotations;
+    this.versionRequirements = versionRequirements;
   }
 
   public static KotlinTypeAliasInfo create(
-      KmTypeAlias alias, DexDefinitionSupplier definitionSupplier, Reporter reporter) {
+      KmTypeAlias alias, DexItemFactory factory, Reporter reporter) {
     return new KotlinTypeAliasInfo(
         alias.getFlags(),
         alias.getName(),
-        KotlinTypeInfo.create(alias.underlyingType, definitionSupplier, reporter),
-        KotlinTypeInfo.create(alias.expandedType, definitionSupplier, reporter),
-        KotlinTypeParameterInfo.create(alias.getTypeParameters(), definitionSupplier, reporter),
-        KotlinAnnotationInfo.create(alias.getAnnotations(), definitionSupplier));
+        KotlinTypeInfo.create(alias.underlyingType, factory, reporter),
+        KotlinTypeInfo.create(alias.expandedType, factory, reporter),
+        KotlinTypeParameterInfo.create(alias.getTypeParameters(), factory, reporter),
+        KotlinAnnotationInfo.create(alias.getAnnotations(), factory),
+        KotlinVersionRequirementInfo.create(alias.getVersionRequirements()));
   }
 
   void rewrite(
       KmVisitorProviders.KmTypeAliasVisitorProvider visitorProvider,
-      AppView<AppInfoWithLiveness> appView,
+      AppView<?> appView,
       NamingLens namingLens) {
     KmTypeAliasVisitor kmTypeAliasVisitor = visitorProvider.get(flags, name);
     underlyingType.rewrite(kmTypeAliasVisitor::visitUnderlyingType, appView, namingLens);
@@ -64,5 +71,14 @@
     for (KotlinAnnotationInfo annotation : annotations) {
       annotation.rewrite(kmTypeAliasVisitor::visitAnnotation, appView, namingLens);
     }
+    versionRequirements.rewrite(kmTypeAliasVisitor::visitVersionRequirement);
+  }
+
+  @Override
+  public void trace(DexDefinitionSupplier definitionSupplier) {
+    underlyingType.trace(definitionSupplier);
+    expandedType.trace(definitionSupplier);
+    forEachApply(typeParameters, typeParam -> typeParam::trace, definitionSupplier);
+    forEachApply(annotations, annotation -> annotation::trace, definitionSupplier);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeInfo.java
index 8601667..4e74391 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeInfo.java
@@ -4,10 +4,13 @@
 
 package com.android.tools.r8.kotlin;
 
+import static com.android.tools.r8.utils.FunctionUtils.forEachApply;
+
 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.naming.NamingLens;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.Reporter;
 import com.google.common.collect.ImmutableList;
 import java.util.List;
@@ -18,7 +21,7 @@
 import kotlinx.metadata.jvm.JvmTypeExtensionVisitor;
 
 // Provides access to Kotlin information about a kotlin type.
-public class KotlinTypeInfo {
+public class KotlinTypeInfo implements EnqueuerMetadataTraceable {
 
   private static final List<KotlinTypeProjectionInfo> EMPTY_ARGUMENTS = ImmutableList.of();
 
@@ -28,7 +31,7 @@
   private final KotlinTypeInfo outerType;
   private final List<KotlinTypeProjectionInfo> arguments;
   private final List<KotlinAnnotationInfo> annotations;
-  private final KotlinFlexibleTypeUpperBoundInfo flexibleTypeUpperBoundInfo;
+  private final KotlinFlexibleTypeUpperBoundInfo flexibleTypeUpperBound;
 
   KotlinTypeInfo(
       int flags,
@@ -37,49 +40,46 @@
       KotlinTypeInfo outerType,
       List<KotlinTypeProjectionInfo> arguments,
       List<KotlinAnnotationInfo> annotations,
-      KotlinFlexibleTypeUpperBoundInfo flexibleTypeUpperBoundInfo) {
+      KotlinFlexibleTypeUpperBoundInfo flexibleTypeUpperBound) {
     this.flags = flags;
     this.classifier = classifier;
     this.abbreviatedType = abbreviatedType;
     this.outerType = outerType;
     this.arguments = arguments;
     this.annotations = annotations;
-    this.flexibleTypeUpperBoundInfo = flexibleTypeUpperBoundInfo;
+    this.flexibleTypeUpperBound = flexibleTypeUpperBound;
   }
 
-  static KotlinTypeInfo create(
-      KmType kmType, DexDefinitionSupplier definitionSupplier, Reporter reporter) {
+  static KotlinTypeInfo create(KmType kmType, DexItemFactory factory, Reporter reporter) {
     if (kmType == null) {
       return null;
     }
     return new KotlinTypeInfo(
         kmType.getFlags(),
-        KotlinClassifierInfo.create(kmType.classifier, definitionSupplier, reporter),
-        KotlinTypeInfo.create(kmType.getAbbreviatedType(), definitionSupplier, reporter),
-        KotlinTypeInfo.create(kmType.getOuterType(), definitionSupplier, reporter),
-        getArguments(kmType.getArguments(), definitionSupplier, reporter),
-        KotlinAnnotationInfo.create(JvmExtensionsKt.getAnnotations(kmType), definitionSupplier),
+        KotlinClassifierInfo.create(kmType.classifier, factory, reporter),
+        KotlinTypeInfo.create(kmType.getAbbreviatedType(), factory, reporter),
+        KotlinTypeInfo.create(kmType.getOuterType(), factory, reporter),
+        getArguments(kmType.getArguments(), factory, reporter),
+        KotlinAnnotationInfo.create(JvmExtensionsKt.getAnnotations(kmType), factory),
         KotlinFlexibleTypeUpperBoundInfo.create(
-            kmType.getFlexibleTypeUpperBound(), definitionSupplier, reporter));
+            kmType.getFlexibleTypeUpperBound(), factory, reporter));
   }
 
   static List<KotlinTypeProjectionInfo> getArguments(
-      List<KmTypeProjection> projections,
-      DexDefinitionSupplier definitionSupplier,
-      Reporter reporter) {
+      List<KmTypeProjection> projections, DexItemFactory factory, Reporter reporter) {
     if (projections.isEmpty()) {
       return EMPTY_ARGUMENTS;
     }
     ImmutableList.Builder<KotlinTypeProjectionInfo> arguments = ImmutableList.builder();
     for (KmTypeProjection projection : projections) {
-      arguments.add(KotlinTypeProjectionInfo.create(projection, definitionSupplier, reporter));
+      arguments.add(KotlinTypeProjectionInfo.create(projection, factory, reporter));
     }
     return arguments.build();
   }
 
   public void rewrite(
       KmVisitorProviders.KmTypeVisitorProvider visitorProvider,
-      AppView<AppInfoWithLiveness> appView,
+      AppView<?> appView,
       NamingLens namingLens) {
     // TODO(b/154348683): Check for correct flags
     KmTypeVisitor kmTypeVisitor = visitorProvider.get(flags);
@@ -94,8 +94,7 @@
       argument.rewrite(
           kmTypeVisitor::visitArgument, kmTypeVisitor::visitStarProjection, appView, namingLens);
     }
-    flexibleTypeUpperBoundInfo.rewrite(
-        kmTypeVisitor::visitFlexibleTypeUpperBound, appView, namingLens);
+    flexibleTypeUpperBound.rewrite(kmTypeVisitor::visitFlexibleTypeUpperBound, appView, namingLens);
     if (annotations.isEmpty()) {
       return;
     }
@@ -107,4 +106,18 @@
       }
     }
   }
+
+  @Override
+  public void trace(DexDefinitionSupplier definitionSupplier) {
+    classifier.trace(definitionSupplier);
+    if (abbreviatedType != null) {
+      abbreviatedType.trace(definitionSupplier);
+    }
+    if (outerType != null) {
+      outerType.trace(definitionSupplier);
+    }
+    forEachApply(arguments, argument -> argument::trace, definitionSupplier);
+    flexibleTypeUpperBound.trace(definitionSupplier);
+    forEachApply(annotations, annotation -> annotation::trace, definitionSupplier);
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeParameterInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeParameterInfo.java
index fd11c11..d8457ed 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeParameterInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeParameterInfo.java
@@ -4,10 +4,13 @@
 
 package com.android.tools.r8.kotlin;
 
+import static com.android.tools.r8.utils.FunctionUtils.forEachApply;
+
 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.naming.NamingLens;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.Reporter;
 import com.google.common.collect.ImmutableList;
 import java.util.List;
@@ -19,7 +22,7 @@
 import kotlinx.metadata.jvm.JvmTypeParameterExtensionVisitor;
 
 // Provides access to Kotlin information about a type-parameter.
-public class KotlinTypeParameterInfo {
+public class KotlinTypeParameterInfo implements EnqueuerMetadataTraceable {
 
   private static final List<KotlinTypeParameterInfo> EMPTY_TYPE_PARAMETERS = ImmutableList.of();
   private static final List<KotlinTypeInfo> EMPTY_UPPER_BOUNDS = ImmutableList.of();
@@ -47,48 +50,43 @@
   }
 
   private static KotlinTypeParameterInfo create(
-      KmTypeParameter kmTypeParameter,
-      DexDefinitionSupplier definitionSupplier,
-      Reporter reporter) {
+      KmTypeParameter kmTypeParameter, DexItemFactory factory, Reporter reporter) {
     return new KotlinTypeParameterInfo(
         kmTypeParameter.getFlags(),
         kmTypeParameter.getId(),
         kmTypeParameter.getName(),
         kmTypeParameter.getVariance(),
-        getUpperBounds(kmTypeParameter.getUpperBounds(), definitionSupplier, reporter),
-        KotlinAnnotationInfo.create(
-            JvmExtensionsKt.getAnnotations(kmTypeParameter), definitionSupplier));
+        getUpperBounds(kmTypeParameter.getUpperBounds(), factory, reporter),
+        KotlinAnnotationInfo.create(JvmExtensionsKt.getAnnotations(kmTypeParameter), factory));
   }
 
   static List<KotlinTypeParameterInfo> create(
-      List<KmTypeParameter> kmTypeParameters,
-      DexDefinitionSupplier definitionSupplier,
-      Reporter reporter) {
+      List<KmTypeParameter> kmTypeParameters, DexItemFactory factory, Reporter reporter) {
     if (kmTypeParameters.isEmpty()) {
       return EMPTY_TYPE_PARAMETERS;
     }
     ImmutableList.Builder<KotlinTypeParameterInfo> builder = ImmutableList.builder();
     for (KmTypeParameter kmTypeParameter : kmTypeParameters) {
-      builder.add(create(kmTypeParameter, definitionSupplier, reporter));
+      builder.add(create(kmTypeParameter, factory, reporter));
     }
     return builder.build();
   }
 
   private static List<KotlinTypeInfo> getUpperBounds(
-      List<KmType> upperBounds, DexDefinitionSupplier definitionSupplier, Reporter reporter) {
+      List<KmType> upperBounds, DexItemFactory factory, Reporter reporter) {
     if (upperBounds.isEmpty()) {
       return EMPTY_UPPER_BOUNDS;
     }
     ImmutableList.Builder<KotlinTypeInfo> builder = ImmutableList.builder();
     for (KmType upperBound : upperBounds) {
-      builder.add(KotlinTypeInfo.create(upperBound, definitionSupplier, reporter));
+      builder.add(KotlinTypeInfo.create(upperBound, factory, reporter));
     }
     return builder.build();
   }
 
   void rewrite(
       KmVisitorProviders.KmTypeParameterVisitorProvider visitorProvider,
-      AppView<AppInfoWithLiveness> appView,
+      AppView<?> appView,
       NamingLens namingLens) {
     KmTypeParameterVisitor kmTypeParameterVisitor = visitorProvider.get(flags, name, id, variance);
     for (KotlinTypeInfo originalUpperBound : originalUpperBounds) {
@@ -104,4 +102,10 @@
       annotation.rewrite(extensionVisitor::visitAnnotation, appView, namingLens);
     }
   }
+
+  @Override
+  public void trace(DexDefinitionSupplier definitionSupplier) {
+    forEachApply(originalUpperBounds, upperBound -> upperBound::trace, definitionSupplier);
+    forEachApply(annotations, annotation -> annotation::trace, definitionSupplier);
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeProjectionInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeProjectionInfo.java
index 68da5db..1f2ce01 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeProjectionInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeProjectionInfo.java
@@ -6,14 +6,15 @@
 
 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.naming.NamingLens;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.Reporter;
 import kotlinx.metadata.KmTypeProjection;
 import kotlinx.metadata.KmVariance;
 
 // Provides access to Kotlin information about the type projection of a type (arguments).
-public class KotlinTypeProjectionInfo {
+public class KotlinTypeProjectionInfo implements EnqueuerMetadataTraceable {
 
   final KmVariance variance;
   final KotlinTypeInfo typeInfo;
@@ -24,12 +25,10 @@
   }
 
   static KotlinTypeProjectionInfo create(
-      KmTypeProjection kmTypeProjection,
-      DexDefinitionSupplier definitionSupplier,
-      Reporter reporter) {
+      KmTypeProjection kmTypeProjection, DexItemFactory factory, Reporter reporter) {
     return new KotlinTypeProjectionInfo(
         kmTypeProjection.getVariance(),
-        KotlinTypeInfo.create(kmTypeProjection.getType(), definitionSupplier, reporter));
+        KotlinTypeInfo.create(kmTypeProjection.getType(), factory, reporter));
   }
 
   private boolean isStarProjection() {
@@ -39,7 +38,7 @@
   public void rewrite(
       KmVisitorProviders.KmTypeProjectionVisitorProvider visitorProvider,
       KmVisitorProviders.KmTypeStarProjectionVisitorProvider starProjectionProvider,
-      AppView<AppInfoWithLiveness> appView,
+      AppView<?> appView,
       NamingLens namingLens) {
     if (isStarProjection()) {
       starProjectionProvider.get();
@@ -47,4 +46,11 @@
       typeInfo.rewrite(flags -> visitorProvider.get(flags, variance), appView, namingLens);
     }
   }
+
+  @Override
+  public void trace(DexDefinitionSupplier definitionSupplier) {
+    if (typeInfo != null) {
+      typeInfo.trace(definitionSupplier);
+    }
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java
new file mode 100644
index 0000000..088e7ec
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java
@@ -0,0 +1,108 @@
+// Copyright (c) 2020, 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.DexDefinitionSupplier;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
+import com.android.tools.r8.utils.DescriptorUtils;
+
+/**
+ * To account for invalid type references in kotlin metadata, the class KotlinTypeReference will
+ * either hold a DexType reference, or a String, with the original name reference, which is not a
+ * valid jvm descriptor/name. The values will be disjoint.
+ */
+class KotlinTypeReference implements EnqueuerMetadataTraceable {
+
+  private final DexType known;
+  private final String unknown;
+
+  private KotlinTypeReference(DexType known) {
+    this.known = known;
+    this.unknown = null;
+    assert known != null;
+  }
+
+  private KotlinTypeReference(String unknown) {
+    this.known = null;
+    this.unknown = unknown;
+    assert unknown != null;
+  }
+
+  static KotlinTypeReference fromBinaryName(String binaryName, DexItemFactory factory) {
+    if (DescriptorUtils.isValidBinaryName(binaryName)) {
+      return fromDescriptor(
+          DescriptorUtils.getDescriptorFromClassBinaryName(binaryName), factory, binaryName);
+    }
+    return new KotlinTypeReference(binaryName);
+  }
+
+  static KotlinTypeReference fromDescriptor(String descriptor, DexItemFactory factory) {
+    return fromDescriptor(descriptor, factory, descriptor);
+  }
+
+  static KotlinTypeReference fromDescriptor(
+      String descriptor, DexItemFactory factory, String unknownValue) {
+    if (DescriptorUtils.isDescriptor(descriptor)) {
+      DexType type = factory.createType(descriptor);
+      return new KotlinTypeReference(type);
+    }
+    return new KotlinTypeReference(unknownValue);
+  }
+
+  String toRenamedDescriptorOrDefault(
+      AppView<?> appView, NamingLens namingLens, String defaultValue) {
+    if (unknown != null) {
+      return unknown;
+    }
+    assert known != null;
+    if (!known.isClassType()) {
+      return known.descriptor.toString();
+    }
+    if (appView.appInfo().hasLiveness()
+        && !appView.withLiveness().appInfo().isNonProgramTypeOrLiveProgramType(known)) {
+      return defaultValue;
+    }
+    DexString descriptor = namingLens.lookupDescriptor(known);
+    if (descriptor != null) {
+      return descriptor.toString();
+    }
+    return defaultValue;
+  }
+
+  String toRenamedBinaryNameOrDefault(
+      AppView<?> appView, NamingLens namingLens, String defaultValue) {
+    if (unknown != null) {
+      // Unknown values are always on the input form, so we can just return it.
+      return unknown;
+    }
+    String descriptor = toRenamedDescriptorOrDefault(appView, namingLens, defaultValue);
+    if (descriptor == null) {
+      return null;
+    }
+    if (descriptor.equals(defaultValue)) {
+      // We assume that the default value passed in is already a binary name.
+      return descriptor;
+    }
+    return DescriptorUtils.getBinaryNameFromDescriptor(descriptor);
+  }
+
+  @Override
+  public String toString() {
+    return known != null ? known.descriptor.toString() : unknown;
+  }
+
+  @Override
+  public void trace(DexDefinitionSupplier definitionSupplier) {
+    if (known != null && known.isClassType()) {
+      // Lookup the definition, ignoring the result. This populates the sets in the Enqueuer.
+      definitionSupplier.definitionFor(known);
+    }
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinValueParameterInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinValueParameterInfo.java
index ee2f99b..db54d35 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinValueParameterInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinValueParameterInfo.java
@@ -6,17 +6,19 @@
 
 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.naming.NamingLens;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
 import com.android.tools.r8.utils.Reporter;
 import com.google.common.collect.ImmutableList;
 import java.util.List;
 import kotlinx.metadata.KmType;
 import kotlinx.metadata.KmValueParameter;
 import kotlinx.metadata.KmValueParameterVisitor;
+import kotlinx.metadata.internal.metadata.deserialization.Flags;
 
 // Provides access to Kotlin information about value parameter.
-class KotlinValueParameterInfo {
+class KotlinValueParameterInfo implements EnqueuerMetadataTraceable {
   private static final List<KotlinValueParameterInfo> EMPTY_VALUE_PARAMETERS = ImmutableList.of();
   // Original parameter name.
   final String name;
@@ -35,10 +37,12 @@
     this.varargElementType = varargElementType;
   }
 
+  boolean isCrossInline() {
+    return Flags.IS_CROSSINLINE.get(flags);
+  }
+
   static KotlinValueParameterInfo create(
-      KmValueParameter kmValueParameter,
-      DexDefinitionSupplier definitionSupplier,
-      Reporter reporter) {
+      KmValueParameter kmValueParameter, DexItemFactory factory, Reporter reporter) {
     if (kmValueParameter == null) {
       return null;
     }
@@ -46,28 +50,25 @@
     return new KotlinValueParameterInfo(
         kmValueParameter.getFlags(),
         kmValueParameter.getName(),
-        KotlinTypeInfo.create(kmType, definitionSupplier, reporter),
-        KotlinTypeInfo.create(
-            kmValueParameter.getVarargElementType(), definitionSupplier, reporter));
+        KotlinTypeInfo.create(kmType, factory, reporter),
+        KotlinTypeInfo.create(kmValueParameter.getVarargElementType(), factory, reporter));
   }
 
   static List<KotlinValueParameterInfo> create(
-      List<KmValueParameter> parameters,
-      DexDefinitionSupplier definitionSupplier,
-      Reporter reporter) {
+      List<KmValueParameter> parameters, DexItemFactory factory, Reporter reporter) {
     if (parameters.isEmpty()) {
       return EMPTY_VALUE_PARAMETERS;
     }
     ImmutableList.Builder<KotlinValueParameterInfo> builder = ImmutableList.builder();
     for (KmValueParameter parameter : parameters) {
-      builder.add(create(parameter, definitionSupplier, reporter));
+      builder.add(create(parameter, factory, reporter));
     }
     return builder.build();
   }
 
   void rewrite(
       KmVisitorProviders.KmValueParameterVisitorProvider visitorProvider,
-      AppView<AppInfoWithLiveness> appView,
+      AppView<?> appView,
       NamingLens namingLens) {
     KmValueParameterVisitor kmValueParameterVisitor = visitorProvider.get(flags, name);
     type.rewrite(kmValueParameterVisitor::visitType, appView, namingLens);
@@ -76,4 +77,12 @@
           kmValueParameterVisitor::visitVarargElementType, appView, namingLens);
     }
   }
+
+  @Override
+  public void trace(DexDefinitionSupplier definitionSupplier) {
+    type.trace(definitionSupplier);
+    if (varargElementType != null) {
+      varargElementType.trace(definitionSupplier);
+    }
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinVersionRequirementInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinVersionRequirementInfo.java
new file mode 100644
index 0000000..9530f4c
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinVersionRequirementInfo.java
@@ -0,0 +1,82 @@
+// Copyright (c) 2020, 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.google.common.collect.ImmutableList;
+import java.util.List;
+import kotlinx.metadata.KmVersion;
+import kotlinx.metadata.KmVersionRequirement;
+import kotlinx.metadata.KmVersionRequirementLevel;
+import kotlinx.metadata.KmVersionRequirementVersionKind;
+import kotlinx.metadata.KmVersionRequirementVisitor;
+
+class KotlinVersionRequirementInfo {
+
+  private static final KotlinVersionRequirementInfo NO_VERSION_REQUIREMENTS =
+      new KotlinVersionRequirementInfo(ImmutableList.of());
+
+  private final List<KotlinVersionRequirementPoint> versionRequirements;
+
+  private KotlinVersionRequirementInfo(List<KotlinVersionRequirementPoint> versionRequirements) {
+    this.versionRequirements = versionRequirements;
+  }
+
+  static KotlinVersionRequirementInfo create(List<KmVersionRequirement> kmVersionRequirements) {
+    if (kmVersionRequirements.isEmpty()) {
+      return NO_VERSION_REQUIREMENTS;
+    }
+    ImmutableList.Builder<KotlinVersionRequirementPoint> builder = ImmutableList.builder();
+    for (KmVersionRequirement kmVersionRequirement : kmVersionRequirements) {
+      builder.add(KotlinVersionRequirementPoint.create(kmVersionRequirement));
+    }
+    return new KotlinVersionRequirementInfo(builder.build());
+  }
+
+  public void rewrite(KmVisitorProviders.KmVersionRequirementVisitorProvider visitorProvider) {
+    if (this == NO_VERSION_REQUIREMENTS) {
+      return;
+    }
+    for (KotlinVersionRequirementPoint versionRequirement : versionRequirements) {
+      versionRequirement.rewrite(visitorProvider.get());
+    }
+  }
+
+  private static class KotlinVersionRequirementPoint {
+
+    private final Integer errorCode;
+    private final KmVersionRequirementVersionKind kind;
+    private final KmVersionRequirementLevel level;
+    private final String message;
+    private final KmVersion version;
+
+    private KotlinVersionRequirementPoint(
+        KmVersionRequirementVersionKind kind,
+        KmVersionRequirementLevel level,
+        Integer errorCode,
+        String message,
+        KmVersion version) {
+      this.errorCode = errorCode;
+      this.kind = kind;
+      this.level = level;
+      this.message = message;
+      this.version = version;
+    }
+
+    private static KotlinVersionRequirementPoint create(KmVersionRequirement kmVersionRequirement) {
+      return new KotlinVersionRequirementPoint(
+          kmVersionRequirement.kind,
+          kmVersionRequirement.level,
+          kmVersionRequirement.getErrorCode(),
+          kmVersionRequirement.getMessage(),
+          kmVersionRequirement.version);
+    }
+
+    private void rewrite(KmVersionRequirementVisitor visitor) {
+      visitor.visit(kind, level, errorCode, message);
+      visitor.visitVersion(version.getMajor(), version.getMinor(), version.getPatch());
+      visitor.visitEnd();
+    }
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/naming/Minifier.java b/src/main/java/com/android/tools/r8/naming/Minifier.java
index 8f1a41a..46117a7 100644
--- a/src/main/java/com/android/tools/r8/naming/Minifier.java
+++ b/src/main/java/com/android/tools/r8/naming/Minifier.java
@@ -17,7 +17,6 @@
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.SubtypingInfo;
-import com.android.tools.r8.kotlin.KotlinMetadataRewriter;
 import com.android.tools.r8.naming.ClassNameMinifier.ClassNamingStrategy;
 import com.android.tools.r8.naming.ClassNameMinifier.ClassRenaming;
 import com.android.tools.r8.naming.ClassNameMinifier.PackageNamingStrategy;
@@ -89,10 +88,6 @@
     new IdentifierMinifier(appView, lens).run(executorService);
     timing.end();
 
-    timing.begin("MinifyKotlinMetadata");
-    new KotlinMetadataRewriter(appView, lens).run(executorService);
-    timing.end();
-
     return lens;
   }
 
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
index 3ce8e7f..ef10483 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
@@ -18,7 +18,6 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.SubtypingInfo;
 import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
-import com.android.tools.r8.kotlin.KotlinMetadataRewriter;
 import com.android.tools.r8.naming.ClassNameMinifier.ClassRenaming;
 import com.android.tools.r8.naming.FieldNameMinifier.FieldRenaming;
 import com.android.tools.r8.naming.MemberNaming.FieldSignature;
@@ -175,10 +174,6 @@
     new IdentifierMinifier(appView, lens).run(executorService);
     timing.end();
 
-    timing.begin("MinifyKotlinMetadata");
-    new KotlinMetadataRewriter(appView, lens).run(executorService);
-    timing.end();
-
     return lens;
   }
 
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 6878c05..2bdfa26 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -2604,9 +2604,10 @@
     this.dontWarnPatterns = dontWarnPatterns;
     // Translate the result of root-set computation into enqueuer actions.
     if (appView.options().getProguardConfiguration() != null
-        && !options.kotlinOptimizationOptions().disableKotlinSpecificOptimizations
-        && mode.isInitialTreeShaking()) {
-      registerAnalysis(new KotlinMetadataEnqueuerExtension(appView, enqueuerDefinitionSupplier));
+        && !options.kotlinOptimizationOptions().disableKotlinSpecificOptimizations) {
+      registerAnalysis(
+          new KotlinMetadataEnqueuerExtension(
+              appView, enqueuerDefinitionSupplier, initialPrunedTypes));
     }
     if (appView.options().isShrinking() || appView.options().getProguardConfiguration() == null) {
       enqueueRootItems(rootSet.noShrinking);
diff --git a/src/main/java/com/android/tools/r8/shaking/EnqueuerMetadataTraceable.java b/src/main/java/com/android/tools/r8/shaking/EnqueuerMetadataTraceable.java
new file mode 100644
index 0000000..e17e571
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/shaking/EnqueuerMetadataTraceable.java
@@ -0,0 +1,12 @@
+// Copyright (c) 2020, 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.shaking;
+
+import com.android.tools.r8.graph.DexDefinitionSupplier;
+
+public interface EnqueuerMetadataTraceable {
+
+  void trace(DexDefinitionSupplier definitionSupplier);
+}
diff --git a/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java b/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java
index 196091e..1173ef5 100644
--- a/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java
@@ -512,6 +512,11 @@
     return 'L' + descriptor + ';';
   }
 
+  public static boolean isValidBinaryName(String binaryName) {
+    return isValidJavaType(
+        binaryName.replace(DESCRIPTOR_PACKAGE_SEPARATOR, JAVA_PACKAGE_SEPARATOR));
+  }
+
   public static class ModuleAndDescriptor {
     private final String module;
     private final String descriptor;
diff --git a/src/main/java/com/android/tools/r8/utils/FunctionUtils.java b/src/main/java/com/android/tools/r8/utils/FunctionUtils.java
new file mode 100644
index 0000000..64e8537
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/FunctionUtils.java
@@ -0,0 +1,18 @@
+// Copyright (c) 2020, 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.utils;
+
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+public class FunctionUtils {
+
+  public static <T, R> void forEachApply(
+      Iterable<T> list, Function<T, Consumer<R>> func, R argument) {
+    for (T t : list) {
+      func.apply(t).accept(argument);
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/KotlinMetadataTestBase.java b/src/test/java/com/android/tools/r8/kotlin/metadata/KotlinMetadataTestBase.java
index 87b5d10..99aaf1b 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/KotlinMetadataTestBase.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/KotlinMetadataTestBase.java
@@ -3,13 +3,25 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static junit.framework.TestCase.assertNotNull;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertNull;
+
 import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
 import com.android.tools.r8.kotlin.AbstractR8KotlinTestBase;
+import com.android.tools.r8.kotlin.KotlinMetadataWriter;
 import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
+import junit.framework.TestCase;
+import kotlinx.metadata.jvm.KotlinClassHeader;
+import kotlinx.metadata.jvm.KotlinClassMetadata;
 
-abstract class KotlinMetadataTestBase extends AbstractR8KotlinTestBase {
+public abstract class KotlinMetadataTestBase extends AbstractR8KotlinTestBase {
 
-  KotlinMetadataTestBase(KotlinTargetVersion targetVersion) {
+  public KotlinMetadataTestBase(KotlinTargetVersion targetVersion) {
     super(targetVersion);
   }
 
@@ -27,4 +39,29 @@
 
   static final String KT_FUNCTION1 = "Lkotlin/Function1;";
   static final String KT_COMPARABLE = "Lkotlin/Comparable;";
+
+  public void assertEqualMetadata(CodeInspector originalInspector, CodeInspector rewrittenInspector)
+      throws Exception {
+    for (FoundClassSubject clazzSubject : originalInspector.allClasses()) {
+      ClassSubject r8Clazz = rewrittenInspector.clazz(clazzSubject.getOriginalName());
+      assertThat(r8Clazz, isPresent());
+      KotlinClassMetadata originalMetadata = clazzSubject.getKotlinClassMetadata();
+      KotlinClassMetadata rewrittenMetadata = r8Clazz.getKotlinClassMetadata();
+      if (originalMetadata == null) {
+        assertNull(rewrittenMetadata);
+        continue;
+      }
+      assertNotNull(rewrittenMetadata);
+      KotlinClassHeader originalHeader = originalMetadata.getHeader();
+      KotlinClassHeader rewrittenHeader = rewrittenMetadata.getHeader();
+      TestCase.assertEquals(originalHeader.getKind(), rewrittenHeader.getKind());
+      // TODO(b/154199572): Should we check for meta-data version?
+      TestCase.assertEquals(originalHeader.getPackageName(), rewrittenHeader.getPackageName());
+      // We cannot assert equality of the data since it may be ordered differently. Instead we use
+      // the KotlinMetadataWriter.
+      String expected = KotlinMetadataWriter.kotlinMetadataToString("", originalMetadata);
+      String actual = KotlinMetadataWriter.kotlinMetadataToString("", rewrittenMetadata);
+      TestCase.assertEquals(expected, actual);
+    }
+  }
 }
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
new file mode 100644
index 0000000..11c47de
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java
@@ -0,0 +1,185 @@
+// Copyright (c) 2020, 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.metadata;
+
+import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isNotRenamed;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isRenamed;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
+import com.android.tools.r8.shaking.ProguardKeepAttributes;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.KmTypeAliasSubject;
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import kotlinx.metadata.KmAnnotation;
+import kotlinx.metadata.KmAnnotationArgument;
+import kotlinx.metadata.KmAnnotationArgument.ArrayValue;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class MetadataRewriteAnnotationTest extends KotlinMetadataTestBase {
+
+  private final String EXPECTED =
+      StringUtils.lines(
+          "class com.android.tools.r8.kotlin.metadata.annotation_lib.Foo",
+          "class com.android.tools.r8.kotlin.metadata.annotation_lib.Foo",
+          "class com.android.tools.r8.kotlin.metadata.annotation_lib.Bar",
+          "class com.android.tools.r8.kotlin.metadata.annotation_lib.Foo",
+          "UP",
+          "class com.android.tools.r8.kotlin.metadata.annotation_lib.Foo",
+          "LEFT",
+          "class com.android.tools.r8.kotlin.metadata.annotation_lib.Foo",
+          "RIGHT",
+          "class com.android.tools.r8.kotlin.metadata.annotation_lib.Foo",
+          "DOWN",
+          "class com.android.tools.r8.kotlin.metadata.annotation_lib.Foo",
+          "UP",
+          "Top most",
+          "class com.android.tools.r8.kotlin.metadata.annotation_lib.Foo",
+          "DOWN",
+          "com.android.tools.r8.kotlin.metadata.annotation_lib.Foo");
+  private static final String PKG_LIB = PKG + ".annotation_lib";
+  private static final String PKG_APP = PKG + ".annotation_app";
+  private static final String FOO_ORIGINAL_NAME = PKG_LIB + ".Foo";
+  private static final String FOO_FINAL_NAME = "a.b.c";
+
+  @Parameterized.Parameters(name = "{0} target: {1}")
+  public static Collection<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+  }
+
+  public MetadataRewriteAnnotationTest(
+      TestParameters parameters, KotlinTargetVersion targetVersion) {
+    super(targetVersion);
+    this.parameters = parameters;
+  }
+
+  private static Map<KotlinTargetVersion, Path> libJars = new HashMap<>();
+  private final TestParameters parameters;
+
+  @BeforeClass
+  public static void createLibJar() throws Exception {
+    for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
+      Path baseLibJar =
+          kotlinc(KOTLINC, targetVersion)
+              .addSourceFiles(
+                  getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib"))
+              .compile();
+      libJars.put(targetVersion, baseLibJar);
+    }
+  }
+
+  @Test
+  public void smokeTest() throws Exception {
+    Path libJar = libJars.get(targetVersion);
+    Path output =
+        kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+            .addClasspathFiles(libJar)
+            .addSourceFiles(
+                getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
+            .setOutputPath(temp.newFolder().toPath())
+            .compile();
+    testForJvm()
+        .addRunClasspathFiles(
+            ToolHelper.getKotlinStdlibJar(), ToolHelper.getKotlinReflectJar(), libJar)
+        .addClasspath(output)
+        .run(parameters.getRuntime(), PKG_APP + ".MainKt")
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
+  @Test
+  public void testMetadataForLib() throws Exception {
+    Path libJar =
+        testForR8(parameters.getBackend())
+            .addProgramFiles(libJars.get(targetVersion))
+            /// Keep the annotations
+            .addKeepClassAndMembersRules(PKG_LIB + ".AnnoWithClassAndEnum")
+            .addKeepClassAndMembersRules(PKG_LIB + ".AnnoWithClassArr")
+            .addKeepRules("-keep class " + PKG_LIB + ".Nested { *** kept(); } ")
+            .addKeepRules("-keep class " + PKG_LIB + ".Nested { *** message(); } ")
+            // .addKeepRules("-keep class " + PKG_LIB + ".Nested { *** kept; *** getKept(); } ")
+            // Keep Foo but rename to test arguments
+            .addKeepClassAndMembersRulesWithAllowObfuscation(FOO_ORIGINAL_NAME)
+            .addApplyMapping(FOO_ORIGINAL_NAME + " -> " + FOO_FINAL_NAME + ":")
+            // Keep Direction but rename the enum
+            .addKeepClassAndMembersRules(PKG_LIB + ".Direction")
+            // Keep Bar and Baz and Quux because we are directly reflecting on them
+            .addKeepClassAndMembersRules(PKG_LIB + ".Bar")
+            .addKeepClassAndMembersRules(PKG_LIB + ".Baz")
+            .addKeepClassAndMembersRules(PKG_LIB + ".Quux")
+            // Keep the static class for the type alias
+            .addKeepClassAndMembersRules(PKG_LIB + ".LibKt")
+            .addKeepAttributes(
+                ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS,
+                ProguardKeepAttributes.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS,
+                ProguardKeepAttributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS)
+            .compile()
+            .inspect(this::inspect)
+            .writeToZip();
+    Path output =
+        kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+            .addClasspathFiles(libJar)
+            .addSourceFiles(
+                getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
+            .compile();
+    testForJvm()
+        .addRunClasspathFiles(
+            ToolHelper.getKotlinStdlibJar(), ToolHelper.getKotlinReflectJar(), libJar)
+        .addProgramFiles(output)
+        .run(parameters.getRuntime(), PKG_APP + ".MainKt")
+        .assertSuccessWithOutput(EXPECTED.replace(FOO_ORIGINAL_NAME, FOO_FINAL_NAME));
+  }
+
+  private void inspect(CodeInspector inspector) {
+    // Assert that foo is renamed.
+    ClassSubject foo = inspector.clazz(PKG_LIB + ".Foo");
+    assertThat(foo, isRenamed());
+    assertEquals(FOO_FINAL_NAME, foo.getFinalName());
+    // Assert that bar exists and is not renamed.
+    ClassSubject bar = inspector.clazz(PKG_LIB + ".Bar");
+    assertThat(bar, isPresent());
+    assertThat(bar, isNotRenamed());
+    // Check that the annotation type on the type alias has been renamed
+    inspectTypeAliasAnnotation(inspector, foo, bar);
+  }
+
+  private void inspectTypeAliasAnnotation(
+      CodeInspector inspector, ClassSubject foo, ClassSubject bar) {
+    ClassSubject libKt = inspector.clazz(PKG_LIB + ".LibKt");
+    assertThat(libKt, isPresent());
+    assertThat(libKt.getKmPackage(), isPresent());
+    KmTypeAliasSubject qux = libKt.getKmPackage().kmTypeAliasWithUniqueName("Qux");
+    assertThat(qux, isPresent());
+    assertEquals(1, qux.annotations().size());
+    KmAnnotation annotation = qux.annotations().get(0);
+    assertEquals(
+        DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB) + "/AnnoWithClassArr",
+        annotation.getClassName());
+    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());
+    assertEquals(
+        "KClassValue(value=" + bar.getFinalBinaryName() + ")",
+        classes.getValue().get(1).toString());
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineAnonFunctionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineAnonFunctionTest.java
new file mode 100644
index 0000000..1ebdddb
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineAnonFunctionTest.java
@@ -0,0 +1,95 @@
+// Copyright (c) 2020, 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.metadata;
+
+import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.StringUtils;
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class MetadataRewriteCrossinlineAnonFunctionTest extends KotlinMetadataTestBase {
+
+  private final String EXPECTED = StringUtils.lines("foo");
+  private static final String PKG_LIB = PKG + ".crossinline_anon_lib";
+  private static final String PKG_APP = PKG + ".crossinline_anon_app";
+
+  @Parameterized.Parameters(name = "{0} target: {1}")
+  public static Collection<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+  }
+
+  public MetadataRewriteCrossinlineAnonFunctionTest(
+      TestParameters parameters, KotlinTargetVersion targetVersion) {
+    super(targetVersion);
+    this.parameters = parameters;
+  }
+
+  private static Map<KotlinTargetVersion, Path> libJars = new HashMap<>();
+  private final TestParameters parameters;
+
+  @BeforeClass
+  public static void createLibJar() throws Exception {
+    for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
+      Path baseLibJar =
+          kotlinc(KOTLINC, targetVersion)
+              .addSourceFiles(
+                  getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib"))
+              .compile();
+      libJars.put(targetVersion, baseLibJar);
+    }
+  }
+
+  @Test
+  public void smokeTest() throws Exception {
+    Path libJar = libJars.get(targetVersion);
+    Path output =
+        kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+            .addClasspathFiles(libJar)
+            .addSourceFiles(
+                getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
+            .setOutputPath(temp.newFolder().toPath())
+            .compile();
+    testForJvm()
+        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+        .addClasspath(output)
+        .run(parameters.getRuntime(), PKG_APP + ".MainKt")
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
+  @Test
+  public void testMetadataForLib() throws Exception {
+    Path libJar =
+        testForR8(parameters.getBackend())
+            .addProgramFiles(libJars.get(targetVersion))
+            .addKeepAllClassesRule()
+            .addKeepAllAttributes()
+            .compile()
+            .writeToZip();
+    Path output =
+        kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+            .addClasspathFiles(libJar)
+            .addSourceFiles(
+                getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
+            .compile();
+    testForJvm()
+        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+        .addProgramFiles(output)
+        .run(parameters.getRuntime(), PKG_APP + ".MainKt")
+        .assertSuccessWithOutput(EXPECTED);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineConcreteFunctionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineConcreteFunctionTest.java
new file mode 100644
index 0000000..ce26b77
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineConcreteFunctionTest.java
@@ -0,0 +1,96 @@
+// Copyright (c) 2020, 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.metadata;
+
+import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.StringUtils;
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class MetadataRewriteCrossinlineConcreteFunctionTest extends KotlinMetadataTestBase {
+
+  private final String EXPECTED = StringUtils.lines("foo");
+  private static final String PKG_LIB = PKG + ".crossinline_concrete_lib";
+  private static final String PKG_APP = PKG + ".crossinline_concrete_app";
+
+  @Parameterized.Parameters(name = "{0} target: {1}")
+  public static Collection<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+  }
+
+  public MetadataRewriteCrossinlineConcreteFunctionTest(
+      TestParameters parameters, KotlinTargetVersion targetVersion) {
+    super(targetVersion);
+    this.parameters = parameters;
+  }
+
+  private static Map<KotlinTargetVersion, Path> libJars = new HashMap<>();
+  private final TestParameters parameters;
+
+  @BeforeClass
+  public static void createLibJar() throws Exception {
+    for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
+      Path baseLibJar =
+          kotlinc(KOTLINC, targetVersion)
+              .addSourceFiles(
+                  getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib"))
+              .compile();
+      libJars.put(targetVersion, baseLibJar);
+    }
+  }
+
+  @Test
+  public void smokeTest() throws Exception {
+    Path libJar = libJars.get(targetVersion);
+    Path output =
+        kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+            .addClasspathFiles(libJar)
+            .addSourceFiles(
+                getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
+            .setOutputPath(temp.newFolder().toPath())
+            .compile();
+    testForJvm()
+        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+        .addClasspath(output)
+        .run(parameters.getRuntime(), PKG_APP + ".MainKt")
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
+  @Test
+  public void testMetadataForLib() throws Exception {
+    Path libJar =
+        testForR8(parameters.getBackend())
+            .addProgramFiles(libJars.get(targetVersion))
+            .addKeepAllClassesRule()
+            .addKeepAllAttributes()
+            .compile()
+            .writeToZip();
+    Path output =
+        kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+            .addClasspathFiles(libJar)
+            .addSourceFiles(
+                getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
+            .setOutputPath(temp.newFolder().toPath())
+            .compile();
+    testForJvm()
+        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+        .addClasspath(output)
+        .run(parameters.getRuntime(), PKG_APP + ".MainKt")
+        .assertSuccessWithOutput(EXPECTED);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java
new file mode 100644
index 0000000..95da64e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java
@@ -0,0 +1,93 @@
+// Copyright (c) 2020, 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.metadata;
+
+import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
+import com.android.tools.r8.shaking.ProguardKeepAttributes;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class MetadataRewriteDelegatedPropertyTest extends KotlinMetadataTestBase {
+
+  private static final String PKG_APP = PKG + ".delegated_property_app";
+  private static final String EXPECTED_MAIN =
+      StringUtils.lines(
+          "Initial string has been read in CustomDelegate from 'x'",
+          "Initial string has been read in CustomDelegate from 'x'",
+          "New value has been read in CustomDelegate from 'x'",
+          "New value has been read in CustomDelegate from 'x'",
+          "null",
+          "New value has been read in CustomDelegate from 'x'");
+
+  @Parameterized.Parameters(name = "{0} target: {1}")
+  public static Collection<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+  }
+
+  public MetadataRewriteDelegatedPropertyTest(
+      TestParameters parameters, KotlinTargetVersion targetVersion) {
+    super(targetVersion);
+    this.parameters = parameters;
+  }
+
+  private final TestParameters parameters;
+  private static Map<KotlinTargetVersion, Path> jars = new HashMap<>();
+
+  @BeforeClass
+  public static void createJar() throws Exception {
+    for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
+      Path baseLibJar =
+          kotlinc(KOTLINC, targetVersion)
+              .addSourceFiles(
+                  getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
+              .compile();
+      jars.put(targetVersion, baseLibJar);
+    }
+  }
+
+  @Test
+  public void smokeTest() throws Exception {
+    testForJvm()
+        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), ToolHelper.getKotlinReflectJar())
+        .addClasspath(jars.get(targetVersion))
+        .run(parameters.getRuntime(), PKG_APP + ".MainKt")
+        .assertSuccessWithOutput(EXPECTED_MAIN);
+  }
+
+  @Test
+  public void testMetadataForLib() throws Exception {
+    Path outputJar =
+        testForR8(parameters.getBackend())
+            .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
+            .addProgramFiles(jars.get(targetVersion))
+            .addKeepAllClassesRule()
+            .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
+            .compile()
+            .inspect(
+                inspector ->
+                    assertEqualMetadata(new CodeInspector(jars.get(targetVersion)), inspector))
+            .writeToZip();
+    testForJvm()
+        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), ToolHelper.getKotlinReflectJar())
+        .addClasspath(outputJar)
+        .run(parameters.getRuntime(), PKG_APP + ".MainKt")
+        .assertSuccessWithOutput(EXPECTED_MAIN);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDoNotEmitValuesIfEmpty.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDoNotEmitValuesIfEmpty.java
new file mode 100644
index 0000000..788e64b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDoNotEmitValuesIfEmpty.java
@@ -0,0 +1,81 @@
+// Copyright (c) 2020, 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.metadata;
+
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
+import com.android.tools.r8.graph.DexAnnotationElement;
+import com.android.tools.r8.shaking.ProguardKeepAttributes;
+import com.android.tools.r8.utils.codeinspector.AnnotationSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
+import com.google.common.collect.Sets;
+import java.util.Collection;
+import java.util.Set;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class MetadataRewriteDoNotEmitValuesIfEmpty extends KotlinMetadataTestBase {
+
+  private final Set<String> nullableFieldKeys = Sets.newHashSet("pn", "xs", "xi");
+
+  @Parameterized.Parameters(name = "{0} target: {1}")
+  public static Collection<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+  }
+
+  private final TestParameters parameters;
+
+  public MetadataRewriteDoNotEmitValuesIfEmpty(
+      TestParameters parameters, KotlinTargetVersion targetVersion) {
+    super(targetVersion);
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testKotlinStdLib() throws Exception {
+    testForR8(parameters.getBackend())
+        .addProgramFiles(ToolHelper.getKotlinStdlibJar())
+        .setMinApi(parameters.getApiLevel())
+        .addKeepAllClassesRule()
+        .addKeepKotlinMetadata()
+        .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
+        .compile()
+        .inspect(this::inspectEmptyValuesAreNotPresent);
+  }
+
+  private void inspectEmptyValuesAreNotPresent(CodeInspector inspector) {
+    boolean seenNullableField = false;
+    boolean seenMetadataWithoutNullableField = false;
+    for (FoundClassSubject clazz : inspector.allClasses()) {
+      AnnotationSubject annotation = clazz.annotation("kotlin.Metadata");
+      if (annotation.isPresent()) {
+        boolean seenNullableFieldForAnnotation = false;
+        for (DexAnnotationElement element : annotation.getAnnotation().elements) {
+          if (nullableFieldKeys.contains(element.name.toString())) {
+            if (element.value.isDexValueInt()) {
+              assertNotEquals(0, element.value.asDexValueInt().value);
+            } else {
+              String value = element.value.asDexValueString().value.toString();
+              assertNotEquals("", value);
+            }
+            seenNullableField = true;
+            seenNullableFieldForAnnotation = true;
+          }
+        }
+        seenMetadataWithoutNullableField |= !seenNullableFieldForAnnotation;
+      }
+    }
+    assertTrue(seenNullableField);
+    assertTrue(seenMetadataWithoutNullableField);
+  }
+}
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
new file mode 100644
index 0000000..2d3834b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteJvmStaticTest.java
@@ -0,0 +1,156 @@
+// Copyright (c) 2020, 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.metadata;
+
+import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
+import com.android.tools.r8.kotlin.metadata.jvmstatic_app.MainJava;
+import com.android.tools.r8.shaking.ProguardKeepAttributes;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.KmClassSubject;
+import com.android.tools.r8.utils.codeinspector.KmFunctionSubject;
+import com.android.tools.r8.utils.codeinspector.KmPropertySubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class MetadataRewriteJvmStaticTest extends KotlinMetadataTestBase {
+
+  private static final String EXPECTED =
+      StringUtils.lines("Hello, Hello", "Calling func...", "Foo");
+  private static final String PKG_LIB = PKG + ".jvmstatic_lib";
+  private static final String PKG_APP = PKG + ".jvmstatic_app";
+
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0} target: {1}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withCfRuntimes().build();
+  }
+
+  public MetadataRewriteJvmStaticTest(TestParameters parameters) {
+    // We are testing static methods on interfaces which requires java 8.
+    super(KotlinTargetVersion.JAVA_8);
+    this.parameters = parameters;
+  }
+
+  private static Path kotlincLibJar = Paths.get("");
+
+  @BeforeClass
+  public static void createLibJar() throws Exception {
+    kotlincLibJar =
+        kotlinc(KOTLINC, KotlinTargetVersion.JAVA_8)
+            .addSourceFiles(
+                getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib"))
+            .compile();
+  }
+
+  @Test
+  public void smokeTest() throws Exception {
+    Path output =
+        kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+            .addClasspathFiles(kotlincLibJar)
+            .addSourceFiles(
+                getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
+            .setOutputPath(temp.newFolder().toPath())
+            .compile();
+    testForJvm()
+        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), kotlincLibJar)
+        .addClasspath(output)
+        .run(parameters.getRuntime(), PKG_APP + ".MainKt")
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
+  @Test
+  public void smokeTestJava() throws Exception {
+    testForJvm()
+        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), kotlincLibJar)
+        .addProgramClassFileData(MainJava.dump())
+        .run(parameters.getRuntime(), MainJava.class)
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
+  @Test
+  public void testMetadata() throws Exception {
+    Path libJar =
+        testForR8(parameters.getBackend())
+            .addProgramFiles(kotlincLibJar)
+            .addKeepAllClassesRule()
+            .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
+            .compile()
+            .inspect(this::inspect)
+            .writeToZip();
+    testKotlin(libJar);
+    testJava(libJar);
+  }
+
+  private void testKotlin(Path libJar) throws Exception {
+    Path output =
+        kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+            .addClasspathFiles(libJar)
+            .addSourceFiles(
+                getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
+            .setOutputPath(temp.newFolder().toPath())
+            .compile();
+    testForJvm()
+        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+        .addClasspath(output)
+        .run(parameters.getRuntime(), PKG_APP + ".MainKt")
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
+  private void testJava(Path libJar) throws Exception {
+    testForJvm()
+        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+        .addProgramClassFileData(MainJava.dump())
+        .run(parameters.getRuntime(), MainJava.class)
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
+  private void inspect(CodeInspector inspector) {
+    inspectLib(inspector);
+    inspectInterfaceWithCompanion(inspector);
+  }
+
+  private void inspectLib(CodeInspector inspector) {
+    ClassSubject clazz = inspector.clazz(PKG_LIB + ".Lib");
+    assertThat(clazz, isPresent());
+    KmClassSubject kmClass = clazz.getKmClass();
+    assertThat(kmClass, isPresent());
+    KmFunctionSubject staticFun = kmClass.kmFunctionWithUniqueName("staticFun");
+    assertThat(staticFun, isPresent());
+    assertEquals("staticFun(Lkotlin/jvm/functions/Function0;)V", staticFun.signature().asString());
+    KmPropertySubject staticProp = kmClass.kmPropertyWithUniqueName("staticProp");
+    assertThat(staticProp, isPresent());
+  }
+
+  private void inspectInterfaceWithCompanion(CodeInspector inspector) {
+    ClassSubject itf = inspector.clazz(PKG_LIB + ".InterfaceWithCompanion");
+    assertThat(itf, isPresent());
+    MethodSubject greet = itf.uniqueMethodWithName("greet");
+    assertThat(greet, isPresent());
+
+    ClassSubject itfCompanion = inspector.clazz(PKG_LIB + ".InterfaceWithCompanion$Companion");
+    assertThat(itfCompanion, isPresent());
+    KmClassSubject kmClass = itfCompanion.getKmClass();
+    KmFunctionSubject greetKm = kmClass.kmFunctionWithUniqueName("greet");
+    assertThat(greetKm, isPresent());
+    assertEquals("greet(Ljava/lang/String;)V", greetKm.signature().asString());
+  }
+}
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 a17f7dc..71d888c 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
@@ -4,25 +4,12 @@
 
 package com.android.tools.r8.kotlin.metadata;
 
-import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static junit.framework.TestCase.assertEquals;
-import static junit.framework.TestCase.assertNotNull;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertNull;
-
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
-import com.android.tools.r8.kotlin.KotlinMetadataWriter;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
-import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
-import java.io.IOException;
 import java.util.Collection;
-import java.util.concurrent.ExecutionException;
-import kotlinx.metadata.jvm.KotlinClassHeader;
-import kotlinx.metadata.jvm.KotlinClassMetadata;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -53,31 +40,8 @@
         .addKeepKotlinMetadata()
         .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
         .compile()
-        .inspect(this::inspect);
-  }
-
-  public void inspect(CodeInspector inspector) throws IOException, ExecutionException {
-    CodeInspector stdLibInspector = new CodeInspector(ToolHelper.getKotlinStdlibJar());
-    for (FoundClassSubject clazzSubject : stdLibInspector.allClasses()) {
-      ClassSubject r8Clazz = inspector.clazz(clazzSubject.getOriginalName());
-      assertThat(r8Clazz, isPresent());
-      KotlinClassMetadata originalMetadata = clazzSubject.getKotlinClassMetadata();
-      KotlinClassMetadata rewrittenMetadata = r8Clazz.getKotlinClassMetadata();
-      if (originalMetadata == null) {
-        assertNull(rewrittenMetadata);
-        continue;
-      }
-      assertNotNull(rewrittenMetadata);
-      KotlinClassHeader originalHeader = originalMetadata.getHeader();
-      KotlinClassHeader rewrittenHeader = rewrittenMetadata.getHeader();
-      assertEquals(originalHeader.getKind(), rewrittenHeader.getKind());
-      // TODO(b/154199572): Should we check for meta-data version?
-      assertEquals(originalHeader.getPackageName(), rewrittenHeader.getPackageName());
-      // We cannot assert equality of the data since it may be ordered differently. Instead we use
-      // the KotlinMetadataWriter.
-      String expected = KotlinMetadataWriter.kotlinMetadataToString("", originalMetadata);
-      String actual = KotlinMetadataWriter.kotlinMetadataToString("", rewrittenMetadata);
-      assertEquals(expected, actual);
-    }
+        .inspect(
+            inspector ->
+                assertEqualMetadata(new CodeInspector(ToolHelper.getKotlinStdlibJar()), inspector));
   }
 }
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePrunedObjectsTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePrunedObjectsTest.java
new file mode 100644
index 0000000..2a33484
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePrunedObjectsTest.java
@@ -0,0 +1,115 @@
+// Copyright (c) 2020, 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.metadata;
+
+import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static junit.framework.TestCase.assertEquals;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.KmClassSubject;
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class MetadataRewritePrunedObjectsTest extends KotlinMetadataTestBase {
+
+  private final String EXPECTED = StringUtils.lines("42");
+  private static final String PKG_LIB = PKG + ".pruned_lib";
+  private static final String PKG_APP = PKG + ".pruned_app";
+
+  private static Map<KotlinTargetVersion, Path> libJars = new HashMap<>();
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0} target: {1}")
+  public static Collection<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+  }
+
+  public MetadataRewritePrunedObjectsTest(
+      TestParameters parameters, KotlinTargetVersion targetVersion) {
+    super(targetVersion);
+    this.parameters = parameters;
+  }
+
+  @BeforeClass
+  public static void createLibJar() throws Exception {
+    for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
+      Path baseLibJar =
+          kotlinc(KOTLINC, targetVersion)
+              .addSourceFiles(
+                  getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib"))
+              .compile();
+      libJars.put(targetVersion, baseLibJar);
+    }
+  }
+
+  @Test
+  public void smokeTest() throws Exception {
+    Path libJar = libJars.get(targetVersion);
+    Path output =
+        kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+            .addClasspathFiles(libJar)
+            .addSourceFiles(
+                getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
+            .setOutputPath(temp.newFolder().toPath())
+            .compile();
+    testForJvm()
+        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+        .addClasspath(output)
+        .run(parameters.getRuntime(), PKG_APP + ".MainKt")
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
+  @Test
+  public void testMetadataForLib() throws Exception {
+    Path libJar =
+        testForR8(parameters.getBackend())
+            .addProgramFiles(libJars.get(targetVersion))
+            .addKeepRules("-keep class " + PKG_LIB + ".Sub { <init>(); *** kept(); }")
+            .addKeepRuntimeVisibleAnnotations()
+            .noMinification()
+            .compile()
+            .inspect(this::checkPruned)
+            .writeToZip();
+    Path output =
+        kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+            .addClasspathFiles(libJar)
+            .addSourceFiles(
+                getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
+            .compile();
+    testForJvm()
+        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+        .addProgramFiles(output)
+        .run(parameters.getRuntime(), PKG_APP + ".MainKt")
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
+  private void checkPruned(CodeInspector inspector) {
+    ClassSubject base = inspector.clazz(PKG_LIB + ".Base");
+    assertThat(base, not(isPresent()));
+    ClassSubject sub = inspector.clazz(PKG_LIB + ".Sub");
+    assertThat(sub, isPresent());
+    KmClassSubject kmClass = sub.getKmClass();
+    assertThat(kmClass, isPresent());
+    assertEquals(0, kmClass.getSuperTypes().size());
+    assertThat(kmClass.kmFunctionWithUniqueName("notKept"), not(isPresent()));
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/annotation_app/main.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/annotation_app/main.kt
new file mode 100644
index 0000000..d7ed237
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/annotation_app/main.kt
@@ -0,0 +1,47 @@
+// Copyright (c) 2020, 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.metadata.annotation_app
+
+import com.android.tools.r8.kotlin.metadata.annotation_lib.AnnoWithClassAndEnum
+import com.android.tools.r8.kotlin.metadata.annotation_lib.AnnoWithClassArr
+import com.android.tools.r8.kotlin.metadata.annotation_lib.Bar
+import com.android.tools.r8.kotlin.metadata.annotation_lib.Baz
+import com.android.tools.r8.kotlin.metadata.annotation_lib.Nested
+import com.android.tools.r8.kotlin.metadata.annotation_lib.Quux
+import kotlin.reflect.full.memberProperties
+import kotlin.reflect.full.primaryConstructor
+import kotlin.reflect.full.valueParameters
+
+fun main() {
+  Bar::class.primaryConstructor?.annotations?.get(0)?.printAnnoWithClassArr()
+  Baz::class.annotations.get(0).printAnnoWithClassArr()
+  Baz::class.annotations.get(1).printAnnoWithClassAndEnum()
+  Baz::prop.annotations.get(0).printAnnoWithClassAndEnum()
+  Baz::baz.annotations.get(0).printAnnoWithClassAndEnum()
+  Baz::baz.valueParameters.get(0).annotations.get(0).printAnnoWithClassAndEnum()
+  // We cannot reflect on annotations on typealiases:
+  // https://youtrack.jetbrains.com/issue/KT-21489
+  Quux::methodWithTypeAnnotations
+      .returnType.arguments.get(0).type?.annotations?.get(0)?.printAnnoWithClassAndEnum()
+  val nested = Quux::methodWithNestedAnnotations.returnType.arguments[0].type?.annotations?.get(0) as Nested
+  println(nested.message)
+  nested.kept.printAnnoWithClassAndEnum()
+  if (nested::class::memberProperties.get().any { it.name.equals("notKept") }) {
+    println("com.android.tools.r8.kotlin.metadata.annotation_lib.Foo")
+  } else {
+    println("a.b.c")
+  }
+}
+
+fun Annotation.printAnnoWithClassArr() {
+  val annoWithClassArr = this as AnnoWithClassArr
+  annoWithClassArr.classes.forEach { println(it) }
+}
+
+fun Annotation.printAnnoWithClassAndEnum() {
+  val annoWithClassAndEnum = this as AnnoWithClassAndEnum
+  println(annoWithClassAndEnum.clazz)
+  println(annoWithClassAndEnum.direction)
+}
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/annotation_lib/lib.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/annotation_lib/lib.kt
new file mode 100644
index 0000000..0c6ff6c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/annotation_lib/lib.kt
@@ -0,0 +1,61 @@
+// Copyright (c) 2020, 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.metadata.annotation_lib
+
+import kotlin.reflect.KClass
+
+enum class Direction {
+  UP, RIGHT, DOWN, LEFT
+}
+
+@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION,
+        AnnotationTarget.VALUE_PARAMETER,
+        AnnotationTarget.PROPERTY,
+        AnnotationTarget.TYPE)
+@Retention(AnnotationRetention.RUNTIME)
+annotation class AnnoWithClassAndEnum(val clazz : KClass<*>, val direction : Direction)
+
+@Target(AnnotationTarget.CLASS, AnnotationTarget.CONSTRUCTOR, AnnotationTarget.TYPEALIAS,
+        AnnotationTarget.TYPE)
+@Retention(AnnotationRetention.RUNTIME)
+annotation class AnnoWithClassArr(val classes: Array<KClass<*>>)
+
+class Foo
+
+class Bar @AnnoWithClassArr([Foo::class]) constructor()
+
+@AnnoWithClassArr([Foo::class, Bar::class])
+@AnnoWithClassAndEnum(Foo::class, Direction.UP) class Baz {
+
+  @AnnoWithClassAndEnum(Foo::class, Direction.LEFT) val prop : Int = 0
+
+  @AnnoWithClassAndEnum(Foo::class, Direction.RIGHT) fun baz(@AnnoWithClassAndEnum(Foo::class, Direction.DOWN) foo: Int): Int {
+    return 1
+  }
+}
+
+@AnnoWithClassArr([Foo::class, Bar::class])
+typealias Qux = Foo
+
+annotation class AnnoNotKept
+
+@Target(AnnotationTarget.TYPE)
+annotation class Nested(
+  val message: String,
+  val kept: AnnoWithClassAndEnum,
+  val notKept: AnnoNotKept
+)
+
+class Quux {
+
+  fun methodWithTypeAnnotations() : Array<@AnnoWithClassAndEnum(Foo::class, Direction.UP) Int> {
+    return arrayOf(1)
+  }
+
+  fun methodWithNestedAnnotations() : Array<@Nested("Top most", AnnoWithClassAndEnum(Foo::class, Direction.DOWN), AnnoNotKept()) Int> {
+    return arrayOf(1)
+  }
+}
+
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/crossinline_anon_app/main.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/crossinline_anon_app/main.kt
new file mode 100644
index 0000000..99a3882
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/crossinline_anon_app/main.kt
@@ -0,0 +1,18 @@
+// Copyright (c) 2020, 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.metadata.crossinline_anon_app
+
+import com.android.tools.r8.kotlin.metadata.crossinline_anon_lib.Context
+import com.android.tools.r8.kotlin.metadata.crossinline_anon_lib.Handler
+
+fun main() {
+  Handler({ context, throwable ->
+    println(context)
+  }).handle(object : Context {
+    override fun toString(): String {
+      return "foo"
+    }
+  }, NullPointerException())
+}
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/crossinline_anon_lib/lib.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/crossinline_anon_lib/lib.kt
new file mode 100644
index 0000000..b820f4a
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/crossinline_anon_lib/lib.kt
@@ -0,0 +1,19 @@
+// Copyright (c) 2020, 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.metadata.crossinline_anon_lib
+
+public interface Context {
+
+}
+
+public inline fun Handler(crossinline handler: (Context, Throwable) -> Unit): Handler =
+  object : Handler {
+    override fun handle(context: Context, exception: Throwable) =
+      handler.invoke(context, exception)
+  }
+
+public interface Handler {
+  fun handle(context: Context, exception: Throwable)
+}
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/crossinline_concrete_app/main.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/crossinline_concrete_app/main.kt
new file mode 100644
index 0000000..4c5c3a7
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/crossinline_concrete_app/main.kt
@@ -0,0 +1,18 @@
+// Copyright (c) 2020, 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.metadata.crossinline_concrete_app
+
+import com.android.tools.r8.kotlin.metadata.crossinline_concrete_lib.Context
+import com.android.tools.r8.kotlin.metadata.crossinline_concrete_lib.Handler
+
+fun main() {
+  Handler({ context, throwable ->
+    println(context)
+  }).handle(object : Context {
+    override fun toString(): String {
+      return "foo"
+    }
+  }, NullPointerException())
+}
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/crossinline_concrete_lib/lib.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/crossinline_concrete_lib/lib.kt
new file mode 100644
index 0000000..cf5da42
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/crossinline_concrete_lib/lib.kt
@@ -0,0 +1,25 @@
+// Copyright (c) 2020, 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.metadata.crossinline_concrete_lib
+
+public interface Context {
+
+}
+
+public inline fun Handler(crossinline handler: (Context, Throwable) -> Unit): Handler =
+  ConcreteClass().getHandler(handler)
+
+class ConcreteClass {
+
+  inline fun getHandler(crossinline handler: (Context, Throwable) -> Unit): Handler =
+    object : Handler {
+      override fun handle(context: Context, exception: Throwable) =
+        handler.invoke(context, exception)
+    }
+}
+
+public interface Handler {
+  fun handle(context: Context, exception: Throwable)
+}
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/delegated_property_app/main.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/delegated_property_app/main.kt
new file mode 100644
index 0000000..a35754f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/delegated_property_app/main.kt
@@ -0,0 +1,59 @@
+// Copyright (c) 2020, 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.metadata.delegated_property_app
+
+import kotlin.reflect.KMutableProperty1
+import kotlin.reflect.KProperty
+import kotlin.reflect.full.declaredMemberProperties
+import kotlin.reflect.jvm.isAccessible
+
+class Resource(private var s : String = "Initial string") {
+
+  override fun toString(): String {
+    return s;
+  }
+}
+
+object CustomDelegate {
+
+  private var resource : Resource = Resource()
+
+  operator fun getValue(thisRef: Any?, property: KProperty<*>): Resource {
+    println("$resource has been read in CustomDelegate from '${property.name}'")
+    return resource;
+  }
+
+  operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Resource) {
+    println("$value has been assigned to '${property.name}'")
+    this.resource = resource;
+  }
+}
+
+open class Base {
+
+  fun doSomethingOnBarRef() : Resource {
+    var x by CustomDelegate
+    val propRef = x.javaClass.kotlin.declaredMemberProperties.first() as KMutableProperty1<Resource, String>
+    propRef.isAccessible = true
+    propRef.set(x, "New value")
+    propRef.get(x)
+    // Getting the delegate is not yet supported and will return null. We are printing the value
+    // allowing us to observe if the behavior changes.
+    println(propRef.getDelegate(x))
+    return x
+  }
+}
+
+object Impl : Base() {
+  operator fun invoke(): Impl {
+    return this
+  }
+}
+
+
+fun main() {
+  val impl = Impl()
+  impl.doSomethingOnBarRef()
+}
+
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/jvmstatic_app/MainJava.java b/src/test/java/com/android/tools/r8/kotlin/metadata/jvmstatic_app/MainJava.java
new file mode 100644
index 0000000..cfae3ef
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/jvmstatic_app/MainJava.java
@@ -0,0 +1,130 @@
+// Copyright (c) 2020, 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.metadata.jvmstatic_app;
+
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Handle;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+public class MainJava implements Opcodes {
+
+  // The java code cannot reference the kotlin-code when running in gradle, so we have it here
+  // as a dump.
+
+  // public static void main(String[] args) {
+  //   InterfaceWithCompanion.greet("Hello");
+  //   Lib.staticFun(() -> true);
+  //   Lib.setStaticProp("Foo");
+  //   System.out.println(Lib.getStaticProp());
+  // }
+
+  public static byte[] dump() {
+
+    ClassWriter classWriter = new ClassWriter(0);
+    MethodVisitor methodVisitor;
+
+    classWriter.visit(
+        V1_8,
+        ACC_PUBLIC | ACC_SUPER,
+        "com/android/tools/r8/kotlin/metadata/jvmstatic_app/MainJava",
+        null,
+        "java/lang/Object",
+        null);
+
+    classWriter.visitInnerClass(
+        "java/lang/invoke/MethodHandles$Lookup",
+        "java/lang/invoke/MethodHandles",
+        "Lookup",
+        ACC_PUBLIC | ACC_FINAL | ACC_STATIC);
+
+    {
+      methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+      methodVisitor.visitCode();
+      methodVisitor.visitVarInsn(ALOAD, 0);
+      methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
+      methodVisitor.visitInsn(RETURN);
+      methodVisitor.visitMaxs(1, 1);
+      methodVisitor.visitEnd();
+    }
+    {
+      methodVisitor =
+          classWriter.visitMethod(
+              ACC_PUBLIC | ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
+      methodVisitor.visitCode();
+      methodVisitor.visitLdcInsn("Hello");
+      methodVisitor.visitMethodInsn(
+          INVOKESTATIC,
+          "com/android/tools/r8/kotlin/metadata/jvmstatic_lib/InterfaceWithCompanion",
+          "greet",
+          "(Ljava/lang/String;)V",
+          true);
+      methodVisitor.visitInvokeDynamicInsn(
+          "invoke",
+          "()Lkotlin/jvm/functions/Function0;",
+          new Handle(
+              Opcodes.H_INVOKESTATIC,
+              "java/lang/invoke/LambdaMetafactory",
+              "metafactory",
+              "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;",
+              false),
+          new Object[] {
+            Type.getType("()Ljava/lang/Object;"),
+            new Handle(
+                Opcodes.H_INVOKESTATIC,
+                "com/android/tools/r8/kotlin/metadata/jvmstatic_app/MainJava",
+                "lambda$main$0",
+                "()Ljava/lang/Boolean;",
+                false),
+            Type.getType("()Ljava/lang/Boolean;")
+          });
+      methodVisitor.visitMethodInsn(
+          INVOKESTATIC,
+          "com/android/tools/r8/kotlin/metadata/jvmstatic_lib/Lib",
+          "staticFun",
+          "(Lkotlin/jvm/functions/Function0;)V",
+          false);
+      methodVisitor.visitLdcInsn("Foo");
+      methodVisitor.visitMethodInsn(
+          INVOKESTATIC,
+          "com/android/tools/r8/kotlin/metadata/jvmstatic_lib/Lib",
+          "setStaticProp",
+          "(Ljava/lang/String;)V",
+          false);
+      methodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
+      methodVisitor.visitMethodInsn(
+          INVOKESTATIC,
+          "com/android/tools/r8/kotlin/metadata/jvmstatic_lib/Lib",
+          "getStaticProp",
+          "()Ljava/lang/String;",
+          false);
+      methodVisitor.visitMethodInsn(
+          INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
+      methodVisitor.visitInsn(RETURN);
+      methodVisitor.visitMaxs(2, 1);
+      methodVisitor.visitEnd();
+    }
+    {
+      methodVisitor =
+          classWriter.visitMethod(
+              ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC,
+              "lambda$main$0",
+              "()Ljava/lang/Boolean;",
+              null,
+              null);
+      methodVisitor.visitCode();
+      methodVisitor.visitInsn(ICONST_1);
+      methodVisitor.visitMethodInsn(
+          INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
+      methodVisitor.visitInsn(ARETURN);
+      methodVisitor.visitMaxs(1, 0);
+      methodVisitor.visitEnd();
+    }
+    classWriter.visitEnd();
+
+    return classWriter.toByteArray();
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/jvmstatic_app/main.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/jvmstatic_app/main.kt
new file mode 100644
index 0000000..6bd1218
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/jvmstatic_app/main.kt
@@ -0,0 +1,15 @@
+// Copyright (c) 2020, 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.metadata.jvmstatic_app
+
+import com.android.tools.r8.kotlin.metadata.jvmstatic_lib.InterfaceWithCompanion
+import com.android.tools.r8.kotlin.metadata.jvmstatic_lib.Lib
+
+fun main() {
+  InterfaceWithCompanion.greet("Hello")
+  Lib.staticFun { true }
+  Lib.staticProp = "Foo"
+  println(Lib.staticProp)
+}
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/jvmstatic_lib/lib.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/jvmstatic_lib/lib.kt
new file mode 100644
index 0000000..cc0f1fb
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/jvmstatic_lib/lib.kt
@@ -0,0 +1,25 @@
+// Copyright (c) 2020, 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.metadata.jvmstatic_lib
+
+interface InterfaceWithCompanion {
+  companion object {
+    @JvmStatic fun greet(username: String) {
+      println("Hello, $username")
+    }
+  }
+}
+
+object Lib {
+
+  @JvmStatic
+  fun staticFun(func : () -> Boolean) {
+    println("Calling func...")
+    func()
+  }
+
+  @JvmStatic
+  var staticProp : String = ""
+}
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/pruned_app/main.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/pruned_app/main.kt
new file mode 100644
index 0000000..fb35a60
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/pruned_app/main.kt
@@ -0,0 +1,11 @@
+// Copyright (c) 2020, 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.metadata.pruned_app
+
+import com.android.tools.r8.kotlin.metadata.pruned_lib.Sub
+
+fun main() {
+  println(Sub().kept())
+}
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/pruned_lib/lib.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/pruned_lib/lib.kt
new file mode 100644
index 0000000..3ceaa4d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/pruned_lib/lib.kt
@@ -0,0 +1,20 @@
+// Copyright (c) 2020, 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.metadata.pruned_lib
+
+// The Base class will be removed during
+open class Base
+
+class Sub : Base() {
+
+  fun notKept() : Boolean {
+    return true
+  }
+
+  fun kept() : Int {
+    return 42
+  }
+}
+
diff --git a/src/test/java/com/android/tools/r8/shaking/b134858535/EventPublisherTest.java b/src/test/java/com/android/tools/r8/shaking/b134858535/EventPublisherTest.java
index d4801ea..23a5616 100644
--- a/src/test/java/com/android/tools/r8/shaking/b134858535/EventPublisherTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/b134858535/EventPublisherTest.java
@@ -4,6 +4,8 @@
 
 package com.android.tools.r8.shaking.b134858535;
 
+import static org.hamcrest.CoreMatchers.containsString;
+
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.utils.AndroidApiLevel;
@@ -26,7 +28,13 @@
         .addProgramClassFileData(EventPublisher$bDump.dump())
         .addKeepClassRules(Interface.class)
         .addKeepMainRule(Main.class)
+        .allowDiagnosticInfoMessages()
         .setMinApi(AndroidApiLevel.L)
-        .compile();
+        .compile()
+        // TODO(b/157537996): Handle JStyle lambdas with private methods.
+        .assertAllInfoMessagesMatch(
+            containsString(
+                "Unrecognized Kotlin lambda"
+                    + " [com.android.tools.r8.shaking.b134858535.EventPublisher$b]"));
   }
 }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmTypeAliasSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmTypeAliasSubject.java
index 78ac796..622db02 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmTypeAliasSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmTypeAliasSubject.java
@@ -5,7 +5,9 @@
 package com.android.tools.r8.utils.codeinspector;
 
 import com.android.tools.r8.errors.Unreachable;
+import com.google.common.collect.ImmutableList;
 import java.util.List;
+import kotlinx.metadata.KmAnnotation;
 
 public class AbsentKmTypeAliasSubject extends KmTypeAliasSubject {
 
@@ -48,4 +50,9 @@
   public KmTypeSubject underlyingType() {
     return null;
   }
+
+  @Override
+  public List<KmAnnotation> annotations() {
+    return ImmutableList.of();
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmTypeAliasSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmTypeAliasSubject.java
index a07125c..396ef98 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmTypeAliasSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmTypeAliasSubject.java
@@ -9,6 +9,7 @@
 
 import java.util.List;
 import java.util.stream.Collectors;
+import kotlinx.metadata.KmAnnotation;
 import kotlinx.metadata.KmTypeAlias;
 
 public class FoundKmTypeAliasSubject extends KmTypeAliasSubject {
@@ -62,4 +63,9 @@
   public KmTypeSubject underlyingType() {
     return new KmTypeSubject(codeInspector, kmTypeAlias.underlyingType);
   }
+
+  @Override
+  public List<KmAnnotation> annotations() {
+    return kmTypeAlias.getAnnotations();
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/KmTypeAliasSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/KmTypeAliasSubject.java
index f87d368..8ff3c90 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/KmTypeAliasSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/KmTypeAliasSubject.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.utils.codeinspector;
 
 import java.util.List;
+import kotlinx.metadata.KmAnnotation;
 
 public abstract class KmTypeAliasSubject extends Subject {
 
@@ -17,4 +18,6 @@
   public abstract KmTypeSubject expandedType();
 
   public abstract KmTypeSubject underlyingType();
+
+  public abstract List<KmAnnotation> annotations();
 }