[NI] Do not avoid trivial constraints if they aren't from upper bounds

Since we skipped trivial constraint with `Any?` from parameter type of
 function `equals`, the compiler thought that there is no proper
 constraints (upper bounds do not matter here) and marked resolved
 call as a failed one, then diagnostic about missing equals was added

 Also, tune `TrivialConstraintTypeInferenceOracle` for `Any?`-like
 constraints

 #KT-30724 Fixed
This commit is contained in:
Mikhail Zarechenskiy
2019-04-01 02:58:56 +03:00
parent 5fa518fd55
commit c458393e2f
17 changed files with 74 additions and 26 deletions
@@ -201,9 +201,8 @@ class KotlinCallCompleter(
val variableWithConstraints = csBuilder.currentStorage().notFixedTypeVariables[constructor] ?: return false
val constraints = variableWithConstraints.constraints
return constraints.isNotEmpty() && constraints.all {
!trivialConstraintTypeInferenceOracle.isTrivialConstraint(it) &&
with(context) { !it.type.typeConstructor().isIntegerLiteralTypeConstructor() } &&
it.kind.isLower() && csBuilder.isProperType(it.type)
with(context) { !it.type.typeConstructor().isIntegerLiteralTypeConstructor() } &&
it.kind.isLower() && csBuilder.isProperType(it.type)
}
}
@@ -156,13 +156,19 @@ class ConstraintIncorporator(
if (baseConstraint.kind != ConstraintKind.UPPER) {
val generatedConstraintType = approximateCapturedTypes(typeForApproximation, toSuper = false)
if (!trivialConstraintTypeInferenceOracle.isGeneratedConstraintTrivial(otherConstraint, generatedConstraintType)) {
if (!trivialConstraintTypeInferenceOracle.isGeneratedConstraintTrivial(
otherConstraint, generatedConstraintType, isSubtype = true
)
) {
addNewIncorporatedConstraint(generatedConstraintType, targetVariable.defaultType())
}
}
if (baseConstraint.kind != ConstraintKind.LOWER) {
val generatedConstraintType = approximateCapturedTypes(typeForApproximation, toSuper = true)
if (!trivialConstraintTypeInferenceOracle.isGeneratedConstraintTrivial(otherConstraint, generatedConstraintType)) {
if (!trivialConstraintTypeInferenceOracle.isGeneratedConstraintTrivial(
otherConstraint, generatedConstraintType, isSubtype = false
)
) {
addNewIncorporatedConstraint(targetVariable.defaultType(), generatedConstraintType)
}
}
@@ -101,7 +101,11 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
}
if (constraintType.isSimpleType()) {
if (constraint.kind == UPPER && constraintType.isNullableAny()) return true // T <: Any?
if (constraint.position.from is DeclaredUpperBoundConstraintPosition &&
constraint.kind == UPPER && constraintType.isNullableAny()
) {
return true // T <: Any?
}
}
return false
@@ -7,19 +7,19 @@ package org.jetbrains.kotlin.resolve.calls.inference.components
import org.jetbrains.kotlin.resolve.calls.inference.model.Constraint
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind
import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.TypeSystemInferenceExtensionContext
import org.jetbrains.kotlin.types.model.TypeSystemInferenceExtensionContextDelegate
import org.jetbrains.kotlin.types.typeUtil.contains
import org.jetbrains.kotlin.types.typeUtil.isNothing
import org.jetbrains.kotlin.types.typeUtil.isNullableNothing
class TrivialConstraintTypeInferenceOracle(context: TypeSystemInferenceExtensionContextDelegate) :
TypeSystemInferenceExtensionContext by context {
// The idea is to add knowledge that constraint `Nothing(?) <: T` is quite useless and
// it's totally fine to go and resolve postponed argument without fixation T to Nothing(?).
// In other words, constraint `Nothing(?) <: T` is *not* proper
fun isTrivialConstraint(
constraint: Constraint
): Boolean {
// TODO: probably we also can take into account `T <: Any(?)` constraints
fun isNotInterestingConstraint(constraint: Constraint): Boolean {
return constraint.kind == ConstraintKind.LOWER && constraint.type.typeConstructor().isNothingConstructor()
}
@@ -39,9 +39,11 @@ class TrivialConstraintTypeInferenceOracle(context: TypeSystemInferenceExtension
// Therefore, here we avoid adding such trivial constraints to have stable constraint system
fun isGeneratedConstraintTrivial(
otherConstraint: Constraint,
generatedConstraintType: KotlinTypeMarker
generatedConstraintType: KotlinTypeMarker,
isSubtype: Boolean
): Boolean {
if (generatedConstraintType.isNothing()) return true
if (isSubtype && generatedConstraintType.isNothing()) return true
if (!isSubtype && generatedConstraintType.isNullableAny()) return true
// If type that will be used to generate new constraint already contains `Nothing(?)`,
// then we can't decide that resulting constraint will be useless
@@ -107,7 +107,7 @@ class VariableFixationFinder(
private fun Context.variableHasTrivialOrNonProperConstraints(variable: TypeConstructorMarker): Boolean {
return notFixedTypeVariables[variable]?.constraints?.all { constraint ->
val isProperConstraint = isProperArgumentConstraint(constraint)
isProperConstraint && trivialConstraintTypeInferenceOracle.isTrivialConstraint(constraint) || !isProperConstraint
isProperConstraint && trivialConstraintTypeInferenceOracle.isNotInterestingConstraint(constraint) || !isProperConstraint
} ?: false
}