From 7173e56393beb811af1e43381c61e868643b4edd Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Thu, 9 Mar 2017 17:14:52 +0300 Subject: [PATCH] Make computation of arguments for raw types lazy See how we translate raw types to Kotlin model: RawType(A) = A ErasedUpperBound(T : G) = G<*> // UpperBound(T) is a type G 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 // NB: raw type B in upper bound class B // 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 --- .../recursiveRawTypes/kt16528.kt | 19 +++++++++++++++++ .../recursiveRawTypes/kt16639.kt | 21 +++++++++++++++++++ .../rawTypes/interClassesRecursion.kt | 4 ++++ .../rawTypes/interClassesRecursion.txt | 15 +++++++++++++ .../checkers/DiagnosticsTestGenerated.java | 6 ++++++ ...ackBoxAgainstJavaCodegenTestGenerated.java | 21 +++++++++++++++++++ .../load/java/lazy/types/JavaTypeResolver.kt | 6 ++++-- 7 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 compiler/testData/codegen/boxAgainstJava/recursiveRawTypes/kt16528.kt create mode 100644 compiler/testData/codegen/boxAgainstJava/recursiveRawTypes/kt16639.kt create mode 100644 compiler/testData/diagnostics/tests/platformTypes/rawTypes/interClassesRecursion.kt create mode 100644 compiler/testData/diagnostics/tests/platformTypes/rawTypes/interClassesRecursion.txt diff --git a/compiler/testData/codegen/boxAgainstJava/recursiveRawTypes/kt16528.kt b/compiler/testData/codegen/boxAgainstJava/recursiveRawTypes/kt16528.kt new file mode 100644 index 00000000000..c556592861d --- /dev/null +++ b/compiler/testData/codegen/boxAgainstJava/recursiveRawTypes/kt16528.kt @@ -0,0 +1,19 @@ +// FILE: JavaScriptParser.java +public class JavaScriptParser { + public String foo() {return "OK";} +} +// FILE: JSPsiTypeParser.java +public class JSPsiTypeParser {} + +// FILE: ES6Parser.java + +public class ES6Parser extends JavaScriptParser {} + +// FILE: main.kt + +fun createParser(): JavaScriptParser<*> { + return ES6Parser>() +} + +fun box(): String = createParser().foo() + diff --git a/compiler/testData/codegen/boxAgainstJava/recursiveRawTypes/kt16639.kt b/compiler/testData/codegen/boxAgainstJava/recursiveRawTypes/kt16639.kt new file mode 100644 index 00000000000..41a21c41c7c --- /dev/null +++ b/compiler/testData/codegen/boxAgainstJava/recursiveRawTypes/kt16639.kt @@ -0,0 +1,21 @@ +// WITH_RUNTIME +// FILE: Device.java +import java.util.Collection; + +public class Device { + public static Collection> getLoop() { + return null; + } +} + +// FILE: Service.java + +public class Service { +} + +// FILE: loop.kt + +fun box(): String { + val x = Device.getLoop()?.firstOrNull() // compilation error + return "OK" +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/rawTypes/interClassesRecursion.kt b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/interClassesRecursion.kt new file mode 100644 index 00000000000..a0351f21e5c --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/interClassesRecursion.kt @@ -0,0 +1,4 @@ +// FILE: JavaScriptParser.java +public class JavaScriptParser {} +// FILE: JSPsiTypeParser.java +public class JSPsiTypeParser {} diff --git a/compiler/testData/diagnostics/tests/platformTypes/rawTypes/interClassesRecursion.txt b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/interClassesRecursion.txt new file mode 100644 index 00000000000..b704791a33b --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/interClassesRecursion.txt @@ -0,0 +1,15 @@ +package + +public open class JSPsiTypeParser!>!> { + public constructor 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!>!> { + public constructor 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 +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index cf360dcb14a..e9c6058ec8b 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -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"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxAgainstJavaCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxAgainstJavaCodegenTestGenerated.java index 24a71d97837..24b3db77bf9 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxAgainstJavaCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxAgainstJavaCodegenTestGenerated.java @@ -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) diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/types/JavaTypeResolver.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/types/JavaTypeResolver.kt index bc4958ce1e0..f0044598a6a 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/types/JavaTypeResolver.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/types/JavaTypeResolver.kt @@ -218,8 +218,10 @@ class JavaTypeResolver( // so we get A<*, *>. // Summary result for upper bound of T is `A, A<*, *>>..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)