K2: Refine handling of Delegate resolution mode
- Move it out of the ContextDependent hierarchy
- Get rid of many controversial checks that were necessary because
Delegate was a ContextDependent inheritor
- Actually fix semantics for lambda processing
Previously, lambdas as delegate expression were not being analyzed
thus leading to an exception (see KT-64635), and this change
forces analyzing them in the same mode as ContextIndependent
(thus `{}` made by default `() -> Unit` leaving to DELEGATE_SPECIAL_FUNCTION_MISSING)
Before this change, new test was failing with an exception.
I've analyzed all `is ContextDependent` and it seems that none of them
is relevant to delegates.
^KT-64635 Fixed
This commit is contained in:
committed by
Space Team
parent
47a51f6499
commit
df2a1d4d02
+6
@@ -10687,6 +10687,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
|
|||||||
runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/labeledDelegatedExpression.kt");
|
runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/labeledDelegatedExpression.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("lambdaDelegate.kt")
|
||||||
|
public void testLambdaDelegate() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/lambdaDelegate.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("lambdaWithMultipleReturns.kt")
|
@TestMetadata("lambdaWithMultipleReturns.kt")
|
||||||
public void testLambdaWithMultipleReturns() throws Exception {
|
public void testLambdaWithMultipleReturns() throws Exception {
|
||||||
|
|||||||
+6
@@ -10687,6 +10687,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
|
|||||||
runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/labeledDelegatedExpression.kt");
|
runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/labeledDelegatedExpression.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("lambdaDelegate.kt")
|
||||||
|
public void testLambdaDelegate() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/lambdaDelegate.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("lambdaWithMultipleReturns.kt")
|
@TestMetadata("lambdaWithMultipleReturns.kt")
|
||||||
public void testLambdaWithMultipleReturns() throws Exception {
|
public void testLambdaWithMultipleReturns() throws Exception {
|
||||||
|
|||||||
+6
@@ -10681,6 +10681,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
|
|||||||
runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/labeledDelegatedExpression.kt");
|
runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/labeledDelegatedExpression.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("lambdaDelegate.kt")
|
||||||
|
public void testLambdaDelegate() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/lambdaDelegate.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("lambdaWithMultipleReturns.kt")
|
@TestMetadata("lambdaWithMultipleReturns.kt")
|
||||||
public void testLambdaWithMultipleReturns() throws Exception {
|
public void testLambdaWithMultipleReturns() throws Exception {
|
||||||
|
|||||||
+6
@@ -10687,6 +10687,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
|
|||||||
runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/labeledDelegatedExpression.kt");
|
runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/labeledDelegatedExpression.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("lambdaDelegate.kt")
|
||||||
|
public void testLambdaDelegate() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/lambdaDelegate.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("lambdaWithMultipleReturns.kt")
|
@TestMetadata("lambdaWithMultipleReturns.kt")
|
||||||
public void testLambdaWithMultipleReturns() throws Exception {
|
public void testLambdaWithMultipleReturns() throws Exception {
|
||||||
|
|||||||
@@ -23,10 +23,11 @@ sealed class ResolutionMode(
|
|||||||
override fun toString(): String = "ContextDependent"
|
override fun toString(): String = "ContextDependent"
|
||||||
}
|
}
|
||||||
|
|
||||||
data object Delegate : ContextDependent()
|
|
||||||
data object AugmentedAssignmentCallOption : ContextDependent(skipCompletion = true)
|
data object AugmentedAssignmentCallOption : ContextDependent(skipCompletion = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data object Delegate : ResolutionMode(forceFullCompletion = false)
|
||||||
|
|
||||||
data object ContextIndependent : ResolutionMode(forceFullCompletion = true)
|
data object ContextIndependent : ResolutionMode(forceFullCompletion = true)
|
||||||
|
|
||||||
sealed class ReceiverResolution(val forCallableReference: Boolean) : ResolutionMode(forceFullCompletion = true) {
|
sealed class ReceiverResolution(val forCallableReference: Boolean) : ResolutionMode(forceFullCompletion = true) {
|
||||||
|
|||||||
+2
-2
@@ -63,7 +63,7 @@ class FirPCLAInferenceSession(
|
|||||||
|
|
||||||
// Integrating back would happen at FirDelegatedPropertyInferenceSession.completeSessionOrPostponeIfNonRoot
|
// Integrating back would happen at FirDelegatedPropertyInferenceSession.completeSessionOrPostponeIfNonRoot
|
||||||
// after all other delegation-related calls are being analyzed
|
// after all other delegation-related calls are being analyzed
|
||||||
if (resolutionMode == ResolutionMode.ContextDependent.Delegate) return
|
if (resolutionMode == ResolutionMode.Delegate) return
|
||||||
|
|
||||||
currentCommonSystem.replaceContentWith(candidate.system.currentStorage())
|
currentCommonSystem.replaceContentWith(candidate.system.currentStorage())
|
||||||
|
|
||||||
@@ -211,7 +211,7 @@ class FirPCLAInferenceSession(
|
|||||||
}
|
}
|
||||||
if (callInfo.arguments.any { it.isQualifiedAccessContainingTypeVariables() || it.doesArgumentUseOuterCS() }) return true
|
if (callInfo.arguments.any { it.isQualifiedAccessContainingTypeVariables() || it.doesArgumentUseOuterCS() }) return true
|
||||||
|
|
||||||
if (callInfo.resolutionMode is ResolutionMode.ContextDependent.Delegate) return true
|
if (callInfo.resolutionMode is ResolutionMode.Delegate) return true
|
||||||
|
|
||||||
// For assignments like myVarContainingTV = SomeCallWithNonTrivialInference(...)
|
// For assignments like myVarContainingTV = SomeCallWithNonTrivialInference(...)
|
||||||
// We should integrate the call into the PCLA tree, too
|
// We should integrate the call into the PCLA tree, too
|
||||||
|
|||||||
+7
-2
@@ -440,7 +440,7 @@ open class FirDeclarationsResolveTransformer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun transformDelegateExpression(delegate: FirWrappedDelegateExpression): FirExpression =
|
private fun transformDelegateExpression(delegate: FirWrappedDelegateExpression): FirExpression =
|
||||||
delegate.expression.transformSingle(transformer, ResolutionMode.ContextDependent.Delegate)
|
delegate.expression.transformSingle(transformer, ResolutionMode.Delegate)
|
||||||
.transformSingle(components.integerLiteralAndOperatorApproximationTransformer, null)
|
.transformSingle(components.integerLiteralAndOperatorApproximationTransformer, null)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1024,7 +1024,12 @@ open class FirDeclarationsResolveTransformer(
|
|||||||
}
|
}
|
||||||
is ResolutionMode.WithExpectedType ->
|
is ResolutionMode.WithExpectedType ->
|
||||||
transformAnonymousFunctionWithExpectedType(anonymousFunction, data.expectedTypeRef, data)
|
transformAnonymousFunctionWithExpectedType(anonymousFunction, data.expectedTypeRef, data)
|
||||||
is ResolutionMode.ContextIndependent, is ResolutionMode.AssignmentLValue, is ResolutionMode.ReceiverResolution ->
|
|
||||||
|
is ResolutionMode.ContextIndependent,
|
||||||
|
is ResolutionMode.AssignmentLValue,
|
||||||
|
is ResolutionMode.ReceiverResolution,
|
||||||
|
is ResolutionMode.Delegate,
|
||||||
|
->
|
||||||
transformAnonymousFunctionWithExpectedType(anonymousFunction, FirImplicitTypeRefImplWithoutSource, data)
|
transformAnonymousFunctionWithExpectedType(anonymousFunction, FirImplicitTypeRefImplWithoutSource, data)
|
||||||
is ResolutionMode.WithStatus ->
|
is ResolutionMode.WithStatus ->
|
||||||
throw AssertionError("Should not be here in WithStatus/WithExpectedTypeFromCast mode")
|
throw AssertionError("Should not be here in WithStatus/WithExpectedTypeFromCast mode")
|
||||||
|
|||||||
+2
-6
@@ -491,10 +491,7 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT
|
|||||||
)
|
)
|
||||||
|
|
||||||
val approximationIsNeeded =
|
val approximationIsNeeded =
|
||||||
resolutionMode !is ResolutionMode.ReceiverResolution &&
|
resolutionMode !is ResolutionMode.ReceiverResolution && resolutionMode !is ResolutionMode.ContextDependent
|
||||||
(resolutionMode !is ResolutionMode.ContextDependent ||
|
|
||||||
// TODO check why we need a special case for ContextDependent.Delegate
|
|
||||||
resolutionMode is ResolutionMode.ContextDependent.Delegate)
|
|
||||||
|
|
||||||
val integerOperatorCall = buildIntegerLiteralOperatorCall {
|
val integerOperatorCall = buildIntegerLiteralOperatorCall {
|
||||||
source = originalCall.source
|
source = originalCall.source
|
||||||
@@ -1070,8 +1067,7 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT
|
|||||||
|
|
||||||
transformedLHS?.let { callableReferenceAccess.replaceExplicitReceiver(transformedLHS) }
|
transformedLHS?.let { callableReferenceAccess.replaceExplicitReceiver(transformedLHS) }
|
||||||
|
|
||||||
// TODO check why we need a special case for ContextDependent.Delegate
|
return if (data is ResolutionMode.ContextDependent) {
|
||||||
return if (data is ResolutionMode.ContextDependent && data !is ResolutionMode.ContextDependent.Delegate) {
|
|
||||||
context.storeCallableReferenceContext(callableReferenceAccess)
|
context.storeCallableReferenceContext(callableReferenceAccess)
|
||||||
callableReferenceAccess
|
callableReferenceAccess
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
// ISSUE: KT-64635
|
||||||
|
// FIR_IDENTICAL
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
class Context
|
||||||
|
|
||||||
|
interface MyReadOnlyProperty<in T, out V> {
|
||||||
|
operator fun getValue(thisRef: T, property: KProperty<*>): V
|
||||||
|
}
|
||||||
|
|
||||||
|
open class NodeHolder {
|
||||||
|
operator fun ((Context).() -> Unit).provideDelegate(
|
||||||
|
thisRef: Any?,
|
||||||
|
prop: KProperty<*>
|
||||||
|
): MyReadOnlyProperty<Any?, Unit> = TODO()
|
||||||
|
}
|
||||||
|
|
||||||
|
class SubClass1 : NodeHolder() {
|
||||||
|
val foo: (Context).() -> Unit = {}
|
||||||
|
val x by foo
|
||||||
|
}
|
||||||
|
|
||||||
|
class SubClass2 : NodeHolder() {
|
||||||
|
val x by <!DELEGATE_SPECIAL_FUNCTION_MISSING!>{}<!>
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
val my_holder_works =
|
||||||
|
object : NodeHolder() {
|
||||||
|
val foo: (Context).() -> Unit = {}
|
||||||
|
val x by foo
|
||||||
|
}
|
||||||
|
|
||||||
|
val my_holder_bad =
|
||||||
|
object : NodeHolder() {
|
||||||
|
val x by <!DELEGATE_SPECIAL_FUNCTION_MISSING!>{}<!>
|
||||||
|
}
|
||||||
|
}
|
||||||
Generated
+6
@@ -10687,6 +10687,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
|||||||
runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/labeledDelegatedExpression.kt");
|
runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/labeledDelegatedExpression.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("lambdaDelegate.kt")
|
||||||
|
public void testLambdaDelegate() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/lambdaDelegate.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("lambdaWithMultipleReturns.kt")
|
@TestMetadata("lambdaWithMultipleReturns.kt")
|
||||||
public void testLambdaWithMultipleReturns() throws Exception {
|
public void testLambdaWithMultipleReturns() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user