[NI] Fix completion for ILT when Nothing constraint is present
Full completion should not be done if lower `Nothing` is the only proper constraint when constraint with ILT type is present. ILT will be selected as a resulting type and transformed into `Int` without attention to possible restrictions from outer calls.
This commit is contained in:
+28
-11
@@ -52,7 +52,7 @@ class CompletionModeCalculator {
|
||||
private val candidate: KotlinResolutionCandidate,
|
||||
private val returnType: UnwrappedType?,
|
||||
private val csCompleterContext: CsCompleterContext,
|
||||
private val trivialConstraintTypeInferenceOracle: TrivialConstraintTypeInferenceOracle
|
||||
private val trivialConstraintTypeInferenceOracle: TrivialConstraintTypeInferenceOracle,
|
||||
) {
|
||||
private enum class FixationDirection {
|
||||
TO_SUBTYPE, EQUALITY
|
||||
@@ -192,13 +192,32 @@ class CompletionModeCalculator {
|
||||
val constraints = variableWithConstraints.constraints
|
||||
val variable = variableWithConstraints.typeVariable
|
||||
|
||||
// todo check correctness for @Exact
|
||||
return constraints.isNotEmpty() && constraints.any { constraint ->
|
||||
constraint.hasRequiredKind(direction)
|
||||
&& isProperType(constraint.type)
|
||||
&& !constraint.type.typeConstructor().isIntegerLiteralTypeConstructor()
|
||||
&& !isNothingConstraintForPartiallyAnalyzedVariable(constraint, variable)
|
||||
// ILT constraint tracking is necessary to prevent incorrect full completion from Nothing constraint
|
||||
// Consider ILT <: T; Nothing <: T for T requiring lower constraint
|
||||
// Nothing would trigger full completion, but resulting type would be Int
|
||||
// Possible restrictions on integer constant from outer calls would be ignored
|
||||
|
||||
var iltConstraintPresent = false
|
||||
var properConstraintPresent = false
|
||||
var nonNothingProperConstraintPresent = false
|
||||
|
||||
for (constraint in constraints) {
|
||||
if (!constraint.hasRequiredKind(direction) || !isProperType(constraint.type))
|
||||
continue
|
||||
|
||||
if (constraint.type.typeConstructor().isIntegerLiteralTypeConstructor()) {
|
||||
iltConstraintPresent = true
|
||||
} else if (trivialConstraintTypeInferenceOracle.isSuitableResultedType(constraint.type)) {
|
||||
properConstraintPresent = true
|
||||
nonNothingProperConstraintPresent = true
|
||||
} else if (!isLowerConstraintForPartiallyAnalyzedVariable(constraint, variable)) {
|
||||
properConstraintPresent = true
|
||||
}
|
||||
}
|
||||
|
||||
if (!properConstraintPresent) return false
|
||||
|
||||
return !iltConstraintPresent || nonNothingProperConstraintPresent
|
||||
}
|
||||
|
||||
private fun Constraint.hasRequiredKind(direction: FixationDirection) = when (direction) {
|
||||
@@ -206,13 +225,11 @@ class CompletionModeCalculator {
|
||||
FixationDirection.EQUALITY -> kind.isEqual()
|
||||
}
|
||||
|
||||
private fun CsCompleterContext.isNothingConstraintForPartiallyAnalyzedVariable(
|
||||
private fun CsCompleterContext.isLowerConstraintForPartiallyAnalyzedVariable(
|
||||
constraint: Constraint,
|
||||
variable: TypeVariableMarker
|
||||
): Boolean {
|
||||
if (trivialConstraintTypeInferenceOracle.isSuitableResultedType(constraint.type) || !constraint.kind.isLower())
|
||||
return false
|
||||
return postponedAtoms.any { atom ->
|
||||
return constraint.kind.isLower() && postponedAtoms.any { atom ->
|
||||
atom.expectedType?.contains { type -> variable.defaultType() == type } ?: false
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user