[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.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.SimpleConstraintSystemConstraintPosition
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.typeForTypeVariable
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults
|
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
|
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
|
||||||
|
import org.jetbrains.kotlin.types.TypeConstructor
|
||||||
|
|
||||||
abstract class ManyCandidatesResolver<D : CallableDescriptor>(
|
abstract class ManyCandidatesResolver<D : CallableDescriptor>(
|
||||||
private val psiCallResolver: PSICallResolver,
|
private val psiCallResolver: PSICallResolver,
|
||||||
@@ -94,11 +97,39 @@ abstract class ManyCandidatesResolver<D : CallableDescriptor>(
|
|||||||
val allCandidates = arrayListOf<ResolutionResultCallInfo<D>>()
|
val allCandidates = arrayListOf<ResolutionResultCallInfo<D>>()
|
||||||
|
|
||||||
if (hasOneSuccessfulAndOneErrorCandidate) {
|
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 {
|
val system = NewConstraintSystemImpl(callComponents.constraintInjector, builtIns).apply {
|
||||||
addOtherSystem(callInfo.callResolutionResult.constraintSystem)
|
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)
|
val resolutionResult = callInfo.asCallResolutionResult(diagnosticHolder, system)
|
||||||
allCandidates += ResolutionResultCallInfo(
|
allCandidates += ResolutionResultCallInfo(
|
||||||
resolutionResult,
|
resolutionResult,
|
||||||
|
|||||||
+7
@@ -217,6 +217,13 @@ class KotlinConstraintSystemCompleter(
|
|||||||
typeConstructor.takeIf { c.notFixedTypeVariables.containsKey(typeConstructor) }
|
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) {
|
if (analyzed) {
|
||||||
subResolvedAtoms?.forEach { it.process(to) }
|
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.inference.model.TypeVariableForLambdaReturnType
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.TypeConstructor
|
||||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||||
import org.jetbrains.kotlin.types.UnwrappedType
|
import org.jetbrains.kotlin.types.UnwrappedType
|
||||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||||
@@ -246,4 +247,12 @@ class PartialCallContainer(val result: PartialCallResolutionResult?) {
|
|||||||
companion object {
|
companion object {
|
||||||
val empty = PartialCallContainer(null)
|
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