[NI] Fix completion of error delegates with receiver with type parameters
This commit is contained in:
+33
-2
@@ -12,9 +12,12 @@ import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem
|
||||
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.SimpleConstraintSystemConstraintPosition
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.typeForTypeVariable
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
|
||||
import org.jetbrains.kotlin.types.TypeConstructor
|
||||
|
||||
abstract class ManyCandidatesResolver<D : CallableDescriptor>(
|
||||
private val psiCallResolver: PSICallResolver,
|
||||
@@ -94,11 +97,39 @@ abstract class ManyCandidatesResolver<D : CallableDescriptor>(
|
||||
val allCandidates = arrayListOf<ResolutionResultCallInfo<D>>()
|
||||
|
||||
if (hasOneSuccessfulAndOneErrorCandidate) {
|
||||
for (callInfo in resolvedCallsInfo) {
|
||||
val goodCandidate = resolvedCallsInfo.first { it.callResolutionResult.constraintSystem.errors.isEmpty() && it.callResolutionResult.diagnostics.isEmpty() }
|
||||
val badCandidate = resolvedCallsInfo.first { it.callResolutionResult.constraintSystem.errors.isNotEmpty() || it.callResolutionResult.diagnostics.isNotEmpty()}
|
||||
|
||||
for (callInfo in listOf(goodCandidate, badCandidate)) {
|
||||
val atomsToAnalyze = mutableListOf<ResolvedAtom>(callInfo.callResolutionResult)
|
||||
val system = NewConstraintSystemImpl(callComponents.constraintInjector, builtIns).apply {
|
||||
addOtherSystem(callInfo.callResolutionResult.constraintSystem)
|
||||
/*
|
||||
* This is needed for very stupid case, when we have some delegate with good `getValue` and bad `setValue` that
|
||||
* was provided by some function call with generic (e.g. var x by lazy { "" })
|
||||
* The problem is that we want to complete candidates for `getValue` and `setValue` separately, so diagnostics
|
||||
* from `setValue` don't leak into resolved call of `getValue`, but both calls can have same
|
||||
* atom for receiver (and type variables from it). After we complete first call, completion of
|
||||
* second call fails because it's atoms don't contains type variable from receiver, because
|
||||
* they was completed in first call
|
||||
* To fix that we add equality constraints from first call to system of second call and create
|
||||
* stub atoms in order to call completer doesn't fail
|
||||
*/
|
||||
if (callInfo === badCandidate) {
|
||||
for ((typeVariable, fixedType) in allCandidates[0].resolutionResult.constraintSystem.fixedTypeVariables) {
|
||||
if (typeVariable in this.notFixedTypeVariables) {
|
||||
val type = (typeVariable as TypeConstructor).typeForTypeVariable()
|
||||
addEqualityConstraint(
|
||||
type,
|
||||
fixedType,
|
||||
SimpleConstraintSystemConstraintPosition
|
||||
)
|
||||
atomsToAnalyze += StubResolvedAtom(typeVariable)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
runCompletion(system, listOf(callInfo.callResolutionResult))
|
||||
runCompletion(system, atomsToAnalyze)
|
||||
val resolutionResult = callInfo.asCallResolutionResult(diagnosticHolder, system)
|
||||
allCandidates += ResolutionResultCallInfo(
|
||||
resolutionResult,
|
||||
|
||||
+7
@@ -217,6 +217,13 @@ class KotlinConstraintSystemCompleter(
|
||||
typeConstructor.takeIf { c.notFixedTypeVariables.containsKey(typeConstructor) }
|
||||
}
|
||||
|
||||
/*
|
||||
* Hack for completing error candidates in delegate resolve
|
||||
*/
|
||||
if (this is StubResolvedAtom && typeVariable in c.notFixedTypeVariables) {
|
||||
to += typeVariable
|
||||
}
|
||||
|
||||
if (analyzed) {
|
||||
subResolvedAtoms?.forEach { it.process(to) }
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableForLambdaReturnType
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeConstructor
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||
@@ -246,4 +247,12 @@ class PartialCallContainer(val result: PartialCallResolutionResult?) {
|
||||
companion object {
|
||||
val empty = PartialCallContainer(null)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Used only for delegated properties with one good candidate and one for bad
|
||||
* e.g. in case `var x by lazy { "" }
|
||||
*/
|
||||
class StubResolvedAtom(val typeVariable: TypeConstructor) : ResolvedAtom() {
|
||||
override val atom: ResolutionAtom? get() = null
|
||||
}
|
||||
Reference in New Issue
Block a user