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 e49c27ace3e..c6de1ffab07 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 @@ -14801,6 +14801,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 a918d26fb83..ed19c87192a 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 @@ -14801,6 +14801,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 49b8fd4020e..47af1e02b2f 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 @@ -14801,6 +14801,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/testData/diagnostics/tests/inference/capturedTypes/kt52782.fir.kt b/compiler/testData/diagnostics/tests/inference/capturedTypes/kt52782.fir.kt new file mode 100644 index 00000000000..afd7aab277a --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/capturedTypes/kt52782.fir.kt @@ -0,0 +1,62 @@ +// SKIP_TXT +// FILE: Foo.java +public abstract class Foo>> { + abstract String getTest(); +} + +// FILE: Bar.java +public abstract class Bar>> {} + +// FILE: main.kt + +fun >> Foo.bar() {} + +fun box(foo: Foo<*>) { + // How inference for the `foo.bar()` call works + // + // X = Captured(*) + // Foo <: Foo => X = Fv => NewBound(X <: Fv), NewBound(Fv <: X) + // + // Incorporation 1: + // X <: Fv && Fv <: Bar> => X <: Bar> + // X has one supertype – Bar> ~ Bar where Y = Captured(out Foo) + // X <: Bar> => Bar <: Bar> => + // Y <: Foo + // Y has two supertypes --> (Foo>, Foo) + // Let Z be a captured type in Foo> + // Foo <: Foo => Z = Fv => + // But since Z is captured from subtyping we run approximation over it resulting to + // Z ~ Bar> + // NewBound(Bar> <: Fv) + // + // But since Fv <: X, Bar> should be a subtype of X, but it is not :( + // + // Note the problematic part is when Y has two supertypes + // And we just check only first one one the second one would work + // In K2, it's covered by fork-points, see https://youtrack.jetbrains.com/issue/KT-50401 and org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector.TypeCheckerStateForConstraintInjector.runForkingPoint + + + // Without approximation (just theoretically what would happen if we didn't approximated FROM_SUBTYPING captured types). + // Actually, it's not really relevant but just in case someone need it. + // + // X = Captured(*) + // Foo <: Foo => X = Fv => NewBound(X <: Fv), NewBound(Fv <: X) + // + // Incorporation 1: + // X <: Fv && Fv <: Bar> => X <: Bar> + // X has one supertype – Bar> ~ Bar where Y = Captured(out Foo) + // X <: Bar> => Bar <: Bar> => + // Y <: Foo + // Y has two supertypes --> (Foo>, Foo) + // Let Z be a captured type in Foo> + // Foo <: Foo => Z = Fv => NewBound(Z <: Fv) + // + // Incorporation 2: + // Z <: Fv && Fv <: Bar> => Z <: Bar> + // Z has two supertypes --> (Bar>, Bar) + // ... went into recursion + + foo.bar() + + foo.test +} 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..4f6b5df8c2d --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/capturedTypes/kt52782.kt @@ -0,0 +1,62 @@ +// SKIP_TXT +// FILE: Foo.java +public abstract class Foo>> { + abstract String getTest(); +} + +// FILE: Bar.java +public abstract class Bar>> {} + +// FILE: main.kt + +fun >> Foo.bar() {} + +fun box(foo: Foo<*>) { + // How inference for the `foo.bar()` call works + // + // X = Captured(*) + // Foo <: Foo => X = Fv => NewBound(X <: Fv), NewBound(Fv <: X) + // + // Incorporation 1: + // X <: Fv && Fv <: Bar> => X <: Bar> + // X has one supertype – Bar> ~ Bar where Y = Captured(out Foo) + // X <: Bar> => Bar <: Bar> => + // Y <: Foo + // Y has two supertypes --> (Foo>, Foo) + // Let Z be a captured type in Foo> + // Foo <: Foo => Z = Fv => + // But since Z is captured from subtyping we run approximation over it resulting to + // Z ~ Bar> + // NewBound(Bar> <: Fv) + // + // But since Fv <: X, Bar> should be a subtype of X, but it is not :( + // + // Note the problematic part is when Y has two supertypes + // And we just check only first one one the second one would work + // In K2, it's covered by fork-points, see https://youtrack.jetbrains.com/issue/KT-50401 and org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector.TypeCheckerStateForConstraintInjector.runForkingPoint + + + // Without approximation (just theoretically what would happen if we didn't approximated FROM_SUBTYPING captured types). + // Actually, it's not really relevant but just in case someone need it. + // + // X = Captured(*) + // Foo <: Foo => X = Fv => NewBound(X <: Fv), NewBound(Fv <: X) + // + // Incorporation 1: + // X <: Fv && Fv <: Bar> => X <: Bar> + // X has one supertype – Bar> ~ Bar where Y = Captured(out Foo) + // X <: Bar> => Bar <: Bar> => + // Y <: Foo + // Y has two supertypes --> (Foo>, Foo) + // Let Z be a captured type in Foo> + // Foo <: Foo => Z = Fv => NewBound(Z <: Fv) + // + // Incorporation 2: + // Z <: Fv && Fv <: Bar> => Z <: Bar> + // Z has two supertypes --> (Bar>, Bar) + // ... went into recursion + + foo.bar() + + foo.test +} diff --git a/compiler/testData/diagnostics/tests/inference/kt47316.fir.kt b/compiler/testData/diagnostics/tests/inference/kt47316.fir.kt index c7ac7b3e863..87f706349da 100644 --- a/compiler/testData/diagnostics/tests/inference/kt47316.fir.kt +++ b/compiler/testData/diagnostics/tests/inference/kt47316.fir.kt @@ -30,6 +30,8 @@ fun String.asFsdAddress(): String { fun box(): String { val state = Test().state if (state is GoBuildingRunningState<*>) { + // Actually, that code is valid and met at IJ, but unfortunately it was broken since 1.7.0 + // See KT-52782 and testData/diagnostics/tests/inference/capturedTypes/kt52782.kt state.buildingWorkingDirectory.asFsdAddress() } return "OK" diff --git a/compiler/testData/diagnostics/tests/inference/kt47316.kt b/compiler/testData/diagnostics/tests/inference/kt47316.kt index f881ef0e15d..1b69337dc45 100644 --- a/compiler/testData/diagnostics/tests/inference/kt47316.kt +++ b/compiler/testData/diagnostics/tests/inference/kt47316.kt @@ -30,6 +30,8 @@ fun String.asFsdAddress(): String { fun box(): String { val state = Test().state if (state is GoBuildingRunningState<*>) { + // Actually, that code is valid and met at IJ, but unfortunately it was broken since 1.7.0 + // See KT-52782 and testData/diagnostics/tests/inference/capturedTypes/kt52782.kt 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 0b00120221d..0c8ec1c888b 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 @@ -14807,6 +14807,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 {