Make computation of arguments for raw types lazy

See how we translate raw types to Kotlin model:
RawType(A) = A<ErasedUpperBound(T1), ...>
ErasedUpperBound(T : G<t>) = G<*> // UpperBound(T) is a type G<t> with arguments
ErasedUpperBound(T : A) = A // UpperBound(T) is a type A without arguments
ErasedUpperBound(T : F) = UpperBound(F) // UB(T) is another type parameter F

Stack overflow happens with the following classes:
class A<X extends B> // NB: raw type B in upper bound
class B<Y extends A> // NB: raw type A in upper bound

when calculating raw type for A, we start calculate ErasedUpperBound(Y),
thus starting calculating raw type for B => ErasedUpperBound(X) => RawType(A),
so we have SOE here.
The problem is that we calculating the arguments for these raw types eagerly,
while from the definition of ErasedUpperBound(Y) we only need a type constructor
of raw type B (and the number of parameters), we don't use its arguments.

The solution is to make arguments calculating for raw types lazy

 #KT-16528 Fixed
This commit is contained in:
Denis Zharkov
2017-03-09 17:14:52 +03:00
parent f2fea9a04a
commit 7173e56393
7 changed files with 90 additions and 2 deletions
@@ -0,0 +1,19 @@
// FILE: JavaScriptParser.java
public class JavaScriptParser<T extends JSPsiTypeParser> {
public String foo() {return "OK";}
}
// FILE: JSPsiTypeParser.java
public class JSPsiTypeParser<T extends JavaScriptParser> {}
// FILE: ES6Parser.java
public class ES6Parser<T extends JSPsiTypeParser> extends JavaScriptParser<T> {}
// FILE: main.kt
fun createParser(): JavaScriptParser<*> {
return ES6Parser<JSPsiTypeParser<*>>()
}
fun box(): String = createParser().foo()
@@ -0,0 +1,21 @@
// WITH_RUNTIME
// FILE: Device.java
import java.util.Collection;
public class Device<D extends Device, S extends Service> {
public static Collection<Device<Device, Service>> getLoop() {
return null;
}
}
// FILE: Service.java
public class Service<D extends Device, S extends Service> {
}
// FILE: loop.kt
fun box(): String {
val x = Device.getLoop()?.firstOrNull() // compilation error
return "OK"
}
@@ -0,0 +1,4 @@
// FILE: JavaScriptParser.java
public class JavaScriptParser<F extends JSPsiTypeParser> {}
// FILE: JSPsiTypeParser.java
public class JSPsiTypeParser<T extends JavaScriptParser> {}
@@ -0,0 +1,15 @@
package
public open class JSPsiTypeParser</*0*/ T : JavaScriptParser<(raw) JSPsiTypeParser<*>!>!> {
public constructor JSPsiTypeParser</*0*/ T : JavaScriptParser<(raw) JSPsiTypeParser<*>!>!>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public open class JavaScriptParser</*0*/ F : JSPsiTypeParser<(raw) JavaScriptParser<*>!>!> {
public constructor JavaScriptParser</*0*/ F : JSPsiTypeParser<(raw) JavaScriptParser<*>!>!>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -15273,6 +15273,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("interClassesRecursion.kt")
public void testInterClassesRecursion() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/platformTypes/rawTypes/interClassesRecursion.kt");
doTest(fileName);
}
@TestMetadata("nonGenericRawMember.kt")
public void testNonGenericRawMember() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/platformTypes/rawTypes/nonGenericRawMember.kt");
@@ -477,6 +477,27 @@ public class BlackBoxAgainstJavaCodegenTestGenerated extends AbstractBlackBoxAga
}
}
@TestMetadata("compiler/testData/codegen/boxAgainstJava/recursiveRawTypes")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class RecursiveRawTypes extends AbstractBlackBoxAgainstJavaCodegenTest {
public void testAllFilesPresentInRecursiveRawTypes() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxAgainstJava/recursiveRawTypes"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("kt16528.kt")
public void testKt16528() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxAgainstJava/recursiveRawTypes/kt16528.kt");
doTest(fileName);
}
@TestMetadata("kt16639.kt")
public void testKt16639() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxAgainstJava/recursiveRawTypes/kt16639.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/boxAgainstJava/reflection")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -218,8 +218,10 @@ class JavaTypeResolver(
// so we get A<*, *>.
// Summary result for upper bound of T is `A<A<*, *>, A<*, *>>..A<out A<*, *>, out A<*, *>>`
val erasedUpperBound =
parameter.getErasedUpperBound(attr.upperBoundOfTypeParameter) {
constructor.declarationDescriptor!!.defaultType.replaceArgumentsWithStarProjections()
LazyWrappedType(c.storageManager) {
parameter.getErasedUpperBound(attr.upperBoundOfTypeParameter) {
constructor.declarationDescriptor!!.defaultType.replaceArgumentsWithStarProjections()
}
}
RawSubstitution.computeProjection(parameter, attr, erasedUpperBound)