Rewrite expanded and underlying type for Kotlin type-aliases

Bug: 151194785
Change-Id: I1926288c7a3d9ad3fa4a9d5fd8d26308180a91fd
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignature.java b/src/main/java/com/android/tools/r8/graph/GenericSignature.java
index fa1ce28..3b4d284 100644
--- a/src/main/java/com/android/tools/r8/graph/GenericSignature.java
+++ b/src/main/java/com/android/tools/r8/graph/GenericSignature.java
@@ -306,7 +306,6 @@
     }
   }
 
-
   public static class ClassTypeSignature extends FieldTypeSignature {
     static final ClassTypeSignature UNKNOWN_CLASS_TYPE_SIGNATURE =
         new ClassTypeSignature(DexItemFactory.nullValueType, ImmutableList.of());
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 2495016..b4308b9 100644
--- a/src/main/java/com/android/tools/r8/kotlin/Kotlin.java
+++ b/src/main/java/com/android/tools/r8/kotlin/Kotlin.java
@@ -42,7 +42,7 @@
 
   public static final class ClassClassifiers {
 
-    public static final String arrayDescriptor = NAME + "/Array";
+    public static final String arrayBinaryName = NAME + "/Array";
   }
 
   // Mappings from JVM types to Kotlin types (of type DexType)
@@ -62,6 +62,7 @@
             // 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;")))
@@ -70,6 +71,7 @@
             .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;")))
@@ -101,13 +103,17 @@
                 factory.createType(addKotlinPrefix("collections/ListIterator;")))
             .put(factory.iterableType, factory.createType(addKotlinPrefix("collections/Iterable;")))
             .put(
-                factory.mapEntryType,
-                factory.createType(addKotlinPrefix("collections/Map$Entry;")))
+                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 + ";")))))
+                IntStream.rangeClosed(0, 22)
+                    .boxed()
+                    .collect(
+                        Collectors.toMap(
+                            i ->
+                                factory.createType(
+                                    addKotlinPrefix("jvm/functions/Function" + i + ";")),
+                            i -> factory.createType(addKotlinPrefix("Function" + i + ";")))))
             .build();
   }
 
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClass.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClass.java
index f8bd449..db37d8c 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClass.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClass.java
@@ -147,7 +147,7 @@
       if (!method.isInstanceInitializer()) {
         continue;
       }
-      KmConstructor constructor = synthesizer.toRenamedKmConstructor(method);
+      KmConstructor constructor = synthesizer.toRenamedKmConstructor(clazz, method);
       if (constructor != null) {
         constructors.add(constructor);
       }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinInfo.java
index ee07b83..e516ff9 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinInfo.java
@@ -18,10 +18,12 @@
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.Action;
+import com.android.tools.r8.utils.Reporter;
 import com.android.tools.r8.utils.StringUtils;
 import com.google.common.collect.ImmutableList;
 import java.util.Comparator;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.function.BiConsumer;
@@ -146,6 +148,7 @@
     KmDeclarationContainer kmDeclarationContainer = getDeclarations();
     rewriteFunctions(synthesizer, kmDeclarationContainer.getFunctions());
     rewriteProperties(synthesizer, kmDeclarationContainer.getProperties());
+    rewriteTypeAliases(synthesizer, kmDeclarationContainer.getTypeAliases());
   }
 
   private void rewriteFunctions(KotlinMetadataSynthesizer synthesizer, List<KmFunction> functions) {
@@ -164,6 +167,37 @@
     }
   }
 
+  private void rewriteTypeAliases(
+      KotlinMetadataSynthesizer synthesizer, List<KmTypeAlias> typeAliases) {
+    Iterator<KmTypeAlias> iterator = typeAliases.iterator();
+    while (iterator.hasNext()) {
+      KmTypeAlias typeAlias = iterator.next();
+      KotlinTypeInfo expandedRenamed =
+          KotlinTypeInfo.create(typeAlias.expandedType).toRenamed(synthesizer);
+      if (expandedRenamed == null) {
+        // If the expanded type is pruned, the type-alias is also removed. Type-aliases can refer to
+        // other type-aliases in the underlying type, however, we only remove a type-alias when the
+        // expanded type is removed making it impossible to construct any type that references the
+        // type-alias anyway.
+        // TODO(b/151719926): Add a test for the above.
+        iterator.remove();
+        continue;
+      }
+      typeAlias.setExpandedType(expandedRenamed.asKmType());
+      // Modify the underlying type (right-hand side) of the type-alias.
+      KotlinTypeInfo underlyingRenamed =
+          KotlinTypeInfo.create(typeAlias.underlyingType).toRenamed(synthesizer);
+      if (underlyingRenamed == null) {
+        Reporter reporter = synthesizer.appView.options().reporter;
+        reporter.warning(
+            KotlinMetadataDiagnostic.messageInvalidUnderlyingType(clazz, typeAlias.getName()));
+        iterator.remove();
+        continue;
+      }
+      typeAlias.setUnderlyingType(underlyingRenamed.asKmType());
+    }
+  }
+
   private void rewriteProperties(
       KotlinMetadataSynthesizer synthesizer, List<KmProperty> properties) {
     Map<String, KmPropertyGroup.Builder> propertyGroupBuilderMap = new HashMap<>();
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataDiagnostic.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataDiagnostic.java
new file mode 100644
index 0000000..da33940
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataDiagnostic.java
@@ -0,0 +1,49 @@
+// 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.Diagnostic;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.position.Position;
+
+public class KotlinMetadataDiagnostic implements Diagnostic {
+
+  private final Origin origin;
+  private final Position position;
+  private final String message;
+
+  public KotlinMetadataDiagnostic(Origin origin, Position position, String message) {
+    this.origin = origin;
+    this.position = position;
+    this.message = message;
+  }
+
+  @Override
+  public Origin getOrigin() {
+    return origin;
+  }
+
+  @Override
+  public Position getPosition() {
+    return position;
+  }
+
+  @Override
+  public String getDiagnosticMessage() {
+    return message;
+  }
+
+  static KotlinMetadataDiagnostic messageInvalidUnderlyingType(DexClass clazz, String typeAlias) {
+    return new KotlinMetadataDiagnostic(
+        clazz.getOrigin(),
+        Position.UNKNOWN,
+        "The type alias "
+            + typeAlias
+            + " in class "
+            + clazz.type.getName()
+            + " has an invalid underlying type. The type-alias is removed from the output.");
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizer.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizer.java
index 81984d1..65d7f7e 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizer.java
@@ -28,8 +28,10 @@
 import com.android.tools.r8.graph.GenericSignature.FormalTypeParameter;
 import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
 import com.android.tools.r8.graph.GenericSignature.TypeSignature;
+import com.android.tools.r8.graph.InnerClassAttribute;
 import com.android.tools.r8.kotlin.KotlinMemberInfo.KotlinFunctionInfo;
 import com.android.tools.r8.kotlin.KotlinMemberInfo.KotlinPropertyInfo;
+import com.android.tools.r8.kotlin.KotlinMetadataSynthesizerUtils.AddKotlinAnyType;
 import com.android.tools.r8.kotlin.KotlinMetadataSynthesizerUtils.KmVisitorOption;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -37,6 +39,7 @@
 import com.google.common.collect.ImmutableList;
 import java.util.List;
 import java.util.function.Consumer;
+import kotlinx.metadata.KmClassifier;
 import kotlinx.metadata.KmConstructor;
 import kotlinx.metadata.KmFunction;
 import kotlinx.metadata.KmProperty;
@@ -49,8 +52,8 @@
 
 class KotlinMetadataSynthesizer {
 
-  private final AppView<AppInfoWithLiveness> appView;
-  private final NamingLens lens;
+  final AppView<AppInfoWithLiveness> appView;
+  final NamingLens lens;
   private final List<KmTypeParameter> classTypeParameters;
 
   public KotlinMetadataSynthesizer(
@@ -120,7 +123,6 @@
   }
 
   private KmType toRenamedKmTypeWithClassifierForFieldSignature(
-      DexType type,
       KotlinTypeInfo originalTypeInfo,
       FieldTypeSignature fieldSignature,
       List<KmTypeParameter> typeParameters) {
@@ -135,7 +137,8 @@
           return value;
         },
         typeParameters,
-        appView.dexItemFactory());
+        appView.dexItemFactory(),
+        AddKotlinAnyType.ADD);
     return kmTypeBox.get();
   }
 
@@ -147,7 +150,7 @@
     if (typeSignature != null && typeSignature.isFieldTypeSignature()) {
       KmType renamedKmType =
           toRenamedKmTypeWithClassifierForFieldSignature(
-              type, originalTypeInfo, typeSignature.asFieldTypeSignature(), typeParameters);
+              originalTypeInfo, typeSignature.asFieldTypeSignature(), typeParameters);
       if (renamedKmType != null) {
         return renamedKmType;
       }
@@ -173,7 +176,7 @@
     return renamedKmType;
   }
 
-  KmConstructor toRenamedKmConstructor(DexEncodedMethod method) {
+  KmConstructor toRenamedKmConstructor(DexClass clazz, DexEncodedMethod method) {
     // Make sure it is an instance initializer and live.
     if (!method.isInstanceInitializer()
         || !appView.appInfo().liveMethods.contains(method.method)) {
@@ -204,6 +207,52 @@
     if (!populateKmValueParameters(method, signature, parameters, typeParameters)) {
       return null;
     }
+    // For inner, non-static classes, the type-parameter for the receiver should not have a
+    // value-parameter:
+    // val myInner : OuterNestedInner = nested.Inner(1)
+    // Will have value-parameters for the constructor:
+    // #  constructors: KmConstructor[
+    // #    KmConstructor{
+    // #      flags: 6,
+    // #      valueParameters: KmValueParameter[
+    // #        KmValueParameter{
+    // #          flags: 0,
+    // #          name: x,
+    // #          type: KmType{
+    // #            flags: 0,
+    // #            classifier: Class(name=kotlin/Int),
+    // #            arguments: KmTypeProjection[],
+    // #            abbreviatedType: null,
+    // #            outerType: null,
+    // #            raw: false,
+    // #            annotations: KmAnnotion[],
+    // #          },
+    // #          varargElementType: null,
+    // #        }
+    // #      ],
+    // #     signature: <init>(Lcom/android/tools/r8/kotlin/metadata/typealias_lib/Outer$Nested;I)V,
+    // #    }
+    // #  ],
+    // A bit weird since the signature obviously have two value-parameters.
+    List<InnerClassAttribute> innerClasses = clazz.getInnerClasses();
+    if (!parameters.isEmpty() && !innerClasses.isEmpty()) {
+      DexType immediateOuterType = null;
+      for (InnerClassAttribute innerClass : innerClasses) {
+        if (innerClass.getInner() == clazz.type) {
+          immediateOuterType = innerClass.getOuter();
+          break;
+        }
+      }
+      if (immediateOuterType != null) {
+        String classifier = toRenamedClassifier(immediateOuterType);
+        KmType potentialReceiver = parameters.get(0).getType();
+        if (potentialReceiver != null
+            && potentialReceiver.classifier instanceof KmClassifier.Class
+            && ((KmClassifier.Class) potentialReceiver.classifier).getName().equals(classifier)) {
+          parameters.remove(0);
+        }
+      }
+    }
     return kmConstructor;
   }
 
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizerUtils.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizerUtils.java
index c7c118c..67fb7da 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizerUtils.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizerUtils.java
@@ -33,26 +33,37 @@
     VISIT_PARENT
   }
 
+  // The AddKotlinAnyType is carrying around information regarding the need for adding the trivial
+  // type Kotlin/Any. The information is not consistently added, for example, for upper bounds
+  // the trivial bound is not recorded.
+  public enum AddKotlinAnyType {
+    ADD,
+    DISREGARD
+  }
+
   static void populateKmTypeFromSignature(
       FieldTypeSignature typeSignature,
       KotlinTypeInfo originalTypeInfo,
       Function<KmVisitorOption, KmTypeVisitor> typeVisitor,
       List<KmTypeParameter> allTypeParameters,
-      DexItemFactory factory) {
+      DexItemFactory factory,
+      AddKotlinAnyType addAny) {
     if (typeSignature.isClassTypeSignature()) {
       populateKmTypeFromClassTypeSignature(
           typeSignature.asClassTypeSignature(),
           originalTypeInfo,
           typeVisitor,
           allTypeParameters,
-          factory);
+          factory,
+          addAny);
     } else if (typeSignature.isArrayTypeSignature()) {
       populateKmTypeFromArrayTypeSignature(
           typeSignature.asArrayTypeSignature(),
           originalTypeInfo,
           typeVisitor,
           allTypeParameters,
-          factory);
+          factory,
+          addAny);
     } else if (typeSignature.isTypeVariableSignature()) {
       populateKmTypeFromTypeVariableSignature(
           typeSignature.asTypeVariableSignature(), typeVisitor, allTypeParameters);
@@ -81,13 +92,14 @@
       KotlinTypeInfo originalTypeInfo,
       Function<KmVisitorOption, KmTypeVisitor> typeVisitor,
       List<KmTypeParameter> allTypeParameters,
-      DexItemFactory factory) {
+      DexItemFactory factory,
+      AddKotlinAnyType addAny) {
     ArrayTypeSignature arrayTypeSignature = typeSignature.asArrayTypeSignature();
     if (!arrayTypeSignature.elementSignature().isFieldTypeSignature()) {
       return;
     }
     KmTypeVisitor kmType = typeVisitor.apply(KmVisitorOption.VISIT_NEW);
-    kmType.visitClass(ClassClassifiers.arrayDescriptor);
+    kmType.visitClass(ClassClassifiers.arrayBinaryName);
     KotlinTypeProjectionInfo projectionInfo =
         originalTypeInfo == null ? null : originalTypeInfo.getArgumentOrNull(0);
     populateKmTypeFromSignature(
@@ -104,7 +116,8 @@
           }
         },
         allTypeParameters,
-        factory);
+        factory,
+        addAny);
   }
 
   private static void populateKmTypeFromClassTypeSignature(
@@ -112,9 +125,10 @@
       KotlinTypeInfo originalTypeInfo,
       Function<KmVisitorOption, KmTypeVisitor> typeVisitor,
       List<KmTypeParameter> allTypeParameters,
-      DexItemFactory factory) {
+      DexItemFactory factory,
+      AddKotlinAnyType addAny) {
     // No need to record the trivial argument.
-    if (factory.objectType == typeSignature.type()) {
+    if (addAny == AddKotlinAnyType.DISREGARD && factory.objectType == typeSignature.type()) {
       return;
     }
     KmTypeVisitor kmType = typeVisitor.apply(KmVisitorOption.VISIT_NEW);
@@ -137,7 +151,8 @@
             }
           },
           allTypeParameters,
-          factory);
+          factory,
+          addAny);
     }
   }
 
@@ -249,6 +264,7 @@
           return parameter.visitUpperBound(flagsOf());
         },
         allTypeParameters,
-        factory);
+        factory,
+        AddKotlinAnyType.DISREGARD);
   }
 }
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 7e5e612..9826f3a 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeInfo.java
@@ -4,12 +4,19 @@
 
 package com.android.tools.r8.kotlin;
 
+import static kotlinx.metadata.FlagsKt.flagsOf;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.kotlin.Kotlin.ClassClassifiers;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.DescriptorUtils;
 import com.google.common.collect.ImmutableList;
 import java.util.List;
 import kotlinx.metadata.KmClassifier;
 import kotlinx.metadata.KmType;
 import kotlinx.metadata.KmTypeProjection;
+import kotlinx.metadata.KmTypeVisitor;
 
 // Provides access to Kotlin information about a kotlin type.
 public class KotlinTypeInfo {
@@ -50,10 +57,22 @@
     return classifier instanceof KmClassifier.Class;
   }
 
+  public KmClassifier.Class asClass() {
+    return (KmClassifier.Class) classifier;
+  }
+
+  public boolean isTypeParameter() {
+    return classifier instanceof KmClassifier.TypeParameter;
+  }
+
+  public KmClassifier.TypeParameter asTypeParameter() {
+    return (KmClassifier.TypeParameter) classifier;
+  }
+
   public boolean isObjectArray() {
     if (!isClass()) {
       KmClassifier.Class classifier = (KmClassifier.Class) this.classifier;
-      return classifier.getName().equals(ClassClassifiers.arrayDescriptor) && arguments.size() == 1;
+      return classifier.getName().equals(ClassClassifiers.arrayBinaryName) && arguments.size() == 1;
     }
     return false;
   }
@@ -66,4 +85,63 @@
     List<KotlinTypeProjectionInfo> arguments = getArguments();
     return arguments.size() >= index ? getArguments().get(index) : null;
   }
+
+  public KotlinTypeInfo toRenamed(KotlinMetadataSynthesizer synthesizer) {
+    DexType originalType = getLiveDexTypeFromClassClassifier(synthesizer.appView);
+    if (isClass() && originalType == null) {
+      return null;
+    }
+    KmClassifier renamedClassifier = classifier;
+    if (originalType != null) {
+      String typeClassifier = synthesizer.toRenamedClassifier(originalType);
+      if (typeClassifier != null) {
+        renamedClassifier = new KmClassifier.Class(typeClassifier);
+      }
+    }
+    if (arguments.isEmpty()) {
+      return renamedClassifier == classifier
+          ? this
+          : new KotlinTypeInfo(renamedClassifier, EMPTY_ARGUMENTS);
+    }
+    ImmutableList.Builder<KotlinTypeProjectionInfo> builder = ImmutableList.builder();
+    for (KotlinTypeProjectionInfo argument : arguments) {
+      builder.add(
+          new KotlinTypeProjectionInfo(
+              argument.variance,
+              argument.typeInfo == null ? null : argument.typeInfo.toRenamed(synthesizer)));
+    }
+    return new KotlinTypeInfo(renamedClassifier, builder.build());
+  }
+
+  private DexType getLiveDexTypeFromClassClassifier(AppView<AppInfoWithLiveness> appView) {
+    if (!isClass()) {
+      return null;
+    }
+    String descriptor = DescriptorUtils.getDescriptorFromKotlinClassifier(asClass().getName());
+    DexType type = appView.dexItemFactory().createType(descriptor);
+    if (appView.appInfo().wasPruned(type)) {
+      return null;
+    }
+    return type;
+  }
+
+  public KmType asKmType() {
+    KmType kmType = new KmType(flagsOf());
+    visit(kmType);
+    return kmType;
+  }
+
+  public void visit(KmTypeVisitor visitor) {
+    if (isClass()) {
+      visitor.visitClass(asClass().getName());
+    } else if (isTypeAlias()) {
+      visitor.visitTypeAlias(asTypeAlias().getName());
+    } else {
+      assert isTypeParameter();
+      visitor.visitTypeParameter(asTypeParameter().getId());
+    }
+    for (KotlinTypeProjectionInfo argument : arguments) {
+      argument.visit(visitor);
+    }
+  }
 }
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 bd40bc4..0bee8cc 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeProjectionInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeProjectionInfo.java
@@ -4,7 +4,10 @@
 
 package com.android.tools.r8.kotlin;
 
+import static kotlinx.metadata.FlagsKt.flagsOf;
+
 import kotlinx.metadata.KmTypeProjection;
+import kotlinx.metadata.KmTypeVisitor;
 import kotlinx.metadata.KmVariance;
 
 // Provides access to Kotlin information about the type projection of a type (arguments).
@@ -13,7 +16,7 @@
   final KmVariance variance;
   final KotlinTypeInfo typeInfo;
 
-  private KotlinTypeProjectionInfo(KmVariance variance, KotlinTypeInfo typeInfo) {
+  KotlinTypeProjectionInfo(KmVariance variance, KotlinTypeInfo typeInfo) {
     this.variance = variance;
     this.typeInfo = typeInfo;
   }
@@ -26,4 +29,13 @@
   public boolean isStarProjection() {
     return variance == null && typeInfo == null;
   }
+
+  public void visit(KmTypeVisitor visitor) {
+    KmTypeVisitor kmTypeVisitor = visitor.visitArgument(flagsOf(), variance);
+    if (isStarProjection()) {
+      kmTypeVisitor.visitStarProjection();
+    } else {
+      typeInfo.visit(kmTypeVisitor);
+    }
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index ad290b6..7772f09 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -773,7 +773,7 @@
 
   private String messageWarningMissingNestHost(DexClass compiledClass) {
     return messageErrorMissingNestHost(compiledClass)
-        + "Class"
+        + "Class "
         + compiledClass.type.getName()
         + " is considered as not being part of any nest.";
   }
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeAliasTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeAliasTest.java
index 734ce50..5cd7513 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeAliasTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeAliasTest.java
@@ -4,22 +4,29 @@
 package com.android.tools.r8.kotlin.metadata;
 
 import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isDexClass;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isRenamed;
-import static org.hamcrest.CoreMatchers.containsString;
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertNotNull;
+import static junit.framework.TestCase.assertTrue;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertNotEquals;
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
-import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.kotlin.Kotlin.ClassClassifiers;
 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.KmClassifierSubject;
 import com.android.tools.r8.utils.codeinspector.KmPackageSubject;
+import com.android.tools.r8.utils.codeinspector.KmTypeAliasSubject;
+import com.android.tools.r8.utils.codeinspector.KmTypeProjectionSubject;
+import com.android.tools.r8.utils.codeinspector.KmTypeSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import java.nio.file.Path;
 import java.util.Collection;
@@ -47,6 +54,7 @@
           "true",
           "42",
           "1",
+          "ClassWithCompanion::fooOnCompanion",
           "42",
           "42",
           "1",
@@ -86,6 +94,8 @@
   public void smokeTest() throws Exception {
     Path libJar = typeAliasLibJarMap.get(targetVersion);
 
+    testForJvm().addProgramFiles(libJar).run(parameters.getRuntime(), "Main").disassemble();
+
     Path output =
         kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
             .addClasspathFiles(libJar)
@@ -107,33 +117,49 @@
             .addProgramFiles(typeAliasLibJarMap.get(targetVersion))
             // Keep non-private members of Impl
             .addKeepRules("-keep class **.Impl { !private *; }")
-            // Keep Itf, but allow minification.
-            .addKeepRules("-keep,allowobfuscation class **.Itf")
+            // Keep but allow obfuscation of types.
+            .addKeepRules("-keep,allowobfuscation class " + PKG + ".typealias_lib.** { *; }")
+            .addKeepRules("-keepclassmembernames class " + PKG + ".typealias_lib.**" + " { *; }")
+            // Keep the Companion class for ClassWithCompanionC.
+            .addKeepRules("-keep class **.ClassWithCompanion$Companion { *; }")
+            // Keep the inner class, otherwise it cannot be constructed.
+            .addKeepRules("-keep class **.*Inner { *; }")
             // Keep LibKt that contains the type-aliases and utils.
-            .addKeepRules("-keep class **.LibKt { *; }")
-            .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
+            .addKeepRules("-keep class **.LibKt, **.Lib_extKt { *; }")
+            // Keep the library test methods
+            .addKeepRules("-keep class " + PKG + ".typealias_lib.*Tester { *; }")
+            .addKeepRules("-keep class " + PKG + ".typealias_lib.*Tester$Companion { *; }")
+            .addKeepAttributes(
+                ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS,
+                ProguardKeepAttributes.SIGNATURE,
+                ProguardKeepAttributes.INNER_CLASSES,
+                ProguardKeepAttributes.ENCLOSING_METHOD)
             .compile()
             .inspect(this::inspect)
             .writeToZip();
 
-    ProcessResult kotlinTestCompileResult =
+    Path appJar =
         kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
             .addClasspathFiles(libJar)
             .addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/typealias_app", "main"))
-            .setOutputPath(temp.newFolder().toPath())
-            // TODO(b/151194785): update to just .compile() once fixed.
-            .compileRaw();
-    // TODO(b/151194785): should be able to compile!
-    assertNotEquals(0, kotlinTestCompileResult.exitCode);
-    assertThat(
-        kotlinTestCompileResult.stderr,
-        containsString(
-            "type mismatch: inferred type is ProgramClass but API /* = Itf */ was expected"));
+            .compile();
+
+    testForJvm()
+        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+        .addClasspath(appJar)
+        .run(parameters.getRuntime(), PKG + ".typealias_app.MainKt")
+        .assertSuccessWithOutput(EXPECTED);
   }
 
   private void inspect(CodeInspector inspector) {
-    String itfClassName = PKG + ".typealias_lib.Itf";
-    String libKtClassName = PKG + ".typealias_lib.LibKt";
+    inspectLib(inspector);
+    inspectLibExt(inspector);
+  }
+
+  private void inspectLib(CodeInspector inspector) {
+    String packageName = PKG + ".typealias_lib";
+    String itfClassName = packageName + ".Itf";
+    String libKtClassName = packageName + ".LibKt";
 
     ClassSubject itf = inspector.clazz(itfClassName);
     assertThat(itf, isRenamed());
@@ -149,6 +175,115 @@
     // API entry is kept, hence the presence of Metadata.
     KmPackageSubject kmPackage = libKt.getKmPackage();
     assertThat(kmPackage, isPresent());
-    // TODO(b/151194785): need further inspection: many kinds of type appearances in typealias.
+
+    String arrayDescriptor =
+        DescriptorUtils.getDescriptorFromKotlinClassifier(ClassClassifiers.arrayBinaryName);
+
+    // Check that typealias myAliasedArray<T> = Array<T> exists.
+    KmTypeAliasSubject myAliasedArray = kmPackage.kmTypeAliasWithUniqueName("myAliasedArray");
+    assertThat(myAliasedArray, isPresent());
+    assertEquals(arrayDescriptor, myAliasedArray.expandedType().descriptor());
+
+    // Check that typealias API = Itf has been rewritten correctly.
+    KmTypeAliasSubject api = kmPackage.kmTypeAliasWithUniqueName("API");
+    assertThat(api, isPresent());
+    assertThat(api.expandedType(), isDexClass(itf.getDexClass()));
+    assertThat(api.underlyingType(), isDexClass(itf.getDexClass()));
+
+    // Check that the type-alias APIs exist and that the expanded type is renamed.
+    KmTypeAliasSubject apIs = kmPackage.kmTypeAliasWithUniqueName("APIs");
+    assertThat(apIs, isPresent());
+    assertEquals(arrayDescriptor, apIs.expandedType().descriptor());
+    assertEquals(1, apIs.expandedType().typeArguments().size());
+    KmTypeProjectionSubject expandedArgument = apIs.expandedType().typeArguments().get(0);
+    assertThat(expandedArgument.type(), isDexClass(itf.getDexClass()));
+
+    assertEquals(myAliasedArray.descriptor(packageName), apIs.underlyingType().descriptor());
+    assertEquals(1, apIs.underlyingType().typeArguments().size());
+    KmTypeProjectionSubject underlyingArgument = apIs.underlyingType().typeArguments().get(0);
+    KmTypeSubject type = underlyingArgument.type();
+    assertNotNull(type);
+    assertTrue(type.classifier().isTypeAlias());
+    assertEquals(api.descriptor(packageName), type.descriptor());
+  }
+
+  private void inspectLibExt(CodeInspector inspector) {
+    String packageName = PKG + ".typealias_lib";
+    String libKtClassName = packageName + ".Lib_extKt";
+
+    // Check that Arr has been renamed.
+    ClassSubject arr = inspector.clazz(packageName + ".Arr");
+    assertThat(arr, isRenamed());
+
+    ClassSubject libKt = inspector.clazz(libKtClassName);
+    KmPackageSubject kmPackage = libKt.getKmPackage();
+
+    // typealias Arr1D<K> = Arr<K>
+    KmTypeAliasSubject arr1D = kmPackage.kmTypeAliasWithUniqueName("Arr1D");
+    assertThat(arr1D, isPresent());
+    assertThat(arr1D.expandedType(), isDexClass(arr.getDexClass()));
+
+    // typealias Arr2D<K> = Arr1D<Arr1D<K>>
+    KmTypeAliasSubject arr2D = kmPackage.kmTypeAliasWithUniqueName("Arr2D");
+    assertThat(arr2D, isPresent());
+    assertThat(arr2D.expandedType(), isDexClass(arr.getDexClass()));
+    assertEquals(1, arr2D.expandedType().typeArguments().size());
+    KmTypeProjectionSubject arr2DexpandedArg = arr2D.expandedType().typeArguments().get(0);
+    assertThat(arr2DexpandedArg.type(), isDexClass(arr.getDexClass()));
+
+    assertEquals(arr1D.descriptor(packageName), arr2D.underlyingType().descriptor());
+    assertEquals(1, arr2D.underlyingType().typeArguments().size());
+    KmTypeProjectionSubject arr2DunderlyingArg = arr2D.underlyingType().typeArguments().get(0);
+    assertEquals(arr1D.descriptor(packageName), arr2DunderlyingArg.type().descriptor());
+
+    // typealias IntSet = Set<Int>
+    // typealias MyMapToSetOfInt<K> = MutableMap<K, IntSet>
+    KmTypeAliasSubject intSet = kmPackage.kmTypeAliasWithUniqueName("IntSet");
+    assertThat(intSet, isPresent());
+
+    KmTypeAliasSubject myMapToSetOfInt = kmPackage.kmTypeAliasWithUniqueName("MyMapToSetOfInt");
+    assertThat(myMapToSetOfInt, isPresent());
+    assertEquals(2, myMapToSetOfInt.underlyingType().typeArguments().size());
+    assertEquals(2, myMapToSetOfInt.expandedType().typeArguments().size());
+    assertEquals(1, myMapToSetOfInt.typeParameters().size());
+    KmClassifierSubject typeClassifier =
+        myMapToSetOfInt.underlyingType().typeArguments().get(0).type().classifier();
+    assertTrue(typeClassifier.isTypeParameter());
+    // Check that the type-variable K in 'MyMapToSetOfInt<K>' is the first argument in
+    // MutableMap<K, IntSet>.
+    assertEquals(
+        myMapToSetOfInt.typeParameters().get(0).getId(), typeClassifier.asTypeParameter().getId());
+
+    KmTypeSubject underlyingType = myMapToSetOfInt.underlyingType().typeArguments().get(1).type();
+    assertEquals(intSet.descriptor(packageName), underlyingType.descriptor());
+
+    KmTypeSubject expandedType = myMapToSetOfInt.expandedType().typeArguments().get(1).type();
+    assertEquals(intSet.expandedType(), expandedType);
+
+    // Check that the following exist:
+    // typealias MyHandler = (Int, Any) -> Unit
+    // typealias MyGenericPredicate<T> = (T) -> Boolean
+    assertThat(kmPackage.kmTypeAliasWithUniqueName("MyHandler"), isPresent());
+    KmTypeAliasSubject genericPredicate = kmPackage.kmTypeAliasWithUniqueName("MyGenericPredicate");
+    assertThat(genericPredicate, isPresent());
+
+    // Check that the type-variable T in 'MyGenericPredicate<T>' is the receiver argument in
+    // MutableMap<K, IntSet>.
+    assertEquals(1, genericPredicate.typeParameters().size());
+    assertEquals(1, genericPredicate.expandedType().typeArguments().size());
+    KmTypeProjectionSubject kmTypeProjectionSubject =
+        genericPredicate.expandedType().typeArguments().get(0);
+    assertTrue(kmTypeProjectionSubject.type().classifier().isTypeParameter());
+    assertEquals(
+        genericPredicate.typeParameters().get(0).getId(),
+        kmTypeProjectionSubject.type().classifier().asTypeParameter().getId());
+
+    // typealias ClassWithCompanionC = ClassWithCompanion.Companion
+    KmTypeAliasSubject classWithCompanionC =
+        kmPackage.kmTypeAliasWithUniqueName("ClassWithCompanionC");
+    assertThat(classWithCompanionC, isPresent());
+
+    ClassSubject companionClazz = inspector.clazz(packageName + ".ClassWithCompanion$Companion");
+    assertThat(classWithCompanionC.expandedType(), isDexClass(companionClazz.getDexClass()));
   }
 }
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/typealias_app/main.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/typealias_app/main.kt
index 396c2e4..f836216 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/typealias_app/main.kt
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/typealias_app/main.kt
@@ -5,7 +5,7 @@
 
 import com.android.tools.r8.kotlin.metadata.typealias_lib.API
 import com.android.tools.r8.kotlin.metadata.typealias_lib.AlphaNaming
-import com.android.tools.r8.kotlin.metadata.typealias_lib.Arr
+import com.android.tools.r8.kotlin.metadata.typealias_lib.Arr1D
 import com.android.tools.r8.kotlin.metadata.typealias_lib.Arr2D
 import com.android.tools.r8.kotlin.metadata.typealias_lib.Arr2DTester
 import com.android.tools.r8.kotlin.metadata.typealias_lib.CWithConstructor
@@ -13,6 +13,7 @@
 import com.android.tools.r8.kotlin.metadata.typealias_lib.ClassWithCompanionC
 import com.android.tools.r8.kotlin.metadata.typealias_lib.FunctionTester
 import com.android.tools.r8.kotlin.metadata.typealias_lib.Impl
+import com.android.tools.r8.kotlin.metadata.typealias_lib.IntSet
 import com.android.tools.r8.kotlin.metadata.typealias_lib.InterfaceTester
 import com.android.tools.r8.kotlin.metadata.typealias_lib.MyAdvancedMap
 import com.android.tools.r8.kotlin.metadata.typealias_lib.MyI
@@ -22,11 +23,10 @@
 import com.android.tools.r8.kotlin.metadata.typealias_lib.OuterTester
 import com.android.tools.r8.kotlin.metadata.typealias_lib.SimpleClassTester
 import com.android.tools.r8.kotlin.metadata.typealias_lib.StillCWithConstructor
-import com.android.tools.r8.kotlin.metadata.typealias_lib.UnderlyingTypeTest
+import com.android.tools.r8.kotlin.metadata.typealias_lib.UnderlyingTypeTester
 import com.android.tools.r8.kotlin.metadata.typealias_lib.UnusedTypeArgument
 import com.android.tools.r8.kotlin.metadata.typealias_lib.VerticalClassMergingTester
 import com.android.tools.r8.kotlin.metadata.typealias_lib.seq
-import com.android.tools.r8.kotlin.metadata.typealias_lib.IntSet as IntSet1
 
 class ProgramClass : Impl() {
   override fun foo(): API {
@@ -46,7 +46,7 @@
 }
 
 fun testArr2D() {
-  val arr1d : Arr<Int> = Arr(42);
+  val arr1d : Arr1D<Int> = Arr1D(42);
   val arr2d : Arr2D<Int> = Arr2D(arr1d);
   println(Arr2DTester.f(Arr2DTester.g(arr2d)).x.x);
 }
@@ -57,10 +57,10 @@
       println("42");
     }
   }
-  InterfaceTester.f(InterfaceTester.g(myInstance)).f()
+  InterfaceTester.f(myInstance).f()
 
   val map : MyMapToSetOfInt<Int> = HashMap();
-  val set : IntSet1 = mutableSetOf(42);
+  val set : IntSet = mutableSetOf(42);
   map.put(1, set);
   println(InterfaceTester.i(InterfaceTester.h(map))[1]?.iterator()?.next() ?: "");
 }
@@ -79,12 +79,12 @@
 fun testNestedClasses() {
   val nested = OuterNested(42);
   val myInner : OuterNestedInner = nested.Inner(1)
-  println(OuterTester.g(nested).y)
-  println(OuterTester.f(myInner).x)
+  println(OuterTester.f(OuterTester.g(nested)).y)
+  println(OuterTester.h(OuterTester.i(myInner)).x)
 }
 
 fun testCompanion() {
-  ClassWithCompanionC.foo;
+  println(ClassWithCompanionC.fooOnCompanion);
 }
 
 fun testConstructor() {
@@ -93,12 +93,12 @@
 
 fun testUnderlyingType() {
   val cWithConstructor = StillCWithConstructor(42)
-  println(UnderlyingTypeTest.f(UnderlyingTypeTest.g(cWithConstructor)).x)
+  println(UnderlyingTypeTester.f(UnderlyingTypeTester.g(cWithConstructor)).x)
   val advancedMap : MyAdvancedMap = HashMap();
   val nested = OuterNested(42);
   val myInner : OuterNestedInner = nested.Inner(1)
   advancedMap.put(nested, myInner);
-  val sameMap = UnderlyingTypeTest.h(UnderlyingTypeTest.i(advancedMap))
+  val sameMap = UnderlyingTypeTester.h(UnderlyingTypeTester.i(advancedMap))
   println(sameMap.get(nested)?.x)
 }
 
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/typealias_lib/lib_ext.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/typealias_lib/lib_ext.kt
index ba63667..60d5bda 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/typealias_lib/lib_ext.kt
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/typealias_lib/lib_ext.kt
@@ -1,6 +1,8 @@
 // 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.
+@file:Suppress("UNCHECKED_CAST")
+
 package com.android.tools.r8.kotlin.metadata.typealias_lib
 
 // Unused type aliases
@@ -51,13 +53,14 @@
 class SimpleClassTester {
 
   companion object {
-    fun f(a : SimpleClass) : AlphaNaming {
+    fun f(a : Any) : AlphaNaming {
+      return a as AlphaNaming;
+    }
+
+    fun g(a : AlphaNaming) : Any {
       return a;
     }
 
-    fun g(a : AlphaNaming) : SimpleClass {
-      return a;
-    }
   }
 }
 
@@ -196,11 +199,11 @@
 
   companion object {
 
-    fun f(i : I<Int>) : MyI {
-      return i;
+    fun f(i : Any) : MyI {
+      return i as MyI
     }
 
-    fun g(myI : MyI) : I<Int> {
+    fun g(myI : MyI) : Any {
       return myI;
     }
 
@@ -301,14 +304,21 @@
 
   companion object {
 
-    fun f(a : Outer.Nested.Inner) : OuterNestedInner {
+    fun f(a : Any) : OuterNested {
+      return a as OuterNested;
+    }
+
+    fun g(a : OuterNested) : Any {
       return a;
     }
 
-    fun g(a : OuterNested) : Outer.Nested {
-      return a;
+    fun h(a : Any) : OuterNestedInner {
+      return a as OuterNestedInner;
     }
 
+    fun i(a : OuterNestedInner) : Any {
+      return a;
+    }
   }
 }
 
@@ -317,8 +327,8 @@
 class ClassWithCompanion {
 
   companion object {
-    val foo: String
-      get() = "A.Companion::foo"
+    val fooOnCompanion: String
+      get() = "ClassWithCompanion::fooOnCompanion"
   }
 }
 
@@ -355,11 +365,11 @@
 
   companion object {
 
-    fun f(a : C) : CWithConstructor {
-      return a;
+    fun f(a : Any) : CWithConstructor {
+      return a as CWithConstructor;
     }
 
-    fun g(a : CWithConstructor) : C {
+    fun g(a : CWithConstructor) : Any {
       return a;
     }
   }
@@ -391,7 +401,7 @@
 // },
 typealias MyAdvancedMap = MutableMap<OuterNested, OuterNestedInner>
 
-class UnderlyingTypeTest {
+class UnderlyingTypeTester {
 
   companion object {
 
@@ -399,7 +409,7 @@
       return a;
     }
 
-    fun g(a : C) : StillCWithConstructor {
+    fun g(a : CWithConstructor) : StillCWithConstructor {
       return a;
     }
 
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmClassSubject.java
index c4d2078..a58d5ee 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmClassSubject.java
@@ -96,6 +96,16 @@
   }
 
   @Override
+  public List<KmTypeAliasSubject> getTypeAliases() {
+    return null;
+  }
+
+  @Override
+  public KmTypeAliasSubject kmTypeAliasWithUniqueName(String name) {
+    return null;
+  }
+
+  @Override
   public List<String> getSuperTypeDescriptors() {
     return null;
   }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmPackageSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmPackageSubject.java
index a71d6f0..bbd1df6 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmPackageSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmPackageSubject.java
@@ -88,4 +88,14 @@
   public List<ClassSubject> getReturnTypesInProperties() {
     return null;
   }
+
+  @Override
+  public List<KmTypeAliasSubject> getTypeAliases() {
+    return null;
+  }
+
+  @Override
+  public KmTypeAliasSubject kmTypeAliasWithUniqueName(String name) {
+    return null;
+  }
 }
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
new file mode 100644
index 0000000..78ac796
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmTypeAliasSubject.java
@@ -0,0 +1,51 @@
+// 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.codeinspector;
+
+import com.android.tools.r8.errors.Unreachable;
+import java.util.List;
+
+public class AbsentKmTypeAliasSubject extends KmTypeAliasSubject {
+
+  @Override
+  public boolean isPresent() {
+    return false;
+  }
+
+  @Override
+  public boolean isRenamed() {
+    throw new Unreachable("Cannot determine if an absent KmTypeAlias is renamed");
+  }
+
+  @Override
+  public boolean isSynthetic() {
+    throw new Unreachable("Cannot determine if an absent KmTypeAlias is synthetic");
+  }
+
+  @Override
+  public String name() {
+    return null;
+  }
+
+  @Override
+  public List<KmTypeParameterSubject> typeParameters() {
+    return null;
+  }
+
+  @Override
+  public String descriptor(String pkg) {
+    return null;
+  }
+
+  @Override
+  public KmTypeSubject expandedType() {
+    return null;
+  }
+
+  @Override
+  public KmTypeSubject underlyingType() {
+    return null;
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmDeclarationContainerSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmDeclarationContainerSubject.java
index 626388f..6363747 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmDeclarationContainerSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmDeclarationContainerSubject.java
@@ -18,6 +18,7 @@
 import kotlinx.metadata.KmPropertyExtensionVisitor;
 import kotlinx.metadata.KmPropertyVisitor;
 import kotlinx.metadata.KmType;
+import kotlinx.metadata.KmTypeAlias;
 import kotlinx.metadata.jvm.JvmFieldSignature;
 import kotlinx.metadata.jvm.JvmFunctionExtensionVisitor;
 import kotlinx.metadata.jvm.JvmMethodSignature;
@@ -245,4 +246,22 @@
         .filter(ClassSubject::isPresent)
         .collect(Collectors.toList());
   }
+
+  @Override
+  default List<KmTypeAliasSubject> getTypeAliases() {
+    CodeInspector inspector = codeInspector();
+    return getKmDeclarationContainer().getTypeAliases().stream()
+        .map(typeAlias -> new FoundKmTypeAliasSubject(inspector, typeAlias))
+        .collect(Collectors.toList());
+  }
+
+  @Override
+  default KmTypeAliasSubject kmTypeAliasWithUniqueName(String name) {
+    for (KmTypeAlias typeAlias : getKmDeclarationContainer().getTypeAliases()) {
+      if (typeAlias.getName().equals(name)) {
+        return new FoundKmTypeAliasSubject(codeInspector(), typeAlias);
+      }
+    }
+    return new AbsentKmTypeAliasSubject();
+  }
 }
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
new file mode 100644
index 0000000..a07125c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmTypeAliasSubject.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.utils.codeinspector;
+
+import static com.android.tools.r8.utils.DescriptorUtils.DESCRIPTOR_PACKAGE_SEPARATOR;
+import static com.android.tools.r8.utils.DescriptorUtils.getBinaryNameFromJavaType;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import kotlinx.metadata.KmTypeAlias;
+
+public class FoundKmTypeAliasSubject extends KmTypeAliasSubject {
+
+  private final KmTypeAlias kmTypeAlias;
+  private final CodeInspector codeInspector;
+
+  FoundKmTypeAliasSubject(CodeInspector codeInspector, KmTypeAlias kmTypeAlias) {
+    this.codeInspector = codeInspector;
+    this.kmTypeAlias = kmTypeAlias;
+  }
+
+  @Override
+  public boolean isPresent() {
+    return true;
+  }
+
+  @Override
+  public boolean isRenamed() {
+    return false;
+  }
+
+  @Override
+  public boolean isSynthetic() {
+    return false;
+  }
+
+  @Override
+  public String name() {
+    return kmTypeAlias.getName();
+  }
+
+  @Override
+  public List<KmTypeParameterSubject> typeParameters() {
+    return kmTypeAlias.getTypeParameters().stream()
+        .map(kmTypeParameter -> new FoundKmTypeParameterSubject(codeInspector, kmTypeParameter))
+        .collect(Collectors.toList());
+  }
+
+  @Override
+  public String descriptor(String pkg) {
+    return "L" + getBinaryNameFromJavaType(pkg) + DESCRIPTOR_PACKAGE_SEPARATOR + name() + ";";
+  }
+
+  @Override
+  public KmTypeSubject expandedType() {
+    return new KmTypeSubject(codeInspector, kmTypeAlias.expandedType);
+  }
+
+  @Override
+  public KmTypeSubject underlyingType() {
+    return new KmTypeSubject(codeInspector, kmTypeAlias.underlyingType);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmTypeParameterSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmTypeParameterSubject.java
index a15e78b..fb5e909 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmTypeParameterSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmTypeParameterSubject.java
@@ -51,4 +51,28 @@
         .map(kmType -> new KmTypeSubject(codeInspector, kmType))
         .collect(Collectors.toList());
   }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (!(obj instanceof FoundKmTypeParameterSubject)) {
+      return false;
+    }
+    KmTypeParameter other = ((FoundKmTypeParameterSubject) obj).kmTypeParameter;
+    if (!kmTypeParameter.getName().equals(other.getName())
+        || kmTypeParameter.getId() != other.getId()
+        || kmTypeParameter.getFlags() != other.getFlags()
+        || kmTypeParameter.getVariance() != other.getVariance()) {
+      return false;
+    }
+    if (kmTypeParameter.getUpperBounds().size() != other.getUpperBounds().size()) {
+      return false;
+    }
+    for (int i = 0; i < kmTypeParameter.getUpperBounds().size(); i++) {
+      if (!KmTypeSubject.areEqual(
+          kmTypeParameter.getUpperBounds().get(i), other.getUpperBounds().get(i))) {
+        return false;
+      }
+    }
+    return true;
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/KmClassifierSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/KmClassifierSubject.java
index a716822..8adb293 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/KmClassifierSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/KmClassifierSubject.java
@@ -22,6 +22,14 @@
     return (KmClassifier.TypeParameter) classifier;
   }
 
+  public boolean isTypeAlias() {
+    return classifier instanceof KmClassifier.TypeAlias;
+  }
+
+  public KmClassifier.TypeAlias asTypeAlias() {
+    return (KmClassifier.TypeAlias) classifier;
+  }
+
   @Override
   public boolean isPresent() {
     return true;
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/KmDeclarationContainerSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/KmDeclarationContainerSubject.java
index 0893077..24e26da 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/KmDeclarationContainerSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/KmDeclarationContainerSubject.java
@@ -29,4 +29,8 @@
   List<KmPropertySubject> getProperties();
 
   List<ClassSubject> getReturnTypesInProperties();
+
+  List<KmTypeAliasSubject> getTypeAliases();
+
+  KmTypeAliasSubject kmTypeAliasWithUniqueName(String name);
 }
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
new file mode 100644
index 0000000..f87d368
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/KmTypeAliasSubject.java
@@ -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.utils.codeinspector;
+
+import java.util.List;
+
+public abstract class KmTypeAliasSubject extends Subject {
+
+  public abstract String name();
+
+  public abstract List<KmTypeParameterSubject> typeParameters();
+
+  public abstract String descriptor(String pkg);
+
+  public abstract KmTypeSubject expandedType();
+
+  public abstract KmTypeSubject underlyingType();
+}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/KmTypeProjectionSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/KmTypeProjectionSubject.java
index dd6b4a4..76f3782 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/KmTypeProjectionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/KmTypeProjectionSubject.java
@@ -38,4 +38,25 @@
   public boolean isSynthetic() {
     throw new Unreachable("Cannot determine if a type argument is synthetic");
   }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (!(obj instanceof KmTypeProjectionSubject)) {
+      return false;
+    }
+    return areEqual(this.kmTypeProjection, ((KmTypeProjectionSubject) obj).kmTypeProjection);
+  }
+
+  public static boolean areEqual(KmTypeProjection one, KmTypeProjection other) {
+    if (one == null && other == null) {
+      return true;
+    }
+    if (one == null || other == null) {
+      return false;
+    }
+    if (one.getVariance() != other.getVariance()) {
+      return false;
+    }
+    return KmTypeSubject.areEqual(one.getType(), other.getType());
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/KmTypeSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/KmTypeSubject.java
index 6523ec2..44a141a 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/KmTypeSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/KmTypeSubject.java
@@ -10,8 +10,10 @@
 import com.android.tools.r8.utils.Box;
 import java.util.List;
 import java.util.stream.Collectors;
+import kotlinx.metadata.KmAnnotation;
 import kotlinx.metadata.KmType;
 import kotlinx.metadata.KmTypeVisitor;
+import kotlinx.metadata.jvm.JvmExtensionsKt;
 
 public class KmTypeSubject extends Subject {
   private final CodeInspector codeInspector;
@@ -76,4 +78,66 @@
   public boolean isSynthetic() {
     throw new Unreachable("Cannot determine if a type is synthetic");
   }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (!(obj instanceof KmTypeSubject)) {
+      return false;
+    }
+    return areEqual(this.kmType, ((KmTypeSubject) obj).kmType);
+  }
+
+  public static boolean areEqual(KmType one, KmType other) {
+    if (one == null && other == null) {
+      return true;
+    }
+    if (one == null || other == null) {
+      return false;
+    }
+    if (one.getFlags() != other.getFlags()) {
+      return false;
+    }
+    if (!one.classifier.toString().equals(other.classifier.toString())) {
+      return false;
+    }
+    if (one.getArguments().size() != other.getArguments().size()) {
+      return false;
+    }
+    for (int i = 0; i < one.getArguments().size(); i++) {
+      if (!KmTypeProjectionSubject.areEqual(
+          one.getArguments().get(i), other.getArguments().get(i))) {
+        return false;
+      }
+    }
+    if (!areEqual(one.getAbbreviatedType(), other.getAbbreviatedType())) {
+      return false;
+    }
+    if (!areEqual(one.getOuterType(), other.getOuterType())) {
+      return false;
+    }
+    // TODO(b/152745540): Add equality for flexibleUpperBoundType.
+    if (JvmExtensionsKt.isRaw(one) != JvmExtensionsKt.isRaw(other)) {
+      return false;
+    }
+    List<KmAnnotation> annotationsOne = JvmExtensionsKt.getAnnotations(one);
+    List<KmAnnotation> annotationsOther = JvmExtensionsKt.getAnnotations(other);
+    if (annotationsOne.size() != annotationsOther.size()) {
+      return false;
+    }
+    for (int i = 0; i < annotationsOne.size(); i++) {
+      KmAnnotation kmAnnotationOne = annotationsOne.get(i);
+      KmAnnotation kmAnnotationOther = annotationsOther.get(i);
+      if (!kmAnnotationOne.getClassName().equals(kmAnnotationOther.getClassName())) {
+        return false;
+      }
+      if (!kmAnnotationOne
+          .getArguments()
+          .keySet()
+          .equals(kmAnnotationOther.getArguments().keySet())) {
+        return false;
+      }
+      assert false : "Not defined how to compare kmAnnotationArguments";
+    }
+    return true;
+  }
 }