[NI] Discriminate Nothing? result type from nullability constraints
Nullability constraints should not be chosen when proper argument constraints for variables in contravariant position present. ^KT-32106 Fixed ^KT-33166 Fixed
This commit is contained in:
+4
-1
@@ -175,7 +175,10 @@ class ConstraintIncorporator(
|
||||
val inputTypePosition = if (baseConstraint.position.from is OnlyInputTypeConstraintPosition)
|
||||
baseConstraint.position else null
|
||||
|
||||
addNewIncorporatedConstraint(targetVariable, newConstraint, ConstraintContext(kind, derivedFrom, inputTypePosition))
|
||||
val isNullabilityConstraint = isUsefulForNullabilityConstraint && newConstraint.isNullableNothing()
|
||||
val constraintContext = ConstraintContext(kind, derivedFrom, inputTypePosition, isNullabilityConstraint)
|
||||
|
||||
addNewIncorporatedConstraint(targetVariable, newConstraint, constraintContext)
|
||||
}
|
||||
|
||||
fun Context.containsConstrainingTypeWithoutProjection(
|
||||
|
||||
+10
-4
@@ -178,7 +178,7 @@ class ConstraintInjector(
|
||||
val typeVariable = c.allTypeVariables[typeVariableConstructor]
|
||||
?: error("Should by type variableConstructor: $typeVariableConstructor. ${c.allTypeVariables.values}")
|
||||
|
||||
addNewIncorporatedConstraint(typeVariable, type, ConstraintContext(kind, emptySet()))
|
||||
addNewIncorporatedConstraint(typeVariable, type, ConstraintContext(kind, emptySet(), isNullabilityConstraint = false))
|
||||
}
|
||||
|
||||
// from ConstraintIncorporator.Context
|
||||
@@ -194,7 +194,7 @@ class ConstraintInjector(
|
||||
type: KotlinTypeMarker,
|
||||
constraintContext: ConstraintContext
|
||||
) {
|
||||
val (kind, derivedFrom, inputTypePosition) = constraintContext
|
||||
val (kind, derivedFrom, inputTypePosition, isNullabilityConstraint) = constraintContext
|
||||
|
||||
var targetType = type
|
||||
if (targetType.isUninferredParameter()) {
|
||||
@@ -231,7 +231,12 @@ class ConstraintInjector(
|
||||
}
|
||||
}
|
||||
|
||||
possibleNewConstraints.add(typeVariable to Constraint(kind, targetType, position, derivedFrom = derivedFrom))
|
||||
val newConstraint = Constraint(
|
||||
kind, targetType, position,
|
||||
derivedFrom = derivedFrom,
|
||||
isNullabilityConstraint = isNullabilityConstraint
|
||||
)
|
||||
possibleNewConstraints.add(typeVariable to newConstraint)
|
||||
inputTypePosition?.let { preservedInputTypePositions.add(it) }
|
||||
}
|
||||
|
||||
@@ -264,5 +269,6 @@ class ConstraintInjector(
|
||||
data class ConstraintContext(
|
||||
val kind: ConstraintKind,
|
||||
val derivedFrom: Set<TypeVariableMarker>,
|
||||
val inputTypePosition: ConstraintPosition? = null
|
||||
val inputTypePosition: ConstraintPosition? = null,
|
||||
val isNullabilityConstraint: Boolean
|
||||
)
|
||||
|
||||
+13
-9
@@ -80,23 +80,27 @@ class ResultTypeResolver(
|
||||
}
|
||||
|
||||
private fun Context.isSuitableType(resultType: KotlinTypeMarker, variableWithConstraints: VariableWithConstraints): Boolean {
|
||||
for (constraint in variableWithConstraints.constraints) {
|
||||
if (!isProperType(constraint.type)) continue
|
||||
val filteredConstraints = variableWithConstraints.constraints.filter { isProperType(it.type) }
|
||||
for (constraint in filteredConstraints) {
|
||||
if (!checkConstraint(this, constraint.type, constraint.kind, resultType)) return false
|
||||
}
|
||||
if (
|
||||
!trivialConstraintTypeInferenceOracle.isSuitableResultedType(resultType)
|
||||
&& isNothingNotSuitableFor(variableWithConstraints.typeVariable)
|
||||
) return false
|
||||
if (!trivialConstraintTypeInferenceOracle.isSuitableResultedType(resultType)) {
|
||||
if (nothingIsForbiddenFor(variableWithConstraints.typeVariable)) return false
|
||||
if (resultType.isNullableType() && checkSingleLowerNullabilityConstraint(filteredConstraints)) return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun isNothingNotSuitableFor(variable: TypeVariableMarker): Boolean {
|
||||
private fun nothingIsForbiddenFor(variable: TypeVariableMarker): Boolean {
|
||||
val parameterName = variable.safeAs<TypeVariableFromCallableDescriptor>()?.originalTypeParameter?.name ?: return false
|
||||
val isSpecialFunctionParameter = statelessCallbacks?.isSpecialFunctionTypeParameterName(parameterName) ?: false
|
||||
val isBangBangParameter = isSpecialFunctionParameter && statelessCallbacks?.isExclExclTypeParameterName(parameterName) ?: false
|
||||
return isSpecialFunctionParameter && !isBangBangParameter
|
||||
val isFromExclExcl = isSpecialFunctionParameter && statelessCallbacks?.isExclExclTypeParameterName(parameterName) ?: false
|
||||
return isSpecialFunctionParameter && !isFromExclExcl
|
||||
}
|
||||
|
||||
private fun checkSingleLowerNullabilityConstraint(constraints: List<Constraint>): Boolean {
|
||||
return constraints.singleOrNull { it.kind.isLower() }?.isNullabilityConstraint ?: false
|
||||
}
|
||||
|
||||
private fun Context.findSubType(variableWithConstraints: VariableWithConstraints): KotlinTypeMarker? {
|
||||
|
||||
+2
-1
@@ -68,7 +68,8 @@ class Constraint(
|
||||
val type: KotlinTypeMarker, // flexible types here is allowed
|
||||
val position: IncorporationConstraintPosition,
|
||||
val typeHashCode: Int = type.hashCode(),
|
||||
val derivedFrom: Set<TypeVariableMarker>
|
||||
val derivedFrom: Set<TypeVariableMarker>,
|
||||
val isNullabilityConstraint: Boolean
|
||||
) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
|
||||
+2
-1
@@ -68,7 +68,8 @@ class MutableVariableWithConstraints(
|
||||
constraint.type,
|
||||
constraint.position,
|
||||
constraint.typeHashCode,
|
||||
derivedFrom = constraint.derivedFrom
|
||||
derivedFrom = constraint.derivedFrom,
|
||||
isNullabilityConstraint = false
|
||||
)
|
||||
else
|
||||
constraint
|
||||
|
||||
Reference in New Issue
Block a user