[NI] Soften restictions on using Nothing as proper constraint for full call completion
Consider lower `Nothing` constraint non-proper only if there is a dependant not analyzed postponed atom. Early completion to `Nothing` provides data flow info for smart casts. KT-35668 Fixed
This commit is contained in:
+23
-3
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.components.TrivialConstraint
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.Constraint
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints
|
||||
import org.jetbrains.kotlin.resolve.calls.model.KotlinResolutionCandidate
|
||||
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtom
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.model.*
|
||||
@@ -39,11 +40,14 @@ class CompletionModeCalculator {
|
||||
if (csBuilder.isProperType(returnType)) return ConstraintSystemCompletionMode.FULL
|
||||
|
||||
// For nested call with variables in return type check possibility of full completion
|
||||
return CalculatorForNestedCall(returnType, csCompleterContext, trivialConstraintTypeInferenceOracle).computeCompletionMode()
|
||||
return CalculatorForNestedCall(
|
||||
candidate, returnType, csCompleterContext, trivialConstraintTypeInferenceOracle
|
||||
).computeCompletionMode()
|
||||
}
|
||||
}
|
||||
|
||||
private class CalculatorForNestedCall(
|
||||
private val candidate: KotlinResolutionCandidate,
|
||||
private val returnType: UnwrappedType?,
|
||||
private val csCompleterContext: CsCompleterContext,
|
||||
private val trivialConstraintTypeInferenceOracle: TrivialConstraintTypeInferenceOracle
|
||||
@@ -57,6 +61,10 @@ class CompletionModeCalculator {
|
||||
private val variablesWithQueuedConstraints = mutableSetOf<TypeVariableMarker>()
|
||||
private val typesToProcess: Queue<KotlinTypeMarker> = ArrayDeque()
|
||||
|
||||
private val postponedAtoms: List<PostponedResolvedAtom> by lazy {
|
||||
KotlinConstraintSystemCompleter.getOrderedNotAnalyzedPostponedArguments(listOf(candidate.resolvedCall))
|
||||
}
|
||||
|
||||
fun computeCompletionMode(): ConstraintSystemCompletionMode = with(csCompleterContext) {
|
||||
// Add fixation directions for variables based on effective variance in type
|
||||
typesToProcess.add(returnType)
|
||||
@@ -163,13 +171,14 @@ class CompletionModeCalculator {
|
||||
direction: FixationDirection
|
||||
): Boolean {
|
||||
val constraints = variableWithConstraints.constraints
|
||||
val variable = variableWithConstraints.typeVariable
|
||||
|
||||
// todo check correctness for @Exact
|
||||
return constraints.isNotEmpty() && constraints.any { constraint ->
|
||||
constraint.hasRequiredKind(direction)
|
||||
&& !constraint.type.typeConstructor().isIntegerLiteralTypeConstructor()
|
||||
&& isProperType(constraint.type)
|
||||
&& trivialConstraintTypeInferenceOracle.isSuitableResultedType(constraint.type)
|
||||
&& !constraint.type.typeConstructor().isIntegerLiteralTypeConstructor()
|
||||
&& !isNothingConstraintForPartiallyAnalyzedVariable(constraint, variable)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,5 +186,16 @@ class CompletionModeCalculator {
|
||||
FixationDirection.TO_SUBTYPE -> kind.isLower() || kind.isEqual()
|
||||
FixationDirection.EQUALITY -> kind.isEqual()
|
||||
}
|
||||
|
||||
private fun CsCompleterContext.isNothingConstraintForPartiallyAnalyzedVariable(
|
||||
constraint: Constraint,
|
||||
variable: TypeVariableMarker
|
||||
): Boolean {
|
||||
if (trivialConstraintTypeInferenceOracle.isSuitableResultedType(constraint.type) || !constraint.kind.isLower())
|
||||
return false
|
||||
return postponedAtoms.any { atom ->
|
||||
atom.expectedType?.contains { type -> variable.defaultType() == type } ?: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
-19
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.resolve.calls.inference.components
|
||||
|
||||
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalType
|
||||
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalTypeOrSubtype
|
||||
import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionStatelessCallbacks
|
||||
import org.jetbrains.kotlin.resolve.calls.components.transformToResolvedLambda
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.*
|
||||
@@ -23,7 +22,6 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
class KotlinConstraintSystemCompleter(
|
||||
private val resultTypeResolver: ResultTypeResolver,
|
||||
val variableFixationFinder: VariableFixationFinder,
|
||||
private val statelessCallbacks: KotlinResolutionStatelessCallbacks
|
||||
) {
|
||||
enum class ConstraintSystemCompletionMode {
|
||||
FULL,
|
||||
@@ -214,23 +212,6 @@ class KotlinConstraintSystemCompleter(
|
||||
return false
|
||||
}
|
||||
|
||||
private fun getOrderedNotAnalyzedPostponedArguments(topLevelAtoms: List<ResolvedAtom>): List<PostponedResolvedAtom> {
|
||||
fun ResolvedAtom.process(to: MutableList<PostponedResolvedAtom>) {
|
||||
to.addIfNotNull(this.safeAs<PostponedResolvedAtom>()?.takeUnless { it.analyzed })
|
||||
|
||||
if (analyzed) {
|
||||
subResolvedAtoms?.forEach { it.process(to) }
|
||||
}
|
||||
}
|
||||
|
||||
val notAnalyzedArguments = arrayListOf<PostponedResolvedAtom>()
|
||||
for (primitive in topLevelAtoms) {
|
||||
primitive.process(notAnalyzedArguments)
|
||||
}
|
||||
|
||||
return notAnalyzedArguments
|
||||
}
|
||||
|
||||
private fun getOrderedAllTypeVariables(
|
||||
c: Context,
|
||||
collectVariablesFromContext: Boolean,
|
||||
@@ -352,4 +333,23 @@ class KotlinConstraintSystemCompleter(
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getOrderedNotAnalyzedPostponedArguments(topLevelAtoms: List<ResolvedAtom>): List<PostponedResolvedAtom> {
|
||||
fun ResolvedAtom.process(to: MutableList<PostponedResolvedAtom>) {
|
||||
to.addIfNotNull(this.safeAs<PostponedResolvedAtom>()?.takeUnless { it.analyzed })
|
||||
|
||||
if (analyzed) {
|
||||
subResolvedAtoms?.forEach { it.process(to) }
|
||||
}
|
||||
}
|
||||
|
||||
val notAnalyzedArguments = arrayListOf<PostponedResolvedAtom>()
|
||||
for (primitive in topLevelAtoms) {
|
||||
primitive.process(notAnalyzedArguments)
|
||||
}
|
||||
|
||||
return notAnalyzedArguments
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user