Fix coercion to Unit when variable already have other constraints

Don't add `Unit` if variable has an upper constraint T <: A.

 It's impossible to coerce variable T to Unit as constraint system will
 be always contradictory: T := Unit => Unit should be subtype of A

 #KT-39900 Fixed
This commit is contained in:
Mikhail Zarechenskiy
2020-07-02 18:15:18 +03:00
parent 026f54f3d8
commit 0ee7306d9c
10 changed files with 76 additions and 13 deletions
@@ -10,7 +10,7 @@ import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.synthetic.SyntheticMemberDescriptor
import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem
import org.jetbrains.kotlin.resolve.calls.inference.addSubtypeConstraintIfCompatible
import org.jetbrains.kotlin.resolve.calls.inference.addEqualityConstraintIfCompatible
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode
import org.jetbrains.kotlin.resolve.calls.inference.components.TrivialConstraintTypeInferenceOracle
@@ -285,7 +285,7 @@ class KotlinCallCompleter(
}
expectedType === TypeUtils.UNIT_EXPECTED_TYPE ->
csBuilder.addSubtypeConstraintIfCompatible(
csBuilder.addEqualityConstraintIfCompatible(
returnType, csBuilder.builtIns.unitType, ExpectedTypeConstraintPosition(resolvedCall.atom)
)
@@ -35,7 +35,6 @@ class PostponedArgumentsAnalyzer(
fun canBeProper(type: KotlinTypeMarker): Boolean
fun hasUpperOrEqualUnitConstraint(type: KotlinTypeMarker): Boolean
fun hasEqualNothingConstraint(type: KotlinTypeMarker): Boolean
// mutable operations
fun addOtherSystem(otherSystem: ConstraintStorage)
@@ -123,7 +122,7 @@ class PostponedArgumentsAnalyzer(
c.canBeProper(rawReturnType) -> substitute(rawReturnType)
// For Unit-coercion
c.hasUpperOrEqualUnitConstraint(rawReturnType) && !c.hasEqualNothingConstraint(rawReturnType) -> builtIns.unitType
c.hasUpperOrEqualUnitConstraint(rawReturnType) -> builtIns.unitType
else -> null
}
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.resolve.calls.inference
import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintPosition
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
import org.jetbrains.kotlin.resolve.calls.model.CallableReferenceKotlinCallArgument
@@ -62,9 +63,30 @@ fun ConstraintSystemBuilder.addSubtypeConstraintIfCompatible(
lowerType: KotlinTypeMarker,
upperType: KotlinTypeMarker,
position: ConstraintPosition
): Boolean =
addConstraintIfCompatible(lowerType, upperType, position, ConstraintKind.LOWER)
fun ConstraintSystemBuilder.addEqualityConstraintIfCompatible(
lowerType: KotlinTypeMarker,
upperType: KotlinTypeMarker,
position: ConstraintPosition
): Boolean =
addConstraintIfCompatible(lowerType, upperType, position, ConstraintKind.EQUALITY)
private fun ConstraintSystemBuilder.addConstraintIfCompatible(
lowerType: KotlinTypeMarker,
upperType: KotlinTypeMarker,
position: ConstraintPosition,
kind: ConstraintKind
) =
runTransaction {
if (!hasContradiction) addSubtypeConstraint(lowerType, upperType, position)
if (!hasContradiction) {
when (kind) {
ConstraintKind.LOWER -> addSubtypeConstraint(lowerType, upperType, position)
ConstraintKind.UPPER -> addSubtypeConstraint(upperType, lowerType, position)
ConstraintKind.EQUALITY -> addEqualityConstraint(lowerType, upperType, position)
}
}
!hasContradiction
}
@@ -389,10 +389,4 @@ class NewConstraintSystemImpl(
val constraints = storage.notFixedTypeVariables[type.typeConstructor()]?.constraints ?: return false
return constraints.any { (it.kind == ConstraintKind.UPPER || it.kind == ConstraintKind.EQUALITY) && it.type.isUnit() }
}
override fun hasEqualNothingConstraint(type: KotlinTypeMarker): Boolean {
checkState(State.BUILDING, State.COMPLETION, State.FREEZED)
val constraints = storage.notFixedTypeVariables[type.typeConstructor()]?.constraints ?: return false
return constraints.any { (it.kind == ConstraintKind.EQUALITY) && it.type.isNothing() }
}
}