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 244b33e1f0c..20d5ae4f56f 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 @@ -9550,6 +9550,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia runTest("compiler/testData/diagnostics/tests/delegatedProperty/useTypeParameterOfExtensionProperty_Disabled.kt"); } + @Test + @TestMetadata("withInvokes.kt") + public void testWithInvokes() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/withInvokes.kt"); + } + @Test @TestMetadata("wrongCountOfParametersInGet.kt") public void testWrongCountOfParametersInGet() throws Exception { @@ -9577,6 +9583,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/delegatedProperty/inference"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true, "multiplatform"); } + @Test + @TestMetadata("annotatedAccessor.kt") + public void testAnnotatedAccessor() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/annotatedAccessor.kt"); + } + @Test @TestMetadata("callableReferenceArgumentInDelegatedExpression.kt") public void testCallableReferenceArgumentInDelegatedExpression() throws Exception { @@ -9625,6 +9637,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/extensionProperty.kt"); } + @Test + @TestMetadata("fullyCompleteDelegateWhenPossible.kt") + public void testFullyCompleteDelegateWhenPossible() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/fullyCompleteDelegateWhenPossible.kt"); + } + @Test @TestMetadata("genericMethodInGenericClass.kt") public void testGenericMethodInGenericClass() throws Exception { @@ -9655,6 +9673,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/labeledDelegatedExpression.kt"); } + @Test + @TestMetadata("lambdaWithMultipleReturns.kt") + public void testLambdaWithMultipleReturns() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/lambdaWithMultipleReturns.kt"); + } + @Test @TestMetadata("manyIncompleteCandidates.kt") public void testManyIncompleteCandidates() throws Exception { @@ -9691,12 +9715,36 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/notNullAssertionInLocalDelegated.kt"); } + @Test + @TestMetadata("nothingTypeThisRef.kt") + public void testNothingTypeThisRef() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/nothingTypeThisRef.kt"); + } + + @Test + @TestMetadata("provideDelegateFixationResultContainsOtherInnerVariable.kt") + public void testProvideDelegateFixationResultContainsOtherInnerVariable() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/provideDelegateFixationResultContainsOtherInnerVariable.kt"); + } + + @Test + @TestMetadata("provideDelegateReturningOuterTypeVariable.kt") + public void testProvideDelegateReturningOuterTypeVariable() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/provideDelegateReturningOuterTypeVariable.kt"); + } + @Test @TestMetadata("resultTypeOfLambdaForConventionMethods.kt") public void testResultTypeOfLambdaForConventionMethods() throws Exception { runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/resultTypeOfLambdaForConventionMethods.kt"); } + @Test + @TestMetadata("successfulProvideDelegateLeadsToRedGetValue.kt") + public void testSuccessfulProvideDelegateLeadsToRedGetValue() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/successfulProvideDelegateLeadsToRedGetValue.kt"); + } + @Test @TestMetadata("tryInGenerated.kt") public void testTryInGenerated() throws Exception { @@ -9709,6 +9757,18 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/typeOfLazyDelegatedPropertyWithObject.kt"); } + @Test + @TestMetadata("typeVariablesFlow.kt") + public void testTypeVariablesFlow() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/typeVariablesFlow.kt"); + } + + @Test + @TestMetadata("typeVariablesFlowComplex.kt") + public void testTypeVariablesFlowComplex() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/typeVariablesFlowComplex.kt"); + } + @Test @TestMetadata("useCompleterWithoutExpectedType.kt") public void testUseCompleterWithoutExpectedType() throws Exception { @@ -9833,6 +9893,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia runTest("compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/provideDelegateResolutionWithStubTypes.kt"); } + @Test + @TestMetadata("provideDelegateResolutionWithStubTypesAndExtensionGetValue.kt") + public void testProvideDelegateResolutionWithStubTypesAndExtensionGetValue() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/provideDelegateResolutionWithStubTypesAndExtensionGetValue.kt"); + } + @Test @TestMetadata("setValue.kt") public void testSetValue() 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 820d966675b..092a158504f 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 @@ -9550,6 +9550,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated runTest("compiler/testData/diagnostics/tests/delegatedProperty/useTypeParameterOfExtensionProperty_Disabled.kt"); } + @Test + @TestMetadata("withInvokes.kt") + public void testWithInvokes() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/withInvokes.kt"); + } + @Test @TestMetadata("wrongCountOfParametersInGet.kt") public void testWrongCountOfParametersInGet() throws Exception { @@ -9577,6 +9583,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/delegatedProperty/inference"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true, "multiplatform"); } + @Test + @TestMetadata("annotatedAccessor.kt") + public void testAnnotatedAccessor() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/annotatedAccessor.kt"); + } + @Test @TestMetadata("callableReferenceArgumentInDelegatedExpression.kt") public void testCallableReferenceArgumentInDelegatedExpression() throws Exception { @@ -9625,6 +9637,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/extensionProperty.kt"); } + @Test + @TestMetadata("fullyCompleteDelegateWhenPossible.kt") + public void testFullyCompleteDelegateWhenPossible() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/fullyCompleteDelegateWhenPossible.kt"); + } + @Test @TestMetadata("genericMethodInGenericClass.kt") public void testGenericMethodInGenericClass() throws Exception { @@ -9655,6 +9673,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/labeledDelegatedExpression.kt"); } + @Test + @TestMetadata("lambdaWithMultipleReturns.kt") + public void testLambdaWithMultipleReturns() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/lambdaWithMultipleReturns.kt"); + } + @Test @TestMetadata("manyIncompleteCandidates.kt") public void testManyIncompleteCandidates() throws Exception { @@ -9691,12 +9715,36 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/notNullAssertionInLocalDelegated.kt"); } + @Test + @TestMetadata("nothingTypeThisRef.kt") + public void testNothingTypeThisRef() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/nothingTypeThisRef.kt"); + } + + @Test + @TestMetadata("provideDelegateFixationResultContainsOtherInnerVariable.kt") + public void testProvideDelegateFixationResultContainsOtherInnerVariable() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/provideDelegateFixationResultContainsOtherInnerVariable.kt"); + } + + @Test + @TestMetadata("provideDelegateReturningOuterTypeVariable.kt") + public void testProvideDelegateReturningOuterTypeVariable() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/provideDelegateReturningOuterTypeVariable.kt"); + } + @Test @TestMetadata("resultTypeOfLambdaForConventionMethods.kt") public void testResultTypeOfLambdaForConventionMethods() throws Exception { runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/resultTypeOfLambdaForConventionMethods.kt"); } + @Test + @TestMetadata("successfulProvideDelegateLeadsToRedGetValue.kt") + public void testSuccessfulProvideDelegateLeadsToRedGetValue() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/successfulProvideDelegateLeadsToRedGetValue.kt"); + } + @Test @TestMetadata("tryInGenerated.kt") public void testTryInGenerated() throws Exception { @@ -9709,6 +9757,18 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/typeOfLazyDelegatedPropertyWithObject.kt"); } + @Test + @TestMetadata("typeVariablesFlow.kt") + public void testTypeVariablesFlow() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/typeVariablesFlow.kt"); + } + + @Test + @TestMetadata("typeVariablesFlowComplex.kt") + public void testTypeVariablesFlowComplex() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/typeVariablesFlowComplex.kt"); + } + @Test @TestMetadata("useCompleterWithoutExpectedType.kt") public void testUseCompleterWithoutExpectedType() throws Exception { @@ -9833,6 +9893,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated runTest("compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/provideDelegateResolutionWithStubTypes.kt"); } + @Test + @TestMetadata("provideDelegateResolutionWithStubTypesAndExtensionGetValue.kt") + public void testProvideDelegateResolutionWithStubTypesAndExtensionGetValue() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/provideDelegateResolutionWithStubTypesAndExtensionGetValue.kt"); + } + @Test @TestMetadata("setValue.kt") public void testSetValue() throws Exception { diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/delegates/delegateWithAnonymousObject.dot b/compiler/fir/analysis-tests/testData/resolveWithStdlib/delegates/delegateWithAnonymousObject.dot index e9fbb1152e8..5ccaab568c0 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/delegates/delegateWithAnonymousObject.dot +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/delegates/delegateWithAnonymousObject.dot @@ -144,7 +144,7 @@ digraph delegateWithAnonymousObject_kt { } 55 [label="Postponed exit from lambda"]; 56 [label="Function call: this@R|/IssuesListUserProfile|.R|/delegate|(...)" style="filled" fillcolor=yellow]; - 57 [label="Function call: this@R|/IssuesListUserProfile|.R|/delegate|(...).#(...)" style="filled" fillcolor=yellow]; + 57 [label="Function call: this@R|/IssuesListUserProfile|.R|/delegate|(...).R?C|special/error|(...)" style="filled" fillcolor=yellow]; 58 [label="Exit property delegate" style="filled" fillcolor=yellow]; 59 [label="Exit property" style="filled" fillcolor=red]; } 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 2b1924fb6c3..ea537207826 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 @@ -9550,6 +9550,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir runTest("compiler/testData/diagnostics/tests/delegatedProperty/useTypeParameterOfExtensionProperty_Disabled.kt"); } + @Test + @TestMetadata("withInvokes.kt") + public void testWithInvokes() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/withInvokes.kt"); + } + @Test @TestMetadata("wrongCountOfParametersInGet.kt") public void testWrongCountOfParametersInGet() throws Exception { @@ -9577,6 +9583,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/delegatedProperty/inference"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true, "multiplatform"); } + @Test + @TestMetadata("annotatedAccessor.kt") + public void testAnnotatedAccessor() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/annotatedAccessor.kt"); + } + @Test @TestMetadata("callableReferenceArgumentInDelegatedExpression.kt") public void testCallableReferenceArgumentInDelegatedExpression() throws Exception { @@ -9625,6 +9637,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/extensionProperty.kt"); } + @Test + @TestMetadata("fullyCompleteDelegateWhenPossible.kt") + public void testFullyCompleteDelegateWhenPossible() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/fullyCompleteDelegateWhenPossible.kt"); + } + @Test @TestMetadata("genericMethodInGenericClass.kt") public void testGenericMethodInGenericClass() throws Exception { @@ -9655,6 +9673,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/labeledDelegatedExpression.kt"); } + @Test + @TestMetadata("lambdaWithMultipleReturns.kt") + public void testLambdaWithMultipleReturns() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/lambdaWithMultipleReturns.kt"); + } + @Test @TestMetadata("manyIncompleteCandidates.kt") public void testManyIncompleteCandidates() throws Exception { @@ -9691,12 +9715,36 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/notNullAssertionInLocalDelegated.kt"); } + @Test + @TestMetadata("nothingTypeThisRef.kt") + public void testNothingTypeThisRef() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/nothingTypeThisRef.kt"); + } + + @Test + @TestMetadata("provideDelegateFixationResultContainsOtherInnerVariable.kt") + public void testProvideDelegateFixationResultContainsOtherInnerVariable() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/provideDelegateFixationResultContainsOtherInnerVariable.kt"); + } + + @Test + @TestMetadata("provideDelegateReturningOuterTypeVariable.kt") + public void testProvideDelegateReturningOuterTypeVariable() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/provideDelegateReturningOuterTypeVariable.kt"); + } + @Test @TestMetadata("resultTypeOfLambdaForConventionMethods.kt") public void testResultTypeOfLambdaForConventionMethods() throws Exception { runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/resultTypeOfLambdaForConventionMethods.kt"); } + @Test + @TestMetadata("successfulProvideDelegateLeadsToRedGetValue.kt") + public void testSuccessfulProvideDelegateLeadsToRedGetValue() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/successfulProvideDelegateLeadsToRedGetValue.kt"); + } + @Test @TestMetadata("tryInGenerated.kt") public void testTryInGenerated() throws Exception { @@ -9709,6 +9757,18 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/typeOfLazyDelegatedPropertyWithObject.kt"); } + @Test + @TestMetadata("typeVariablesFlow.kt") + public void testTypeVariablesFlow() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/typeVariablesFlow.kt"); + } + + @Test + @TestMetadata("typeVariablesFlowComplex.kt") + public void testTypeVariablesFlowComplex() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/typeVariablesFlowComplex.kt"); + } + @Test @TestMetadata("useCompleterWithoutExpectedType.kt") public void testUseCompleterWithoutExpectedType() throws Exception { @@ -9833,6 +9893,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir runTest("compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/provideDelegateResolutionWithStubTypes.kt"); } + @Test + @TestMetadata("provideDelegateResolutionWithStubTypesAndExtensionGetValue.kt") + public void testProvideDelegateResolutionWithStubTypesAndExtensionGetValue() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/provideDelegateResolutionWithStubTypesAndExtensionGetValue.kt"); + } + @Test @TestMetadata("setValue.kt") public void testSetValue() 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 5412bfb9597..b492a392710 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 @@ -9556,6 +9556,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia runTest("compiler/testData/diagnostics/tests/delegatedProperty/useTypeParameterOfExtensionProperty_Disabled.kt"); } + @Test + @TestMetadata("withInvokes.kt") + public void testWithInvokes() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/withInvokes.kt"); + } + @Test @TestMetadata("wrongCountOfParametersInGet.kt") public void testWrongCountOfParametersInGet() throws Exception { @@ -9583,6 +9589,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/delegatedProperty/inference"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true, "multiplatform"); } + @Test + @TestMetadata("annotatedAccessor.kt") + public void testAnnotatedAccessor() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/annotatedAccessor.kt"); + } + @Test @TestMetadata("callableReferenceArgumentInDelegatedExpression.kt") public void testCallableReferenceArgumentInDelegatedExpression() throws Exception { @@ -9631,6 +9643,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/extensionProperty.kt"); } + @Test + @TestMetadata("fullyCompleteDelegateWhenPossible.kt") + public void testFullyCompleteDelegateWhenPossible() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/fullyCompleteDelegateWhenPossible.kt"); + } + @Test @TestMetadata("genericMethodInGenericClass.kt") public void testGenericMethodInGenericClass() throws Exception { @@ -9661,6 +9679,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/labeledDelegatedExpression.kt"); } + @Test + @TestMetadata("lambdaWithMultipleReturns.kt") + public void testLambdaWithMultipleReturns() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/lambdaWithMultipleReturns.kt"); + } + @Test @TestMetadata("manyIncompleteCandidates.kt") public void testManyIncompleteCandidates() throws Exception { @@ -9697,12 +9721,36 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/notNullAssertionInLocalDelegated.kt"); } + @Test + @TestMetadata("nothingTypeThisRef.kt") + public void testNothingTypeThisRef() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/nothingTypeThisRef.kt"); + } + + @Test + @TestMetadata("provideDelegateFixationResultContainsOtherInnerVariable.kt") + public void testProvideDelegateFixationResultContainsOtherInnerVariable() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/provideDelegateFixationResultContainsOtherInnerVariable.kt"); + } + + @Test + @TestMetadata("provideDelegateReturningOuterTypeVariable.kt") + public void testProvideDelegateReturningOuterTypeVariable() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/provideDelegateReturningOuterTypeVariable.kt"); + } + @Test @TestMetadata("resultTypeOfLambdaForConventionMethods.kt") public void testResultTypeOfLambdaForConventionMethods() throws Exception { runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/resultTypeOfLambdaForConventionMethods.kt"); } + @Test + @TestMetadata("successfulProvideDelegateLeadsToRedGetValue.kt") + public void testSuccessfulProvideDelegateLeadsToRedGetValue() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/successfulProvideDelegateLeadsToRedGetValue.kt"); + } + @Test @TestMetadata("tryInGenerated.kt") public void testTryInGenerated() throws Exception { @@ -9715,6 +9763,18 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/typeOfLazyDelegatedPropertyWithObject.kt"); } + @Test + @TestMetadata("typeVariablesFlow.kt") + public void testTypeVariablesFlow() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/typeVariablesFlow.kt"); + } + + @Test + @TestMetadata("typeVariablesFlowComplex.kt") + public void testTypeVariablesFlowComplex() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/typeVariablesFlowComplex.kt"); + } + @Test @TestMetadata("useCompleterWithoutExpectedType.kt") public void testUseCompleterWithoutExpectedType() throws Exception { @@ -9839,6 +9899,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia runTest("compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/provideDelegateResolutionWithStubTypes.kt"); } + @Test + @TestMetadata("provideDelegateResolutionWithStubTypesAndExtensionGetValue.kt") + public void testProvideDelegateResolutionWithStubTypesAndExtensionGetValue() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/provideDelegateResolutionWithStubTypesAndExtensionGetValue.kt"); + } + @Test @TestMetadata("setValue.kt") public void testSetValue() throws Exception { diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java index 166ab76e2a6..043a257b35d 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java @@ -15513,6 +15513,12 @@ public class FirLightTreeBlackBoxCodegenTestGenerated extends AbstractFirLightTr runTest("compiler/testData/codegen/box/delegatedProperty/varInInnerClass.kt"); } + @Test + @TestMetadata("withInvoke.kt") + public void testWithInvoke() throws Exception { + runTest("compiler/testData/codegen/box/delegatedProperty/withInvoke.kt"); + } + @Nested @TestMetadata("compiler/testData/codegen/box/delegatedProperty/delegateToAnother") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenWithIrFakeOverrideGeneratorTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenWithIrFakeOverrideGeneratorTestGenerated.java index d604ba3d095..338b0542e9e 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenWithIrFakeOverrideGeneratorTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenWithIrFakeOverrideGeneratorTestGenerated.java @@ -15405,6 +15405,12 @@ public class FirLightTreeBlackBoxCodegenWithIrFakeOverrideGeneratorTestGenerated runTest("compiler/testData/codegen/box/delegatedProperty/kt9712.kt"); } + @Test + @TestMetadata("noTypeVariablesLeft.kt") + public void testNoTypeVariablesLeft() throws Exception { + runTest("compiler/testData/codegen/box/delegatedProperty/noTypeVariablesLeft.kt"); + } + @Test @TestMetadata("privateInSubClass.kt") public void testPrivateInSubClass() throws Exception { @@ -15513,6 +15519,12 @@ public class FirLightTreeBlackBoxCodegenWithIrFakeOverrideGeneratorTestGenerated runTest("compiler/testData/codegen/box/delegatedProperty/varInInnerClass.kt"); } + @Test + @TestMetadata("withInvoke.kt") + public void testWithInvoke() throws Exception { + runTest("compiler/testData/codegen/box/delegatedProperty/withInvoke.kt"); + } + @Nested @TestMetadata("compiler/testData/codegen/box/delegatedProperty/delegateToAnother") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java index 8d0777092c1..c81cca3b6c1 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java @@ -15513,6 +15513,12 @@ public class FirPsiBlackBoxCodegenTestGenerated extends AbstractFirPsiBlackBoxCo runTest("compiler/testData/codegen/box/delegatedProperty/varInInnerClass.kt"); } + @Test + @TestMetadata("withInvoke.kt") + public void testWithInvoke() throws Exception { + runTest("compiler/testData/codegen/box/delegatedProperty/withInvoke.kt"); + } + @Nested @TestMetadata("compiler/testData/codegen/box/delegatedProperty/delegateToAnother") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt index f970ea5a745..96008604668 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt @@ -52,7 +52,7 @@ class Candidate( private var systemInitialized: Boolean = false val system: NewConstraintSystemImpl by lazy(LazyThreadSafetyMode.NONE) { val system = constraintSystemFactory.createConstraintSystem() - system.addOtherSystem(baseSystem) + system.setBaseSystem(baseSystem) systemInitialized = true system } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateFactory.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateFactory.kt index 5b4982d1422..2c0b6628442 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateFactory.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateFactory.kt @@ -35,10 +35,10 @@ class CandidateFactory private constructor( companion object { private fun buildBaseSystem(context: ResolutionContext, callInfo: CallInfo): ConstraintStorage { val system = context.inferenceComponents.createConstraintSystem() + system.addOuterSystem(context.bodyResolveContext.outerConstraintStorage) callInfo.arguments.forEach { system.addSubsystemFromExpression(it) } - system.addOtherSystem(context.bodyResolveContext.inferenceSession.currentConstraintStorage) return system.asReadOnlyStorage() } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/ConstraintSystemCompleter.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/ConstraintSystemCompleter.kt index ca16682037a..2159c7dbbe8 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/ConstraintSystemCompleter.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/ConstraintSystemCompleter.kt @@ -256,17 +256,7 @@ class ConstraintSystemCompleter(components: BodyResolveComponents, private val c ) ?: return false val variableWithConstraints = notFixedTypeVariables.getValue(variableForFixation.variable) - if (!variableForFixation.hasProperConstraint) { - if (context.inferenceSession.isSyntheticTypeVariable(variableWithConstraints.typeVariable)) { - context.inferenceSession.fixSyntheticTypeVariableWithNotEnoughInformation( - variableWithConstraints.typeVariable as ConeTypeVariable, - this - ) - return true - } - - return false - } + if (!variableForFixation.hasProperConstraint) return false fixVariable(this, variableWithConstraints) @@ -379,18 +369,30 @@ class ConstraintSystemCompleter(components: BodyResolveComponents, private val c topLevelAtom.collectAllTypeVariables() } - if (context.inferenceSession.hasSyntheticTypeVariables()) { - result.addAll(notFixedTypeVariables.filter { context.inferenceSession.isSyntheticTypeVariable(it.value.typeVariable) }.keys.asIterable()) - } - - require(result.size == notFixedTypeVariables.size) { - val notFoundTypeVariables = notFixedTypeVariables.keys.toMutableSet().apply { removeAll(result) } - "Not all type variables found: $notFoundTypeVariables" - } + checkNotFixedTypeVariablesCountConsistency(result) return result.toList() } + private fun ConstraintSystemCompletionContext.checkNotFixedTypeVariablesCountConsistency( + result: LinkedHashSet, + ) { + val notFixedTypeVariablesToUse = + when (outerSystemVariablesPrefixSize) { + 0 -> notFixedTypeVariables.keys + else -> notFixedTypeVariables.keys.toMutableSet().apply { + removeAll(allTypeVariables.keys.take(outerSystemVariablesPrefixSize).toSet()) + } + } + + require(result.size == notFixedTypeVariablesToUse.size) { + val notFoundTypeVariables = notFixedTypeVariablesToUse.toMutableSet().apply { + removeAll(result) + } + "Not all type variables found: $notFoundTypeVariables" + } + } + private fun fixVariable( c: ConstraintSystemCompletionContext, variableWithConstraints: VariableWithConstraints diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirBuilderInferenceSession.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirBuilderInferenceSession.kt index 50c3a0d34d4..818065189d8 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirBuilderInferenceSession.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirBuilderInferenceSession.kt @@ -10,6 +10,8 @@ import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.hasAnnotation +import org.jetbrains.kotlin.fir.expressions.FirResolvable +import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.resolve.calls.Candidate import org.jetbrains.kotlin.fir.resolve.calls.ImplicitExtensionReceiverValue @@ -31,7 +33,6 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImp import org.jetbrains.kotlin.resolve.calls.inference.registerTypeVariableIfNotPresent import org.jetbrains.kotlin.resolve.descriptorUtil.BUILDER_INFERENCE_ANNOTATION_FQ_NAME import org.jetbrains.kotlin.types.model.TypeConstructorMarker -import org.jetbrains.kotlin.types.model.TypeVariableMarker /** * General documentation for builder inference algorithm is located at `/docs/fir/builder_inference.md` @@ -45,15 +46,6 @@ class FirBuilderInferenceSession( private val commonCalls: MutableList> = mutableListOf() private var lambdaImplicitReceivers: MutableList = mutableListOf() - override val currentConstraintStorage: ConstraintStorage - get() = ConstraintStorage.Empty - - override fun hasSyntheticTypeVariables(): Boolean = false - - override fun isSyntheticTypeVariable(typeVariable: TypeVariableMarker): Boolean { - return false - } - override fun shouldRunCompletion(call: T): Boolean where T : FirResolvable, T : FirStatement { val candidate = call.candidate val system = candidate.system @@ -154,8 +146,6 @@ class FirBuilderInferenceSession( return commonSystem.fixedTypeVariables as Map } - override fun createSyntheticStubTypes(system: NewConstraintSystemImpl): Map = emptyMap() - private fun buildCommonSystem(initialStorage: ConstraintStorage): Pair { val commonSystem = components.session.inferenceComponents.createConstraintSystem() val nonFixedToVariablesSubstitutor = createNonFixedTypeToVariableSubstitutor() diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt index b16e720a8ae..e8a3b6172f7 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt @@ -77,7 +77,20 @@ class FirCallCompleter( val completionMode = candidate.computeCompletionMode( session.inferenceComponents, resolutionMode, initialType - ) + ).let { + // The difference between `shouldAvoidFullCompletion` and `!shouldRunCompletion` is very subtle: + // we don't run even partial completion for `!inferenceSession.shouldRunCompletion(call)`, while actually + // do that for `shouldAvoidFullCompletion` + // + // As for implementations, `shouldRunCompletion` only works for Builder inference, while `shouldAvoidFullCompletion` is for + // delegate inference where it's assumed to have partially completed intermediate calls. + // + // Ideally, we should get rid of `shouldRunCompletion` once Builder inference is rewritten (see KT-61041 for tracking) + if (it == ConstraintSystemCompletionMode.FULL && inferenceSession.shouldAvoidFullCompletion(call)) + ConstraintSystemCompletionMode.PARTIAL + else + it + } val analyzer = createPostponedArgumentsAnalyzer(transformer.resolutionContext) if (call is FirFunctionCall) { @@ -105,18 +118,15 @@ class FirCallCompleter( inferenceSession.addCompletedCall(completedCall, candidate) completedCall } else { - inferenceSession.addPartiallyResolvedCall(call) + inferenceSession.processPartiallyResolvedCall(call, resolutionMode) call } } ConstraintSystemCompletionMode.PARTIAL -> { runCompletionForCall(candidate, completionMode, call, initialType, analyzer) - - // Add top-level delegate call as partially resolved to inference session - if (resolutionMode is ResolutionMode.ContextDependent.Delegate) { - require(inferenceSession is FirDelegatedPropertyInferenceSession) - inferenceSession.addPartiallyResolvedCall(call) + if (inferenceSession is FirDelegatedPropertyInferenceSession) { + inferenceSession.processPartiallyResolvedCall(call, resolutionMode) } call diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirDelegatedPropertyInferenceSession.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirDelegatedPropertyInferenceSession.kt index e7b2389d42b..8c20a0f06b6 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirDelegatedPropertyInferenceSession.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirDelegatedPropertyInferenceSession.kt @@ -6,25 +6,25 @@ package org.jetbrains.kotlin.fir.resolve.inference import org.jetbrains.kotlin.fir.declarations.FirProperty +import org.jetbrains.kotlin.fir.expressions.FirFunctionCall +import org.jetbrains.kotlin.fir.expressions.FirFunctionCallOrigin import org.jetbrains.kotlin.fir.expressions.FirResolvable import org.jetbrains.kotlin.fir.expressions.FirStatement -import org.jetbrains.kotlin.fir.resolve.calls.* -import org.jetbrains.kotlin.fir.resolve.inference.model.ConeFixVariableConstraintPosition -import org.jetbrains.kotlin.fir.resolve.substitution.ChainedSubstitutor +import org.jetbrains.kotlin.fir.resolve.ResolutionMode +import org.jetbrains.kotlin.fir.resolve.calls.Candidate +import org.jetbrains.kotlin.fir.resolve.calls.InferenceError +import org.jetbrains.kotlin.fir.resolve.calls.ResolutionContext +import org.jetbrains.kotlin.fir.resolve.calls.candidate import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor -import org.jetbrains.kotlin.fir.resolve.substitution.NotFixedTypeToVariableSubstitutorForDelegateInference -import org.jetbrains.kotlin.fir.resolve.substitution.replaceStubsAndTypeVariablesToErrors -import org.jetbrains.kotlin.fir.types.* +import org.jetbrains.kotlin.fir.types.ConeClassLikeType +import org.jetbrains.kotlin.fir.types.ConeKotlinType +import org.jetbrains.kotlin.fir.types.ConeTypeVariableTypeConstructor +import org.jetbrains.kotlin.fir.types.typeContext import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder -import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem import org.jetbrains.kotlin.resolve.calls.inference.buildAbstractResultingSubstitutor -import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintSystemCompletionContext import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintSystemCompletionMode -import org.jetbrains.kotlin.resolve.calls.inference.model.BuilderInferencePosition import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage -import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl -import org.jetbrains.kotlin.resolve.calls.inference.registerTypeVariableIfNotPresent -import org.jetbrains.kotlin.types.model.* +import org.jetbrains.kotlin.util.OperatorNameConventions class FirDelegatedPropertyInferenceSession( val property: FirProperty, @@ -32,80 +32,48 @@ class FirDelegatedPropertyInferenceSession( private val postponedArgumentsAnalyzer: PostponedArgumentsAnalyzer, ) : FirInferenceSessionForChainedResolve(resolutionContext) { - private val currentConstraintSystem = components.session.inferenceComponents.createConstraintSystem() - override val currentConstraintStorage: ConstraintStorage get() = currentConstraintSystem.currentStorage() + private var currentConstraintSystem = components.session.inferenceComponents.createConstraintSystem() + val currentConstraintStorage: ConstraintStorage get() = currentConstraintSystem.currentStorage() private val unitType: ConeClassLikeType = components.session.builtinTypes.unitType.type - private lateinit var resultingConstraintSystem: NewConstraintSystem - private fun ConeKotlinType.containsStubType(): Boolean { - return this.contains { - it is ConeStubTypeForChainInference - } + // TODO after PCLA (KT-59107): + // Outer system seems to be a property of a concrete call resolution and probably should be applied to concrete call resolution + override fun onCandidatesResolution(call: FirFunctionCall, candidatesResolutionCallback: () -> R): R { + return if (!call.isAnyOfDelegateOperators()) + candidatesResolutionCallback() + else + resolutionContext.bodyResolveContext.withOuterConstraintStorage( + currentConstraintSystem.currentStorage(), + candidatesResolutionCallback + ) } - private fun integrateResolvedCall(storage: ConstraintStorage) { - registerSyntheticVariables(storage) - val stubToTypeVariableSubstitutor = createToSyntheticTypeVariableSubstitutor() - integrateConstraints( - currentConstraintSystem, - storage, - stubToTypeVariableSubstitutor, - false - ) + override fun shouldAvoidFullCompletion(call: T): Boolean where T : FirResolvable, T : FirStatement = + call.isAnyOfDelegateOperators() + + override fun processPartiallyResolvedCall(call: T, resolutionMode: ResolutionMode) where T : FirResolvable, T : FirStatement { + if (resolutionMode != ResolutionMode.ContextDependent.Delegate && !call.isAnyOfDelegateOperators()) return + + val candidate = call.candidate + + // Ignore unsuccessful `provideDelegate` candidates + // This behavior is aligned with a relevant part at FirDeclarationsResolveTransformer.transformWrappedDelegateExpression + if (call.isProvideDelegate() && !candidate.isSuccessful) return + + val candidateSystem = candidate.system + + partiallyResolvedCalls.add(call to candidate) + currentConstraintSystem = candidateSystem } - override fun addCompletedCall(call: T, candidate: Candidate) where T : FirResolvable, T : FirStatement { - partiallyResolvedCalls += call to candidate - if (candidate.isSuccessful) { - integrateResolvedCall(candidate.system.asReadOnlyStorage()) - } - } + private fun T.isProvideDelegate() where T : FirResolvable, T : FirStatement = + isAnyOfDelegateOperators() && (this as FirFunctionCall).calleeReference.name == OperatorNameConventions.PROVIDE_DELEGATE - override fun addPartiallyResolvedCall(call: T) where T : FirResolvable, T : FirStatement { - super.addPartiallyResolvedCall(call) - if (call.candidate.isSuccessful) { - integrateResolvedCall(call.candidate.system.currentStorage()) - } - } - - override fun shouldRunCompletion(call: T): Boolean where T : FirResolvable, T : FirStatement { - val callee = call.calleeReference as? FirNamedReferenceWithCandidate ?: return true - - if (callee.candidate.system.hasContradiction) return true - - val hasStubType = - callee.candidate.chosenExtensionReceiver?.resolvedType?.containsStubType() ?: false - || callee.candidate.dispatchReceiver?.resolvedType?.containsStubType() ?: false - - if (!hasStubType) { - return true - } - - val system = call.candidate.system - - val storage = system.getBuilder().currentStorage() - - if (call.hasPostponed()) return true - - return storage.notFixedTypeVariables.keys.all { - val variable = storage.allTypeVariables[it] - val isPostponed = variable != null && variable in storage.postponedTypeVariables - isPostponed || isSyntheticTypeVariable(variable!!) || - components.callCompleter.completer.variableFixationFinder.isTypeVariableHasProperConstraint(system, it) - } - } - - private fun FirStatement.hasPostponed(): Boolean { - var result = false - processAllContainingCallCandidates(processBlocks = false) { - result = result || it.hasPostponed() - } - return result - } - - private fun Candidate.hasPostponed(): Boolean { - return postponedAtoms.any { !it.analyzed } + private fun T.isAnyOfDelegateOperators(): Boolean where T : FirResolvable { + if (this !is FirFunctionCall || origin != FirFunctionCallOrigin.Operator) return false + val name = calleeReference.name + return name == OperatorNameConventions.PROVIDE_DELEGATE || name == OperatorNameConventions.GET_VALUE || name == OperatorNameConventions.SET_VALUE } override fun inferPostponedVariables( @@ -114,59 +82,8 @@ class FirDelegatedPropertyInferenceSession( completionMode: ConstraintSystemCompletionMode ): Map? = null - private fun createNonFixedTypeToVariableSubstitutor(): NotFixedTypeToVariableSubstitutorForDelegateInference { - val typeContext = components.session.typeContext - - val bindings = mutableMapOf() - for ((variable, synthetic) in syntheticTypeVariableByTypeVariable) { - bindings[synthetic] = variable.defaultType(typeContext) as ConeKotlinType - } - - return NotFixedTypeToVariableSubstitutorForDelegateInference(bindings, typeContext) - } - - - /* - * This creates Stub-preserving substitution to synthetic type variables - * Stub(R) => Stub(_R) - * R => _R - */ - private fun createToSyntheticTypeVariableSubstitutor(): ConeSubstitutor { - - val typeContext = components.session.typeContext - val bindings = mutableMapOf() - for ((variable, syntheticVariable) in syntheticTypeVariableByTypeVariable) { - bindings[variable.freshTypeConstructor(typeContext)] = syntheticVariable.defaultType - } - - return typeContext.typeSubstitutorByTypeConstructor(bindings) - } - - override fun hasSyntheticTypeVariables(): Boolean { - return syntheticTypeVariableByTypeVariable.isNotEmpty() - } - - override fun isSyntheticTypeVariable(typeVariable: TypeVariableMarker): Boolean { - return typeVariable in syntheticTypeVariableByTypeVariable.values - } - - override fun fixSyntheticTypeVariableWithNotEnoughInformation( - typeVariable: TypeVariableMarker, - completionContext: ConstraintSystemCompletionContext - ) { - typeVariable as ConeTypeVariable - completionContext.fixVariable( - typeVariable, - ConeStubTypeForSyntheticFixation( - ConeStubTypeConstructor(typeVariable, isTypeVariableInSubtyping = false, isForFixation = true), - ConeNullability.create(typeVariable.defaultType.isMarkedNullable) - ), - ConeFixVariableConstraintPosition(typeVariable) - ) - } - fun completeCandidates(): List { - val commonSystem = components.session.inferenceComponents.createConstraintSystem() + val commonSystem = currentConstraintSystem.apply { prepareForGlobalCompletion() } val notCompletedCalls = partiallyResolvedCalls.mapNotNull { partiallyResolvedCall -> partiallyResolvedCall.first.takeIf { resolvable -> @@ -174,20 +91,6 @@ class FirDelegatedPropertyInferenceSession( } } - val stubToTypeVariableSubstitutor = createNonFixedTypeToVariableSubstitutor() - - for ((call, candidate) in partiallyResolvedCalls) { - if (candidate.isSuccessful) { - integrateConstraints( - commonSystem, - candidate.system.asReadOnlyStorage(), - stubToTypeVariableSubstitutor, - call.candidate() != null - ) - } - } - - resolutionContext.bodyResolveContext.withInferenceSession(DEFAULT) { @Suppress("UNCHECKED_CAST") components.callCompleter.completer.complete( @@ -221,97 +124,14 @@ class FirDelegatedPropertyInferenceSession( } } - resultingConstraintSystem = commonSystem return notCompletedCalls } - fun createFinalSubstitutor(): ConeSubstitutor { - val stubTypeSubstitutor = createNonFixedTypeToVariableSubstitutor() + fun createFinalSubstitutor(): ConeSubstitutor = + currentConstraintSystem.asReadOnlyStorage() + .buildAbstractResultingSubstitutor(components.session.typeContext) as ConeSubstitutor - val typeContext = components.session.typeContext - val resultSubstitutor = resultingConstraintSystem.asReadOnlyStorage() - .buildAbstractResultingSubstitutor(typeContext) as ConeSubstitutor - return ChainedSubstitutor(stubTypeSubstitutor, resultSubstitutor) - .replaceStubsAndTypeVariablesToErrors(typeContext, stubTypesByTypeVariable.values.map { it.constructor }) - } + override fun addCompletedCall(call: T, candidate: Candidate) where T : FirResolvable, T : FirStatement {} - private val stubTypesByTypeVariable: MutableMap = mutableMapOf() - private val syntheticTypeVariableByTypeVariable = mutableMapOf() - - private fun registerSyntheticVariables(storage: ConstraintStorage) { - for (variableWithConstraints in storage.notFixedTypeVariables.values) { - val variable = variableWithConstraints.typeVariable as ConeTypeVariable - - val syntheticVariable = syntheticTypeVariableByTypeVariable.getOrPut(variable) { - ConeTypeVariable("+" + variable.typeConstructor.name).also { - currentConstraintSystem.registerVariable(it) - } - } - - stubTypesByTypeVariable.getOrPut(variable) { - ConeStubTypeForChainInference( - syntheticVariable, - ConeNullability.create(syntheticVariable.defaultType.isMarkedNullable) - ) - } - } - } - - override fun createSyntheticStubTypes(system: NewConstraintSystemImpl): Map { - - val bindings = mutableMapOf() - registerSyntheticVariables(system.currentStorage()) - for (variable in system.postponedTypeVariables) { - variable as ConeTypeVariable - - bindings[variable.typeConstructor] = stubTypesByTypeVariable[variable]!! - } - - return bindings - } - - override fun registerStubTypes(map: Map) { -// @Suppress("UNCHECKED_CAST") -// stubTypesByTypeVariable.putAll(map as Map) - } - - - private fun integrateConstraints( - commonSystem: NewConstraintSystemImpl, - storage: ConstraintStorage, - nonFixedToVariablesSubstitutor: ConeSubstitutor, - shouldIntegrateAllConstraints: Boolean - ) { - if (shouldIntegrateAllConstraints) { - storage.notFixedTypeVariables.values.forEach { - if (isSyntheticTypeVariable(it.typeVariable)) return@forEach - commonSystem.registerTypeVariableIfNotPresent(it.typeVariable) - } - } - /* - * storage can contain the following substitutions: - * TypeVariable(A) -> ProperType - * TypeVariable(B) -> Special-Non-Fixed-Type - * - * while substitutor from parameter map non-fixed types to the original type variable - * */ - val callSubstitutor = - storage.buildAbstractResultingSubstitutor(commonSystem, transformTypeVariablesToErrorTypes = false) as ConeSubstitutor - - for (initialConstraint in storage.initialConstraints) { - integrateConstraintToSystem( - commonSystem, initialConstraint, callSubstitutor, nonFixedToVariablesSubstitutor, storage.fixedTypeVariables - ) - } - - if (shouldIntegrateAllConstraints) { - for ((variableConstructor, type) in storage.fixedTypeVariables) { - val typeVariable = storage.allTypeVariables.getValue(variableConstructor) - if (isSyntheticTypeVariable(typeVariable)) continue - - commonSystem.registerTypeVariableIfNotPresent(typeVariable) - commonSystem.addEqualityConstraint((typeVariable as ConeTypeVariable).defaultType, type, BuilderInferencePosition) - } - } - } + override fun shouldRunCompletion(call: T): Boolean where T : FirResolvable, T : FirStatement = true } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirInferenceSession.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirInferenceSession.kt index 3e7f83d52f7..fdfd6b04039 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirInferenceSession.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirInferenceSession.kt @@ -5,19 +5,16 @@ package org.jetbrains.kotlin.fir.resolve.inference +import org.jetbrains.kotlin.fir.expressions.FirFunctionCall import org.jetbrains.kotlin.fir.expressions.FirResolvable import org.jetbrains.kotlin.fir.expressions.FirStatement +import org.jetbrains.kotlin.fir.resolve.ResolutionMode import org.jetbrains.kotlin.fir.resolve.calls.Candidate import org.jetbrains.kotlin.fir.types.ConeKotlinType -import org.jetbrains.kotlin.fir.types.ConeStubType import org.jetbrains.kotlin.fir.types.ConeTypeVariableTypeConstructor import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder -import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintSystemCompletionContext import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintSystemCompletionMode -import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage -import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl import org.jetbrains.kotlin.types.model.StubTypeMarker -import org.jetbrains.kotlin.types.model.TypeConstructorMarker import org.jetbrains.kotlin.types.model.TypeVariableMarker abstract class FirInferenceSession { @@ -26,20 +23,18 @@ abstract class FirInferenceSession { } abstract fun shouldRunCompletion(call: T): Boolean where T : FirResolvable, T : FirStatement - abstract val currentConstraintStorage: ConstraintStorage - abstract fun addPartiallyResolvedCall(call: T) where T : FirResolvable, T : FirStatement + /** + * In some cases (like getValue/setValue resolution of property delegation convention), it might be necessary to postpone full completion + * even with the ContextIndependent mode (which is used for delegated accessors bodies) + */ + open fun shouldAvoidFullCompletion(call: T): Boolean where T : FirResolvable, T : FirStatement = false + + abstract fun processPartiallyResolvedCall(call: T, resolutionMode: ResolutionMode) where T : FirResolvable, T : FirStatement abstract fun addCompletedCall(call: T, candidate: Candidate) where T : FirResolvable, T : FirStatement abstract fun registerStubTypes(map: Map) - abstract fun hasSyntheticTypeVariables(): Boolean - abstract fun isSyntheticTypeVariable(typeVariable: TypeVariableMarker): Boolean - abstract fun fixSyntheticTypeVariableWithNotEnoughInformation( - typeVariable: TypeVariableMarker, - completionContext: ConstraintSystemCompletionContext - ) - abstract fun inferPostponedVariables( lambda: ResolvedLambdaAtom, constraintSystemBuilder: ConstraintSystemBuilder, @@ -48,16 +43,13 @@ abstract class FirInferenceSession { ): Map? abstract fun clear() - abstract fun createSyntheticStubTypes(system: NewConstraintSystemImpl): Map + open fun onCandidatesResolution(call: FirFunctionCall, candidatesResolutionCallback: () -> R) = candidatesResolutionCallback() } abstract class FirStubInferenceSession : FirInferenceSession() { override fun shouldRunCompletion(call: T): Boolean where T : FirResolvable, T : FirStatement = true - override val currentConstraintStorage: ConstraintStorage - get() = ConstraintStorage.Empty - - override fun addPartiallyResolvedCall(call: T) where T : FirResolvable, T : FirStatement {} + override fun processPartiallyResolvedCall(call: T, resolutionMode: ResolutionMode) where T : FirResolvable, T : FirStatement {} override fun addCompletedCall(call: T, candidate: Candidate) where T : FirResolvable, T : FirStatement {} override fun inferPostponedVariables( @@ -68,15 +60,6 @@ abstract class FirStubInferenceSession : FirInferenceSession() { override fun registerStubTypes(map: Map) {} - override fun hasSyntheticTypeVariables(): Boolean = false - override fun isSyntheticTypeVariable(typeVariable: TypeVariableMarker): Boolean = false - override fun fixSyntheticTypeVariableWithNotEnoughInformation( - typeVariable: TypeVariableMarker, - completionContext: ConstraintSystemCompletionContext - ) {} - - override fun createSyntheticStubTypes(system: NewConstraintSystemImpl): Map = emptyMap() - override fun clear() { } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirInferenceSessionForChainedResolve.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirInferenceSessionForChainedResolve.kt index a5dfb432a8d..25a9a9eb729 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirInferenceSessionForChainedResolve.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirInferenceSessionForChainedResolve.kt @@ -8,13 +8,13 @@ package org.jetbrains.kotlin.fir.resolve.inference import org.jetbrains.kotlin.fir.expressions.FirResolvable import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents +import org.jetbrains.kotlin.fir.resolve.ResolutionMode import org.jetbrains.kotlin.fir.resolve.calls.Candidate import org.jetbrains.kotlin.fir.resolve.calls.ResolutionContext import org.jetbrains.kotlin.fir.resolve.calls.candidate import org.jetbrains.kotlin.fir.resolve.inference.model.ConeBuilderInferenceSubstitutionConstraintPosition import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.types.* -import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintSystemCompletionContext import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind import org.jetbrains.kotlin.resolve.calls.inference.model.InitialConstraint import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl @@ -23,12 +23,6 @@ import org.jetbrains.kotlin.types.model.* abstract class FirInferenceSessionForChainedResolve( protected val resolutionContext: ResolutionContext ) : FirInferenceSession() { - override fun fixSyntheticTypeVariableWithNotEnoughInformation( - typeVariable: TypeVariableMarker, - completionContext: ConstraintSystemCompletionContext - ) { - } - protected val partiallyResolvedCalls: MutableList> = mutableListOf() private val completedCalls: MutableSet = mutableSetOf() @@ -39,7 +33,7 @@ abstract class FirInferenceSessionForChainedResolve( // do nothing } - override fun addPartiallyResolvedCall(call: T) where T : FirResolvable, T : FirStatement { + override fun processPartiallyResolvedCall(call: T, resolutionMode: ResolutionMode) where T : FirResolvable, T : FirStatement { partiallyResolvedCalls += call to call.candidate } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt index 23c13ee60bf..bfb326fdad2 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt @@ -94,6 +94,7 @@ class FirCallCompletionResultsWriterTransformer( qualifiedAccessExpression: T, calleeReference: FirNamedReferenceWithCandidate, ): T { val subCandidate = calleeReference.candidate + val declaration = subCandidate.symbol.fir val typeArguments = computeTypeArguments(qualifiedAccessExpression, subCandidate) val type = if (declaration is FirCallableDeclaration) { @@ -117,6 +118,12 @@ class FirCallCompletionResultsWriterTransformer( ) } + if (mode == Mode.DelegatedPropertyCompletion) { + // Update type for `$delegateField` in `$$delegateField.get/setValue()` calls inside accessors + val typeUpdater = TypeUpdaterForDelegateArguments() + qualifiedAccessExpression.transformExplicitReceiver(typeUpdater, null) + } + var dispatchReceiver = subCandidate.dispatchReceiverExpression() var extensionReceiver = subCandidate.chosenExtensionReceiverExpression() if (!declaration.isWrappedIntegerOperator()) { @@ -157,13 +164,7 @@ class FirCallCompletionResultsWriterTransformer( data: ExpectedArgumentType?, ): FirStatement { val calleeReference = qualifiedAccessExpression.calleeReference as? FirNamedReferenceWithCandidate - ?: return run { - if (mode == Mode.DelegatedPropertyCompletion) { - val typeUpdater = TypeUpdaterForDelegateArguments() - qualifiedAccessExpression.transformSingle(typeUpdater, null) - } - qualifiedAccessExpression - } + ?: return qualifiedAccessExpression val result = prepareQualifiedTransform(qualifiedAccessExpression, calleeReference) val subCandidate = calleeReference.candidate @@ -172,11 +173,6 @@ class FirCallCompletionResultsWriterTransformer( result.replaceConeTypeOrNull(resultType) session.lookupTracker?.recordTypeResolveAsLookup(resultType, qualifiedAccessExpression.source, context.file.source) - if (mode == Mode.DelegatedPropertyCompletion) { - val typeUpdater = TypeUpdaterForDelegateArguments() - result.transformExplicitReceiver(typeUpdater, null) - } - if (calleeReference.candidate.doesResolutionResultOverrideOtherToPreserveCompatibility()) { result.addNonFatalDiagnostic(ConeResolutionResultOverridesOtherToPreserveCompatibility) } @@ -227,12 +223,6 @@ class FirCallCompletionResultsWriterTransformer( result.replaceConeTypeOrNull(resultType) session.lookupTracker?.recordTypeResolveAsLookup(resultType, functionCall.source, context.file.source) - if (mode == Mode.DelegatedPropertyCompletion) { - val typeUpdater = TypeUpdaterForDelegateArguments() - result.argumentList.transformArguments(typeUpdater, null) - result.transformExplicitReceiver(typeUpdater, null) - } - if (enableArrayOfCallTransformation) { return arrayOfCallTransformer.transformFunctionCall(result, session) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/BodyResolveContext.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/BodyResolveContext.kt index 210fd672a83..3f66dbfe79e 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/BodyResolveContext.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/BodyResolveContext.kt @@ -7,13 +7,15 @@ package org.jetbrains.kotlin.fir.resolve.transformers.body.resolve import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.ClassKind -import org.jetbrains.kotlin.fir.* +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.correspondingProperty import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor import org.jetbrains.kotlin.fir.declarations.utils.isCompanion import org.jetbrains.kotlin.fir.declarations.utils.isInner import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess import org.jetbrains.kotlin.fir.expressions.FirWhenExpression +import org.jetbrains.kotlin.fir.languageVersionSettings import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.calls.ImplicitExtensionReceiverValue import org.jetbrains.kotlin.fir.resolve.calls.ImplicitReceiverValue @@ -38,6 +40,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.SpecialNames.UNDERSCORE_FOR_UNUSED_VAR +import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage import org.jetbrains.kotlin.util.PrivateForInline class BodyResolveContext( @@ -87,6 +90,16 @@ class BodyResolveContext( @set:PrivateForInline var inferenceSession: FirInferenceSession = FirInferenceSession.DEFAULT + /** + * CS for an outer type system if it's relevant, for example, in the case of `val x by myGenericDelegateCall()`, + * relevant `getValue` call is expected to be resolved in the context of an outer CS built from `myGenericDelegateCall()` and + * probably using its type variables inside `getValue` candidates resolution. + * + * Note that it's not assumed to modify the storage, but only use it as a base system content for the candidate. + */ + @set:PrivateForInline + var outerConstraintStorage: ConstraintStorage = ConstraintStorage.Empty + val anonymousFunctionsAnalyzedInDependentContext: MutableSet> = mutableSetOf() var containingClassDeclarations: ArrayDeque = ArrayDeque() @@ -831,6 +844,21 @@ class BodyResolveContext( } } + @OptIn(PrivateForInline::class) + inline fun withOuterConstraintStorage( + storage: ConstraintStorage, + f: () -> T + ): T { + val oldStorage = this.outerConstraintStorage + this.outerConstraintStorage = storage + return try { + f() + } finally { + this.outerConstraintStorage = oldStorage + } + } + + @OptIn(PrivateForInline::class) inline fun withConstructor(constructor: FirConstructor, f: () -> T): T = withContainer(constructor, f) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt index d94538eaa1e..a65f658d6c4 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt @@ -28,14 +28,15 @@ import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.references.FirResolvedErrorReference import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference import org.jetbrains.kotlin.fir.resolve.* -import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate +import org.jetbrains.kotlin.fir.resolve.calls.Candidate import org.jetbrains.kotlin.fir.resolve.calls.candidate import org.jetbrains.kotlin.fir.resolve.dfa.FirControlFlowGraphReferenceImpl import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeLocalVariableNoTypeOrInitializer -import org.jetbrains.kotlin.fir.resolve.inference.FirStubTypeTransformer +import org.jetbrains.kotlin.fir.resolve.inference.FirDelegatedPropertyInferenceSession import org.jetbrains.kotlin.fir.resolve.inference.ResolvedLambdaAtom import org.jetbrains.kotlin.fir.resolve.inference.extractLambdaInfoFromFunctionType -import org.jetbrains.kotlin.fir.resolve.substitution.createTypeSubstitutorByTypeConstructor +import org.jetbrains.kotlin.fir.resolve.substitution.ChainedSubstitutor +import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.transformers.FirCallCompletionResultsWriterTransformer import org.jetbrains.kotlin.fir.resolve.transformers.FirStatusResolver import org.jetbrains.kotlin.fir.resolve.transformers.contracts.runContractResolveForFunction @@ -47,6 +48,10 @@ import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef import org.jetbrains.kotlin.fir.types.impl.FirImplicitTypeRefImplWithoutSource import org.jetbrains.kotlin.fir.visitors.FirTransformer import org.jetbrains.kotlin.fir.visitors.transformSingle +import org.jetbrains.kotlin.resolve.calls.inference.buildCurrentSubstitutor +import org.jetbrains.kotlin.resolve.calls.inference.components.TypeVariableDirectionCalculator +import org.jetbrains.kotlin.resolve.calls.inference.model.ProvideDelegateFixationPosition +import org.jetbrains.kotlin.types.model.TypeConstructorMarker open class FirDeclarationsResolveTransformer( transformer: FirAbstractBodyResolveTransformerDispatcher @@ -288,8 +293,11 @@ open class FirDeclarationsResolveTransformer( val finalSubstitutor = createFinalSubstitutor() - val stubTypeCompletionResultsWriter = FirStubTypeTransformer(finalSubstitutor) - property.transformSingle(stubTypeCompletionResultsWriter, null) + finalSubstitutor.substituteOrNull(property.returnTypeRef.coneType)?.let { substitutedType -> + property.replaceReturnTypeRef(property.returnTypeRef.withReplacedConeType(substitutedType)) + } + property.getter?.transformTypeWithPropertyType(property.returnTypeRef, forceUpdateForNonImplicitTypes = true) + property.setter?.transformTypeWithPropertyType(property.returnTypeRef, forceUpdateForNonImplicitTypes = true) property.replaceReturnTypeRef( property.returnTypeRef.approximateDeclarationType( session, @@ -326,29 +334,10 @@ open class FirDeclarationsResolveTransformer( data: ResolutionMode, ): FirStatement { // First, resolve delegate expression in dependent context, and add potentially partially resolved call to inference session - // (that is why we use ContextDependent.Delegate instead of plain ContextDependent) + // (that is why we use ResolutionMode.ContextDependent.Delegate instead of plain ContextDependent) val delegateExpression = wrappedDelegateExpression.expression.transformSingle(transformer, ResolutionMode.ContextDependent.Delegate) .transformSingle(components.integerLiteralAndOperatorApproximationTransformer, null) - // Second, replace result type of delegate expression with stub type if delegate not yet resolved - if (delegateExpression is FirResolvable) { - val calleeReference = delegateExpression.calleeReference - if (calleeReference is FirNamedReferenceWithCandidate) { - val system = calleeReference.candidate.system - system.notFixedTypeVariables.forEach { - system.markPostponedVariable(it.value.typeVariable) - } - val typeVariableTypeToStubType = context.inferenceSession.createSyntheticStubTypes(system) - - val substitutor = createTypeSubstitutorByTypeConstructor( - typeVariableTypeToStubType, session.typeContext, approximateIntegerLiterals = true - ) - val delegateExpressionType = delegateExpression.resolvedType - val stubTypeSubstituted = substitutor.substituteOrNull(delegateExpressionType) - delegateExpression.replaceConeTypeOrNull(stubTypeSubstituted) - } - } - val provideDelegateCall = wrappedDelegateExpression.delegateProvider as FirFunctionCall provideDelegateCall.replaceExplicitReceiver(delegateExpression) @@ -356,28 +345,25 @@ open class FirDeclarationsResolveTransformer( // TODO: this generates some nodes in the control flow graph which we don't want if we // end up not selecting this option, KT-59684 transformer.expressionsTransformer?.transformFunctionCallInternal( - provideDelegateCall, ResolutionMode.ContextIndependent, provideDelegate = true + provideDelegateCall, ResolutionMode.ContextDependent, provideDelegate = true ) // If we got successful candidate for provideDelegate, let's select it val provideDelegateCandidate = provideDelegateCall.candidate() if (provideDelegateCandidate != null && provideDelegateCandidate.isSuccessful) { - val system = provideDelegateCandidate.system - system.notFixedTypeVariables.forEach { - system.markPostponedVariable(it.value.typeVariable) - } - val typeVariableTypeToStubType = context.inferenceSession.createSyntheticStubTypes(system) - val substitutor = createTypeSubstitutorByTypeConstructor( - typeVariableTypeToStubType, session.typeContext, approximateIntegerLiterals = true + val additionalBinding = findResultTypeForInnerVariableIfNeeded(provideDelegateCall, provideDelegateCandidate) + + val substitutor = ChainedSubstitutor( + provideDelegateCandidate.substitutor, + (context.inferenceSession as FirDelegatedPropertyInferenceSession).currentConstraintStorage.buildCurrentSubstitutor( + session.typeContext, additionalBinding?.let(::mapOf) ?: emptyMap() + ) as ConeSubstitutor ) - val stubTypeSubstituted = substitutor.substituteOrSelf( - provideDelegateCandidate.substitutor.substituteOrSelf( - components.typeFromCallee(provideDelegateCall).type - ) - ) + val toTypeVariableSubstituted = + substitutor.substituteOrSelf(components.typeFromCallee(provideDelegateCall).type) - provideDelegateCall.replaceConeTypeOrNull(stubTypeSubstituted) + provideDelegateCall.replaceConeTypeOrNull(toTypeVariableSubstituted) return provideDelegateCall } @@ -390,6 +376,92 @@ open class FirDeclarationsResolveTransformer( return delegateExpression } + /** + * For supporting the case when `provideDelegate` has a signature with type variable as a return type, like + * fun K.provideDelegate(receiver: Any?, property: kotlin.reflect.KProperty<*>): K = this + * + * Here, if delegate expression returns something like `Delegate` where Tv is a variable and the `Delegate` class contains + * the member `getValue`, we need to fix `K` into `Delegate`, so that resulting `provideDelegate()` expression would have the type, + * so we could look into its member scope (as we can't look into the member scope of `K` type variable). + * + * On another hand, we can't just actually fix `K` variable (or just run FULL completion there) as the current result might refer + * other not fixed yet type variables, and we would break the contract that fixation results should not contain other type variables. + * + * Thus, to support exactly the case when we had to look into the member scope of `K`, we just pretend like we fixing it + * + * @see compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/provideDelegateResolutionWithStubTypes.kt + * + * In K1, it was working because we used stub types that are not counted as actual type variables, and we've been completing + * `provideDelegate` FULLy in the context where outer type variables were stubs (thus counted as proper types). + * + * But in K2, we decided to get rid of the stub type concept and just stick to the type variables. + * + * @return K to Delegate or null in case return type of `provideDelegate` is not a type variable. + * + * TODO: reconsider the place where the function belong and it necessity after PCLA is implemented (KT-61740 for tracking) + */ + private fun findResultTypeForInnerVariableIfNeeded( + provideDelegate: FirFunctionCall, + candidate: Candidate + ): Pair? { + // We're only interested in the case when `provideDelegate` candidate returns a type variable + // because in other cases we could look into the member scope of the type. + val returnTypeBasedOnVariable = + components.typeFromCallee(provideDelegate).type + // Substitut type parameter to type variable + .let(candidate.substitutor::substituteOrSelf) + .unwrapTopLevelVariableType() ?: return null + val typeVariable = returnTypeBasedOnVariable.lookupTag + + val candidateSystem = candidate.system + val candidateStorage = candidateSystem.currentStorage() + val allTypeVariables = candidateStorage.allTypeVariables.keys.toList() + // Subset of type variables obtained from the `provideDelegate` call + val typeVariablesRelatedToProvideDelegate = + allTypeVariables.subList(candidateStorage.outerSystemVariablesPrefixSize, allTypeVariables.size).toSet() + + check(typeVariable in typeVariablesRelatedToProvideDelegate) { + "Return type of provideDelegate is expected to be one of the type variables of a candidate, but $typeVariable was found" + } + + val variableWithConstraints = + candidateSystem.notFixedTypeVariables[typeVariable] ?: error("Not found type variable $typeVariable") + + var resultType: ConeKotlinType? = null + + // Temporary declare all the "outer" variables as proper (i.e., all inner variables as improper) + // Without that, all variables (both inner and outer ones) would be considered as improper, + // while we want to fix to assume `Delegate` as proper because `Tv` belongs to the outer system + candidateSystem.withTypeVariablesThatAreNotCountedAsProperTypes(typeVariablesRelatedToProvideDelegate) { + // TODO: reconsider the approach here (KT-61781 for tracking) + // Actually, this code might fail with an exception in some rare cases (see KT-61781) + // The problem is that in the issue example, when fixing T type variable, it has two upper bounds: X and Delegate + // So, when ResultTypeResolver builds result type, it tries to intersect them and fails with an exception, + // because both TypeIntersector and CommonSuperTypeCalculator are not ready to the situation + // where the part of an input is a type variable. + // + // Just for the inspiration, take a look at ResultTypeResolver.Context.buildNotFixedVariablesToStubTypesSubstitutor usages: + // it seems like they do something relevant. + resultType = inferenceComponents.resultTypeResolver.findResultTypeOrNull( + candidateSystem, variableWithConstraints, TypeVariableDirectionCalculator.ResolveDirection.UNKNOWN + ) as? ConeKotlinType ?: return@withTypeVariablesThatAreNotCountedAsProperTypes + + + check(!candidateStorage.hasContradiction) { "We only should try fixing variables on successful provideDelegate candidate" } + // We don't actually fix it, but add an equality constraint as approximation + candidateSystem.addEqualityConstraint(returnTypeBasedOnVariable, resultType!!, ProvideDelegateFixationPosition) + + check(!candidateStorage.hasContradiction) { + "Currently, we see no cases when contradiction might happen after adding equality constraint like that." + + "But if you see the message, please report your case to https://youtrack.jetbrains.com/newIssue?project=KT" + } + } + + return resultType?.let { + typeVariable to it + } + } + private fun transformLocalVariable(variable: FirProperty): FirProperty = whileAnalysing(session, variable) { assert(variable.isLocal) val delegate = variable.delegate @@ -445,6 +517,13 @@ open class FirDeclarationsResolveTransformer( } } + private fun ConeKotlinType.unwrapTopLevelVariableType(): ConeTypeVariableType? = when { + this is ConeTypeVariableType -> this + this is ConeFlexibleType -> lowerBound.unwrapTopLevelVariableType() + this is ConeDefinitelyNotNullType -> original.unwrapTopLevelVariableType() + else -> null + } + private fun FirProperty.resolveSetter( mayResolveSetterBody: Boolean, ) { @@ -469,7 +548,7 @@ open class FirDeclarationsResolveTransformer( } isSetter -> { val valueParameter = valueParameters.firstOrNull() ?: return - if (valueParameter.returnTypeRef is FirImplicitTypeRef) { + if (valueParameter.returnTypeRef is FirImplicitTypeRef || forceUpdateForNonImplicitTypes) { valueParameter.replaceReturnTypeRef(propertyTypeRef.copyWithNewSource(returnTypeRef.source)) } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt index afa6b674716..e94d11f013f 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt @@ -427,7 +427,11 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT } else { functionCall } - val resultExpression = callResolver.resolveCallAndSelectCandidate(withTransformedArguments) + + val resultExpression = context.inferenceSession.onCandidatesResolution(withTransformedArguments) { + callResolver.resolveCallAndSelectCandidate(withTransformedArguments) + } + val completeInference = callCompleter.completeCall(resultExpression, data) val result = completeInference.transformToIntegerOperatorCallOrApproximateItIfNeeded(data) if (!resolvingAugmentedAssignment) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt index 23a5911e8c1..a3c5527ba3a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt @@ -599,8 +599,8 @@ class DiagnosticReporterByTrackingStrategy( is CallableReferenceConstraintPosition<*>, is IncorporationConstraintPosition, is InjectedAnotherStubTypeConstraintPosition<*>, - is LHSArgumentConstraintPosition<*, *>, - SimpleConstraintSystemConstraintPosition -> { + is LHSArgumentConstraintPosition<*, *>, SimpleConstraintSystemConstraintPosition, ProvideDelegateFixationPosition + -> { if (AbstractTypeChecker.RUN_SLOW_ASSERTIONS) { throw AssertionError("Constraint error in unexpected position: $position") } else if (reportAdditionalErrors) { 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 be95656652d..8bdfdb14b8f 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 @@ -11,7 +11,7 @@ import org.jetbrains.kotlin.types.model.* fun ConstraintStorage.buildCurrentSubstitutor( context: TypeSystemInferenceExtensionContext, - additionalBindings: Map + additionalBindings: Map ): TypeSubstitutorMarker { return context.typeSubstitutorByTypeConstructor(fixedTypeVariables.entries.associate { it.key to it.value } + additionalBindings) } diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintSystemCompletionContext.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintSystemCompletionContext.kt index 0fda2b69957..82761384d72 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintSystemCompletionContext.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/ConstraintSystemCompletionContext.kt @@ -21,6 +21,11 @@ abstract class ConstraintSystemCompletionContext : VariableFixationFinder.Contex abstract override val fixedTypeVariables: Map abstract override val postponedTypeVariables: List + /** + * See [org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage.outerSystemVariablesPrefixSize] + */ + abstract val outerSystemVariablesPrefixSize: Int + abstract fun getBuilder(): ConstraintSystemBuilder // type can be proper if it not contains not fixed type variables 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 97e7ef3644a..de12ac5c1c4 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 @@ -63,7 +63,7 @@ class ResultTypeResolver( return c.getDefaultType(direction, variableWithConstraints.constraints, variableWithConstraints.typeVariable) } - private fun findResultTypeOrNull( + fun findResultTypeOrNull( c: Context, variableWithConstraints: VariableWithConstraints, direction: ResolveDirection diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/VariableFixationFinder.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/VariableFixationFinder.kt index 4f725e3ada8..f9c51d3b820 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/VariableFixationFinder.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/VariableFixationFinder.kt @@ -28,6 +28,17 @@ class VariableFixationFinder( val postponedTypeVariables: List val constraintsFromAllForkPoints: MutableList> + /** + * If not null, that property means that we should assume temporary + * `allTypeVariables.keys.minus(typeVariablesThatAreNotCountedAsProperTypes)` as proper types when fixating some variables. + * + * By default, if that property is null, we assume all `allTypeVariables` as not proper. + * + * Currently, that is only used for `provideDelegate` resolution, see + * [org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirDeclarationsResolveTransformer.fixInnerVariablesForProvideDelegateIfNeeded] + */ + val typeVariablesThatAreNotCountedAsProperTypes: Set? + fun isReified(variable: TypeVariableMarker): Boolean } @@ -182,7 +193,13 @@ class VariableFixationFinder( && !c.isNullabilityConstraint private fun Context.isProperType(type: KotlinTypeMarker): Boolean = - isProperTypeForFixation(type) { t -> !t.contains { notFixedTypeVariables.containsKey(it.typeConstructor()) } } + isProperTypeForFixation(type) { t -> !t.contains { isNotFixedRelevantVariable(it) } } + + private fun Context.isNotFixedRelevantVariable(it: KotlinTypeMarker): Boolean { + if (!notFixedTypeVariables.containsKey(it.typeConstructor())) return false + if (typeVariablesThatAreNotCountedAsProperTypes == null) return true + return typeVariablesThatAreNotCountedAsProperTypes!!.contains(it.typeConstructor()) + } private fun Context.isReified(variable: TypeConstructorMarker): Boolean = notFixedTypeVariables[variable]?.typeVariable?.let { isReified(it) } ?: false diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/ConstraintPositionAndErrors.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/ConstraintPositionAndErrors.kt index f6bda3f5942..d1254ef6cd0 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/ConstraintPositionAndErrors.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/ConstraintPositionAndErrors.kt @@ -93,6 +93,8 @@ object BuilderInferencePosition : ConstraintPosition() { override fun toString(): String = "For builder inference call" } +data object ProvideDelegateFixationPosition : ConstraintPosition() + // TODO: should be used only in SimpleConstraintSystemImpl, KT-59675 object SimpleConstraintSystemConstraintPosition : ConstraintPosition() diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/ConstraintStorage.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/ConstraintStorage.kt index be56d0df2ad..9f8fb0ff878 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/ConstraintStorage.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/ConstraintStorage.kt @@ -48,6 +48,20 @@ interface ConstraintStorage { val builtFunctionalTypesForPostponedArgumentsByExpectedTypeVariables: Map val constraintsFromAllForkPoints: List> + /** + * In case some candidate's CS is built in the context of some outer CS, first [outerSystemVariablesPrefixSize] in the list + * of [allTypeVariables] belong to the outer CS. + * + * That information is very limitedly used in a couple of cases when we need to separate those kinds of variables + * - When completing `provideDelegate` calls, we assume outer variables as proper types + * (see fixInnerVariablesForProvideDelegateIfNeeded). + * - When checking consistency of collected variables for the inner candidate + * (see checkNotFixedTypeVariablesCountConsistency). + * + * Also, see docs/fir/delegated_property_inference.md + */ + val outerSystemVariablesPrefixSize: Int + object Empty : ConstraintStorage { override val allTypeVariables: Map get() = emptyMap() override val notFixedTypeVariables: Map get() = emptyMap() @@ -61,6 +75,8 @@ interface ConstraintStorage { override val builtFunctionalTypesForPostponedArgumentsByTopLevelTypeVariables: Map>>, KotlinTypeMarker> = emptyMap() override val builtFunctionalTypesForPostponedArgumentsByExpectedTypeVariables: Map = emptyMap() override val constraintsFromAllForkPoints: List> = emptyList() + + override val outerSystemVariablesPrefixSize: Int get() = 0 } } diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/MutableConstraintStorage.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/MutableConstraintStorage.kt index a1706f5b3d4..5b85be1293c 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/MutableConstraintStorage.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/MutableConstraintStorage.kt @@ -241,4 +241,6 @@ internal class MutableConstraintStorage : ConstraintStorage { LinkedHashMap() override val constraintsFromAllForkPoints: MutableList> = SmartList() + + override var outerSystemVariablesPrefixSize: Int = 0 } diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt index a47f80ad758..85935fa1f5c 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt @@ -42,10 +42,35 @@ class NewConstraintSystemImpl( private val properTypesCache: MutableSet = SmartSet.create() private val notProperTypesCache: MutableSet = SmartSet.create() private val intersectionTypesCache: MutableMap, EmptyIntersectionTypeInfo?> = mutableMapOf() + override var typeVariablesThatAreNotCountedAsProperTypes: Set? = null + private var couldBeResolvedWithUnrestrictedBuilderInference: Boolean = false override var atCompletionState: Boolean = false + /** + * @see [org.jetbrains.kotlin.resolve.calls.inference.components.VariableFixationFinder.Context.typeVariablesThatAreNotCountedAsProperTypes] + * @see [org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirDeclarationsResolveTransformer.fixInnerVariablesForProvideDelegateIfNeeded] + */ + fun withTypeVariablesThatAreNotCountedAsProperTypes(typeVariables: Set, block: () -> Unit) { + checkState(State.BUILDING) + // Cleaning cache is necessary because temporarily we change the meaning of what does "proper type" mean + properTypesCache.clear() + notProperTypesCache.clear() + + require(typeVariablesThatAreNotCountedAsProperTypes == null) { + "Currently there should be no nested withDisallowingOnlyThisTypeVariablesForProperTypes calls" + } + + typeVariablesThatAreNotCountedAsProperTypes = typeVariables + + block() + + typeVariablesThatAreNotCountedAsProperTypes = null + properTypesCache.clear() + notProperTypesCache.clear() + } + private enum class State { BUILDING, TRANSACTION, @@ -276,6 +301,21 @@ class NewConstraintSystemImpl( ) } + fun addOuterSystem(outerSystem: ConstraintStorage) { + addOtherSystem(outerSystem) + storage.outerSystemVariablesPrefixSize = outerSystem.allTypeVariables.size + } + + fun setBaseSystem(outerSystem: ConstraintStorage) { + addOtherSystem(outerSystem) + storage.outerSystemVariablesPrefixSize = outerSystem.outerSystemVariablesPrefixSize + } + + fun prepareForGlobalCompletion() { + // There's no more separation of outer/inner variables once global completion starts + storage.outerSystemVariablesPrefixSize = 0 + } + override fun addOtherSystem(otherSystem: ConstraintStorage) { if (otherSystem.allTypeVariables.isNotEmpty()) { otherSystem.allTypeVariables.forEach { @@ -317,6 +357,9 @@ class NewConstraintSystemImpl( it if (typeToCheck == null) return@contains false + if (typeVariablesThatAreNotCountedAsProperTypes != null) { + return@contains typeVariablesThatAreNotCountedAsProperTypes!!.contains(typeToCheck.typeConstructor()) + } storage.allTypeVariables.containsKey(typeToCheck.typeConstructor()) } @@ -369,6 +412,9 @@ class NewConstraintSystemImpl( return storage.postponedTypeVariables } + override val outerSystemVariablesPrefixSize: Int + get() = storage.outerSystemVariablesPrefixSize + override val constraintsFromAllForkPoints: MutableList> get() { checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION) diff --git a/compiler/testData/codegen/box/delegatedProperty/withInvoke.kt b/compiler/testData/codegen/box/delegatedProperty/withInvoke.kt new file mode 100644 index 00000000000..166c952024e --- /dev/null +++ b/compiler/testData/codegen/box/delegatedProperty/withInvoke.kt @@ -0,0 +1,17 @@ +// TARGET_BACKEND: JVM_IR +// IGNORE_BACKEND_K1: JVM_IR +// ISSUE: KT-61633 + +class C(val p: T3) +class D(val p: T4) + +val C.getValue: D get() = D(p) +operator fun D.invoke(x: Any?, y: Any?): X4 = p + +fun foo(c: C): String { + val y1 by c + + return y1 +} + +fun box(): String = foo(C("OK")) \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/inference/annotatedAccessor.kt b/compiler/testData/diagnostics/tests/delegatedProperty/inference/annotatedAccessor.kt new file mode 100644 index 00000000000..5dab5bec0dd --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegatedProperty/inference/annotatedAccessor.kt @@ -0,0 +1,23 @@ +// FIR_IDENTICAL +// ISSUE: KT-61075 +// WITH_REFLECT + +import kotlin.properties.ReadWriteProperty + +open class BaseState +interface CustomComparable +annotation class XCollection + +fun treeSet(): ReadWriteProperty where E: BaseState, E: CustomComparable = TODO() + +internal class VisibleTreeState { + internal class State: BaseState(), CustomComparable + + // K1: ok + // K2: NEW_INFERENCE_ERROR + @get:XCollection var expandedNodes: State by treeSet() + + // K1: ok + // K2: NEW_INFERENCE_ERROR + @set:XCollection var selectedNodes: State by treeSet() +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/inference/fullyCompleteDelegateWhenPossible.kt b/compiler/testData/diagnostics/tests/delegatedProperty/inference/fullyCompleteDelegateWhenPossible.kt new file mode 100644 index 00000000000..12b417db35b --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegatedProperty/inference/fullyCompleteDelegateWhenPossible.kt @@ -0,0 +1,16 @@ +// FIR_IDENTICAL +// WITH_STDLIB + +import kotlin.reflect.KProperty + +class Cached(val f: () -> T) { + operator fun getValue(thisRef: Any?, property: KProperty<*>): T = TODO() +} + +private val map: MutableMap> = TODO() + +fun foo() { + val bar by map.getOrPut("A") { + Cached { "B" } + } +} diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/inference/lambdaWithMultipleReturns.kt b/compiler/testData/diagnostics/tests/delegatedProperty/inference/lambdaWithMultipleReturns.kt new file mode 100644 index 00000000000..9fe191297f6 --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegatedProperty/inference/lambdaWithMultipleReturns.kt @@ -0,0 +1,19 @@ +// FIR_IDENTICAL +import kotlin.reflect.KProperty + +fun myEmptyList1(): List = TODO() +fun myEmptyList2(): List = TODO() + +var b: Boolean = false + +val foo: List by myLazy { + if (b) return@myLazy myEmptyList1() + + myEmptyList2() +} + +private fun myLazy(initialValue: () -> T): ReadProperty = TODO() + +class ReadProperty(val v: V) { + operator fun getValue(thisRef: Any?, property: KProperty<*>): V = v +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/inference/nothingTypeThisRef.kt b/compiler/testData/diagnostics/tests/delegatedProperty/inference/nothingTypeThisRef.kt new file mode 100644 index 00000000000..7e8b7b362dc --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegatedProperty/inference/nothingTypeThisRef.kt @@ -0,0 +1,22 @@ +// FIR_IDENTICAL +// WITH_STDLIB + +import kotlin.reflect.KProperty + +class DelegateProvider { + operator fun provideDelegate( + thisRef: Nothing?, + prop: KProperty<*> + ): RDelegate = TODO() +} + +class RDelegate { + operator fun getValue(thisRef: Nothing?, property: KProperty<*>): String = "" +} + +fun builder(name: String? = null, block: () -> Unit): DelegateProvider = TODO() +val x by builder {} + +fun main() { + x.length +} diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/inference/provideDelegateFixationResultContainsOtherInnerVariable.kt b/compiler/testData/diagnostics/tests/delegatedProperty/inference/provideDelegateFixationResultContainsOtherInnerVariable.kt new file mode 100644 index 00000000000..fc722388e40 --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegatedProperty/inference/provideDelegateFixationResultContainsOtherInnerVariable.kt @@ -0,0 +1,17 @@ +// FIR_IDENTICAL + +interface A { + operator fun getValue(x: Any?, y: Any?): T = TODO() +} + +fun foo(): A = TODO() + +fun bar1() { + val x: String by foo() +} + +fun bar2() { + operator fun , E> A.provideDelegate(x: Any?, y: Any?): F = TODO() + + val x: String by foo() +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/inference/provideDelegateReturningOuterTypeVariable.fir.kt b/compiler/testData/diagnostics/tests/delegatedProperty/inference/provideDelegateReturningOuterTypeVariable.fir.kt new file mode 100644 index 00000000000..1d362f02859 --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegatedProperty/inference/provideDelegateReturningOuterTypeVariable.fir.kt @@ -0,0 +1,19 @@ +// ISSUE: KT-61747 + +interface A { + operator fun getValue(x: Any?, y: Any?): String = "" +} + +fun foo(x: (T) -> Unit): T = TODO() + +fun bar1(a: A) { + val x by foo { x: A -> } +} + +fun bar2(a: A) { + operator fun F.provideDelegate(x: Any?, y: Any?): F { + return this + } + + val x by foo { x: A -> } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/inference/provideDelegateReturningOuterTypeVariable.kt b/compiler/testData/diagnostics/tests/delegatedProperty/inference/provideDelegateReturningOuterTypeVariable.kt new file mode 100644 index 00000000000..63bd577fa31 --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegatedProperty/inference/provideDelegateReturningOuterTypeVariable.kt @@ -0,0 +1,19 @@ +// ISSUE: KT-61747 + +interface A { + operator fun getValue(x: Any?, y: Any?): String = "" +} + +fun foo(x: (T) -> Unit): T = TODO() + +fun bar1(a: A) { + val x by foo { x: A -> } +} + +fun bar2(a: A) { + operator fun F.provideDelegate(x: Any?, y: Any?): F { + return this + } + + val x by foo { x: A -> } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/inference/successfulProvideDelegateLeadsToRedGetValue.fir.kt b/compiler/testData/diagnostics/tests/delegatedProperty/inference/successfulProvideDelegateLeadsToRedGetValue.fir.kt new file mode 100644 index 00000000000..df7d206548f --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegatedProperty/inference/successfulProvideDelegateLeadsToRedGetValue.fir.kt @@ -0,0 +1,11 @@ +// ISSUE: KT-61077 + +val test: Int by materializeDelegate() + +fun materializeDelegate(): Box = TODO() + +operator fun > Box.provideDelegate(receiver: Any?, property: kotlin.reflect.KProperty<*>): K = TODO() + +operator fun > Q.getValue(thisRef: Any?, property: kotlin.reflect.KProperty<*>): Q = TODO() + +class Box {} diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/inference/successfulProvideDelegateLeadsToRedGetValue.kt b/compiler/testData/diagnostics/tests/delegatedProperty/inference/successfulProvideDelegateLeadsToRedGetValue.kt new file mode 100644 index 00000000000..1b900f230cf --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegatedProperty/inference/successfulProvideDelegateLeadsToRedGetValue.kt @@ -0,0 +1,11 @@ +// ISSUE: KT-61077 + +val test: Int by materializeDelegate() + +fun materializeDelegate(): Box = TODO() + +operator fun > Box.provideDelegate(receiver: Any?, property: kotlin.reflect.KProperty<*>): K = TODO() + +operator fun > Q.getValue(thisRef: Any?, property: kotlin.reflect.KProperty<*>): Q = TODO() + +class Box {} diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/inference/typeVariablesFlow.kt b/compiler/testData/diagnostics/tests/delegatedProperty/inference/typeVariablesFlow.kt new file mode 100644 index 00000000000..b1826362b94 --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegatedProperty/inference/typeVariablesFlow.kt @@ -0,0 +1,28 @@ +// FIR_IDENTICAL +// ISSUE: KT-59529 +import kotlin.reflect.KProperty + +interface Out { + val x: F +} +interface Out2 { + val x: E +} +interface Inv { + val u: U +} + +val outString: Out = TODO() + +val invOut2String by foo(outString) + +operator fun Inv.getValue( + thisRef: Any?, + property: KProperty<*> +): Inv = TODO() + +fun foo(other: Out): Inv> = TODO() + +fun main() { + invOut2String.u.x.length +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/inference/typeVariablesFlowComplex.kt b/compiler/testData/diagnostics/tests/delegatedProperty/inference/typeVariablesFlowComplex.kt new file mode 100644 index 00000000000..e309cedc45e --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegatedProperty/inference/typeVariablesFlowComplex.kt @@ -0,0 +1,37 @@ +// FIR_IDENTICAL +// WITH_STDLIB +// !CHECK_TYPE +// ISSUE: KT-59529 + +import kotlin.reflect.KProperty + +val ows: IgnoringParser = IgnoringParser() + +class MyParser { + + private val booleanLiteral: Parser = TODO() + + val topLevel by ows + booleanLiteral + + fun main() { + topLevel checkType { _, String>>() } + } + + operator fun TransformParser.provideDelegate( + thisRef: MyParser<*>, + property: KProperty<*> + ): TransformParser = TODO() + + operator fun TransformParser.getValue( + thisRef: MyParser<*>, + property: KProperty<*> + ): TransformParser = TODO() +} + +abstract class Parser + +class TransformParser : Parser() +class IgnoringParser : Parser() + +operator fun IgnoringParser.plus(other: Parser): TransformParser, T> = + TODO() diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/provideDelegateResolutionWithStubTypesAndExtensionGetValue.kt b/compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/provideDelegateResolutionWithStubTypesAndExtensionGetValue.kt new file mode 100644 index 00000000000..74241580279 --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/provideDelegateResolutionWithStubTypesAndExtensionGetValue.kt @@ -0,0 +1,10 @@ +// FIR_IDENTICAL +val test: String by materializeDelegate() + +fun materializeDelegate(): Delegate = Delegate() + +operator fun K.provideDelegate(receiver: Any?, property: kotlin.reflect.KProperty<*>): K = this + +operator fun Delegate.getValue(thisRef: Any?, property: kotlin.reflect.KProperty<*>): X = TODO() + +class Delegate diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/setValue.fir.kt b/compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/setValue.fir.kt index 923ce3053a9..ee4dba500bf 100644 --- a/compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/setValue.fir.kt +++ b/compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/setValue.fir.kt @@ -1,5 +1,5 @@ // !DIAGNOSTICS: -UNUSED_PARAMETER - +// ISSUE: KT-61077 class Delegate operator fun Delegate<*>.getValue(receiver: Any?, p: Any): String = "" @@ -10,7 +10,7 @@ operator fun String.provideDelegate(receiver: Any?, p: Any) = Delegate() var test1: String by Delegate() var test2: String by Delegate() -var test3: String by "OK" +var test3: String by "OK" var test4: String by "OK".provideDelegate(null, "") var test5: String by "OK".provideDelegate(null, "") diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/setValue.kt b/compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/setValue.kt index c0c565e46d8..69772c14a12 100644 --- a/compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/setValue.kt +++ b/compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/setValue.kt @@ -1,5 +1,5 @@ // !DIAGNOSTICS: -UNUSED_PARAMETER - +// ISSUE: KT-61077 class Delegate operator fun Delegate<*>.getValue(receiver: Any?, p: Any): String = "" diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/withInvokes.fir.kt b/compiler/testData/diagnostics/tests/delegatedProperty/withInvokes.fir.kt new file mode 100644 index 00000000000..8830e1ce58f --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegatedProperty/withInvokes.fir.kt @@ -0,0 +1,22 @@ +// ISSUE: KT-61633 + +interface A +interface B +interface C +interface D + +val A.provideDelegate: B get() = TODO() +operator fun B.invoke(x: Any?, y: Any?): C = TODO() + +val C.getValue: D get() = TODO() +operator fun D.invoke(x: Any?, y: Any?): X4 = TODO() + +fun foo(a: A, c: C) { + val x1 by a + x1 + x1.length + + val y1 by c + y1 + y1.length +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/withInvokes.kt b/compiler/testData/diagnostics/tests/delegatedProperty/withInvokes.kt new file mode 100644 index 00000000000..8df750227c2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegatedProperty/withInvokes.kt @@ -0,0 +1,22 @@ +// ISSUE: KT-61633 + +interface A +interface B +interface C +interface D + +val A.provideDelegate: B get() = TODO() +operator fun B.invoke(x: Any?, y: Any?): C = TODO() + +val C.getValue: D get() = TODO() +operator fun D.invoke(x: Any?, y: Any?): X4 = TODO() + +fun foo(a: A, c: C) { + val x1 by a + x1 + x1.length + + val y1 by c + y1 + y1.length +} \ No newline at end of file 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 3c57ffe6c9d..6c57afb2ca6 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 @@ -9556,6 +9556,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/delegatedProperty/useTypeParameterOfExtensionProperty_Disabled.kt"); } + @Test + @TestMetadata("withInvokes.kt") + public void testWithInvokes() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/withInvokes.kt"); + } + @Test @TestMetadata("wrongCountOfParametersInGet.kt") public void testWrongCountOfParametersInGet() throws Exception { @@ -9583,6 +9589,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/delegatedProperty/inference"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true); } + @Test + @TestMetadata("annotatedAccessor.kt") + public void testAnnotatedAccessor() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/annotatedAccessor.kt"); + } + @Test @TestMetadata("callableReferenceArgumentInDelegatedExpression.kt") public void testCallableReferenceArgumentInDelegatedExpression() throws Exception { @@ -9631,6 +9643,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/extensionProperty.kt"); } + @Test + @TestMetadata("fullyCompleteDelegateWhenPossible.kt") + public void testFullyCompleteDelegateWhenPossible() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/fullyCompleteDelegateWhenPossible.kt"); + } + @Test @TestMetadata("genericMethodInGenericClass.kt") public void testGenericMethodInGenericClass() throws Exception { @@ -9661,6 +9679,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/labeledDelegatedExpression.kt"); } + @Test + @TestMetadata("lambdaWithMultipleReturns.kt") + public void testLambdaWithMultipleReturns() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/lambdaWithMultipleReturns.kt"); + } + @Test @TestMetadata("manyIncompleteCandidates.kt") public void testManyIncompleteCandidates() throws Exception { @@ -9697,12 +9721,36 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/notNullAssertionInLocalDelegated.kt"); } + @Test + @TestMetadata("nothingTypeThisRef.kt") + public void testNothingTypeThisRef() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/nothingTypeThisRef.kt"); + } + + @Test + @TestMetadata("provideDelegateFixationResultContainsOtherInnerVariable.kt") + public void testProvideDelegateFixationResultContainsOtherInnerVariable() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/provideDelegateFixationResultContainsOtherInnerVariable.kt"); + } + + @Test + @TestMetadata("provideDelegateReturningOuterTypeVariable.kt") + public void testProvideDelegateReturningOuterTypeVariable() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/provideDelegateReturningOuterTypeVariable.kt"); + } + @Test @TestMetadata("resultTypeOfLambdaForConventionMethods.kt") public void testResultTypeOfLambdaForConventionMethods() throws Exception { runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/resultTypeOfLambdaForConventionMethods.kt"); } + @Test + @TestMetadata("successfulProvideDelegateLeadsToRedGetValue.kt") + public void testSuccessfulProvideDelegateLeadsToRedGetValue() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/successfulProvideDelegateLeadsToRedGetValue.kt"); + } + @Test @TestMetadata("tryInGenerated.kt") public void testTryInGenerated() throws Exception { @@ -9715,6 +9763,18 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/typeOfLazyDelegatedPropertyWithObject.kt"); } + @Test + @TestMetadata("typeVariablesFlow.kt") + public void testTypeVariablesFlow() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/typeVariablesFlow.kt"); + } + + @Test + @TestMetadata("typeVariablesFlowComplex.kt") + public void testTypeVariablesFlowComplex() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/typeVariablesFlowComplex.kt"); + } + @Test @TestMetadata("useCompleterWithoutExpectedType.kt") public void testUseCompleterWithoutExpectedType() throws Exception { @@ -9839,6 +9899,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/provideDelegateResolutionWithStubTypes.kt"); } + @Test + @TestMetadata("provideDelegateResolutionWithStubTypesAndExtensionGetValue.kt") + public void testProvideDelegateResolutionWithStubTypesAndExtensionGetValue() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/provideDelegateResolutionWithStubTypesAndExtensionGetValue.kt"); + } + @Test @TestMetadata("setValue.kt") public void testSetValue() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index 77b953b6740..7a633a947cd 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -15513,6 +15513,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/delegatedProperty/varInInnerClass.kt"); } + @Test + @TestMetadata("withInvoke.kt") + public void testWithInvoke() throws Exception { + runTest("compiler/testData/codegen/box/delegatedProperty/withInvoke.kt"); + } + @Nested @TestMetadata("compiler/testData/codegen/box/delegatedProperty/delegateToAnother") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java index b7d944f3fdf..4a10ae8128c 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java @@ -15513,6 +15513,12 @@ public class IrBlackBoxCodegenWithIrInlinerTestGenerated extends AbstractIrBlack runTest("compiler/testData/codegen/box/delegatedProperty/varInInnerClass.kt"); } + @Test + @TestMetadata("withInvoke.kt") + public void testWithInvoke() throws Exception { + runTest("compiler/testData/codegen/box/delegatedProperty/withInvoke.kt"); + } + @Nested @TestMetadata("compiler/testData/codegen/box/delegatedProperty/delegateToAnother") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 6717dbaf9d0..e12751ff9ed 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -12455,6 +12455,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/delegatedProperty/genericDelegateUncheckedCast2.kt"); } + @TestMetadata("withInvoke.kt") + public void ignoreWithInvoke() throws Exception { + runTest("compiler/testData/codegen/box/delegatedProperty/withInvoke.kt"); + } + private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath); } diff --git a/docs/fir/builder_inference.md b/docs/fir/builder_inference.md index b90593e900e..6e286c74297 100644 --- a/docs/fir/builder_inference.md +++ b/docs/fir/builder_inference.md @@ -2,10 +2,6 @@ See also: [Kotlin Spec: Builder-style type inference](https://kotlinlang.org/spec/type-inference.html#builder-style-type-inference) ### Glossary -#### CS = Constraint system -An instance of `org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl` -#### Call-tree -A tree of calls, in which constraint systems are joined and solved(completed) together #### Postponed type variable Type-variable, that was used to build a stub type on, and fixation of which is postponed until the end of lambda analysis. Selection of type variables to postpone happens during [Initiation](#initiation) phase diff --git a/docs/fir/delegated_property_inference.md b/docs/fir/delegated_property_inference.md new file mode 100644 index 00000000000..febd5f510a0 --- /dev/null +++ b/docs/fir/delegated_property_inference.md @@ -0,0 +1,142 @@ +## FIR/Delegated property inference +See also: [Kotlin Spec: Delegated property declaration](https://kotlinlang.org/spec/declarations.html#delegated-property-declaration) and some [Common inference terms definition](inference.md) + +### Glossary +#### Delegation related operator calls +Synthetically generated by Raw FIR builder calls to `getValue`, `setValue` or `provideDelegate` functions. + +*NB:* They might be differentiated from regular calls by comparing origin to `FirFunctionCallOrigin.Operator` + +#### Outer CS +A constraint system that defines type variables with their constraints not brought by the call itself or its arguments. +The general idea is that before running resolution of a specific "inner" candidate, we copy all the outer variables to its own CS in the very +beginning, and after some successful candidate is chosen, we apply the "relevant" changes to the outer CS. + +By "apply" operation currently we mean literally replacement of the old CS with the new one. + +### Desugaring at Raw FIR building stage +The code like this +```kotlin +var prop by delegateExpression() +``` +is being desugared to something similar to this (see `org.jetbrains.kotlin.fir.builder.ConversionUtilsKt.generateAccessorsByDelegate`) +``` +val prop = propertyNode { + delegate = delegate { + expression = "delegateExpression()" + delegateProvider = "expression.provideDelegate()" + } + + get() = delegate$field.getValue($thisRef, ::prop) + set(value) { + delegate$field.setValue($thisRef, ::prop, value) + } +} +``` + +Even in case the property type is specified, all the content types are set as implicit. + +### Delegated property inference algorithm +#### Initiation +At first, we set up a delegate inference session that is necessary to preserve the common CS and partially completed calls that need to be +fully completed in the end. + +For reference, see `org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.BodyResolveContext.forPropertyDelegateAccessors`. + +#### Delegate expression inference +At first, we resolve delegate expression with `ContextDependent.Delegate` resolution mode that behaves just like the regular `ContextDependent` +but it makes DelegateInferenceSession to remember resulting incomplete CS from the call. + +*NB:* If the delegate expression is simple enough, i.e., it does not contain type parameters, or they might be inferred from the call itself, +we just run FULL completion on it as for regular `ContextDependent` and don't store its CS. + +For reference, see `org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirDeclarationsResolveTransformer.transformWrappedDelegateExpression`. + +#### provideDelegate resolution +After delegate expression is resolved, we start regular resolution of `provideDelegate()` call stored at `FirWrappedDelegateExpression::delegateProvider`. + +Note that as explicit receiver it uses just the same instance of `delegateExpression` we've just resolved on the previous step. +As the receiver still might contain some type variables, we use CS of it as [Outer CS](#outer-cs) for all the `provideDelegate` candidates. + +If there is no most specific successful candidate, then we just drop and forget the call. + +Otherwise, after the resulting candidate is chosen, it has some state of CS that contains both "inner" type variables of the candidate itself and some +global ones brought by Outer CS. + +Note that we don't force FULL completion (unlike K1 did), thus potentially leaving some of the type variables not fixed. +The most problematic part with that approach is that in some cases the return type of `provideDelegate` is a type variable _and_ we +might need to look into its member scope to find `getValue` call there. + +```kotlin +val test: String by materializeDelegate() + +fun materializeDelegate(): Delegate = Delegate() + +operator fun K.provideDelegate(receiver: Any?, property: kotlin.reflect.KProperty<*>): K = this + +class Delegate { + operator fun getValue(thisRef: Any?, property: kotlin.reflect.KProperty<*>): V = TODO() +} +``` + +But the problem is that member scope is not defined for variables, thus we emulate K1 full completion behavior by + +- Looking if `provideDelegate` actually returns a type variable (`K`) +- Finding the current result type that might be used for fixation, but under the assumption that all outer type variables +(`[T]` in the example above) are considered proper, so could be used inside a fixation result +- Add equality constraint `K = FoundFixationResult` (`K = Delegate(Tv)` in the example above) +- When creating a final substitutor for `provideDelegate` expression, take that constraint into account + +See `org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirDeclarationsResolveTransformer.findResultTypeForInnerVariableIfNeeded`. + +If `provideDelegate` is completed without contradictions, we effectively replace `delegateExpression` with `delegateExpression.provideDelegate()`. + +#### getValue/setValue analysis + +If a property type is set explicitly, it's being propagated to the accessors' signatures at `FirDeclarationsResolveTransformer::transformAccessors` +(return type of getter and parameter type of setter). +Otherwise, the types remain implicit. + +Then, we effectively call `transformFunctionWithGivenSignature` on getter and _only_ if the property type was explicit, +call `transformFunctionWithGivenSignature` on setter, too. + +We do that under the same delegate inference session, so we've got callbacks for `FirInferenceSession.onCandidatesResolution` thus +exactly for `getValue`/`setValue`/`provideDelegate` calls, we set outer CS from the session. + +Note that there's no need to do that for the delegate expression or nested arguments (they should be resolved as usual in `ContextDependent` resolution mode). + +Also, while accessors have a shape like `delegate$field.getValue($thisRef, ::prop)`, `delegate$field` is a special reference which type +is being set to the current type of `delegateExpression` at `FirExpressionsResolveTransformer.transformQualifiedAccessExpression`. + +For those delegation operator calls, if they're successfully resolved, we preserve their CSs and use them as the main outer ones, +also we collect the calls as ones that need to be completed later (partially completed). + +Note that `transformFunctionWithGivenSignature` if a return type is implicit propagates one from the body of the function, thus +after getter resolution its return type (and the property one) might contain some type variables. + +See `org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirDeclarationsResolveTransformer.transformPropertyAccessorsWithDelegate`. + +#### Partial calls completion + +At that stage, we've got all those delegation operators calls resolved effectively under the same constraint system. +So, what we need to do further is solving that CS, thus find the result types for all the type variables from those calls. + +To achieve that, we run completion for all incomplete calls altogether as a list of `topLevelAtoms`, so it works mostly as regular FULL completion. + +See `org.jetbrains.kotlin.fir.resolve.inference.FirDelegatedPropertyInferenceSession.completeCandidates`. + +#### Completion results writing + +In case of successful completion, we get a final substitutor that we may apply to property return type and accessor signatures, too. +Thus, getting rid of potentially left type variables there. + +After that we run `FirCallCompletionResultsWriterTransformer` on each of the freshly completed calls, with a special mode +`DelegatedPropertyCompletion` that is only different in a meaning that for each qualified access it also, recursively ran on the explicit +receiver (that is necessary to update `delegate$field` references types for `getValue`/`setValue` calls). + +Another nasty tweak that is needed to be made is updating substituted member after completion. +Some of the final candidates might be obtained from member scopes of types with type arguments containing variables +(like `Delegate` from the example above), but after body transformation they should be resolved to the corrected symbols from the +scopes with substituted type arguments. + +See `FirCallCompletionResultsWriterTransformer.updateSubstitutedMemberIfReceiverContainsTypeVariable` for details. diff --git a/docs/fir/inference.md b/docs/fir/inference.md new file mode 100644 index 00000000000..6b626e8a97c --- /dev/null +++ b/docs/fir/inference.md @@ -0,0 +1,12 @@ +## Inference + +Currently, this document contains some basic terms that are common for different specific inference types. +Lately, it might be extended to include some basic description of how inference works. + +### Glossary +#### CS = Constraint system +An instance of `org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl` +#### Call-tree +A tree of calls, in which constraint systems are joined and solved(completed) together +#### Proper constraint +A constraint that doesn't reference any type variables \ No newline at end of file