[NI] Complete calls during one inference session only once

The problem is that delegated properties resolve two calls together:
 `getValue`/`setValue` with a common receiver, which can contain
 callable references. For each completion new anonymous descriptor
 was created and caused "rewrite at slice" exceptions later.
 Now there is a little hack to check that during one inference session
 we don't complete one call more than one time.

 More correct fix would be to explicitly specify common receiver for
 inference session but it requires quite big refactoring, which will
 be done later with a whole refactoring of the common solver

 #KT-30250 Fixed
This commit is contained in:
Mikhail Zarechenskiy
2019-03-04 17:24:27 +03:00
parent 14c93c7c0e
commit 7c357c0ec0
8 changed files with 67 additions and 4 deletions
@@ -15,10 +15,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
import org.jetbrains.kotlin.resolve.calls.inference.model.DelegatedPropertyConstraintPosition import org.jetbrains.kotlin.resolve.calls.inference.model.DelegatedPropertyConstraintPosition
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallComponents import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.model.KotlinResolutionCandidate
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallAtom
import org.jetbrains.kotlin.resolve.calls.model.ResolvedLambdaAtom
import org.jetbrains.kotlin.resolve.calls.tower.ManyCandidatesResolver import org.jetbrains.kotlin.resolve.calls.tower.ManyCandidatesResolver
import org.jetbrains.kotlin.resolve.calls.tower.PSICallResolver import org.jetbrains.kotlin.resolve.calls.tower.PSICallResolver
import org.jetbrains.kotlin.resolve.calls.tower.PSIPartialCallInfo import org.jetbrains.kotlin.resolve.calls.tower.PSIPartialCallInfo
@@ -106,4 +103,5 @@ object InferenceSessionForExistingCandidates : InferenceSession {
): Map<TypeConstructor, UnwrappedType> = emptyMap() ): Map<TypeConstructor, UnwrappedType> = emptyMap()
override fun writeOnlyStubs(): Boolean = false override fun writeOnlyStubs(): Boolean = false
override fun callCompleted(resolvedAtom: ResolvedAtom): Boolean = false
} }
@@ -28,6 +28,7 @@ abstract class ManyCandidatesResolver<D : CallableDescriptor>(
) : InferenceSession { ) : InferenceSession {
private val partiallyResolvedCallsInfo = arrayListOf<PSIPartialCallInfo>() private val partiallyResolvedCallsInfo = arrayListOf<PSIPartialCallInfo>()
private val errorCallsInfo = arrayListOf<PSIErrorCallInfo<D>>() private val errorCallsInfo = arrayListOf<PSIErrorCallInfo<D>>()
private val completedCalls = hashSetOf<ResolvedAtom>()
open fun prepareForCompletion(commonSystem: NewConstraintSystem, resolvedCallsInfo: List<PSIPartialCallInfo>) { open fun prepareForCompletion(commonSystem: NewConstraintSystem, resolvedCallsInfo: List<PSIPartialCallInfo>) {
// do nothing // do nothing
@@ -59,6 +60,9 @@ abstract class ManyCandidatesResolver<D : CallableDescriptor>(
return partiallyResolvedCallsInfo.lastOrNull()?.callResolutionResult?.constraintSystem ?: ConstraintStorage.Empty return partiallyResolvedCallsInfo.lastOrNull()?.callResolutionResult?.constraintSystem ?: ConstraintStorage.Empty
} }
override fun callCompleted(resolvedAtom: ResolvedAtom): Boolean =
!completedCalls.add(resolvedAtom)
fun resolveCandidates(resolutionCallbacks: KotlinResolutionCallbacks): List<ResolutionResultCallInfo<D>> { fun resolveCandidates(resolutionCallbacks: KotlinResolutionCallbacks): List<ResolutionResultCallInfo<D>> {
val resolvedCallsInfo = partiallyResolvedCallsInfo.toList() val resolvedCallsInfo = partiallyResolvedCallsInfo.toList()
@@ -55,6 +55,10 @@ class ResolvedAtomCompleter(
private val topLevelTrace = topLevelCallCheckerContext.trace private val topLevelTrace = topLevelCallCheckerContext.trace
private fun complete(resolvedAtom: ResolvedAtom) { private fun complete(resolvedAtom: ResolvedAtom) {
if (topLevelCallContext.inferenceSession.callCompleted(resolvedAtom)) {
return
}
when (resolvedAtom) { when (resolvedAtom) {
is ResolvedCollectionLiteralAtom -> completeCollectionLiteralCalls(resolvedAtom) is ResolvedCollectionLiteralAtom -> completeCollectionLiteralCalls(resolvedAtom)
is ResolvedCallableReferenceAtom -> completeCallableReference(resolvedAtom) is ResolvedCallableReferenceAtom -> completeCallableReference(resolvedAtom)
@@ -25,6 +25,7 @@ interface InferenceSession {
): Map<TypeConstructor, UnwrappedType> = emptyMap() ): Map<TypeConstructor, UnwrappedType> = emptyMap()
override fun writeOnlyStubs(): Boolean = false override fun writeOnlyStubs(): Boolean = false
override fun callCompleted(resolvedAtom: ResolvedAtom): Boolean = false
} }
} }
@@ -35,6 +36,7 @@ interface InferenceSession {
fun currentConstraintSystem(): ConstraintStorage fun currentConstraintSystem(): ConstraintStorage
fun inferPostponedVariables(lambda: ResolvedLambdaAtom, initialStorage: ConstraintStorage): Map<TypeConstructor, UnwrappedType> fun inferPostponedVariables(lambda: ResolvedLambdaAtom, initialStorage: ConstraintStorage): Map<TypeConstructor, UnwrappedType>
fun writeOnlyStubs(): Boolean fun writeOnlyStubs(): Boolean
fun callCompleted(resolvedAtom: ResolvedAtom): Boolean
} }
interface PartialCallInfo { interface PartialCallInfo {
@@ -0,0 +1,17 @@
// !LANGUAGE: +NewInference
// !DIAGNOSTICS: -UNUSED_PARAMETER
import kotlin.reflect.KProperty
class Inv2<T, K>
fun <T, K> create(g: (T) -> K): Inv2<T, K> = TODO()
operator fun <S1, V1> Inv2<S1, V1>.getValue(o: Sample, desc: KProperty<*>): V1 = TODO()
operator fun <S2, V2> Inv2<S2, V2>.setValue(o: Sample, desc: KProperty<*>, value: V2) {}
class Version(val version: Int)
class Sample {
var version: Version by create(::Version)
}
@@ -0,0 +1,28 @@
package
public fun </*0*/ T, /*1*/ K> create(/*0*/ g: (T) -> K): Inv2<T, K>
public operator fun </*0*/ S1, /*1*/ V1> Inv2<S1, V1>.getValue(/*0*/ o: Sample, /*1*/ desc: kotlin.reflect.KProperty<*>): V1
public operator fun </*0*/ S2, /*1*/ V2> Inv2<S2, V2>.setValue(/*0*/ o: Sample, /*1*/ desc: kotlin.reflect.KProperty<*>, /*2*/ value: V2): kotlin.Unit
public final class Inv2</*0*/ T, /*1*/ K> {
public constructor Inv2</*0*/ T, /*1*/ K>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class Sample {
public constructor Sample()
public final var version: Version
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class Version {
public constructor Version(/*0*/ version: kotlin.Int)
public final val version: kotlin.Int
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -5625,6 +5625,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/delegatedProperty/inference"), Pattern.compile("^(.*)\\.kts?$"), TargetBackend.ANY, true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/delegatedProperty/inference"), Pattern.compile("^(.*)\\.kts?$"), TargetBackend.ANY, true);
} }
@TestMetadata("callableReferenceArgumentInDelegatedExpression.kt")
public void testCallableReferenceArgumentInDelegatedExpression() throws Exception {
runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/callableReferenceArgumentInDelegatedExpression.kt");
}
@TestMetadata("delegateExpressionAsLambda.kt") @TestMetadata("delegateExpressionAsLambda.kt")
public void testDelegateExpressionAsLambda() throws Exception { public void testDelegateExpressionAsLambda() throws Exception {
runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/delegateExpressionAsLambda.kt"); runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/delegateExpressionAsLambda.kt");
@@ -5620,6 +5620,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/delegatedProperty/inference"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/delegatedProperty/inference"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
} }
@TestMetadata("callableReferenceArgumentInDelegatedExpression.kt")
public void testCallableReferenceArgumentInDelegatedExpression() throws Exception {
runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/callableReferenceArgumentInDelegatedExpression.kt");
}
@TestMetadata("delegateExpressionAsLambda.kt") @TestMetadata("delegateExpressionAsLambda.kt")
public void testDelegateExpressionAsLambda() throws Exception { public void testDelegateExpressionAsLambda() throws Exception {
runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/delegateExpressionAsLambda.kt"); runTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/delegateExpressionAsLambda.kt");