Ensure correct replacing of super types when having raw types
Bug: 214509535
Change-Id: I6c809245fb9623c1d8d06fbc21db2a630b979717
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
index a7362e5..c607e30 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -1129,7 +1129,7 @@
return false;
}
- // Rewrite generic signatures before we merge fields.
+ // Rewrite generic signatures before we merge a base with a generic signature.
rewriteGenericSignatures(target, source, directMethods.values(), virtualMethods.values());
// Convert out of DefaultInstanceInitializerCode, since this piece of code will require lens
@@ -1333,16 +1333,18 @@
assert false : "Type should be present in generic signature";
return null;
}
+ Map<String, FieldTypeSignature> substitutionMap = new HashMap<>();
List<FormalTypeParameter> formals = source.getClassSignature().getFormalTypeParameters();
if (genericArgumentsToSuperType.size() != formals.size()) {
- // TODO(b/214509535): Correctly rewrite signature when type arguments is empty.
- assert genericArgumentsToSuperType.isEmpty() : "Invalid argument count to formals";
- return null;
- }
- Map<String, FieldTypeSignature> substitutionMap = new HashMap<>();
- for (int i = 0; i < formals.size(); i++) {
- // It is OK to override a generic type variable so we just use put.
- substitutionMap.put(formals.get(i).getName(), genericArgumentsToSuperType.get(i));
+ if (!genericArgumentsToSuperType.isEmpty()) {
+ assert false : "Invalid argument count to formals";
+ return null;
+ }
+ } else {
+ for (int i = 0; i < formals.size(); i++) {
+ // It is OK to override a generic type variable so we just use put.
+ substitutionMap.put(formals.get(i).getName(), genericArgumentsToSuperType.get(i));
+ }
}
return GenericSignaturePartialTypeArgumentApplier.build(
appView,
@@ -1512,6 +1514,7 @@
.setApiLevelForDefinition(method.getApiLevelForDefinition())
.setApiLevelForCode(method.getApiLevelForDefinition())
.setIsLibraryMethodOverride(method.isLibraryMethodOverride())
+ .setGenericSignature(method.getGenericSignature())
.build();
if (method.accessFlags.isPromotedToPublic()) {
// The bridge is now the public method serving the role of the original method, and should
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergingWithMissingTypeArgsSubstitutionTest.java b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergingWithMissingTypeArgsSubstitutionTest.java
index 50a658f..27b7093 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergingWithMissingTypeArgsSubstitutionTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergingWithMissingTypeArgsSubstitutionTest.java
@@ -4,15 +4,18 @@
package com.android.tools.r8.classmerging.vertical;
-import static org.junit.Assert.assertThrows;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
-import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.DiagnosticsMatcher;
+import com.android.tools.r8.KeepConstantArguments;
import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoMethodStaticizing;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.utils.ExceptionDiagnostic;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
import java.lang.reflect.TypeVariable;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -33,23 +36,41 @@
@Test()
public void test() throws Exception {
- assertThrows(
- CompilationFailedException.class,
- () -> {
- testForR8Compat(parameters.getBackend())
- .addInnerClasses(getClass())
- .addKeepMainRule(Main.class)
- .addKeepClassRules(A.class)
- .addKeepAttributeSignature()
- .addVerticallyMergedClassesInspector(
- inspector -> inspector.assertMergedIntoSubtype(B.class))
- .enableInliningAnnotations()
- .setMinApi(parameters.getApiLevel())
- .compileWithExpectedDiagnostics(
- diagnostics ->
- diagnostics.assertErrorsMatch(
- DiagnosticsMatcher.diagnosticType(ExceptionDiagnostic.class)));
- });
+ testForR8Compat(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .addKeepClassRules(A.class)
+ .addKeepAttributeSignature()
+ .addVerticallyMergedClassesInspector(
+ inspector -> inspector.assertMergedIntoSubtype(B.class))
+ .enableInliningAnnotations()
+ .enableNoMethodStaticizingAnnotations()
+ .enableConstantArgumentAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("T", "Hello World")
+ .inspect(
+ inspector -> {
+ ClassSubject classSubject = inspector.clazz(C.class);
+ assertThat(classSubject, isPresentAndRenamed());
+ assertEquals(
+ "<T:Ljava/lang/Object;>L" + binaryName(A.class) + "<Ljava/lang/Object;>;",
+ classSubject.getFinalSignatureAttribute());
+ MethodSubject bar = classSubject.uniqueMethodWithName("bar");
+ assertThat(bar, isPresentAndRenamed());
+ assertEquals("(TT;)V", bar.getFinalSignatureAttribute());
+ // The NeverInline is transferred to the private vertically merged method, making
+ // it hard to lookup.
+ MethodSubject movedFooSubject =
+ classSubject.uniqueMethodThatMatches(
+ method ->
+ method.getMethod().getReference() != bar.getMethod().getReference()
+ && !method.isInstanceInitializer());
+ assertThat(movedFooSubject, isPresentAndRenamed());
+ assertEquals(
+ "(Ljava/lang/Object;)Ljava/lang/Object;",
+ movedFooSubject.getFinalSignatureAttribute());
+ });
}
static class Main {
@@ -60,7 +81,7 @@
stringC.getClass().getTypeParameters()) {
System.out.println(typeParameter.getName());
}
- stringC.m("Hello World");
+ stringC.bar("Hello World");
}
}
@@ -68,15 +89,23 @@
static class B<T> extends A<T> {
+ @KeepConstantArguments
+ @NoMethodStaticizing
@NeverInline
public T foo(T t) {
+ if (System.currentTimeMillis() == 0) {
+ throw new RuntimeException("Foo");
+ }
return t;
}
}
static class C<T> extends B {
- void m(T t) {
+ @NoMethodStaticizing
+ @KeepConstantArguments
+ @NeverInline
+ void bar(T t) {
System.out.println(foo(t));
}
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/MemberSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/MemberSubject.java
index bd9081e..8a0bab6 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/MemberSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/MemberSubject.java
@@ -12,6 +12,7 @@
public abstract Signature getFinalSignature();
+ @Override
public String getOriginalName() {
return getOriginalName(true);
}