K2: Rewrite delegate inference
The main idea is getting rid of stub types and using just type variables See more detailed description at docs/fir/delegated_property_inference.md The problem with stub types is that they need really special treatment in many places, and on the other hand, there are no clear contracts on how they should work (that regularly leads to bugs like KT-59529) ^KT-61060 Fixed ^KT-61075 Fixed ^KT-61077 Fixed ^KT-59529 Fixed ^KT-61633 Related ^KT-61618 Related ^KT-61740 Related ^KT-59107 Related ^KT-61747 Related ^KT-61077 Related ^KT-61781 Related
This commit is contained in:
committed by
Space Team
parent
cd5105c133
commit
a02cb16fb2
+66
@@ -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 {
|
||||
|
||||
+66
@@ -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 {
|
||||
|
||||
Vendored
+1
-1
@@ -144,7 +144,7 @@ digraph delegateWithAnonymousObject_kt {
|
||||
}
|
||||
55 [label="Postponed exit from lambda"];
|
||||
56 [label="Function call: this@R|/IssuesListUserProfile|.R|/delegate|<R|IssuesListUserProfile|, R|IssuesListUserProfile|, R|IssueListView|>(...)" style="filled" fillcolor=yellow];
|
||||
57 [label="Function call: this@R|/IssuesListUserProfile|.R|/delegate|<R|IssuesListUserProfile|, R|IssuesListUserProfile|, R|IssueListView|>(...).<Unresolved name: provideDelegate>#(...)" style="filled" fillcolor=yellow];
|
||||
57 [label="Function call: this@R|/IssuesListUserProfile|.R|/delegate|<R|IssuesListUserProfile|, R|IssuesListUserProfile|, R|IssueListView|>(...).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];
|
||||
}
|
||||
|
||||
+66
@@ -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 {
|
||||
|
||||
+66
@@ -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 {
|
||||
|
||||
+6
@@ -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")
|
||||
|
||||
+12
@@ -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")
|
||||
|
||||
+6
@@ -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")
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
+21
-19
@@ -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<TypeConstructorMarker>,
|
||||
) {
|
||||
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
|
||||
|
||||
+2
-12
@@ -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<Pair<FirStatement, Candidate>> = mutableListOf()
|
||||
private var lambdaImplicitReceivers: MutableList<ImplicitExtensionReceiverValue> = mutableListOf()
|
||||
|
||||
override val currentConstraintStorage: ConstraintStorage
|
||||
get() = ConstraintStorage.Empty
|
||||
|
||||
override fun hasSyntheticTypeVariables(): Boolean = false
|
||||
|
||||
override fun isSyntheticTypeVariable(typeVariable: TypeVariableMarker): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun <T> 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<ConeTypeVariableTypeConstructor, ConeKotlinType>
|
||||
}
|
||||
|
||||
override fun createSyntheticStubTypes(system: NewConstraintSystemImpl): Map<TypeConstructorMarker, ConeStubType> = emptyMap()
|
||||
|
||||
private fun buildCommonSystem(initialStorage: ConstraintStorage): Pair<NewConstraintSystemImpl, Boolean> {
|
||||
val commonSystem = components.session.inferenceComponents.createConstraintSystem()
|
||||
val nonFixedToVariablesSubstitutor = createNonFixedTypeToVariableSubstitutor()
|
||||
|
||||
+17
-7
@@ -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
|
||||
|
||||
+52
-232
@@ -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 <R> 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 <T> shouldAvoidFullCompletion(call: T): Boolean where T : FirResolvable, T : FirStatement =
|
||||
call.isAnyOfDelegateOperators()
|
||||
|
||||
override fun <T> 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 <T> addCompletedCall(call: T, candidate: Candidate) where T : FirResolvable, T : FirStatement {
|
||||
partiallyResolvedCalls += call to candidate
|
||||
if (candidate.isSuccessful) {
|
||||
integrateResolvedCall(candidate.system.asReadOnlyStorage())
|
||||
}
|
||||
}
|
||||
private fun <T> T.isProvideDelegate() where T : FirResolvable, T : FirStatement =
|
||||
isAnyOfDelegateOperators() && (this as FirFunctionCall).calleeReference.name == OperatorNameConventions.PROVIDE_DELEGATE
|
||||
|
||||
override fun <T> addPartiallyResolvedCall(call: T) where T : FirResolvable, T : FirStatement {
|
||||
super.addPartiallyResolvedCall(call)
|
||||
if (call.candidate.isSuccessful) {
|
||||
integrateResolvedCall(call.candidate.system.currentStorage())
|
||||
}
|
||||
}
|
||||
|
||||
override fun <T> 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> 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<ConeTypeVariableTypeConstructor, ConeKotlinType>? = null
|
||||
|
||||
private fun createNonFixedTypeToVariableSubstitutor(): NotFixedTypeToVariableSubstitutorForDelegateInference {
|
||||
val typeContext = components.session.typeContext
|
||||
|
||||
val bindings = mutableMapOf<TypeVariableMarker, ConeKotlinType>()
|
||||
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<TypeConstructorMarker, ConeKotlinType>()
|
||||
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<FirResolvable> {
|
||||
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 <T> addCompletedCall(call: T, candidate: Candidate) where T : FirResolvable, T : FirStatement {}
|
||||
|
||||
private val stubTypesByTypeVariable: MutableMap<ConeTypeVariable, ConeStubType> = mutableMapOf()
|
||||
private val syntheticTypeVariableByTypeVariable = mutableMapOf<TypeVariableMarker, ConeTypeVariable>()
|
||||
|
||||
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<TypeConstructorMarker, ConeStubType> {
|
||||
|
||||
val bindings = mutableMapOf<TypeConstructorMarker, ConeStubType>()
|
||||
registerSyntheticVariables(system.currentStorage())
|
||||
for (variable in system.postponedTypeVariables) {
|
||||
variable as ConeTypeVariable
|
||||
|
||||
bindings[variable.typeConstructor] = stubTypesByTypeVariable[variable]!!
|
||||
}
|
||||
|
||||
return bindings
|
||||
}
|
||||
|
||||
override fun registerStubTypes(map: Map<TypeVariableMarker, StubTypeMarker>) {
|
||||
// @Suppress("UNCHECKED_CAST")
|
||||
// stubTypesByTypeVariable.putAll(map as Map<ConeTypeVariable, ConeStubType>)
|
||||
}
|
||||
|
||||
|
||||
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 <T> shouldRunCompletion(call: T): Boolean where T : FirResolvable, T : FirStatement = true
|
||||
}
|
||||
|
||||
+11
-28
@@ -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 <T> shouldRunCompletion(call: T): Boolean where T : FirResolvable, T : FirStatement
|
||||
abstract val currentConstraintStorage: ConstraintStorage
|
||||
|
||||
abstract fun <T> 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 <T> shouldAvoidFullCompletion(call: T): Boolean where T : FirResolvable, T : FirStatement = false
|
||||
|
||||
abstract fun <T> processPartiallyResolvedCall(call: T, resolutionMode: ResolutionMode) where T : FirResolvable, T : FirStatement
|
||||
abstract fun <T> addCompletedCall(call: T, candidate: Candidate) where T : FirResolvable, T : FirStatement
|
||||
|
||||
abstract fun registerStubTypes(map: Map<TypeVariableMarker, StubTypeMarker>)
|
||||
|
||||
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<ConeTypeVariableTypeConstructor, ConeKotlinType>?
|
||||
|
||||
abstract fun clear()
|
||||
abstract fun createSyntheticStubTypes(system: NewConstraintSystemImpl): Map<TypeConstructorMarker, ConeStubType>
|
||||
open fun <R> onCandidatesResolution(call: FirFunctionCall, candidatesResolutionCallback: () -> R) = candidatesResolutionCallback()
|
||||
}
|
||||
|
||||
abstract class FirStubInferenceSession : FirInferenceSession() {
|
||||
override fun <T> shouldRunCompletion(call: T): Boolean where T : FirResolvable, T : FirStatement = true
|
||||
|
||||
override val currentConstraintStorage: ConstraintStorage
|
||||
get() = ConstraintStorage.Empty
|
||||
|
||||
override fun <T> addPartiallyResolvedCall(call: T) where T : FirResolvable, T : FirStatement {}
|
||||
override fun <T> processPartiallyResolvedCall(call: T, resolutionMode: ResolutionMode) where T : FirResolvable, T : FirStatement {}
|
||||
override fun <T> 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<TypeVariableMarker, StubTypeMarker>) {}
|
||||
|
||||
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<TypeConstructorMarker, ConeStubType> = emptyMap()
|
||||
|
||||
override fun clear() {
|
||||
}
|
||||
}
|
||||
|
||||
+2
-8
@@ -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<Pair<FirResolvable, Candidate>> = mutableListOf()
|
||||
private val completedCalls: MutableSet<FirResolvable> = mutableSetOf()
|
||||
|
||||
@@ -39,7 +33,7 @@ abstract class FirInferenceSessionForChainedResolve(
|
||||
// do nothing
|
||||
}
|
||||
|
||||
override fun <T> addPartiallyResolvedCall(call: T) where T : FirResolvable, T : FirStatement {
|
||||
override fun <T> processPartiallyResolvedCall(call: T, resolutionMode: ResolutionMode) where T : FirResolvable, T : FirStatement {
|
||||
partiallyResolvedCalls += call to call.candidate
|
||||
}
|
||||
|
||||
|
||||
+8
-18
@@ -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)
|
||||
}
|
||||
|
||||
+29
-1
@@ -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<FirFunctionSymbol<*>> = mutableSetOf()
|
||||
|
||||
var containingClassDeclarations: ArrayDeque<FirRegularClass> = ArrayDeque()
|
||||
@@ -831,6 +844,21 @@ class BodyResolveContext(
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(PrivateForInline::class)
|
||||
inline fun <T> 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 <T> withConstructor(constructor: FirConstructor, f: () -> T): T =
|
||||
withContainer(constructor, f)
|
||||
|
||||
+119
-40
@@ -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> K.provideDelegate(receiver: Any?, property: kotlin.reflect.KProperty<*>): K = this
|
||||
*
|
||||
* Here, if delegate expression returns something like `Delegate<Tv>` where Tv is a variable and the `Delegate` class contains
|
||||
* the member `getValue`, we need to fix `K` into `Delegate<Tv>`, 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<Tv> 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<TypeConstructorMarker, ConeKotlinType>? {
|
||||
// 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<Tv>` 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<Y>
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
+5
-1
@@ -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) {
|
||||
|
||||
+2
-2
@@ -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) {
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.types.model.*
|
||||
|
||||
fun ConstraintStorage.buildCurrentSubstitutor(
|
||||
context: TypeSystemInferenceExtensionContext,
|
||||
additionalBindings: Map<TypeConstructorMarker, StubTypeMarker>
|
||||
additionalBindings: Map<TypeConstructorMarker, KotlinTypeMarker>
|
||||
): TypeSubstitutorMarker {
|
||||
return context.typeSubstitutorByTypeConstructor(fixedTypeVariables.entries.associate { it.key to it.value } + additionalBindings)
|
||||
}
|
||||
|
||||
+5
@@ -21,6 +21,11 @@ abstract class ConstraintSystemCompletionContext : VariableFixationFinder.Contex
|
||||
abstract override val fixedTypeVariables: Map<TypeConstructorMarker, KotlinTypeMarker>
|
||||
abstract override val postponedTypeVariables: List<TypeVariableMarker>
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+18
-1
@@ -28,6 +28,17 @@ class VariableFixationFinder(
|
||||
val postponedTypeVariables: List<TypeVariableMarker>
|
||||
val constraintsFromAllForkPoints: MutableList<Pair<IncorporationConstraintPosition, ForkPointData>>
|
||||
|
||||
/**
|
||||
* 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<TypeConstructorMarker>?
|
||||
|
||||
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
|
||||
|
||||
+2
@@ -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()
|
||||
|
||||
|
||||
+16
@@ -48,6 +48,20 @@ interface ConstraintStorage {
|
||||
val builtFunctionalTypesForPostponedArgumentsByExpectedTypeVariables: Map<TypeConstructorMarker, KotlinTypeMarker>
|
||||
val constraintsFromAllForkPoints: List<Pair<IncorporationConstraintPosition, ForkPointData>>
|
||||
|
||||
/**
|
||||
* 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<TypeConstructorMarker, TypeVariableMarker> get() = emptyMap()
|
||||
override val notFixedTypeVariables: Map<TypeConstructorMarker, VariableWithConstraints> get() = emptyMap()
|
||||
@@ -61,6 +75,8 @@ interface ConstraintStorage {
|
||||
override val builtFunctionalTypesForPostponedArgumentsByTopLevelTypeVariables: Map<Pair<TypeConstructorMarker, List<Pair<TypeConstructorMarker, Int>>>, KotlinTypeMarker> = emptyMap()
|
||||
override val builtFunctionalTypesForPostponedArgumentsByExpectedTypeVariables: Map<TypeConstructorMarker, KotlinTypeMarker> = emptyMap()
|
||||
override val constraintsFromAllForkPoints: List<Pair<IncorporationConstraintPosition, ForkPointData>> = emptyList()
|
||||
|
||||
override val outerSystemVariablesPrefixSize: Int get() = 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
@@ -241,4 +241,6 @@ internal class MutableConstraintStorage : ConstraintStorage {
|
||||
LinkedHashMap()
|
||||
|
||||
override val constraintsFromAllForkPoints: MutableList<Pair<IncorporationConstraintPosition, ForkPointData>> = SmartList()
|
||||
|
||||
override var outerSystemVariablesPrefixSize: Int = 0
|
||||
}
|
||||
|
||||
+46
@@ -42,10 +42,35 @@ class NewConstraintSystemImpl(
|
||||
private val properTypesCache: MutableSet<KotlinTypeMarker> = SmartSet.create()
|
||||
private val notProperTypesCache: MutableSet<KotlinTypeMarker> = SmartSet.create()
|
||||
private val intersectionTypesCache: MutableMap<Collection<KotlinTypeMarker>, EmptyIntersectionTypeInfo?> = mutableMapOf()
|
||||
override var typeVariablesThatAreNotCountedAsProperTypes: Set<TypeConstructorMarker>? = 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<TypeConstructorMarker>, 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<Pair<IncorporationConstraintPosition, ForkPointData>>
|
||||
get() {
|
||||
checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION)
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND_K1: JVM_IR
|
||||
// ISSUE: KT-61633
|
||||
|
||||
class C<T3>(val p: T3)
|
||||
class D<T4>(val p: T4)
|
||||
|
||||
val <X3> C<X3>.getValue: D<X3> get() = D(p)
|
||||
operator fun <X4> D<X4>.invoke(x: Any?, y: Any?): X4 = p
|
||||
|
||||
fun foo(c: C<String>): String {
|
||||
val y1 by c
|
||||
|
||||
return y1
|
||||
}
|
||||
|
||||
fun box(): String = foo(C("OK"))
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// FIR_IDENTICAL
|
||||
// ISSUE: KT-61075
|
||||
// WITH_REFLECT
|
||||
|
||||
import kotlin.properties.ReadWriteProperty
|
||||
|
||||
open class BaseState
|
||||
interface CustomComparable<T>
|
||||
annotation class XCollection
|
||||
|
||||
fun <E> treeSet(): ReadWriteProperty<Any?, E> where E: BaseState, E: CustomComparable<E> = TODO()
|
||||
|
||||
internal class VisibleTreeState {
|
||||
internal class State: BaseState(), CustomComparable<State>
|
||||
|
||||
// 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()
|
||||
}
|
||||
compiler/testData/diagnostics/tests/delegatedProperty/inference/fullyCompleteDelegateWhenPossible.kt
Vendored
+16
@@ -0,0 +1,16 @@
|
||||
// FIR_IDENTICAL
|
||||
// WITH_STDLIB
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class Cached<T>(val f: () -> T) {
|
||||
operator fun getValue(thisRef: Any?, property: KProperty<*>): T = TODO()
|
||||
}
|
||||
|
||||
private val map: MutableMap<String, Cached<String>> = TODO()
|
||||
|
||||
fun foo() {
|
||||
val bar by map.getOrPut("A") {
|
||||
Cached { "B" }
|
||||
}
|
||||
}
|
||||
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
// FIR_IDENTICAL
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
fun <X> myEmptyList1(): List<X> = TODO()
|
||||
fun <Y> myEmptyList2(): List<Y> = TODO()
|
||||
|
||||
var b: Boolean = false
|
||||
|
||||
val foo: List<String> by myLazy {
|
||||
if (b) return@myLazy myEmptyList1()
|
||||
|
||||
myEmptyList2()
|
||||
}
|
||||
|
||||
private fun <T> myLazy(initialValue: () -> T): ReadProperty<T> = TODO()
|
||||
|
||||
class ReadProperty<V>(val v: V) {
|
||||
operator fun getValue(thisRef: Any?, property: KProperty<*>): V = v
|
||||
}
|
||||
+22
@@ -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
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// FIR_IDENTICAL
|
||||
|
||||
interface A<T> {
|
||||
operator fun getValue(x: Any?, y: Any?): T = TODO()
|
||||
}
|
||||
|
||||
fun <T> foo(): A<T> = TODO()
|
||||
|
||||
fun bar1() {
|
||||
val x: String by foo()
|
||||
}
|
||||
|
||||
fun bar2() {
|
||||
operator fun <F : A<E>, E> A<E>.provideDelegate(x: Any?, y: Any?): F = TODO()
|
||||
|
||||
val x: String by foo()
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// ISSUE: KT-61747
|
||||
|
||||
interface A {
|
||||
operator fun getValue(x: Any?, y: Any?): String = ""
|
||||
}
|
||||
|
||||
fun <T> foo(x: (T) -> Unit): T = TODO()
|
||||
|
||||
fun bar1(a: A) {
|
||||
val x by <!DELEGATE_SPECIAL_FUNCTION_MISSING!>foo { x: A -> }<!>
|
||||
}
|
||||
|
||||
fun bar2(a: A) {
|
||||
operator fun <F> F.provideDelegate(x: Any?, y: Any?): F {
|
||||
return this
|
||||
}
|
||||
|
||||
val x by <!DELEGATE_SPECIAL_FUNCTION_MISSING!>foo { x: A -> }<!>
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// ISSUE: KT-61747
|
||||
|
||||
interface A {
|
||||
operator fun getValue(x: Any?, y: Any?): String = ""
|
||||
}
|
||||
|
||||
fun <T> foo(x: (T) -> Unit): T = TODO()
|
||||
|
||||
fun bar1(a: A) {
|
||||
val x by <!DELEGATE_SPECIAL_FUNCTION_MISSING!>foo { x: A -> }<!>
|
||||
}
|
||||
|
||||
fun bar2(a: A) {
|
||||
operator fun <F> F.provideDelegate(x: Any?, y: Any?): F {
|
||||
return this
|
||||
}
|
||||
|
||||
val x by foo { x: A -> }
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// ISSUE: KT-61077
|
||||
|
||||
val test: Int by <!DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE, INFERRED_TYPE_VARIABLE_INTO_POSSIBLE_EMPTY_INTERSECTION!>materializeDelegate()<!>
|
||||
|
||||
fun <T: CharSequence> materializeDelegate(): Box<T> = TODO()
|
||||
|
||||
operator fun <K: Comparable<K>> Box<K>.provideDelegate(receiver: Any?, property: kotlin.reflect.KProperty<*>): K = TODO()
|
||||
|
||||
operator fun <Q: Comparable<Q>> Q.getValue(thisRef: Any?, property: kotlin.reflect.KProperty<*>): Q = TODO()
|
||||
|
||||
class Box<V> {}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// ISSUE: KT-61077
|
||||
|
||||
val test: Int by <!DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE!><!TYPE_MISMATCH!>materializeDelegate<!>()<!>
|
||||
|
||||
fun <T: CharSequence> materializeDelegate(): Box<T> = TODO()
|
||||
|
||||
operator fun <K: Comparable<K>> Box<K>.provideDelegate(receiver: Any?, property: kotlin.reflect.KProperty<*>): K = TODO()
|
||||
|
||||
operator fun <Q: Comparable<Q>> Q.getValue(thisRef: Any?, property: kotlin.reflect.KProperty<*>): Q = TODO()
|
||||
|
||||
class Box<V> {}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
// FIR_IDENTICAL
|
||||
// ISSUE: KT-59529
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
interface Out<out F> {
|
||||
val x: F
|
||||
}
|
||||
interface Out2<out E> {
|
||||
val x: E
|
||||
}
|
||||
interface Inv<U> {
|
||||
val u: U
|
||||
}
|
||||
|
||||
val outString: Out<String> = TODO()
|
||||
|
||||
val invOut2String by foo(outString)
|
||||
|
||||
operator fun <X> Inv<X>.getValue(
|
||||
thisRef: Any?,
|
||||
property: KProperty<*>
|
||||
): Inv<X> = TODO()
|
||||
|
||||
fun <M> foo(other: Out<M>): Inv<Out2<M>> = TODO()
|
||||
|
||||
fun main() {
|
||||
invOut2String.u.x.length
|
||||
}
|
||||
Vendored
+37
@@ -0,0 +1,37 @@
|
||||
// FIR_IDENTICAL
|
||||
// WITH_STDLIB
|
||||
// !CHECK_TYPE
|
||||
// ISSUE: KT-59529
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
val ows: IgnoringParser = IgnoringParser()
|
||||
|
||||
class MyParser<T> {
|
||||
|
||||
private val booleanLiteral: Parser<String> = TODO()
|
||||
|
||||
val topLevel by ows + booleanLiteral
|
||||
|
||||
fun main() {
|
||||
topLevel checkType { _<TransformParser<Pair<Unit, String>, String>>() }
|
||||
}
|
||||
|
||||
operator fun <T, R> TransformParser<T, R>.provideDelegate(
|
||||
thisRef: MyParser<*>,
|
||||
property: KProperty<*>
|
||||
): TransformParser<T, R> = TODO()
|
||||
|
||||
operator fun <T, R> TransformParser<T, R>.getValue(
|
||||
thisRef: MyParser<*>,
|
||||
property: KProperty<*>
|
||||
): TransformParser<T, R> = TODO()
|
||||
}
|
||||
|
||||
abstract class Parser<out T>
|
||||
|
||||
class TransformParser<T, R> : Parser<R>()
|
||||
class IgnoringParser : Parser<Unit>()
|
||||
|
||||
operator fun <T> IgnoringParser.plus(other: Parser<T>): TransformParser<Pair<Unit, T>, T> =
|
||||
TODO()
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// FIR_IDENTICAL
|
||||
val test: String by materializeDelegate()
|
||||
|
||||
fun <T> materializeDelegate(): Delegate<T> = Delegate()
|
||||
|
||||
operator fun <K> K.provideDelegate(receiver: Any?, property: kotlin.reflect.KProperty<*>): K = this
|
||||
|
||||
operator fun <X> Delegate<X>.getValue(thisRef: Any?, property: kotlin.reflect.KProperty<*>): X = TODO()
|
||||
|
||||
class Delegate<V>
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
// ISSUE: KT-61077
|
||||
class Delegate<T>
|
||||
|
||||
operator fun Delegate<*>.getValue(receiver: Any?, p: Any): String = ""
|
||||
@@ -10,7 +10,7 @@ operator fun <T> String.provideDelegate(receiver: Any?, p: Any) = Delegate<T>()
|
||||
var test1: String by Delegate()
|
||||
var test2: String by Delegate<String>()
|
||||
|
||||
var test3: String by <!DELEGATE_SPECIAL_FUNCTION_MISSING, DELEGATE_SPECIAL_FUNCTION_MISSING!>"OK"<!>
|
||||
var test3: String by "OK"
|
||||
|
||||
var test4: String by "OK".provideDelegate(null, "")
|
||||
var test5: String by "OK".provideDelegate<String>(null, "")
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
// ISSUE: KT-61077
|
||||
class Delegate<T>
|
||||
|
||||
operator fun Delegate<*>.getValue(receiver: Any?, p: Any): String = ""
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// ISSUE: KT-61633
|
||||
|
||||
interface A<T1>
|
||||
interface B<T2>
|
||||
interface C<T3>
|
||||
interface D<T4>
|
||||
|
||||
val <X1> A<X1>.provideDelegate: B<X1> get() = TODO()
|
||||
operator fun <X2> B<X2>.invoke(x: Any?, y: Any?): C<X2> = TODO()
|
||||
|
||||
val <X3> C<X3>.getValue: D<X3> get() = TODO()
|
||||
operator fun <X4> D<X4>.invoke(x: Any?, y: Any?): X4 = TODO()
|
||||
|
||||
fun foo(a: A<String>, c: C<String>) {
|
||||
val x1 by a
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>x1<!>
|
||||
x1.length
|
||||
|
||||
val y1 by c
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>y1<!>
|
||||
y1.length
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// ISSUE: KT-61633
|
||||
|
||||
interface A<T1>
|
||||
interface B<T2>
|
||||
interface C<T3>
|
||||
interface D<T4>
|
||||
|
||||
val <X1> A<X1>.provideDelegate: B<X1> get() = TODO()
|
||||
operator fun <X2> B<X2>.invoke(x: Any?, y: Any?): C<X2> = TODO()
|
||||
|
||||
val <X3> C<X3>.getValue: D<X3> get() = TODO()
|
||||
operator fun <X4> D<X4>.invoke(x: Any?, y: Any?): X4 = TODO()
|
||||
|
||||
fun foo(a: A<String>, c: C<String>) {
|
||||
val x1 by a
|
||||
<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE, DEBUG_INFO_EXPRESSION_TYPE("[Error type: Error delegation type for a]")!>x1<!>
|
||||
<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>x1<!>.<!DEBUG_INFO_MISSING_UNRESOLVED!>length<!>
|
||||
|
||||
val y1 by c
|
||||
<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE, DEBUG_INFO_EXPRESSION_TYPE("[Error type: Error delegation type for c]")!>y1<!>
|
||||
<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>y1<!>.<!DEBUG_INFO_MISSING_UNRESOLVED!>length<!>
|
||||
}
|
||||
Generated
+66
@@ -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 {
|
||||
|
||||
+6
@@ -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")
|
||||
|
||||
+6
@@ -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")
|
||||
|
||||
+5
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 <T> materializeDelegate(): Delegate<T> = Delegate()
|
||||
|
||||
operator fun <K> K.provideDelegate(receiver: Any?, property: kotlin.reflect.KProperty<*>): K = this
|
||||
|
||||
class Delegate<V> {
|
||||
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<T>` 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.
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user