From eb19d39cbf0ba17237eac9295e1c3a3e0b9f46fd Mon Sep 17 00:00:00 2001 From: Victor Petukhov Date: Fri, 17 Jun 2022 15:01:53 +0200 Subject: [PATCH] [FE 1.0] Build captured type's supertypes in an alternative way: use own projection type as a first supertype, then supertypes from the corresponding type parameter's upper bounds The original case provoked forking a constraint system which isn't supported in K1 (K2 only). If the captured type is recursive, then type parameter's upper bounds may break subtyping due to substitution the current captured type again, into a recursive type parameter. Note that we already have special logic for recursive captured types. See `isTypeVariableAgainstStarProjectionForSelfType`. ^KT-52782 Fixed --- ...CompilerTestFE10TestdataTestGenerated.java | 6 ++++ ...irOldFrontendDiagnosticsTestGenerated.java | 6 ++++ ...DiagnosticsWithLightTreeTestGenerated.java | 6 ++++ .../components/NewTypeSubstitutor.kt | 6 ++-- .../tests/inference/capturedTypes/kt52782.kt | 13 +++++++ .../tests/inference/capturedTypes/kt52782.txt | 18 ++++++++++ .../diagnostics/tests/inference/kt47316.kt | 2 +- .../test/runners/DiagnosticTestGenerated.java | 6 ++++ .../kotlin/types/checker/NewCapturedType.kt | 34 +++++++++++++------ 9 files changed, 83 insertions(+), 14 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/inference/capturedTypes/kt52782.kt create mode 100644 compiler/testData/diagnostics/tests/inference/capturedTypes/kt52782.txt diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java index ca34aebe711..3590ad08500 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java @@ -14659,6 +14659,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/kt49101.kt"); } + @Test + @TestMetadata("kt52782.kt") + public void testKt52782() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/kt52782.kt"); + } + @Test @TestMetadata("memberScopeOfCaptured.kt") public void testMemberScopeOfCaptured() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java index 556d9698867..9e75bca0143 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java @@ -14659,6 +14659,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/kt49101.kt"); } + @Test + @TestMetadata("kt52782.kt") + public void testKt52782() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/kt52782.kt"); + } + @Test @TestMetadata("memberScopeOfCaptured.kt") public void testMemberScopeOfCaptured() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java index 9cdb0e13770..d98878c7eca 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java @@ -14659,6 +14659,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/kt49101.kt"); } + @Test + @TestMetadata("kt52782.kt") + public void testKt52782() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/kt52782.kt"); + } + @Test @TestMetadata("memberScopeOfCaptured.kt") public void testMemberScopeOfCaptured() throws Exception { diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/NewTypeSubstitutor.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/NewTypeSubstitutor.kt index 6f1b4f79e37..6f5759dc0aa 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/NewTypeSubstitutor.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/NewTypeSubstitutor.kt @@ -106,8 +106,8 @@ interface NewTypeSubstitutor : TypeSubstitutorMarker { val innerType = capturedType.lowerType ?: capturedType.constructor.projection.type.unwrap() val substitutedInnerType = substitute(innerType, keepAnnotation, runCapturedChecks = false) - val substitutedSuperTypes = - capturedType.constructor.supertypes.map { substitute(it, keepAnnotation, runCapturedChecks = false) ?: it } + val (projectionSupertype, boundSupertypes) = + capturedType.constructor.transformSupertypes { substitute(it, keepAnnotation, runCapturedChecks = false) ?: it } if (substitutedInnerType != null) { return if (substitutedInnerType.isCaptured()) substitutedInnerType else { @@ -116,7 +116,7 @@ interface NewTypeSubstitutor : TypeSubstitutorMarker { NewCapturedTypeConstructor( TypeProjectionImpl(typeConstructor.projection.projectionKind, substitutedInnerType), typeParameter = typeConstructor.typeParameter - ).also { it.initializeSupertypes(substitutedSuperTypes) }, + ).also { it.initializeSupertypes(projectionSupertype, boundSupertypes) }, lowerType = if (capturedType.lowerType != null) substitutedInnerType else null ) } diff --git a/compiler/testData/diagnostics/tests/inference/capturedTypes/kt52782.kt b/compiler/testData/diagnostics/tests/inference/capturedTypes/kt52782.kt new file mode 100644 index 00000000000..1b8cb3ea392 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/capturedTypes/kt52782.kt @@ -0,0 +1,13 @@ +// FIR_IDENTICAL +// FILE: Foo.java +public abstract class Foo>> { + abstract String getTest(); +} + +// FILE: Bar.java +public abstract class Bar>> {} + +// FILE: main.kt +fun box(foo: Foo<*>) { + foo.test // unresolved in 1.7.0, OK before +} diff --git a/compiler/testData/diagnostics/tests/inference/capturedTypes/kt52782.txt b/compiler/testData/diagnostics/tests/inference/capturedTypes/kt52782.txt new file mode 100644 index 00000000000..b1d922751e5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/capturedTypes/kt52782.txt @@ -0,0 +1,18 @@ +package + +public fun box(/*0*/ foo: Foo<*>): kotlin.Unit + +public abstract class Bar!>!> { + public constructor Bar!>!>() + 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 abstract class Foo!>!> { + public constructor Foo!>!>() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public/*package*/ abstract fun getTest(): kotlin.String! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/inference/kt47316.kt b/compiler/testData/diagnostics/tests/inference/kt47316.kt index f881ef0e15d..b36c5dcf9df 100644 --- a/compiler/testData/diagnostics/tests/inference/kt47316.kt +++ b/compiler/testData/diagnostics/tests/inference/kt47316.kt @@ -30,7 +30,7 @@ fun String.asFsdAddress(): String { fun box(): String { val state = Test().state if (state is GoBuildingRunningState<*>) { - state.buildingWorkingDirectory.asFsdAddress() + state.buildingWorkingDirectory.asFsdAddress() } return "OK" } diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index 6c9d2da3bb4..897f7fecc39 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -14665,6 +14665,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/kt49101.kt"); } + @Test + @TestMetadata("kt52782.kt") + public void testKt52782() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/kt52782.kt"); + } + @Test @TestMetadata("memberScopeOfCaptured.kt") public void testMemberScopeOfCaptured() throws Exception { diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewCapturedType.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewCapturedType.kt index 55eb1b8207a..44093c37c4d 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewCapturedType.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewCapturedType.kt @@ -173,16 +173,16 @@ private fun captureArguments(type: UnwrappedType, status: CaptureStatus): List) { + private var projectionSupertype: UnwrappedType? = null + + fun initializeSupertypes(projectionSupertype: UnwrappedType?, boundSupertypes: List) { assert(this.supertypesComputation == null) { - "Already initialized! oldValue = ${this.supertypesComputation}, newValue = $supertypes" + "Already initialized! oldValue = ${this.supertypesComputation}, newValue = $boundSupertypes" } - this.supertypesComputation = { supertypes } + this.projectionSupertype = projectionSupertype + this.supertypesComputation = { boundSupertypes } + } + + override fun getSupertypes(): List = buildList { + projectionSupertype?.let { add(it) } + boundSupertypes?.let { addAll(it) } + } + + fun transformSupertypes(transformation: (UnwrappedType) -> UnwrappedType): Pair> { + val projectionSupertypeTransformed = projectionSupertype?.let(transformation) + val boundSupertypesTransformed = boundSupertypes?.map(transformation) ?: emptyList() + return projectionSupertypeTransformed to boundSupertypesTransformed } - override fun getSupertypes() = _supertypes ?: emptyList() override fun getParameters(): List = emptyList() override fun isFinal() = false