Reland "Refactor building of signature contexts to prepare for validation"

This reverts commit 980c2cdb0b487bd41f0cd40b611bdf8919264a9e.

Reason for revert: Not failing

Change-Id: Iae3ca495d924cc329372624e541adf7879324473
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 581d808..782a737 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -33,7 +33,8 @@
 import com.android.tools.r8.graph.DexReference;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.DirectMappedDexApplication;
-import com.android.tools.r8.graph.GenericSignatureTypeVariableRemover;
+import com.android.tools.r8.graph.GenericSignatureContextBuilder;
+import com.android.tools.r8.graph.GenericSignatureCorrectnessHelper;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.PrunedItems;
@@ -376,9 +377,14 @@
           appView.withGeneratedExtensionRegistryShrinker(
               shrinker -> shrinker.run(Mode.INITIAL_TREE_SHAKING));
 
-          // Build enclosing information and type-paramter information before pruning.
-          GenericSignatureTypeVariableRemover typeVariableRemover =
-              GenericSignatureTypeVariableRemover.create(appView, appView.appInfo().classes());
+          // Build enclosing information and type-parameter information before pruning.
+          // TODO(b/187922482): Only consider referenced classes.
+          GenericSignatureContextBuilder genericContextBuilder =
+              GenericSignatureContextBuilder.create(appView.appInfo().classes());
+
+          // Compute if all signatures are valid before modifying them.
+          GenericSignatureCorrectnessHelper.createForInitialCheck(appView, genericContextBuilder)
+              .run(appView.appInfo().classes());
 
           TreePruner pruner = new TreePruner(appViewWithLiveness);
           DirectMappedDexApplication prunedApp = pruner.run(executorService);
@@ -403,8 +409,7 @@
               annotationRemoverBuilder
                   .build(appViewWithLiveness, removedClasses);
           annotationRemover.ensureValid().run();
-          typeVariableRemover.removeDeadGenericSignatureTypeVariables(appView);
-          new GenericSignatureRewriter(appView, NamingLens.getIdentityLens())
+          new GenericSignatureRewriter(appView, NamingLens.getIdentityLens(), genericContextBuilder)
               .run(appView.appInfo().classes(), executorService);
         }
       } finally {
@@ -596,8 +601,8 @@
                     shrinker -> shrinker.run(enqueuer.getMode()),
                     DefaultTreePrunerConfiguration.getInstance());
 
-            GenericSignatureTypeVariableRemover typeVariableRemover =
-                GenericSignatureTypeVariableRemover.create(appView, appView.appInfo().classes());
+            GenericSignatureContextBuilder genericContextBuilder =
+                GenericSignatureContextBuilder.create(appView.appInfo().classes());
 
             TreePruner pruner = new TreePruner(appViewWithLiveness, treePrunerConfiguration);
             DirectMappedDexApplication application = pruner.run(executorService);
@@ -638,7 +643,10 @@
             AnnotationRemover.builder()
                 .build(appView.withLiveness(), removedClasses)
                 .run();
-            typeVariableRemover.removeDeadGenericSignatureTypeVariables(appView);
+            new GenericSignatureRewriter(
+                    appView, NamingLens.getIdentityLens(), genericContextBuilder)
+                .run(appView.appInfo().classes(), executorService);
+
             // Synthesize fields for triggering class initializers.
             new ClassInitFieldSynthesizer(appViewWithLiveness).run(executorService);
           }
@@ -786,6 +794,16 @@
         options.syntheticProguardRulesConsumer.accept(synthesizedProguardRules);
       }
 
+      assert appView.checkForTesting(
+              () ->
+                  !options.isShrinking()
+                      || GenericSignatureCorrectnessHelper.createForVerification(
+                              appView,
+                              GenericSignatureContextBuilder.create(appView.appInfo().classes()))
+                          .run(appView.appInfo().classes())
+                          .isValid())
+          : "Could not validate generic signatures";
+
       NamingLens prefixRewritingNamingLens =
           PrefixRewritingNamingLens.createPrefixRewritingNamingLens(appView, namingLens);
 
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 04cf5cc..860adf1 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -1318,6 +1318,7 @@
             !isAbstract(),
             builder ->
                 builder
+                    .setGenericSignature(MethodTypeSignature.noSignature())
                     .setCode(
                         ForwardMethodBuilder.builder(definitions.dexItemFactory())
                             .setStaticSource(newMethod)
@@ -1379,7 +1380,8 @@
         builder(this)
             .promoteToStatic()
             .withoutThisParameter()
-            .adjustOptimizationInfoAfterRemovingThisParameter();
+            .adjustOptimizationInfoAfterRemovingThisParameter()
+            .setGenericSignature(MethodTypeSignature.noSignature());
     DexEncodedMethod method = builder.build();
     method.copyMetadata(this);
     setObsolete();
@@ -1510,7 +1512,7 @@
 
     private DexMethod method;
     private MethodAccessFlags accessFlags;
-    private final MethodTypeSignature genericSignature;
+    private MethodTypeSignature genericSignature;
     private final DexAnnotationSet annotations;
     private OptionalBool isLibraryMethodOverride = OptionalBool.UNKNOWN;
     private ParameterAnnotationsList parameterAnnotations;
@@ -1710,5 +1712,10 @@
       buildConsumer.accept(result);
       return result;
     }
+
+    public Builder setGenericSignature(MethodTypeSignature methodSignature) {
+      this.genericSignature = methodSignature;
+      return this;
+    }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/graph/EnclosingMethodAttribute.java b/src/main/java/com/android/tools/r8/graph/EnclosingMethodAttribute.java
index fde5f6c..d2ea75e 100644
--- a/src/main/java/com/android/tools/r8/graph/EnclosingMethodAttribute.java
+++ b/src/main/java/com/android/tools/r8/graph/EnclosingMethodAttribute.java
@@ -52,6 +52,10 @@
     return enclosingMethod != null;
   }
 
+  public boolean hasEnclosingClass() {
+    return enclosingClass != null;
+  }
+
   public DexMethod getEnclosingMethod() {
     return enclosingMethod;
   }
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 9a34638..419125d 100644
--- a/src/main/java/com/android/tools/r8/graph/GenericSignature.java
+++ b/src/main/java/com/android/tools/r8/graph/GenericSignature.java
@@ -173,6 +173,7 @@
       this.name = name;
       this.classBound = classBound;
       this.interfaceBounds = interfaceBounds;
+      assert classBound != null;
       assert interfaceBounds != null;
     }
 
@@ -189,14 +190,16 @@
     }
 
     public FormalTypeParameter visit(GenericSignatureVisitor visitor) {
-      FieldTypeSignature rewrittenClassBound =
-          classBound == null ? null : visitor.visitClassBound(classBound);
+      FieldTypeSignature rewrittenClassBound = visitor.visitClassBound(classBound);
       List<FieldTypeSignature> rewrittenInterfaceBounds =
           visitor.visitInterfaceBounds(interfaceBounds);
       if (classBound == rewrittenClassBound && interfaceBounds == rewrittenInterfaceBounds) {
         return this;
       }
-      return new FormalTypeParameter(name, rewrittenClassBound, rewrittenInterfaceBounds);
+      return new FormalTypeParameter(
+          name,
+          rewrittenClassBound == null ? FieldTypeSignature.noSignature() : rewrittenClassBound,
+          rewrittenInterfaceBounds);
     }
   }
 
@@ -286,6 +289,10 @@
     public static ClassSignature noSignature() {
       return NO_CLASS_SIGNATURE;
     }
+
+    public ClassSignature toObjectBoundWithSameFormals(ClassTypeSignature objectBound) {
+      return new ClassSignature(formalTypeParameters, objectBound, getEmptySuperInterfaces());
+    }
   }
 
   private static class InvalidClassSignature extends ClassSignature {
@@ -649,7 +656,7 @@
       if (elementSignature == rewrittenElementSignature) {
         return this;
       }
-      return new ArrayTypeSignature(elementSignature, getWildcardIndicator());
+      return new ArrayTypeSignature(rewrittenElementSignature, getWildcardIndicator());
     }
   }
 
@@ -891,7 +898,7 @@
       return parser.parseClassSignature(signature);
     } catch (GenericSignatureFormatError e) {
       diagnosticsHandler.warning(
-          GenericSignatureDiagnostic.invalidClassSignature(signature, className, origin, e));
+          GenericSignatureFormatDiagnostic.invalidClassSignature(signature, className, origin, e));
       return ClassSignature.NO_CLASS_SIGNATURE;
     }
   }
@@ -910,7 +917,7 @@
       return parser.parseFieldTypeSignature(signature);
     } catch (GenericSignatureFormatError e) {
       diagnosticsHandler.warning(
-          GenericSignatureDiagnostic.invalidFieldSignature(signature, fieldName, origin, e));
+          GenericSignatureFormatDiagnostic.invalidFieldSignature(signature, fieldName, origin, e));
       return GenericSignature.NO_FIELD_TYPE_SIGNATURE;
     }
   }
@@ -929,7 +936,8 @@
       return parser.parseMethodTypeSignature(signature);
     } catch (GenericSignatureFormatError e) {
       diagnosticsHandler.warning(
-          GenericSignatureDiagnostic.invalidMethodSignature(signature, methodName, origin, e));
+          GenericSignatureFormatDiagnostic.invalidMethodSignature(
+              signature, methodName, origin, e));
       return MethodTypeSignature.NO_METHOD_TYPE_SIGNATURE;
     }
   }
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignatureTypeVariableRemover.java b/src/main/java/com/android/tools/r8/graph/GenericSignatureContextBuilder.java
similarity index 65%
rename from src/main/java/com/android/tools/r8/graph/GenericSignatureTypeVariableRemover.java
rename to src/main/java/com/android/tools/r8/graph/GenericSignatureContextBuilder.java
index 7c0ee29..1a05232 100644
--- a/src/main/java/com/android/tools/r8/graph/GenericSignatureTypeVariableRemover.java
+++ b/src/main/java/com/android/tools/r8/graph/GenericSignatureContextBuilder.java
@@ -4,11 +4,11 @@
 
 package com.android.tools.r8.graph;
 
-import static com.android.tools.r8.graph.GenericSignatureTypeVariableRemover.TypeParameterContext.empty;
-import static com.google.common.base.Predicates.alwaysFalse;
+import static com.android.tools.r8.graph.GenericSignatureContextBuilder.TypeParameterContext.empty;
 
 import com.android.tools.r8.graph.GenericSignature.FormalTypeParameter;
 import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -18,9 +18,8 @@
 import java.util.Set;
 import java.util.function.Predicate;
 
-public class GenericSignatureTypeVariableRemover {
+public class GenericSignatureContextBuilder {
 
-  private final DexType objectType;
   private final Map<DexReference, TypeParameterSubstitutions> formalsInfo;
   private final Map<DexReference, DexReference> enclosingInfo;
 
@@ -51,7 +50,7 @@
     }
   }
 
-  static class TypeParameterContext {
+  public static class TypeParameterContext {
 
     private static final TypeParameterContext EMPTY =
         new TypeParameterContext(Collections.emptyMap(), Collections.emptySet());
@@ -69,37 +68,99 @@
       if (information == null) {
         return this;
       }
-      HashMap<String, DexType> newPruned = new HashMap<>(prunedParametersWithBounds);
-      HashSet<String> newLiveParameters = new HashSet<>(liveParameters);
-      information.parametersWithBounds.forEach(
-          (param, type) -> {
-            if (dead) {
-              newPruned.put(param, type);
-              newLiveParameters.remove(param);
-            } else {
-              newLiveParameters.add(param);
-              newPruned.remove(param);
-            }
-          });
-      return new TypeParameterContext(newPruned, newLiveParameters);
+      return dead
+          ? addPrunedSubstitutions(information.parametersWithBounds)
+          : addLiveParameters(information.parametersWithBounds.keySet());
     }
 
     public static TypeParameterContext empty() {
       return EMPTY;
     }
+
+    public boolean isLiveParameter(String parameterName) {
+      return liveParameters.contains(parameterName);
+    }
+
+    public DexType getPrunedSubstitution(String parameterName) {
+      assert !isLiveParameter(parameterName);
+      return prunedParametersWithBounds.get(parameterName);
+    }
+
+    public TypeParameterContext addLiveParameters(Collection<String> typeParameters) {
+      if (typeParameters.isEmpty()) {
+        return this;
+      }
+      HashSet<String> newLiveParameters = new HashSet<>();
+      newLiveParameters.addAll(liveParameters);
+      newLiveParameters.addAll(typeParameters);
+      HashMap<String, DexType> newPruned = new HashMap<>();
+      prunedParametersWithBounds.forEach(
+          (name, type) -> {
+            if (!typeParameters.contains(name)) {
+              newPruned.put(name, type);
+            }
+          });
+      return new TypeParameterContext(newPruned, newLiveParameters);
+    }
+
+    public TypeParameterContext addPrunedSubstitutions(Map<String, DexType> substitutions) {
+      if (substitutions.isEmpty()) {
+        return this;
+      }
+      HashMap<String, DexType> newPruned = new HashMap<>();
+      newPruned.putAll(prunedParametersWithBounds);
+      newPruned.putAll(substitutions);
+      HashSet<String> newLiveParameters = new HashSet<>();
+      liveParameters.forEach(
+          name -> {
+            if (!substitutions.containsKey(name)) {
+              newLiveParameters.add(name);
+            }
+          });
+      return new TypeParameterContext(newPruned, newLiveParameters);
+    }
   }
 
-  private GenericSignatureTypeVariableRemover(
+  public static class AlwaysLiveTypeParameterContext extends TypeParameterContext {
+
+    private AlwaysLiveTypeParameterContext() {
+      super(Collections.emptyMap(), Collections.emptySet());
+    }
+
+    public static AlwaysLiveTypeParameterContext create() {
+      return new AlwaysLiveTypeParameterContext();
+    }
+
+    @Override
+    public boolean isLiveParameter(String parameterName) {
+      return true;
+    }
+
+    @Override
+    public DexType getPrunedSubstitution(String parameterName) {
+      assert false;
+      return null;
+    }
+
+    @Override
+    public TypeParameterContext addLiveParameters(Collection<String> typeParameters) {
+      return this;
+    }
+
+    @Override
+    public TypeParameterContext addPrunedSubstitutions(Map<String, DexType> substitutions) {
+      return this;
+    }
+  }
+
+  private GenericSignatureContextBuilder(
       Map<DexReference, TypeParameterSubstitutions> formalsInfo,
-      Map<DexReference, DexReference> enclosingInfo,
-      DexType objectType) {
+      Map<DexReference, DexReference> enclosingInfo) {
     this.formalsInfo = formalsInfo;
     this.enclosingInfo = enclosingInfo;
-    this.objectType = objectType;
   }
 
-  public static GenericSignatureTypeVariableRemover create(
-      AppView<?> appView, List<DexProgramClass> programClasses) {
+  public static GenericSignatureContextBuilder create(List<DexProgramClass> programClasses) {
     Map<DexReference, TypeParameterSubstitutions> formalsInfo = new IdentityHashMap<>();
     Map<DexReference, DexReference> enclosingInfo = new IdentityHashMap<>();
     programClasses.forEach(
@@ -137,8 +198,13 @@
                     : enclosingMethodAttribute.getEnclosingClass());
           }
         });
-    return new GenericSignatureTypeVariableRemover(
-        formalsInfo, enclosingInfo, appView.dexItemFactory().objectType);
+    return new GenericSignatureContextBuilder(formalsInfo, enclosingInfo);
+  }
+
+  public TypeParameterContext computeTypeParameterContext(
+      AppView<?> appView, DexReference reference, Predicate<DexType> wasPruned) {
+    assert !wasPruned.test(reference.getContextType());
+    return computeTypeParameterContext(appView, reference, wasPruned, false);
   }
 
   private TypeParameterContext computeTypeParameterContext(
@@ -175,7 +241,7 @@
     return typeParameterContext.combine(formalsInfo.get(reference), prunedHere);
   }
 
-  private static boolean hasPrunedRelationship(
+  public boolean hasPrunedRelationship(
       AppView<?> appView,
       DexReference enclosingReference,
       DexType enclosedClassType,
@@ -189,8 +255,17 @@
     if (wasPruned.test(enclosingReference.getContextType()) || wasPruned.test(enclosedClassType)) {
       return true;
     }
-    DexClass enclosingClass = appView.definitionFor(enclosingReference.getContextType());
-    DexClass enclosedClass = appView.definitionFor(enclosedClassType);
+    // TODO(b/187035453): We should visit generic signatures in the enqueuer.
+    DexClass enclosingClass =
+        appView
+            .appInfo()
+            .definitionForWithoutExistenceAssert(
+                appView.graphLens().lookupClassType(enclosingReference.getContextType()));
+    DexClass enclosedClass =
+        appView
+            .appInfo()
+            .definitionForWithoutExistenceAssert(
+                appView.graphLens().lookupClassType(enclosedClassType));
     if (enclosingClass == null || enclosedClass == null) {
       return true;
     }
@@ -207,68 +282,15 @@
     }
   }
 
-  private static boolean hasGenericTypeVariables(
+  public boolean hasGenericTypeVariables(
       AppView<?> appView, DexType type, Predicate<DexType> wasPruned) {
     if (wasPruned.test(type)) {
       return false;
     }
-    DexClass clazz = appView.definitionFor(type);
+    DexClass clazz = appView.definitionFor(appView.graphLens().lookupClassType(type));
     if (clazz == null || clazz.isNotProgramClass() || clazz.getClassSignature().isInvalid()) {
       return true;
     }
     return !clazz.getClassSignature().getFormalTypeParameters().isEmpty();
   }
-
-  public void removeDeadGenericSignatureTypeVariables(AppView<?> appView) {
-    Predicate<DexType> wasPruned =
-        appView.hasLiveness() ? appView.withLiveness().appInfo()::wasPruned : alwaysFalse();
-    GenericSignaturePartialTypeArgumentApplier baseArgumentApplier =
-        GenericSignaturePartialTypeArgumentApplier.build(
-            objectType,
-            (enclosing, enclosed) -> hasPrunedRelationship(appView, enclosing, enclosed, wasPruned),
-            type -> hasGenericTypeVariables(appView, type, wasPruned));
-    appView
-        .appInfo()
-        .classes()
-        .forEach(
-            clazz -> {
-              if (clazz.getClassSignature().isInvalid()) {
-                return;
-              }
-              TypeParameterContext computedClassFormals =
-                  computeTypeParameterContext(appView, clazz.getType(), wasPruned, false);
-              GenericSignaturePartialTypeArgumentApplier classArgumentApplier =
-                  baseArgumentApplier.addSubstitutionsAndVariables(
-                      computedClassFormals.prunedParametersWithBounds,
-                      computedClassFormals.liveParameters);
-              clazz.setClassSignature(
-                  classArgumentApplier.visitClassSignature(clazz.getClassSignature()));
-              clazz
-                  .methods()
-                  .forEach(
-                      method -> {
-                        MethodTypeSignature methodSignature = method.getGenericSignature();
-                        if (methodSignature.hasSignature()
-                            && method.getGenericSignature().isValid()) {
-                          // The reflection api do not distinguish static methods context from
-                          // virtual methods.
-                          method.setGenericSignature(
-                              classArgumentApplier
-                                  .buildForMethod(methodSignature.getFormalTypeParameters())
-                                  .visitMethodSignature(methodSignature));
-                        }
-                      });
-              clazz
-                  .instanceFields()
-                  .forEach(
-                      field -> {
-                        if (field.getGenericSignature().hasSignature()
-                            && field.getGenericSignature().isValid()) {
-                          field.setGenericSignature(
-                              classArgumentApplier.visitFieldTypeSignature(
-                                  field.getGenericSignature()));
-                        }
-                      });
-            });
-  }
 }
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignatureCorrectnessHelper.java b/src/main/java/com/android/tools/r8/graph/GenericSignatureCorrectnessHelper.java
index 3401560..7dcfb37 100644
--- a/src/main/java/com/android/tools/r8/graph/GenericSignatureCorrectnessHelper.java
+++ b/src/main/java/com/android/tools/r8/graph/GenericSignatureCorrectnessHelper.java
@@ -9,7 +9,9 @@
 import static com.android.tools.r8.graph.GenericSignatureCorrectnessHelper.SignatureEvaluationResult.INVALID_SUPER_TYPE;
 import static com.android.tools.r8.graph.GenericSignatureCorrectnessHelper.SignatureEvaluationResult.INVALID_TYPE_VARIABLE_UNDEFINED;
 import static com.android.tools.r8.graph.GenericSignatureCorrectnessHelper.SignatureEvaluationResult.VALID;
+import static com.google.common.base.Predicates.alwaysFalse;
 
+import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.GenericSignature.ClassSignature;
 import com.android.tools.r8.graph.GenericSignature.ClassTypeSignature;
 import com.android.tools.r8.graph.GenericSignature.DexDefinitionSignature;
@@ -18,9 +20,9 @@
 import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
 import com.android.tools.r8.graph.GenericSignature.ReturnType;
 import com.android.tools.r8.graph.GenericSignature.TypeSignature;
-import java.util.HashSet;
+import com.android.tools.r8.graph.GenericSignatureContextBuilder.TypeParameterContext;
+import com.android.tools.r8.utils.ListUtils;
 import java.util.List;
-import java.util.Set;
 import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.function.Supplier;
@@ -29,90 +31,163 @@
 
   private enum Mode {
     VERIFY,
-    MARK_AS_INVALID;
+    CLEAR_IF_INVALID;
 
     public boolean doNotVerify() {
-      return markAsInvalid();
+      return clearIfInvalid();
     }
 
-    public boolean markAsInvalid() {
-      return this == MARK_AS_INVALID;
+    public boolean clearIfInvalid() {
+      return this == CLEAR_IF_INVALID;
     }
   }
 
   public enum SignatureEvaluationResult {
     INVALID_SUPER_TYPE,
+    INVALID_INTERFACE_TYPE,
     INVALID_INTERFACE_COUNT,
     INVALID_APPLICATION_COUNT,
     INVALID_TYPE_VARIABLE_UNDEFINED,
     VALID;
 
-    boolean isValid() {
+    public boolean isValid() {
       return this == VALID;
     }
 
-    boolean isInvalid() {
+    public boolean isInvalid() {
       return this != VALID;
     }
+
+    public SignatureEvaluationResult combine(SignatureEvaluationResult other) {
+      return isInvalid() ? this : other;
+    }
+
+    public String getDescription() {
+      switch (this) {
+        case INVALID_APPLICATION_COUNT:
+          return "The applied generic arguments have different count than the expected formals";
+        case INVALID_INTERFACE_COUNT:
+          return "The generic signature has a different number of interfaces than the class";
+        case INVALID_SUPER_TYPE:
+          return "The generic super type is not the same as the class super type";
+        case INVALID_TYPE_VARIABLE_UNDEFINED:
+          return "A type variable is not in scope";
+        default:
+          assert this.isValid();
+          throw new Unreachable("Should not throw an error for a valid signature");
+      }
+    }
   }
 
   private final AppView<?> appView;
   private final Mode mode;
+  private final GenericSignatureContextBuilder contextBuilder;
 
-  private GenericSignatureCorrectnessHelper(AppView<?> appView, Mode mode) {
+  private GenericSignatureCorrectnessHelper(
+      AppView<?> appView, GenericSignatureContextBuilder contextBuilder, Mode mode) {
     this.appView = appView;
+    this.contextBuilder = contextBuilder;
     this.mode = mode;
   }
 
-  public static GenericSignatureCorrectnessHelper createForInitialCheck(AppView<?> appView) {
-    return new GenericSignatureCorrectnessHelper(appView, Mode.MARK_AS_INVALID);
+  public static GenericSignatureCorrectnessHelper createForInitialCheck(
+      AppView<?> appView, GenericSignatureContextBuilder contextBuilder) {
+    return new GenericSignatureCorrectnessHelper(appView, contextBuilder, Mode.CLEAR_IF_INVALID);
   }
 
-  public static GenericSignatureCorrectnessHelper createForVerification(AppView<?> appView) {
-    return new GenericSignatureCorrectnessHelper(appView, Mode.VERIFY);
+  public static GenericSignatureCorrectnessHelper createForVerification(
+      AppView<?> appView, GenericSignatureContextBuilder contextBuilder) {
+    return new GenericSignatureCorrectnessHelper(appView, contextBuilder, Mode.VERIFY);
   }
 
-  public void run() {
-    appView.appInfo().classes().forEach(this::evaluateSignaturesForClass);
+  public SignatureEvaluationResult run(List<DexProgramClass> programClasses) {
+    if (appView.options().disableGenericSignatureValidation) {
+      return VALID;
+    }
+    for (DexProgramClass clazz : programClasses) {
+      SignatureEvaluationResult evaluationResult = evaluateSignaturesForClass(clazz);
+      if (evaluationResult.isInvalid()) {
+        return evaluationResult;
+      }
+    }
+    return VALID;
   }
 
   public SignatureEvaluationResult evaluateSignaturesForClass(DexProgramClass clazz) {
+    if (appView.options().disableGenericSignatureValidation) {
+      return VALID;
+    }
+
+    TypeParameterContext typeParameterContext =
+        contextBuilder.computeTypeParameterContext(appView, clazz.type, alwaysFalse());
+
     GenericSignatureContextEvaluator genericSignatureContextEvaluator =
-        new GenericSignatureContextEvaluator(appView, clazz, mode);
-    ClassSignature classSignature = clazz.getClassSignature();
-    SignatureEvaluationResult result = VALID;
-    if (classSignature.hasNoSignature() || !classSignature.isInvalid()) {
-      result = genericSignatureContextEvaluator.evaluateClassSignature(classSignature);
-      if (result.isInvalid() && mode.markAsInvalid()) {
-        clazz.setClassSignature(classSignature.toInvalid());
-      }
+        new GenericSignatureContextEvaluator(appView, mode, clazz);
+
+    SignatureEvaluationResult result =
+        genericSignatureContextEvaluator.evaluateClassSignatureForContext(typeParameterContext);
+    if (result.isInvalid() && mode.clearIfInvalid()) {
+      appView
+          .options()
+          .reporter
+          .info(
+              GenericSignatureValidationDiagnostic.invalidClassSignature(
+                  clazz.getClassSignature().toString(),
+                  clazz.getTypeName(),
+                  clazz.getOrigin(),
+                  result));
+      clazz.clearClassSignature();
     }
     for (DexEncodedMethod method : clazz.methods()) {
-      SignatureEvaluationResult methodResult =
-          evaluate(
-              method::getGenericSignature,
-              genericSignatureContextEvaluator::visitMethodSignature,
-              method::setGenericSignature);
-      if (result.isValid() && methodResult.isInvalid()) {
-        result = methodResult;
-      }
+      result =
+          result.combine(
+              evaluate(
+                  method::getGenericSignature,
+                  methodSignature ->
+                      genericSignatureContextEvaluator.visitMethodSignature(
+                          methodSignature, typeParameterContext),
+                  invalidResult -> {
+                    appView
+                        .options()
+                        .reporter
+                        .info(
+                            GenericSignatureValidationDiagnostic.invalidMethodSignature(
+                                method.getGenericSignature().toString(),
+                                method.toSourceString(),
+                                clazz.getOrigin(),
+                                invalidResult));
+                    method.clearGenericSignature();
+                  }));
     }
     for (DexEncodedField field : clazz.fields()) {
-      SignatureEvaluationResult fieldResult =
-          evaluate(
-              field::getGenericSignature,
-              genericSignatureContextEvaluator::visitFieldTypeSignature,
-              field::setGenericSignature);
-      if (result.isValid() && fieldResult.isInvalid()) {
-        result = fieldResult;
-      }
+      result =
+          result.combine(
+              evaluate(
+                  field::getGenericSignature,
+                  fieldSignature ->
+                      genericSignatureContextEvaluator.visitFieldTypeSignature(
+                          fieldSignature, typeParameterContext),
+                  invalidResult -> {
+                    appView
+                        .options()
+                        .reporter
+                        .info(
+                            GenericSignatureValidationDiagnostic.invalidFieldSignature(
+                                field.getGenericSignature().toString(),
+                                field.toSourceString(),
+                                clazz.getOrigin(),
+                                invalidResult));
+                    field.clearGenericSignature();
+                  }));
     }
     return result;
   }
 
   @SuppressWarnings("unchecked")
   private <T extends DexDefinitionSignature<?>> SignatureEvaluationResult evaluate(
-      Supplier<T> getter, Function<T, SignatureEvaluationResult> evaluate, Consumer<T> setter) {
+      Supplier<T> getter,
+      Function<T, SignatureEvaluationResult> evaluate,
+      Consumer<SignatureEvaluationResult> invalidAction) {
     T signature = getter.get();
     if (signature.hasNoSignature() || signature.isInvalid()) {
       // Already marked as invalid, do nothing
@@ -120,8 +195,8 @@
     }
     SignatureEvaluationResult signatureResult = evaluate.apply(signature);
     assert signatureResult.isValid() || mode.doNotVerify();
-    if (signatureResult.isInvalid() && mode.doNotVerify()) {
-      setter.accept((T) signature.toInvalid());
+    if (signatureResult.isInvalid() && mode.clearIfInvalid()) {
+      invalidAction.accept(signatureResult);
     }
     return signatureResult;
   }
@@ -130,39 +205,39 @@
 
     private final AppView<?> appView;
     private final DexProgramClass context;
-    private final Set<String> classFormalTypeParameters = new HashSet<>();
-    private final Set<String> methodTypeArguments = new HashSet<>();
     private final Mode mode;
 
-    public GenericSignatureContextEvaluator(
-        AppView<?> appView, DexProgramClass context, Mode mode) {
+    private GenericSignatureContextEvaluator(
+        AppView<?> appView, Mode mode, DexProgramClass context) {
       this.appView = appView;
-      this.context = context;
       this.mode = mode;
+      this.context = context;
     }
 
-    private SignatureEvaluationResult evaluateClassSignature(ClassSignature classSignature) {
-      classSignature
-          .getFormalTypeParameters()
-          .forEach(param -> classFormalTypeParameters.add(param.name));
-      if (classSignature.hasNoSignature()) {
+    private SignatureEvaluationResult evaluateClassSignatureForContext(
+        TypeParameterContext typeParameterContext) {
+      ClassSignature classSignature = context.classSignature;
+      if (classSignature.hasNoSignature() || classSignature.isInvalid()) {
         return VALID;
       }
       SignatureEvaluationResult signatureEvaluationResult =
-          evaluateFormalTypeParameters(classSignature.formalTypeParameters);
+          evaluateFormalTypeParameters(classSignature.formalTypeParameters, typeParameterContext);
       if (signatureEvaluationResult.isInvalid()) {
         return signatureEvaluationResult;
       }
-      if ((context.superType != appView.dexItemFactory().objectType
-              && context.superType != classSignature.superClassSignature().type())
-          || (context.superType == appView.dexItemFactory().objectType
-              && classSignature.superClassSignature().hasNoSignature())) {
+      if (context.superType == appView.dexItemFactory().objectType
+          && classSignature.superClassSignature().hasNoSignature()) {
+        // We represent no signature as object.
+      } else if (context.superType
+          != appView.graphLens().lookupClassType(classSignature.superClassSignature().type())) {
         assert mode.doNotVerify();
         return INVALID_SUPER_TYPE;
       }
       signatureEvaluationResult =
           evaluateTypeArgumentsAppliedToType(
-              classSignature.superClassSignature().typeArguments(), context.superType);
+              classSignature.superClassSignature().typeArguments(),
+              context.superType,
+              typeParameterContext);
       if (signatureEvaluationResult.isInvalid()) {
         return signatureEvaluationResult;
       }
@@ -175,7 +250,7 @@
       for (int i = 0; i < actualInterfaces.length; i++) {
         signatureEvaluationResult =
             evaluateTypeArgumentsAppliedToType(
-                superInterfaces.get(i).typeArguments(), actualInterfaces[i]);
+                superInterfaces.get(i).typeArguments(), actualInterfaces[i], typeParameterContext);
         if (signatureEvaluationResult.isInvalid()) {
           return signatureEvaluationResult;
         }
@@ -183,37 +258,46 @@
       return VALID;
     }
 
-    private SignatureEvaluationResult visitMethodSignature(MethodTypeSignature methodSignature) {
-      methodSignature
-          .getFormalTypeParameters()
-          .forEach(param -> methodTypeArguments.add(param.name));
+    private SignatureEvaluationResult visitMethodSignature(
+        MethodTypeSignature methodSignature, TypeParameterContext typeParameterContext) {
+      // If the class context is invalid, we cannot reason about the method signatures.
+      if (context.classSignature.isInvalid()) {
+        return VALID;
+      }
+      TypeParameterContext methodContext =
+          methodSignature.formalTypeParameters.isEmpty()
+              ? typeParameterContext
+              : typeParameterContext.addLiveParameters(
+                  ListUtils.map(
+                      methodSignature.getFormalTypeParameters(), FormalTypeParameter::getName));
       SignatureEvaluationResult evaluateResult =
-          evaluateFormalTypeParameters(methodSignature.getFormalTypeParameters());
+          evaluateFormalTypeParameters(methodSignature.getFormalTypeParameters(), methodContext);
       if (evaluateResult.isInvalid()) {
         return evaluateResult;
       }
-      evaluateResult = evaluateTypeArguments(methodSignature.typeSignatures);
+      evaluateResult = evaluateTypeArguments(methodSignature.typeSignatures, methodContext);
       if (evaluateResult.isInvalid()) {
         return evaluateResult;
       }
-      evaluateResult = evaluateTypeArguments(methodSignature.throwsSignatures);
+      evaluateResult = evaluateTypeArguments(methodSignature.throwsSignatures, methodContext);
       if (evaluateResult.isInvalid()) {
         return evaluateResult;
       }
       ReturnType returnType = methodSignature.returnType();
       if (!returnType.isVoidDescriptor()) {
-        evaluateResult = evaluateTypeArgument(returnType.typeSignature());
+        evaluateResult = evaluateTypeArgument(returnType.typeSignature(), methodContext);
         if (evaluateResult.isInvalid()) {
           return evaluateResult;
         }
       }
-      methodTypeArguments.clear();
       return evaluateResult;
     }
 
-    private SignatureEvaluationResult evaluateTypeArguments(List<TypeSignature> typeSignatures) {
+    private SignatureEvaluationResult evaluateTypeArguments(
+        List<TypeSignature> typeSignatures, TypeParameterContext typeParameterContext) {
       for (TypeSignature typeSignature : typeSignatures) {
-        SignatureEvaluationResult signatureEvaluationResult = evaluateTypeArgument(typeSignature);
+        SignatureEvaluationResult signatureEvaluationResult =
+            evaluateTypeArgument(typeSignature, typeParameterContext);
         if (signatureEvaluationResult.isInvalid()) {
           return signatureEvaluationResult;
         }
@@ -221,14 +305,20 @@
       return VALID;
     }
 
-    private SignatureEvaluationResult visitFieldTypeSignature(FieldTypeSignature fieldSignature) {
-      return evaluateTypeArgument(fieldSignature);
+    private SignatureEvaluationResult visitFieldTypeSignature(
+        FieldTypeSignature fieldSignature, TypeParameterContext typeParameterContext) {
+      // If the class context is invalid, we cannot reason about the method signatures.
+      if (context.classSignature.isInvalid()) {
+        return VALID;
+      }
+      return evaluateTypeArgument(fieldSignature, typeParameterContext);
     }
 
     private SignatureEvaluationResult evaluateFormalTypeParameters(
-        List<FormalTypeParameter> typeParameters) {
+        List<FormalTypeParameter> typeParameters, TypeParameterContext typeParameterContext) {
       for (FormalTypeParameter typeParameter : typeParameters) {
-        SignatureEvaluationResult evaluationResult = evaluateTypeParameter(typeParameter);
+        SignatureEvaluationResult evaluationResult =
+            evaluateTypeParameter(typeParameter, typeParameterContext);
         if (evaluationResult.isInvalid()) {
           return evaluationResult;
         }
@@ -236,66 +326,79 @@
       return VALID;
     }
 
-    private SignatureEvaluationResult evaluateTypeParameter(FormalTypeParameter typeParameter) {
-      SignatureEvaluationResult evaluationResult = evaluateTypeArgument(typeParameter.classBound);
+    private SignatureEvaluationResult evaluateTypeParameter(
+        FormalTypeParameter typeParameter, TypeParameterContext typeParameterContext) {
+      SignatureEvaluationResult evaluationResult =
+          evaluateTypeArgument(typeParameter.classBound, typeParameterContext);
       if (evaluationResult.isInvalid()) {
         return evaluationResult;
       }
-      if (typeParameter.interfaceBounds != null) {
-        for (FieldTypeSignature interfaceBound : typeParameter.interfaceBounds) {
-          evaluationResult = evaluateTypeArgument(interfaceBound);
-          if (evaluationResult != VALID) {
-            return evaluationResult;
-          }
+      for (FieldTypeSignature interfaceBound : typeParameter.interfaceBounds) {
+        evaluationResult = evaluateTypeArgument(interfaceBound, typeParameterContext);
+        if (evaluationResult != VALID) {
+          return evaluationResult;
         }
       }
       return VALID;
     }
 
-    private SignatureEvaluationResult evaluateTypeArgument(TypeSignature typeSignature) {
+    private SignatureEvaluationResult evaluateTypeArgument(
+        TypeSignature typeSignature, TypeParameterContext typeParameterContext) {
       if (typeSignature.isBaseTypeSignature()) {
         return VALID;
       }
       FieldTypeSignature fieldTypeSignature = typeSignature.asFieldTypeSignature();
-      if (fieldTypeSignature.hasNoSignature()) {
+      if (fieldTypeSignature.hasNoSignature() || fieldTypeSignature.isStar()) {
         return VALID;
       }
       if (fieldTypeSignature.isTypeVariableSignature()) {
         // This is in an applied position, just check that the variable is registered.
         String typeVariable = fieldTypeSignature.asTypeVariableSignature().typeVariable();
-        if (classFormalTypeParameters.contains(typeVariable)
-            || methodTypeArguments.contains(typeVariable)) {
+        if (typeParameterContext.isLiveParameter(typeVariable)) {
           return VALID;
         }
         assert mode.doNotVerify();
         return INVALID_TYPE_VARIABLE_UNDEFINED;
       }
       if (fieldTypeSignature.isArrayTypeSignature()) {
-        return evaluateTypeArgument(fieldTypeSignature.asArrayTypeSignature().elementSignature());
+        return evaluateTypeArgument(
+            fieldTypeSignature.asArrayTypeSignature().elementSignature(), typeParameterContext);
       }
       assert fieldTypeSignature.isClassTypeSignature();
-      return evaluateTypeArguments(fieldTypeSignature.asClassTypeSignature());
+      return evaluateTypeArguments(fieldTypeSignature.asClassTypeSignature(), typeParameterContext);
     }
 
-    private SignatureEvaluationResult evaluateTypeArguments(ClassTypeSignature classTypeSignature) {
+    private SignatureEvaluationResult evaluateTypeArguments(
+        ClassTypeSignature classTypeSignature, TypeParameterContext typeParameterContext) {
       return evaluateTypeArgumentsAppliedToType(
-          classTypeSignature.typeArguments, classTypeSignature.type());
+          classTypeSignature.typeArguments, classTypeSignature.type(), typeParameterContext);
     }
 
     private SignatureEvaluationResult evaluateTypeArgumentsAppliedToType(
-        List<FieldTypeSignature> typeArguments, DexType type) {
+        List<FieldTypeSignature> typeArguments,
+        DexType type,
+        TypeParameterContext typeParameterContext) {
       for (FieldTypeSignature typeArgument : typeArguments) {
-        SignatureEvaluationResult evaluationResult = evaluateTypeArgument(typeArgument);
+        SignatureEvaluationResult evaluationResult =
+            evaluateTypeArgument(typeArgument, typeParameterContext);
         if (evaluationResult.isInvalid()) {
           assert mode.doNotVerify();
           return evaluationResult;
         }
       }
-      DexClass clazz = appView.definitionFor(type);
+      // TODO(b/187035453): We should visit generic signatures in the enqueuer.
+      DexClass clazz =
+          appView
+              .appInfo()
+              .definitionForWithoutExistenceAssert(appView.graphLens().lookupClassType(type));
       if (clazz == null) {
         // We do not know if the application of arguments works or not.
         return VALID;
       }
+      if (typeArguments.isEmpty()) {
+        // When type arguments are empty we are using the raw type.
+        return VALID;
+      }
       if (typeArguments.size() != clazz.classSignature.getFormalTypeParameters().size()) {
         assert mode.doNotVerify();
         return INVALID_APPLICATION_COUNT;
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignatureDiagnostic.java b/src/main/java/com/android/tools/r8/graph/GenericSignatureFormatDiagnostic.java
similarity index 78%
rename from src/main/java/com/android/tools/r8/graph/GenericSignatureDiagnostic.java
rename to src/main/java/com/android/tools/r8/graph/GenericSignatureFormatDiagnostic.java
index fa95bce..6729890 100644
--- a/src/main/java/com/android/tools/r8/graph/GenericSignatureDiagnostic.java
+++ b/src/main/java/com/android/tools/r8/graph/GenericSignatureFormatDiagnostic.java
@@ -9,13 +9,13 @@
 import com.android.tools.r8.position.Position;
 import java.lang.reflect.GenericSignatureFormatError;
 
-public class GenericSignatureDiagnostic implements Diagnostic {
+public class GenericSignatureFormatDiagnostic implements Diagnostic {
 
   private final Origin origin;
   private final Position position;
   private final String message;
 
-  GenericSignatureDiagnostic(Origin origin, Position position, String message) {
+  GenericSignatureFormatDiagnostic(Origin origin, Position position, String message) {
     this.origin = origin;
     this.position = position;
     this.message = message;
@@ -36,22 +36,22 @@
     return message;
   }
 
-  static GenericSignatureDiagnostic invalidClassSignature(
+  static GenericSignatureFormatDiagnostic invalidClassSignature(
       String signature, String name, Origin origin, GenericSignatureFormatError error) {
     return invalidSignature(signature, "class", name, origin, error);
   }
 
-  static GenericSignatureDiagnostic invalidMethodSignature(
+  static GenericSignatureFormatDiagnostic invalidMethodSignature(
       String signature, String name, Origin origin, GenericSignatureFormatError error) {
     return invalidSignature(signature, "method", name, origin, error);
   }
 
-  static GenericSignatureDiagnostic invalidFieldSignature(
+  static GenericSignatureFormatDiagnostic invalidFieldSignature(
       String signature, String name, Origin origin, GenericSignatureFormatError error) {
     return invalidSignature(signature, "field", name, origin, error);
   }
 
-  private static GenericSignatureDiagnostic invalidSignature(
+  private static GenericSignatureFormatDiagnostic invalidSignature(
       String signature,
       String kind,
       String name,
@@ -70,6 +70,6 @@
             + System.lineSeparator()
             + "Parser error: "
             + error.getMessage();
-    return new GenericSignatureDiagnostic(origin, Position.UNKNOWN, message);
+    return new GenericSignatureFormatDiagnostic(origin, Position.UNKNOWN, message);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignaturePartialTypeArgumentApplier.java b/src/main/java/com/android/tools/r8/graph/GenericSignaturePartialTypeArgumentApplier.java
index c381074..56a6496 100644
--- a/src/main/java/com/android/tools/r8/graph/GenericSignaturePartialTypeArgumentApplier.java
+++ b/src/main/java/com/android/tools/r8/graph/GenericSignaturePartialTypeArgumentApplier.java
@@ -14,52 +14,37 @@
 import com.android.tools.r8.graph.GenericSignature.ReturnType;
 import com.android.tools.r8.graph.GenericSignature.TypeSignature;
 import com.android.tools.r8.graph.GenericSignature.WildcardIndicator;
+import com.android.tools.r8.graph.GenericSignatureContextBuilder.TypeParameterContext;
 import com.android.tools.r8.utils.ListUtils;
-import com.google.common.collect.ImmutableSet;
-import java.util.Collections;
 import java.util.List;
-import java.util.Map;
-import java.util.Set;
 import java.util.function.BiPredicate;
 import java.util.function.Predicate;
 
 public class GenericSignaturePartialTypeArgumentApplier implements GenericSignatureVisitor {
 
-  private final Map<String, DexType> substitutions;
-  private final Set<String> liveTypeVariables;
-  private final DexType objectType;
+  private final TypeParameterContext typeParameterContext;
   private final BiPredicate<DexType, DexType> enclosingPruned;
   private final Predicate<DexType> hasGenericTypeParameters;
+  private final AppView<?> appView;
 
   private GenericSignaturePartialTypeArgumentApplier(
-      Map<String, DexType> substitutions,
-      Set<String> liveTypeVariables,
-      DexType objectType,
+      AppView<?> appView,
+      TypeParameterContext typeParameterContext,
       BiPredicate<DexType, DexType> enclosingPruned,
       Predicate<DexType> hasGenericTypeParameters) {
-    this.substitutions = substitutions;
-    this.liveTypeVariables = liveTypeVariables;
-    this.objectType = objectType;
+    this.appView = appView;
+    this.typeParameterContext = typeParameterContext;
     this.enclosingPruned = enclosingPruned;
     this.hasGenericTypeParameters = hasGenericTypeParameters;
   }
 
   public static GenericSignaturePartialTypeArgumentApplier build(
-      DexType objectType,
+      AppView<?> appView,
+      TypeParameterContext typeParameterContext,
       BiPredicate<DexType, DexType> enclosingPruned,
       Predicate<DexType> hasGenericTypeParameters) {
     return new GenericSignaturePartialTypeArgumentApplier(
-        Collections.emptyMap(),
-        Collections.emptySet(),
-        objectType,
-        enclosingPruned,
-        hasGenericTypeParameters);
-  }
-
-  public GenericSignaturePartialTypeArgumentApplier addSubstitutionsAndVariables(
-      Map<String, DexType> substitutions, Set<String> liveTypeVariables) {
-    return new GenericSignaturePartialTypeArgumentApplier(
-        substitutions, liveTypeVariables, objectType, enclosingPruned, hasGenericTypeParameters);
+        appView, typeParameterContext, enclosingPruned, hasGenericTypeParameters);
   }
 
   public GenericSignaturePartialTypeArgumentApplier buildForMethod(
@@ -67,23 +52,27 @@
     if (formals.isEmpty()) {
       return this;
     }
-    ImmutableSet.Builder<String> liveVariablesBuilder = ImmutableSet.builder();
-    liveVariablesBuilder.addAll(liveTypeVariables);
-    formals.forEach(
-        formal -> {
-          liveVariablesBuilder.add(formal.name);
-        });
     return new GenericSignaturePartialTypeArgumentApplier(
-        substitutions, liveTypeVariables, objectType, enclosingPruned, hasGenericTypeParameters);
+        appView,
+        typeParameterContext.addLiveParameters(
+            ListUtils.map(formals, FormalTypeParameter::getName)),
+        enclosingPruned,
+        hasGenericTypeParameters);
   }
 
   @Override
   public ClassSignature visitClassSignature(ClassSignature classSignature) {
+    if (classSignature.hasNoSignature() || classSignature.isInvalid()) {
+      return classSignature;
+    }
     return classSignature.visit(this);
   }
 
   @Override
   public MethodTypeSignature visitMethodSignature(MethodTypeSignature methodSignature) {
+    if (methodSignature.hasNoSignature() || methodSignature.isInvalid()) {
+      return methodSignature;
+    }
     return methodSignature.visit(this);
   }
 
@@ -111,7 +100,7 @@
 
   @Override
   public List<FieldTypeSignature> visitInterfaceBounds(List<FieldTypeSignature> fieldSignatures) {
-    if (fieldSignatures == null || fieldSignatures.isEmpty()) {
+    if (fieldSignatures.isEmpty()) {
       return fieldSignatures;
     }
     return ListUtils.mapOrElse(fieldSignatures, this::visitFieldTypeSignature);
@@ -142,6 +131,9 @@
 
   @Override
   public FieldTypeSignature visitClassBound(FieldTypeSignature fieldSignature) {
+    if (fieldSignature.hasNoSignature()) {
+      return fieldSignature;
+    }
     return visitFieldTypeSignature(fieldSignature);
   }
 
@@ -205,6 +197,9 @@
 
   @Override
   public FieldTypeSignature visitFieldTypeSignature(FieldTypeSignature fieldSignature) {
+    if (fieldSignature.hasNoSignature() || fieldSignature.isInvalid()) {
+      return fieldSignature;
+    }
     if (fieldSignature.isStar()) {
       return fieldSignature;
     } else if (fieldSignature.isClassTypeSignature()) {
@@ -214,11 +209,10 @@
     } else {
       assert fieldSignature.isTypeVariableSignature();
       String typeVariableName = fieldSignature.asTypeVariableSignature().typeVariable();
-      if (substitutions.containsKey(typeVariableName)
-          && !liveTypeVariables.contains(typeVariableName)) {
-        DexType substitution = substitutions.get(typeVariableName);
+      if (!typeParameterContext.isLiveParameter(typeVariableName)) {
+        DexType substitution = typeParameterContext.getPrunedSubstitution(typeVariableName);
         if (substitution == null) {
-          substitution = objectType;
+          substitution = appView.dexItemFactory().objectType;
         }
         return new ClassTypeSignature(substitution).asArgument(WildcardIndicator.NONE);
       }
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignaturePrinter.java b/src/main/java/com/android/tools/r8/graph/GenericSignaturePrinter.java
index d04e3af..b111c57 100644
--- a/src/main/java/com/android/tools/r8/graph/GenericSignaturePrinter.java
+++ b/src/main/java/com/android/tools/r8/graph/GenericSignaturePrinter.java
@@ -87,15 +87,15 @@
   @Override
   public FieldTypeSignature visitClassBound(FieldTypeSignature fieldSignature) {
     sb.append(":");
+    if (fieldSignature.hasNoSignature()) {
+      return fieldSignature;
+    }
     printFieldTypeSignature(fieldSignature, false);
     return fieldSignature;
   }
 
   @Override
   public List<FieldTypeSignature> visitInterfaceBounds(List<FieldTypeSignature> fieldSignatures) {
-    if (fieldSignatures == null) {
-      return null;
-    }
     fieldSignatures.forEach(this::visitInterfaceBound);
     return fieldSignatures;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignatureTypeRewriter.java b/src/main/java/com/android/tools/r8/graph/GenericSignatureTypeRewriter.java
index da35877..332aa8d 100644
--- a/src/main/java/com/android/tools/r8/graph/GenericSignatureTypeRewriter.java
+++ b/src/main/java/com/android/tools/r8/graph/GenericSignatureTypeRewriter.java
@@ -212,12 +212,15 @@
 
     @Override
     public FieldTypeSignature visitClassBound(FieldTypeSignature fieldSignature) {
+      if (fieldSignature.hasNoSignature()) {
+        return fieldSignature;
+      }
       return visitFieldTypeSignature(fieldSignature);
     }
 
     @Override
     public List<FieldTypeSignature> visitInterfaceBounds(List<FieldTypeSignature> fieldSignatures) {
-      if (fieldSignatures == null || fieldSignatures.isEmpty()) {
+      if (fieldSignatures.isEmpty()) {
         return fieldSignatures;
       }
       return ListUtils.mapOrElse(fieldSignatures, this::visitFieldTypeSignature);
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignatureTypeVisitor.java b/src/main/java/com/android/tools/r8/graph/GenericSignatureTypeVisitor.java
index c6d0e6a..59cd879 100644
--- a/src/main/java/com/android/tools/r8/graph/GenericSignatureTypeVisitor.java
+++ b/src/main/java/com/android/tools/r8/graph/GenericSignatureTypeVisitor.java
@@ -69,14 +69,14 @@
 
   @Override
   public FieldTypeSignature visitClassBound(FieldTypeSignature fieldSignature) {
+    if (fieldSignature.hasNoSignature()) {
+      return fieldSignature;
+    }
     return visitFieldTypeSignature(fieldSignature);
   }
 
   @Override
   public List<FieldTypeSignature> visitInterfaceBounds(List<FieldTypeSignature> fieldSignatures) {
-    if (fieldSignatures == null) {
-      return null;
-    }
     fieldSignatures.forEach(this::visitInterfaceBound);
     return fieldSignatures;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignatureValidationDiagnostic.java b/src/main/java/com/android/tools/r8/graph/GenericSignatureValidationDiagnostic.java
new file mode 100644
index 0000000..4a85abd
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/GenericSignatureValidationDiagnostic.java
@@ -0,0 +1,72 @@
+// 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.graph;
+
+import com.android.tools.r8.Diagnostic;
+import com.android.tools.r8.graph.GenericSignatureCorrectnessHelper.SignatureEvaluationResult;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.position.Position;
+
+public class GenericSignatureValidationDiagnostic implements Diagnostic {
+
+  private final Origin origin;
+  private final Position position;
+  private final String message;
+
+  GenericSignatureValidationDiagnostic(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 GenericSignatureValidationDiagnostic invalidClassSignature(
+      String signature, String name, Origin origin, SignatureEvaluationResult error) {
+    return invalidSignature(signature, "class", name, origin, error);
+  }
+
+  static GenericSignatureValidationDiagnostic invalidMethodSignature(
+      String signature, String name, Origin origin, SignatureEvaluationResult error) {
+    return invalidSignature(signature, "method", name, origin, error);
+  }
+
+  static GenericSignatureValidationDiagnostic invalidFieldSignature(
+      String signature, String name, Origin origin, SignatureEvaluationResult error) {
+    return invalidSignature(signature, "field", name, origin, error);
+  }
+
+  private static GenericSignatureValidationDiagnostic invalidSignature(
+      String signature, String kind, String name, Origin origin, SignatureEvaluationResult error) {
+    String message =
+        "Invalid signature '"
+            + signature
+            + "' for "
+            + kind
+            + " "
+            + name
+            + "."
+            + System.lineSeparator()
+            + "Validation error: "
+            + error.getDescription()
+            + "."
+            + System.lineSeparator()
+            + "Signature is ignored and will not be present in the output.";
+    return new GenericSignatureValidationDiagnostic(origin, Position.UNKNOWN, message);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
index b0df7c7..bd95f96 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
@@ -30,7 +30,9 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.DexValue.DexValueInt;
 import com.android.tools.r8.graph.FieldAccessFlags;
+import com.android.tools.r8.graph.GenericSignature.ClassTypeSignature;
 import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
+import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.MethodCollection;
@@ -70,10 +72,12 @@
   private final InterfaceMethodRewriter rewriter;
   private final Map<DexProgramClass, PostProcessingInterfaceInfo> postProcessingInterfaceInfos =
       new ConcurrentHashMap<>();
+  private final ClassTypeSignature objectTypeSignature;
 
   InterfaceProcessor(AppView<?> appView, InterfaceMethodRewriter rewriter) {
     this.appView = appView;
     this.rewriter = rewriter;
+    this.objectTypeSignature = new ClassTypeSignature(appView.dexItemFactory().objectType);
   }
 
   @Override
@@ -129,6 +133,8 @@
                 appView,
                 builder -> {
                   builder.setSourceFile(iface.sourceFile);
+                  builder.setGenericSignature(
+                      iface.getClassSignature().toObjectBoundWithSameFormals(objectTypeSignature));
                   ensureCompanionClassInitializesInterface(iface, builder);
                   processVirtualInterfaceMethods(iface, builder);
                   processDirectInterfaceMethods(iface, builder);
@@ -260,7 +266,7 @@
                     .setName(companionMethod.getName())
                     .setProto(companionMethod.getProto())
                     .setAccessFlags(newFlags)
-                    .setGenericSignature(virtual.getGenericSignature())
+                    .setGenericSignature(MethodTypeSignature.noSignature())
                     .setAnnotations(virtual.annotations())
                     .setParameterAnnotationsList(virtual.getParameterAnnotations())
                     .setCode(ignored -> virtual.getCode())
diff --git a/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java b/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java
index c44e4e7..16b6508 100644
--- a/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java
+++ b/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java
@@ -4,23 +4,37 @@
 
 package com.android.tools.r8.naming.signature;
 
+import static com.google.common.base.Predicates.alwaysFalse;
+
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GenericSignatureContextBuilder;
+import com.android.tools.r8.graph.GenericSignaturePartialTypeArgumentApplier;
 import com.android.tools.r8.graph.GenericSignatureTypeRewriter;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.utils.ThreadUtils;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
+import java.util.function.BiPredicate;
+import java.util.function.Predicate;
 
 // TODO(b/169516860): We should generalize this to handle rewriting of attributes in general.
 public class GenericSignatureRewriter {
 
   private final AppView<?> appView;
   private final NamingLens namingLens;
+  private final GenericSignatureContextBuilder contextBuilder;
 
   public GenericSignatureRewriter(AppView<?> appView, NamingLens namingLens) {
+    this(appView, namingLens, null);
+  }
+
+  public GenericSignatureRewriter(
+      AppView<?> appView, NamingLens namingLens, GenericSignatureContextBuilder contextBuilder) {
     this.appView = appView;
     this.namingLens = namingLens;
+    this.contextBuilder = contextBuilder;
   }
 
   public void run(Iterable<? extends DexProgramClass> classes, ExecutorService executorService)
@@ -34,20 +48,54 @@
     // arguments. If that is the case, the ProguardMapMinifier will pass in all classes that is
     // either ProgramClass or has a mapping. This is then transitively called inside the
     // ClassNameMinifier.
+    Predicate<DexType> wasPruned =
+        appView.hasLiveness() ? appView.withLiveness().appInfo()::wasPruned : alwaysFalse();
+    BiPredicate<DexType, DexType> hasPrunedRelationship =
+        (enclosing, enclosed) ->
+            contextBuilder.hasPrunedRelationship(appView, enclosing, enclosed, wasPruned);
+    Predicate<DexType> hasGenericTypeVariables =
+        type -> contextBuilder.hasGenericTypeVariables(appView, type, wasPruned);
     ThreadUtils.processItems(
         classes,
         clazz -> {
+          GenericSignaturePartialTypeArgumentApplier classArgumentApplier =
+              contextBuilder != null
+                  ? GenericSignaturePartialTypeArgumentApplier.build(
+                      appView,
+                      contextBuilder.computeTypeParameterContext(
+                          appView, clazz.getType(), wasPruned),
+                      hasPrunedRelationship,
+                      hasGenericTypeVariables)
+                  : null;
           GenericSignatureTypeRewriter genericSignatureTypeRewriter =
               new GenericSignatureTypeRewriter(appView, clazz);
-          clazz.setClassSignature(genericSignatureTypeRewriter.rewrite(clazz.getClassSignature()));
+          clazz.setClassSignature(
+              genericSignatureTypeRewriter.rewrite(
+                  classArgumentApplier != null
+                      ? classArgumentApplier.visitClassSignature(clazz.getClassSignature())
+                      : clazz.getClassSignature()));
           clazz.forEachField(
               field ->
                   field.setGenericSignature(
-                      genericSignatureTypeRewriter.rewrite(field.getGenericSignature())));
+                      genericSignatureTypeRewriter.rewrite(
+                          classArgumentApplier != null
+                              ? classArgumentApplier.visitFieldTypeSignature(
+                                  field.getGenericSignature())
+                              : field.getGenericSignature())));
           clazz.forEachMethod(
-              method ->
-                  method.setGenericSignature(
-                      genericSignatureTypeRewriter.rewrite(method.getGenericSignature())));
+              method -> {
+                // The reflection api do not distinguish static methods context and
+                // from virtual methods we therefore always base the context for a method on
+                // the class context.
+                method.setGenericSignature(
+                    genericSignatureTypeRewriter.rewrite(
+                        classArgumentApplier != null
+                            ? classArgumentApplier
+                                .buildForMethod(
+                                    method.getGenericSignature().getFormalTypeParameters())
+                                .visitMethodSignature(method.getGenericSignature())
+                            : method.getGenericSignature()));
+              });
         },
         executorService);
   }
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceElement.java b/src/main/java/com/android/tools/r8/retrace/RetraceElement.java
index cb2ac8c..55de558 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceElement.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceElement.java
@@ -3,11 +3,14 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.retrace;
 
+import com.android.tools.r8.KeepForSubclassing;
+
 /**
  * Base interface for any element in a retrace result.
  *
  * <p>The element represents an unambiguous retracing.
  */
+@KeepForSubclassing
 public interface RetraceElement<R extends RetraceResult<?>> {
 
   R getRetraceResultContext();
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java
index ef3b4d2..8e78b09 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java
@@ -44,6 +44,7 @@
   private List<DexEncodedMethod> directMethods = new ArrayList<>();
   private List<DexEncodedMethod> virtualMethods = new ArrayList<>();
   private List<SyntheticMethodBuilder> methods = new ArrayList<>();
+  private ClassSignature signature = ClassSignature.noSignature();
 
   SyntheticClassBuilder(DexType type, SynthesizingContext context, DexItemFactory factory) {
     this.factory = factory;
@@ -87,6 +88,11 @@
     return self();
   }
 
+  public B setGenericSignature(ClassSignature signature) {
+    this.signature = signature;
+    return self();
+  }
+
   public B setStaticFields(List<DexEncodedField> fields) {
     staticFields.clear();
     staticFields.addAll(fields);
@@ -153,7 +159,7 @@
             nestMembers,
             enclosingMembers,
             innerClasses,
-            ClassSignature.noSignature(),
+            signature,
             DexAnnotationSet.empty(),
             staticFields.toArray(DexEncodedField.EMPTY_ARRAY),
             instanceFields.toArray(DexEncodedField.EMPTY_ARRAY),
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 849d641..854e8c48 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -657,6 +657,7 @@
   public boolean ignoreMissingClasses = false;
   public boolean reportMissingClassesInEnclosingMethodAttribute = false;
   public boolean reportMissingClassesInInnerClassAttributes = false;
+  public boolean disableGenericSignatureValidation = false;
 
   // EXPERIMENTAL flag to get behaviour as close to Proguard as possible.
   public boolean forceProguardCompatibility = false;
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index b24d16a..789da90 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -7,6 +7,7 @@
 import static com.android.tools.r8.TestBuilder.getTestingAnnotations;
 import static com.android.tools.r8.utils.InternalOptions.ASM_VERSION;
 import static com.google.common.collect.Lists.cartesianProduct;
+import static org.hamcrest.CoreMatchers.containsString;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
@@ -1827,4 +1828,22 @@
         extractor, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
     return extractor.getClassFileVersion();
   }
+
+  public static void verifyAllInfoFromGenericSignatureTypeParameterValidation(
+      TestCompileResult<?, ?> compileResult) {
+    compileResult.assertAtLeastOneInfoMessage();
+    compileResult.assertAllInfoMessagesMatch(containsString("A type variable is not in scope"));
+  }
+
+  public static void verifyHasInfoFromGenericSignatureTypeParameterValidation(
+      TestCompileResult<?, ?> compileResult) {
+    compileResult.assertInfoMessageThatMatches(containsString("A type variable is not in scope"));
+  }
+
+  public static void verifyExpectedInfoFromGenericSignatureSuperTypeValidation(
+      TestCompileResult<?, ?> compileResult) {
+    compileResult.assertAtLeastOneInfoMessage();
+    compileResult.assertAllInfoMessagesMatch(
+        containsString("The generic super type is not the same as the class super type"));
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/cf/bootstrap/BootstrapCurrentEqualityTest.java b/src/test/java/com/android/tools/r8/cf/bootstrap/BootstrapCurrentEqualityTest.java
index a8d57c0..4e9353b 100644
--- a/src/test/java/com/android/tools/r8/cf/bootstrap/BootstrapCurrentEqualityTest.java
+++ b/src/test/java/com/android/tools/r8/cf/bootstrap/BootstrapCurrentEqualityTest.java
@@ -105,7 +105,9 @@
           .setMode(mode)
           .addProgramFiles(ToolHelper.R8_WITH_RELOCATED_DEPS_JAR)
           .addKeepRuleFiles(MAIN_KEEP)
+          .allowDiagnosticInfoMessages()
           .compile()
+          .apply(TestBase::verifyAllInfoFromGenericSignatureTypeParameterValidation)
           .apply(c -> FileUtils.writeTextFile(map, c.getProguardMap()))
           .writeToZip(jar);
     }
diff --git a/src/test/java/com/android/tools/r8/debug/ContinuousKotlinSteppingTest.java b/src/test/java/com/android/tools/r8/debug/ContinuousKotlinSteppingTest.java
index 539af51..c3e45b6 100644
--- a/src/test/java/com/android/tools/r8/debug/ContinuousKotlinSteppingTest.java
+++ b/src/test/java/com/android/tools/r8/debug/ContinuousKotlinSteppingTest.java
@@ -17,7 +17,7 @@
 
   private static final String MAIN_METHOD_NAME = "main";
 
-  @Parameters(name = "{0}")
+  @Parameters(name = "{0}, {1}")
   public static List<Object[]> data() {
     return buildParameters(
         getTestParameters().withDexRuntimes().withAllApiLevels().build(),
diff --git a/src/test/java/com/android/tools/r8/desugar/DesugarLambdaWithAnonymousClass.java b/src/test/java/com/android/tools/r8/desugar/DesugarLambdaWithAnonymousClass.java
index 72549c5..9691b07 100644
--- a/src/test/java/com/android/tools/r8/desugar/DesugarLambdaWithAnonymousClass.java
+++ b/src/test/java/com/android/tools/r8/desugar/DesugarLambdaWithAnonymousClass.java
@@ -29,10 +29,10 @@
 @RunWith(Parameterized.class)
 public class DesugarLambdaWithAnonymousClass extends TestBase {
 
-  private List<String> EXPECTED_JAVAC_RESULT =
+  private final List<String> EXPECTED_JAVAC_RESULT =
       ImmutableList.of("Hello from inside lambda$test$0", "Hello from inside lambda$testStatic$1");
 
-  private List<String> EXPECTED_D8_DESUGARED_RESULT =
+  private final List<String> EXPECTED_D8_DESUGARED_RESULT =
       ImmutableList.of(
           "Hello from inside lambda$test$0$DesugarLambdaWithAnonymousClass$TestClass",
           "Hello from inside lambda$testStatic$1");
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/kotlin/KotlinMetadataTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/kotlin/KotlinMetadataTest.java
index ef8f61a..55e2905 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/kotlin/KotlinMetadataTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/kotlin/KotlinMetadataTest.java
@@ -20,6 +20,7 @@
 import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.R8TestCompileResult;
 import com.android.tools.r8.R8TestRunResult;
+import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
@@ -130,7 +131,7 @@
             .addKeepAllClassesRule()
             .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
             .setMinApi(parameters.getApiLevel())
-            .allowDiagnosticWarningMessages()
+            .allowDiagnosticMessages()
             .allowUnusedDontWarnKotlinReflectJvmInternal(
                 kotlinParameters.getCompiler().isNot(KOTLINC_1_3_72));
     KeepRuleConsumer keepRuleConsumer = null;
@@ -141,6 +142,8 @@
     R8TestCompileResult compileResult =
         testBuilder
             .compile()
+            .assertNoErrorMessages()
+            .apply(TestBase::verifyAllInfoFromGenericSignatureTypeParameterValidation)
             .apply(KotlinMetadataTestBase::verifyExpectedWarningsFromKotlinReflectAndStdLib);
     if (desugarLibrary) {
       assertNotNull(keepRuleConsumer);
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/Java11R8BootstrapTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/Java11R8BootstrapTest.java
index 1eac80e..de1c949 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/Java11R8BootstrapTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/Java11R8BootstrapTest.java
@@ -77,7 +77,9 @@
                       options.desugarState = DesugarState.ON;
                       options.cfToCfDesugar = true;
                     }))
+        .allowDiagnosticInfoMessages()
         .compile()
+        .apply(TestBase::verifyAllInfoFromGenericSignatureTypeParameterValidation)
         .inspect(inspector -> assertNests(inspector, desugar))
         .writeToZip();
   }
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/Java11R8CompilationTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/Java11R8CompilationTest.java
index cb549f5..31f7aba 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/Java11R8CompilationTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/Java11R8CompilationTest.java
@@ -50,7 +50,9 @@
         .setMinApi(parameters.getApiLevel())
         .addProgramFiles(ToolHelper.R8_WITH_RELOCATED_DEPS_11_JAR)
         .addKeepRuleFiles(MAIN_KEEP)
+        .allowDiagnosticInfoMessages()
         .compile()
+        .apply(TestBase::verifyAllInfoFromGenericSignatureTypeParameterValidation)
         .inspect(this::assertNotEmpty)
         .inspect(Java11R8CompilationTest::assertNoNests);
   }
diff --git a/src/test/java/com/android/tools/r8/graph/GenericSignatureIdentityTest.java b/src/test/java/com/android/tools/r8/graph/GenericSignatureIdentityTest.java
index f4adbfb..3cb6899 100644
--- a/src/test/java/com/android/tools/r8/graph/GenericSignatureIdentityTest.java
+++ b/src/test/java/com/android/tools/r8/graph/GenericSignatureIdentityTest.java
@@ -78,6 +78,10 @@
       if (signature == null) {
         return;
       }
+      if (signature.equals(
+          "<R::Lcom/android/tools/r8/synthesis/Rewritable<TR;>;>Ljava/lang/Object;")) {
+        int xyz = 0;
+      }
       TestDiagnosticMessagesImpl testDiagnosticMessages = new TestDiagnosticMessagesImpl();
       ClassSignature classSignature =
           GenericSignature.parseClassSignature(
diff --git a/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignatureCorrectnessHelperTests.java b/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignatureCorrectnessHelperTests.java
index 65b434b..969a59f 100644
--- a/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignatureCorrectnessHelperTests.java
+++ b/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignatureCorrectnessHelperTests.java
@@ -14,6 +14,7 @@
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.GenericSignatureContextBuilder;
 import com.android.tools.r8.graph.GenericSignatureCorrectnessHelper;
 import com.android.tools.r8.graph.GenericSignatureCorrectnessHelper.SignatureEvaluationResult;
 import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
@@ -44,9 +45,10 @@
             buildInnerClasses(GenericSignatureCorrectnessHelperTests.class)
                 .addLibraryFile(ToolHelper.getJava8RuntimeJar())
                 .build());
-    GenericSignatureCorrectnessHelper check =
-        GenericSignatureCorrectnessHelper.createForVerification(appView);
-    check.run();
+    GenericSignatureContextBuilder contextBuilder =
+        GenericSignatureContextBuilder.create(appView.appInfo().classes());
+    GenericSignatureCorrectnessHelper.createForVerification(appView, contextBuilder)
+        .run(appView.appInfo().classes());
   }
 
   @Test
@@ -139,7 +141,7 @@
                     })
                 .transform()),
         ClassWithInvalidArgumentCount.class,
-        SignatureEvaluationResult.INVALID_APPLICATION_COUNT);
+        SignatureEvaluationResult.VALID);
   }
 
   @Test
@@ -182,8 +184,10 @@
                 .addClassProgramData(transformations)
                 .addLibraryFile(ToolHelper.getJava8RuntimeJar())
                 .build());
+    GenericSignatureContextBuilder contextBuilder =
+        GenericSignatureContextBuilder.create(appView.appInfo().classes());
     GenericSignatureCorrectnessHelper check =
-        GenericSignatureCorrectnessHelper.createForInitialCheck(appView);
+        GenericSignatureCorrectnessHelper.createForInitialCheck(appView, contextBuilder);
     DexProgramClass clazz =
         appView
             .definitionFor(
diff --git a/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignaturePartialTypeArgumentApplierTest.java b/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignaturePartialTypeArgumentApplierTest.java
index 64f2ac3..1fb82ab 100644
--- a/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignaturePartialTypeArgumentApplierTest.java
+++ b/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignaturePartialTypeArgumentApplierTest.java
@@ -13,12 +13,16 @@
 import com.android.tools.r8.TestDiagnosticMessagesImpl;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GenericSignature;
 import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
+import com.android.tools.r8.graph.GenericSignatureContextBuilder.TypeParameterContext;
 import com.android.tools.r8.graph.GenericSignaturePartialTypeArgumentApplier;
 import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.BiPredicateUtils;
 import com.google.common.collect.ImmutableMap;
 import java.util.Collections;
@@ -48,7 +52,7 @@
   }
 
   @Test
-  public void testVariablesInOuterPosition() {
+  public void testVariablesInOuterPosition() throws Exception {
     runTest(
             ImmutableMap.of("T", objectType, "R", objectType),
             Collections.emptySet(),
@@ -60,7 +64,7 @@
   }
 
   @Test
-  public void testVariablesInInnerPosition() {
+  public void testVariablesInInnerPosition() throws Exception {
     runTest(
             ImmutableMap.of("T", objectType, "R", objectType),
             Collections.emptySet(),
@@ -72,7 +76,7 @@
   }
 
   @Test
-  public void testRemovingPrunedLink() {
+  public void testRemovingPrunedLink() throws Exception {
     runTest(
             Collections.emptyMap(),
             Collections.emptySet(),
@@ -85,7 +89,7 @@
   }
 
   @Test
-  public void testRemovedGenericArguments() {
+  public void testRemovedGenericArguments() throws Exception {
     runTest(
             Collections.emptyMap(),
             Collections.emptySet(),
@@ -102,11 +106,17 @@
       BiPredicate<DexType, DexType> removedLink,
       Predicate<DexType> hasFormalTypeParameters,
       String initialSignature,
-      String expectedRewrittenSignature) {
+      String expectedRewrittenSignature)
+      throws Exception {
+    AppView<AppInfo> appView = computeAppView(AndroidApp.builder().build());
     GenericSignaturePartialTypeArgumentApplier argumentApplier =
         GenericSignaturePartialTypeArgumentApplier.build(
-                objectType, removedLink, hasFormalTypeParameters)
-            .addSubstitutionsAndVariables(substitutions, liveVariables);
+            appView,
+            TypeParameterContext.empty()
+                .addPrunedSubstitutions(substitutions)
+                .addLiveParameters(liveVariables),
+            removedLink,
+            hasFormalTypeParameters);
     TestDiagnosticMessagesImpl diagnosticsHandler = new TestDiagnosticMessagesImpl();
     MethodTypeSignature methodTypeSignature =
         argumentApplier.visitMethodSignature(
diff --git a/src/test/java/com/android/tools/r8/graph/genericsignature/UnboundedFormalTypeGenericSignatureTest.java b/src/test/java/com/android/tools/r8/graph/genericsignature/UnboundedFormalTypeGenericSignatureTest.java
index 58812ee..80939de 100644
--- a/src/test/java/com/android/tools/r8/graph/genericsignature/UnboundedFormalTypeGenericSignatureTest.java
+++ b/src/test/java/com/android/tools/r8/graph/genericsignature/UnboundedFormalTypeGenericSignatureTest.java
@@ -6,7 +6,6 @@
 
 import static org.hamcrest.CoreMatchers.containsString;
 
-import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -87,53 +86,51 @@
 
   @Test
   public void testUnboundParametersInClassR8() throws Exception {
-    R8TestRunResult runResult =
-        testForR8(parameters.getBackend())
-            .addProgramClassFileData(
-                transformer(Main.class)
-                    .removeInnerClasses()
-                    .setGenericSignature("L" + SUPER_BINARY_NAME + "<TR;>;")
-                    .transform(),
-                transformer(Super.class).removeInnerClasses().transform())
-            .addKeepAllClassesRule()
-            .addKeepAttributes(
-                ProguardKeepAttributes.SIGNATURE,
-                ProguardKeepAttributes.INNER_CLASSES,
-                ProguardKeepAttributes.ENCLOSING_METHOD)
-            .setMinApi(parameters.getApiLevel())
-            .run(parameters.getRuntime(), Main.class);
-    if (parameters.isCfRuntime()) {
-      runResult.assertFailureWithErrorThatMatches(containsString("java.lang.NullPointerException"));
-    } else {
-      runResult.assertSuccessWithOutputLines(Super.class.getTypeName() + "<R>", "R", "T");
-    }
+    testForR8(parameters.getBackend())
+        .addProgramClassFileData(
+            transformer(Main.class)
+                .removeInnerClasses()
+                .setGenericSignature("L" + SUPER_BINARY_NAME + "<TR;>;")
+                .transform(),
+            transformer(Super.class).removeInnerClasses().transform())
+        .addKeepAllClassesRule()
+        .addKeepAttributes(
+            ProguardKeepAttributes.SIGNATURE,
+            ProguardKeepAttributes.INNER_CLASSES,
+            ProguardKeepAttributes.ENCLOSING_METHOD)
+        .setMinApi(parameters.getApiLevel())
+        .allowDiagnosticInfoMessages()
+        .compile()
+        .apply(TestBase::verifyAllInfoFromGenericSignatureTypeParameterValidation)
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines(
+            "class " + Super.class.getTypeName(), "R", "class java.lang.Object");
   }
 
   @Test
   public void testUnboundParametersInMethodR8() throws Exception {
-    R8TestRunResult runResult =
-        testForR8(parameters.getBackend())
-            .addProgramClassFileData(
-                transformer(Main.class)
-                    .removeInnerClasses()
-                    .setGenericSignature(
-                        MethodPredicate.onName("testStatic"), "<R:Ljava/lang/Object;>()TS;")
-                    .setGenericSignature(
-                        MethodPredicate.onName("testVirtual"), "<R:Ljava/lang/Object;>()TQ;")
-                    .transform(),
-                transformer(Super.class).removeInnerClasses().transform())
-            .addKeepAllClassesRule()
-            .addKeepAttributes(
-                ProguardKeepAttributes.SIGNATURE,
-                ProguardKeepAttributes.INNER_CLASSES,
-                ProguardKeepAttributes.ENCLOSING_METHOD)
-            .setMinApi(parameters.getApiLevel())
-            .run(parameters.getRuntime(), Main.class);
-    if (parameters.isCfRuntime()) {
-      runResult.assertSuccessWithOutputLines(Super.class.getTypeName() + "<T>", "null", "null");
-    } else {
-      runResult.assertSuccessWithOutputLines(Super.class.getTypeName() + "<T>", "S", "Q");
-    }
+    testForR8(parameters.getBackend())
+        .addProgramClassFileData(
+            transformer(Main.class)
+                .removeInnerClasses()
+                .setGenericSignature(
+                    MethodPredicate.onName("testStatic"), "<R:Ljava/lang/Object;>()TS;")
+                .setGenericSignature(
+                    MethodPredicate.onName("testVirtual"), "<R:Ljava/lang/Object;>()TQ;")
+                .transform(),
+            transformer(Super.class).removeInnerClasses().transform())
+        .addKeepAllClassesRule()
+        .addKeepAttributes(
+            ProguardKeepAttributes.SIGNATURE,
+            ProguardKeepAttributes.INNER_CLASSES,
+            ProguardKeepAttributes.ENCLOSING_METHOD)
+        .setMinApi(parameters.getApiLevel())
+        .allowDiagnosticInfoMessages()
+        .compile()
+        .apply(TestBase::verifyAllInfoFromGenericSignatureTypeParameterValidation)
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines(
+            Super.class.getTypeName() + "<T>", "class java.lang.Object", "class java.lang.Object");
   }
 
   public static class Super<T> {}
diff --git a/src/test/java/com/android/tools/r8/graph/genericsignature/UnknownClassInSignatureTest.java b/src/test/java/com/android/tools/r8/graph/genericsignature/UnknownClassInSignatureTest.java
index 4c2ac5e..cf67f18 100644
--- a/src/test/java/com/android/tools/r8/graph/genericsignature/UnknownClassInSignatureTest.java
+++ b/src/test/java/com/android/tools/r8/graph/genericsignature/UnknownClassInSignatureTest.java
@@ -7,6 +7,7 @@
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -27,7 +28,6 @@
 public class UnknownClassInSignatureTest extends TestBase {
 
   private final TestParameters parameters;
-  private final String NEW_CLASS_SIGNATURE = "<T:LUnknownClass1;>LUnknownClass2<LUnknownClass3;>;";
   private final String NEW_FIELD_SIGNATURE = "LUnknownClass4<LUnknownClass4;>;";
   private final String NEW_METHOD_SIGNATURE = "()LUnkownClass5<LunknownPackage/UnknownClass6;>;";
 
@@ -46,7 +46,7 @@
         .addProgramClassFileData(
             transformer(Main.class)
                 .removeInnerClasses()
-                .setGenericSignature(NEW_CLASS_SIGNATURE)
+                .setGenericSignature("<T:LUnknownClass1;>LUnknownClass2<LUnknownClass3;>;")
                 .setGenericSignature(FieldPredicate.onName("field"), NEW_FIELD_SIGNATURE)
                 .setGenericSignature(MethodPredicate.onName("main"), NEW_METHOD_SIGNATURE)
                 .transform())
@@ -56,13 +56,16 @@
             ProguardKeepAttributes.ENCLOSING_METHOD,
             ProguardKeepAttributes.INNER_CLASSES)
         .setMinApi(parameters.getApiLevel())
+        .allowDiagnosticInfoMessages()
+        .compile()
+        .apply(TestBase::verifyExpectedInfoFromGenericSignatureSuperTypeValidation)
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines("Hello World!")
         .inspect(
             inspector -> {
               ClassSubject clazz = inspector.clazz(Main.class);
               assertThat(clazz, isPresent());
-              assertEquals(NEW_CLASS_SIGNATURE, clazz.getFinalSignatureAttribute());
+              assertNull(clazz.getFinalSignatureAttribute());
               FieldSubject field = clazz.uniqueFieldWithFinalName("field");
               assertThat(field, isPresent());
               assertEquals(NEW_FIELD_SIGNATURE, field.getFinalSignatureAttribute());
diff --git a/src/test/java/com/android/tools/r8/internal/ClankDepsTest.java b/src/test/java/com/android/tools/r8/internal/ClankDepsTest.java
index 82570e9..00fff76 100644
--- a/src/test/java/com/android/tools/r8/internal/ClankDepsTest.java
+++ b/src/test/java/com/android/tools/r8/internal/ClankDepsTest.java
@@ -45,6 +45,8 @@
         .allowUnusedProguardConfigurationRules()
         .allowUnnecessaryDontWarnWildcards()
         .setMinApi(AndroidApiLevel.N)
-        .compileWithExpectedDiagnostics(TestDiagnosticMessages::assertOnlyInfos);
+        .allowDiagnosticInfoMessages()
+        .compileWithExpectedDiagnostics(TestDiagnosticMessages::assertOnlyInfos)
+        .apply(TestBase::verifyHasInfoFromGenericSignatureTypeParameterValidation);
   }
 }
diff --git a/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinReflectionLibTest.java b/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinReflectionLibTest.java
index 548ce4d..049974c 100644
--- a/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinReflectionLibTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinReflectionLibTest.java
@@ -100,12 +100,20 @@
 
   @Test
   public void testDontOptimize() throws Exception {
-    test(TestShrinkerBuilder::noOptimization);
+    test(
+        builder -> {
+          builder.allowDiagnosticInfoMessages();
+          builder.noOptimization();
+        });
   }
 
   @Test
   public void testDontObfuscate() throws Exception {
-    test(TestShrinkerBuilder::noMinification);
+    test(
+        builder -> {
+          builder.allowDiagnosticInfoMessages();
+          builder.noMinification();
+        });
   }
 
 }
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataStripTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataStripTest.java
index 6406593..ca441cd 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataStripTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataStripTest.java
@@ -14,6 +14,7 @@
 
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.R8TestRunResult;
+import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.codeinspector.AnnotationSubject;
@@ -58,10 +59,12 @@
             .addKeepMainRule(mainClassName)
             .addKeepKotlinMetadata()
             .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
-            .allowDiagnosticWarningMessages()
+            .allowDiagnosticMessages()
             .setMinApi(parameters.getApiLevel())
             .allowUnusedDontWarnKotlinReflectJvmInternal(kotlinc.isNot(KOTLINC_1_3_72))
             .compile()
+            .assertNoErrorMessages()
+            .apply(TestBase::verifyAllInfoFromGenericSignatureTypeParameterValidation)
             .apply(KotlinMetadataTestBase::verifyExpectedWarningsFromKotlinReflectAndStdLib)
             .run(parameters.getRuntime(), mainClassName);
     CodeInspector inspector = result.inspector();
diff --git a/src/test/java/com/android/tools/r8/kotlin/optimize/switches/KotlinEnumSwitchTest.java b/src/test/java/com/android/tools/r8/kotlin/optimize/switches/KotlinEnumSwitchTest.java
index 9c01d63..8a27b3f 100644
--- a/src/test/java/com/android/tools/r8/kotlin/optimize/switches/KotlinEnumSwitchTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/optimize/switches/KotlinEnumSwitchTest.java
@@ -11,8 +11,12 @@
 import static org.junit.Assert.assertNotEquals;
 
 import com.android.tools.r8.KotlinCompilerTool;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion;
 import com.android.tools.r8.KotlinTestBase;
 import com.android.tools.r8.KotlinTestParameters;
+import com.android.tools.r8.R8TestBuilder;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestCompileResult;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -60,10 +64,18 @@
               options.enableEnumValueOptimization = enableSwitchMapRemoval;
               options.enableEnumSwitchMapRemoval = enableSwitchMapRemoval;
             })
-        .allowDiagnosticWarningMessages()
+        .applyIf(
+            kotlinParameters.getCompiler().is(KotlinCompilerVersion.KOTLINC_1_5_0_M2),
+            R8TestBuilder::allowDiagnosticMessages,
+            R8TestBuilder::allowDiagnosticWarningMessages)
         .setMinApi(parameters.getApiLevel())
         .noMinification()
         .compile()
+        .assertNoErrorMessages()
+        .applyIf(
+            kotlinParameters.getCompiler().is(KotlinCompilerVersion.KOTLINC_1_5_0_M2),
+            TestBase::verifyAllInfoFromGenericSignatureTypeParameterValidation,
+            TestCompileResult::assertNoInfoMessages)
         .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
         .inspect(
             inspector -> {
diff --git a/src/test/java/com/android/tools/r8/kotlin/reflection/KotlinReflectTest.java b/src/test/java/com/android/tools/r8/kotlin/reflection/KotlinReflectTest.java
index 4e376ed..6ee2517 100644
--- a/src/test/java/com/android/tools/r8/kotlin/reflection/KotlinReflectTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/reflection/KotlinReflectTest.java
@@ -10,6 +10,7 @@
 import com.android.tools.r8.DexIndexedConsumer.ArchiveConsumer;
 import com.android.tools.r8.KotlinTestBase;
 import com.android.tools.r8.KotlinTestParameters;
+import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.kotlin.metadata.KotlinMetadataTestBase;
@@ -91,11 +92,13 @@
         .setMinApi(parameters.getApiLevel())
         .addKeepAllClassesRule()
         .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
-        .allowDiagnosticWarningMessages()
+        .allowDiagnosticMessages()
         .allowUnusedDontWarnKotlinReflectJvmInternal(kotlinc.isNot(KOTLINC_1_3_72))
         .compile()
-        .writeToZip(foo.toPath())
+        .assertNoErrorMessages()
+        .apply(TestBase::verifyAllInfoFromGenericSignatureTypeParameterValidation)
         .apply(KotlinMetadataTestBase::verifyExpectedWarningsFromKotlinReflectAndStdLib)
+        .writeToZip(foo.toPath())
         .run(parameters.getRuntime(), PKG + ".SimpleReflectKt")
         .assertSuccessWithOutputLines(EXPECTED_OUTPUT);
   }
diff --git a/src/test/java/com/android/tools/r8/naming/MinifierClassSignatureTest.java b/src/test/java/com/android/tools/r8/naming/MinifierClassSignatureTest.java
index dc3acee..0aa7a87 100644
--- a/src/test/java/com/android/tools/r8/naming/MinifierClassSignatureTest.java
+++ b/src/test/java/com/android/tools/r8/naming/MinifierClassSignatureTest.java
@@ -330,7 +330,6 @@
                     internalOptions.testing.disableMappingToOriginalProgramVerification = true)
             .compile();
 
-    compileResult.assertNoInfoMessages();
     compileResult.assertNoErrorMessages();
 
     CodeInspector inspector = compileResult.inspector();
@@ -415,28 +414,6 @@
   }
 
   @Test
-  public void classSignatureOuter_valid() throws Exception {
-    // class Outer<T extends Simple> extends Base<T>
-    String signature = "<T:LSimple;>LBase<TT;>;";
-    testSingleClass(
-        "Outer",
-        signature,
-        TestDiagnosticMessages::assertNoWarnings,
-        inspector -> {
-          ClassSubject outer = inspector.clazz("Outer");
-          ClassSubject simple = inspector.clazz("Simple");
-          ClassSubject base = inspector.clazz("Base");
-          String baseDescriptorWithoutSemicolon =
-              base.getFinalDescriptor().substring(0, base.getFinalDescriptor().length() - 1);
-          String minifiedSignature =
-              "<T:" + simple.getFinalDescriptor() + ">" + baseDescriptorWithoutSemicolon + "<TT;>;";
-          assertEquals(minifiedSignature, outer.getFinalSignatureAttribute());
-          assertEquals(signature, outer.getOriginalSignatureAttribute());
-        },
-        false);
-  }
-
-  @Test
   public void classSignatureExtendsInner_valid() throws Exception {
     String signature = "LOuter<TT;>.Inner;";
     testSingleClass(
@@ -469,9 +446,9 @@
         inspector -> {
           assertThat(inspector.clazz("NotFound"), not(isPresent()));
           ClassSubject outer = inspector.clazz("Outer");
-          assertEquals(signature, outer.getOriginalSignatureAttribute());
+          assertNull(outer.getOriginalSignatureAttribute());
         },
-        false);
+        true);
   }
 
   @Test
@@ -484,8 +461,8 @@
         inspector -> {
           assertThat(inspector.clazz("NotFound"), not(isPresent()));
           ClassSubject outer = inspector.clazz("Outer$ExtendsInner");
-          // TODO(b/1867459990): What to do here.
-          assertEquals("LOuter$NotFound;", outer.getOriginalSignatureAttribute());
+          // TODO(b/186745999): What to do here.
+          assertNull(outer.getOriginalSignatureAttribute());
         },
         false);
   }
@@ -500,7 +477,7 @@
         inspector -> {
           assertThat(inspector.clazz("NotFound"), not(isPresent()));
           ClassSubject outer = inspector.clazz("Outer$ExtendsInner");
-          assertEquals(signature, outer.getOriginalSignatureAttribute());
+          assertNull(outer.getOriginalSignatureAttribute());
         },
         false);
   }
@@ -516,13 +493,13 @@
           assertThat(inspector.clazz("NotFound"), not(isPresent()));
           ClassSubject outer = inspector.clazz("Outer$ExtendsInner");
           // TODO(b/1867459990): What to do here.
-          assertEquals("LOuter$Inner$NotFound;", outer.getOriginalSignatureAttribute());
+          assertNull(outer.getOriginalSignatureAttribute());
         },
         false);
   }
 
   @Test
-  public void classSignatureExtendsInner_multipleMestedInnerClassesNotFound() throws Exception {
+  public void classSignatureExtendsInner_multipleNestedInnerClassesNotFound() throws Exception {
     String signature = "LOuter<TT;>.NotFound.AlsoNotFound;";
     testSingleClass(
         "Outer$ExtendsInner",
@@ -531,8 +508,7 @@
         inspector -> {
           assertThat(inspector.clazz("NotFound"), not(isPresent()));
           ClassSubject outer = inspector.clazz("Outer$ExtendsInner");
-          // TODO(b/1867459990): What to do here.
-          assertEquals("LOuter$NotFound$AlsoNotFound;", outer.getOriginalSignatureAttribute());
+          assertNull(outer.getOriginalSignatureAttribute());
         },
         false);
   }
diff --git a/src/test/java/com/android/tools/r8/shaking/KeepAnnotatedMemberTest.java b/src/test/java/com/android/tools/r8/shaking/KeepAnnotatedMemberTest.java
index 550356e..a7b7bfd 100644
--- a/src/test/java/com/android/tools/r8/shaking/KeepAnnotatedMemberTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/KeepAnnotatedMemberTest.java
@@ -77,9 +77,10 @@
         .addDontWarnGoogle()
         .addDontWarnJavax()
         .addDontWarn("org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement")
+        .allowDiagnosticInfoMessages()
         .compileWithExpectedDiagnostics(
-            diagnostics ->
-                diagnostics.assertErrorsMatch(diagnosticException(AssertionError.class)));
+            diagnostics -> diagnostics.assertErrorsMatch(diagnosticException(AssertionError.class)))
+        .apply(TestBase::verifyAllInfoFromGenericSignatureTypeParameterValidation);
   }
 
   @Test
@@ -92,7 +93,9 @@
         .addDontWarnGoogle()
         .addDontWarnJavax()
         .addDontWarn("org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement")
-        .compile();
+        .allowDiagnosticInfoMessages()
+        .compile()
+        .apply(TestBase::verifyAllInfoFromGenericSignatureTypeParameterValidation);
   }
 
   @Test
@@ -101,7 +104,9 @@
         .addProgramFiles(R8_JAR)
         .allowUnusedProguardConfigurationRules()
         .addKeepRules("-keepclasseswithmembers class * { @" + ABSENT_ANNOTATION + " *; }")
+        .allowDiagnosticInfoMessages()
         .compile()
+        .apply(TestBase::verifyHasInfoFromGenericSignatureTypeParameterValidation)
         .inspect(inspector -> assertEquals(0, inspector.allClasses().size()));
   }
 
@@ -113,7 +118,9 @@
         .addDontWarnGoogle()
         .addDontWarnJavax()
         .addDontWarn("org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement")
+        .allowDiagnosticInfoMessages()
         .compile()
+        .apply(TestBase::verifyAllInfoFromGenericSignatureTypeParameterValidation)
         .inspect(
             inspector -> {
               ClassSubject clazz = inspector.clazz(CLASS_WITH_ANNOTATED_METHOD);
@@ -129,7 +136,9 @@
         // TODO(b/159971974): Technically this rule does not hit anything and should fail due to
         //  missing allowUnusedProguardConfigurationRules()
         .addKeepRules("-keepclassmembers class * { @" + PRESENT_ANNOTATION + " *** *(...); }")
+        .allowDiagnosticInfoMessages()
         .compile()
+        .apply(TestBase::verifyAllInfoFromGenericSignatureTypeParameterValidation)
         .inspect(inspector -> assertEquals(0, inspector.allClasses().size()));
   }
 
@@ -139,7 +148,9 @@
         .addProgramFiles(R8_JAR)
         .addKeepClassRules(CLASS_WITH_ANNOTATED_METHOD)
         .addKeepRules("-keepclassmembers class * { @" + PRESENT_ANNOTATION + " *** *(...); }")
+        .allowDiagnosticInfoMessages()
         .compile()
+        .apply(TestBase::verifyAllInfoFromGenericSignatureTypeParameterValidation)
         .inspect(
             inspector -> {
               assertEquals(1, inspector.allClasses().size());
@@ -162,7 +173,9 @@
         .addProgramFiles(R8_JAR)
         .allowUnusedProguardConfigurationRules()
         .addKeepRules("-if class * -keep class <1> { @" + PRESENT_ANNOTATION + " *** *(...); }")
+        .allowDiagnosticInfoMessages()
         .compile()
+        .apply(TestBase::verifyHasInfoFromGenericSignatureTypeParameterValidation)
         .inspect(inspector -> assertEquals(0, inspector.allClasses().size()));
   }
 
@@ -172,7 +185,9 @@
         .addProgramFiles(R8_JAR)
         .addKeepClassRules(CLASS_WITH_ANNOTATED_METHOD)
         .addKeepRules("-if class * -keep class <1> { @" + PRESENT_ANNOTATION + " *** *(...); }")
+        .allowDiagnosticInfoMessages()
         .compile()
+        .apply(TestBase::verifyAllInfoFromGenericSignatureTypeParameterValidation)
         .inspect(
             inspector -> {
               assertEquals(1, inspector.allClasses().size());
@@ -204,7 +219,9 @@
             .addKeepRules("-keepclassmembers class * { @" + PRESENT_ANNOTATION + " *** *(...); }")
             .addDontWarnGoogle()
             .addDontWarnJavaxNullableAnnotation()
+            .allowDiagnosticInfoMessages()
             .compile()
+            .apply(TestBase::verifyAllInfoFromGenericSignatureTypeParameterValidation)
             .graphInspector();
 
     GraphInspector ifThenKeepClassMembersInspector =
@@ -222,7 +239,9 @@
                     + " *** *(...); }")
             .addDontWarnGoogle()
             .addDontWarnJavaxNullableAnnotation()
+            .allowDiagnosticInfoMessages()
             .compile()
+            .apply(TestBase::verifyAllInfoFromGenericSignatureTypeParameterValidation)
             .graphInspector();
     assertRetainedClassesEqual(referenceInspector, ifThenKeepClassMembersInspector);
 
@@ -241,7 +260,9 @@
                     + " *** *(...); }")
             .addDontWarnGoogle()
             .addDontWarnJavaxNullableAnnotation()
+            .allowDiagnosticInfoMessages()
             .compile()
+            .apply(TestBase::verifyAllInfoFromGenericSignatureTypeParameterValidation)
             .graphInspector();
     assertRetainedClassesEqual(referenceInspector, ifThenKeepClassesWithMembersInspector);
 
@@ -262,7 +283,9 @@
                     + " *** <2>(...); }")
             .addDontWarnGoogle()
             .addDontWarnJavaxNullableAnnotation()
+            .allowDiagnosticInfoMessages()
             .compile()
+            .apply(TestBase::verifyAllInfoFromGenericSignatureTypeParameterValidation)
             .graphInspector();
     assertRetainedClassesEqual(referenceInspector, ifHasMemberThenKeepClassInspector);
   }
diff --git a/src/test/java/com/android/tools/r8/shaking/keptgraph/WhyAreYouKeepingAllTest.java b/src/test/java/com/android/tools/r8/shaking/keptgraph/WhyAreYouKeepingAllTest.java
index 94bdbf1..ac22ab7 100644
--- a/src/test/java/com/android/tools/r8/shaking/keptgraph/WhyAreYouKeepingAllTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/keptgraph/WhyAreYouKeepingAllTest.java
@@ -48,7 +48,9 @@
         .addKeepRuleFiles(MAIN_KEEP)
         .addKeepRules(WHY_ARE_YOU_KEEPING_ALL)
         .collectStdout()
+        .allowDiagnosticInfoMessages()
         .compile()
+        .apply(TestBase::verifyAllInfoFromGenericSignatureTypeParameterValidation)
         .assertStdoutThatMatches(containsString("referenced in keep rule"))
         // TODO(b/124655065): We should always know the reason for keeping.
         // It is OK if this starts failing while the kept-graph API is incomplete, in which case