From 9d91eb2510648d5766460cc8ce430542bf532292 Mon Sep 17 00:00:00 2001 From: Kirill Rakhman Date: Wed, 6 Dec 2023 14:11:29 +0100 Subject: [PATCH] [FIR] Fix inference based on recursive upper bound #KT-59012 Fixed --- ...CompilerTestFE10TestdataTestGenerated.java | 6 +++++ ...sticCompilerFE10TestDataTestGenerated.java | 6 +++++ ...eeOldFrontendDiagnosticsTestGenerated.java | 6 +++++ ...siOldFrontendDiagnosticsTestGenerated.java | 6 +++++ .../resolve/calls/inference/InferenceUtils.kt | 7 +++--- .../components/ResultTypeResolver.kt | 5 ++++ .../kotlin/types/AbstractTypeApproximator.kt | 9 +++++++ .../capturedTypes/capturedInTypeInference.kt | 16 ++++++++++++ .../memberScopeOfCaptured.fir.kt | 4 +-- .../basicInferenceForImplicitSelfType.fir.kt | 23 ++++++++++++----- .../basicInferenceForImplicitSelfType.kt | 11 ++++++++ .../basicInferenceForImplicitSelfType.txt | 25 ------------------- .../recursiveTypeWithTwoTypeParams.fir.kt | 8 +++--- .../test/runners/DiagnosticTestGenerated.java | 6 +++++ 14 files changed, 98 insertions(+), 40 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/inference/capturedTypes/capturedInTypeInference.kt delete mode 100644 compiler/testData/diagnostics/tests/inference/recursiveTypes/selfTypes/enabledInferenceOnSelfTypes/basicInferenceForImplicitSelfType.txt diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java index 7f460335834..d850c18772d 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java @@ -17875,6 +17875,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedFlexibleIntersectionTypesWithDifferentConstructors.kt"); } + @Test + @TestMetadata("capturedInTypeInference.kt") + public void testCapturedInTypeInference() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedInTypeInference.kt"); + } + @Test @TestMetadata("capturedType.kt") public void testCapturedType() throws Exception { diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java index 9be2eda1080..dd73bca2fc7 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java @@ -17875,6 +17875,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedFlexibleIntersectionTypesWithDifferentConstructors.kt"); } + @Test + @TestMetadata("capturedInTypeInference.kt") + public void testCapturedInTypeInference() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedInTypeInference.kt"); + } + @Test @TestMetadata("capturedType.kt") public void testCapturedType() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java index d83603d20ba..981768ced84 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java @@ -17869,6 +17869,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedFlexibleIntersectionTypesWithDifferentConstructors.kt"); } + @Test + @TestMetadata("capturedInTypeInference.kt") + public void testCapturedInTypeInference() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedInTypeInference.kt"); + } + @Test @TestMetadata("capturedType.kt") public void testCapturedType() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java index 33b0521d099..465ab241dfc 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java @@ -17875,6 +17875,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedFlexibleIntersectionTypesWithDifferentConstructors.kt"); } + @Test + @TestMetadata("capturedInTypeInference.kt") + public void testCapturedInTypeInference() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedInTypeInference.kt"); + } + @Test @TestMetadata("capturedType.kt") public void testCapturedType() throws Exception { diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/InferenceUtils.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/InferenceUtils.kt index 8bdfdb14b8f..7c6a29cad52 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/InferenceUtils.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/InferenceUtils.kt @@ -47,8 +47,9 @@ fun ConstraintStorage.buildNotFixedVariablesToNonSubtypableTypesSubstitutor( ) } -fun TypeSystemInferenceExtensionContext.hasRecursiveTypeParametersWithGivenSelfType(selfTypeConstructor: TypeConstructorMarker) = - selfTypeConstructor.getParameters().any { it.hasRecursiveBounds(selfTypeConstructor) } +fun TypeSystemInferenceExtensionContext.hasRecursiveTypeParametersWithGivenSelfType(selfTypeConstructor: TypeConstructorMarker): Boolean = + selfTypeConstructor.getParameters().any { it.hasRecursiveBounds(selfTypeConstructor) } || + isK2 && selfTypeConstructor is CapturedTypeConstructorMarker && selfTypeConstructor.supertypes().any { hasRecursiveTypeParametersWithGivenSelfType(it.typeConstructor()) } fun TypeSystemInferenceExtensionContext.isRecursiveTypeParameter(typeConstructor: TypeConstructorMarker) = typeConstructor.getTypeParameterClassifier()?.hasRecursiveBounds() == true @@ -79,4 +80,4 @@ fun NewConstraintSystemImpl.registerTypeVariableIfNotPresent( if (typeVariable.freshTypeConstructor(this) !in builder.currentStorage().allTypeVariables.keys) { builder.registerVariable(typeVariable) } -} \ No newline at end of file +} diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/ResultTypeResolver.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/ResultTypeResolver.kt index 8780ff9f3cc..b3730885710 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/ResultTypeResolver.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/ResultTypeResolver.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator import org.jetbrains.kotlin.resolve.calls.inference.components.TypeVariableDirectionCalculator.ResolveDirection import org.jetbrains.kotlin.resolve.calls.inference.extractTypeForGivenRecursiveTypeParameter +import org.jetbrains.kotlin.resolve.calls.inference.hasRecursiveTypeParametersWithGivenSelfType import org.jetbrains.kotlin.resolve.calls.inference.model.* import org.jetbrains.kotlin.types.AbstractTypeApproximator import org.jetbrains.kotlin.types.AbstractTypeChecker @@ -349,6 +350,10 @@ class ResultTypeResolver( if (upperConstraints.isNotEmpty()) { val upperType = computeUpperType(upperConstraints) + if (isK2 && hasRecursiveTypeParametersWithGivenSelfType(upperType.typeConstructor())) { + return upperType + } + return typeApproximator.approximateToSubType( upperType, TypeApproximatorConfiguration.InternalTypesApproximation diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/types/AbstractTypeApproximator.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/types/AbstractTypeApproximator.kt index cc627270350..711bd5b8dc5 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/types/AbstractTypeApproximator.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/types/AbstractTypeApproximator.kt @@ -476,6 +476,15 @@ abstract class AbstractTypeApproximator( val argumentType = newArguments[index]?.getType() ?: argument.getType() val capturedType = argumentType.lowerBoundIfFlexible().originalIfDefinitelyNotNullable().asCapturedType() + + // When capturing recursive types with self upper bounds, their super types can contain captured types. + // In approximateCapturedType, we check if the super/subtypes of captured types need approximation even if captured types + // themselves don't need approximation, and will land here. + // To support this case, we also don't want to approximate captured types here if the configuration says so. + if (capturedType != null && isK2 && !conf.capturedType(ctx, capturedType)) { + continue@loop + } + val capturedStarProjectionOrNull = capturedType?.typeConstructorProjection()?.takeIf { it.isStarProjection() } diff --git a/compiler/testData/diagnostics/tests/inference/capturedTypes/capturedInTypeInference.kt b/compiler/testData/diagnostics/tests/inference/capturedTypes/capturedInTypeInference.kt new file mode 100644 index 00000000000..c9f790fe145 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/capturedTypes/capturedInTypeInference.kt @@ -0,0 +1,16 @@ +// FIR_IDENTICAL +class Key +class Box + +fun get(key: Key): T? = null +fun acceptBox(box: Box) {} + +fun test(key: Key>) { + // CS of get: + // Key)> <: Key + // If the type is not approximated to subtype before fixation, the type of the lambda parameter `it` becomes Any? + get(key)?.let { acceptBox(it) } + + val x = get(key) + x?.let { acceptBox(it) } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/capturedTypes/memberScopeOfCaptured.fir.kt b/compiler/testData/diagnostics/tests/inference/capturedTypes/memberScopeOfCaptured.fir.kt index 977e52e5eb0..23bd4db3ece 100644 --- a/compiler/testData/diagnostics/tests/inference/capturedTypes/memberScopeOfCaptured.fir.kt +++ b/compiler/testData/diagnostics/tests/inference/capturedTypes/memberScopeOfCaptured.fir.kt @@ -8,6 +8,6 @@ fun A.bar(): A = this fun baz(x: A) { x.bar() checkType { _>() } - x.bar().foo() checkType { _() } // See KT-10448 - x.bar().foo() checkType { _() } // Inference change in K2 + x.bar().foo() checkType { _() } // See KT-10448 + x.bar().foo() checkType { _() } // Inference change in K2 } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/recursiveTypes/selfTypes/enabledInferenceOnSelfTypes/basicInferenceForImplicitSelfType.fir.kt b/compiler/testData/diagnostics/tests/inference/recursiveTypes/selfTypes/enabledInferenceOnSelfTypes/basicInferenceForImplicitSelfType.fir.kt index 9d97f632031..cbd57fd4dd8 100644 --- a/compiler/testData/diagnostics/tests/inference/recursiveTypes/selfTypes/enabledInferenceOnSelfTypes/basicInferenceForImplicitSelfType.fir.kt +++ b/compiler/testData/diagnostics/tests/inference/recursiveTypes/selfTypes/enabledInferenceOnSelfTypes/basicInferenceForImplicitSelfType.fir.kt @@ -13,14 +13,21 @@ class Builder> { fun test(): T = TODO() fun foo() {} + fun bar(block: () -> Out) {} } +class Out + fun testStar(builder: Builder<*>) { - builder.test() + builder.test() builder - .test() - .foo() + .test() + .foo() + + builder + .test() + .bar { Out() } } fun > testTypeParam(builder: Builder) { @@ -29,14 +36,18 @@ fun > testTypeParam(builder: Builder) { builder .test() .foo() + + builder + .test() + .bar { Out() } } fun testStarJava(builder: JavaBuilder<*>) { - builder.test() + builder.test() builder - .test() - .foo() + .test() + .foo() } fun > testTypeParamJava(builder: JavaBuilder) { diff --git a/compiler/testData/diagnostics/tests/inference/recursiveTypes/selfTypes/enabledInferenceOnSelfTypes/basicInferenceForImplicitSelfType.kt b/compiler/testData/diagnostics/tests/inference/recursiveTypes/selfTypes/enabledInferenceOnSelfTypes/basicInferenceForImplicitSelfType.kt index dba9e266066..b309e53ef35 100644 --- a/compiler/testData/diagnostics/tests/inference/recursiveTypes/selfTypes/enabledInferenceOnSelfTypes/basicInferenceForImplicitSelfType.kt +++ b/compiler/testData/diagnostics/tests/inference/recursiveTypes/selfTypes/enabledInferenceOnSelfTypes/basicInferenceForImplicitSelfType.kt @@ -13,14 +13,21 @@ class Builder> { fun test(): T = TODO() fun foo() {} + fun bar(block: () -> Out) {} } +class Out + fun testStar(builder: Builder<*>) { ")!>builder.test() builder .test() .foo() + + builder + .test() + .bar { Out() } } fun > testTypeParam(builder: Builder) { @@ -29,6 +36,10 @@ fun > testTypeParam(builder: Builder) { builder .test() .foo() + + builder + .test() + .bar { Out() } } fun testStarJava(builder: JavaBuilder<*>) { diff --git a/compiler/testData/diagnostics/tests/inference/recursiveTypes/selfTypes/enabledInferenceOnSelfTypes/basicInferenceForImplicitSelfType.txt b/compiler/testData/diagnostics/tests/inference/recursiveTypes/selfTypes/enabledInferenceOnSelfTypes/basicInferenceForImplicitSelfType.txt deleted file mode 100644 index a649ecfa7d8..00000000000 --- a/compiler/testData/diagnostics/tests/inference/recursiveTypes/selfTypes/enabledInferenceOnSelfTypes/basicInferenceForImplicitSelfType.txt +++ /dev/null @@ -1,25 +0,0 @@ -package - -public fun testStar(/*0*/ builder: Builder<*>): kotlin.Unit -public fun testStarJava(/*0*/ builder: JavaBuilder<*>): kotlin.Unit -public fun > testTypeParam(/*0*/ builder: Builder): kotlin.Unit -public fun > testTypeParamJava(/*0*/ builder: JavaBuilder): kotlin.Unit - -public final class Builder> { - public constructor Builder>() - public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean - public final fun foo(): kotlin.Unit - public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int - public final fun test(): T - public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String -} - -public open class JavaBuilder!> { - public constructor JavaBuilder!>() - public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean - public/*package*/ open fun foo(): kotlin.Unit - public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int - public/*package*/ open fun test(): T! - public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String -} - diff --git a/compiler/testData/diagnostics/tests/inference/recursiveTypes/selfTypes/enabledInferenceOnSelfTypes/recursiveTypeWithTwoTypeParams.fir.kt b/compiler/testData/diagnostics/tests/inference/recursiveTypes/selfTypes/enabledInferenceOnSelfTypes/recursiveTypeWithTwoTypeParams.fir.kt index f55fa6eb146..216897055b4 100644 --- a/compiler/testData/diagnostics/tests/inference/recursiveTypes/selfTypes/enabledInferenceOnSelfTypes/recursiveTypeWithTwoTypeParams.fir.kt +++ b/compiler/testData/diagnostics/tests/inference/recursiveTypes/selfTypes/enabledInferenceOnSelfTypes/recursiveTypeWithTwoTypeParams.fir.kt @@ -13,11 +13,11 @@ interface BodySpec> { } fun test(b: BodySpec) { - val x = b.isEqualTo("") - x + val x = b.isEqualTo("") + ")!>x } fun testJava(b: JavaBodySpec) { - val x = b.isEqualTo("") - x + val x = b.isEqualTo("") + ..JavaBodySpec?!")!>x } 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 405ebae99ac..ac9844f3a38 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 @@ -17875,6 +17875,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedFlexibleIntersectionTypesWithDifferentConstructors.kt"); } + @Test + @TestMetadata("capturedInTypeInference.kt") + public void testCapturedInTypeInference() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedInTypeInference.kt"); + } + @Test @TestMetadata("capturedType.kt") public void testCapturedType() throws Exception {