[NI] Discriminate constraints with Nothing(?) lower bounds
This commit is contained in:
+13
-15
@@ -69,27 +69,27 @@ class KotlinConstraintSystemCompleter(
|
||||
|
||||
val allTypeVariables = getOrderedAllTypeVariables(c, collectVariablesFromContext, topLevelAtoms)
|
||||
val postponedKtPrimitives = getOrderedNotAnalyzedPostponedArguments(topLevelAtoms)
|
||||
val variableForFixation = variableFixationFinder.findFirstVariableForFixation(
|
||||
c, allTypeVariables, postponedKtPrimitives, completionMode, topLevelType
|
||||
)
|
||||
val variableForFixation =
|
||||
variableFixationFinder.findFirstVariableForFixation(
|
||||
c, allTypeVariables, postponedKtPrimitives, completionMode, topLevelType
|
||||
) ?: break
|
||||
|
||||
if (shouldForceCallableReferenceOrLambdaResolution(completionMode, variableForFixation)) {
|
||||
if (forcePostponedAtomResolution<ResolvedCallableReferenceAtom>(topLevelAtoms, analyze)) continue
|
||||
if (forcePostponedAtomResolution<LambdaWithTypeVariableAsExpectedTypeAtom>(topLevelAtoms, analyze)) continue
|
||||
}
|
||||
|
||||
if (variableForFixation != null) {
|
||||
if (variableForFixation.hasProperConstraint || completionMode == ConstraintSystemCompletionMode.FULL) {
|
||||
val variableWithConstraints = c.notFixedTypeVariables[variableForFixation.variable]!!
|
||||
if (variableForFixation.hasProperConstraint || completionMode == ConstraintSystemCompletionMode.FULL) {
|
||||
val variableWithConstraints = c.notFixedTypeVariables.getValue(variableForFixation.variable)
|
||||
|
||||
fixVariable(c, topLevelType, variableWithConstraints, postponedKtPrimitives)
|
||||
fixVariable(c, topLevelType, variableWithConstraints, postponedKtPrimitives)
|
||||
|
||||
if (!variableForFixation.hasProperConstraint) {
|
||||
c.addError(NotEnoughInformationForTypeParameter(variableWithConstraints.typeVariable))
|
||||
}
|
||||
continue
|
||||
if (!variableForFixation.hasProperConstraint) {
|
||||
c.addError(NotEnoughInformationForTypeParameter(variableWithConstraints.typeVariable))
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
@@ -105,12 +105,10 @@ class KotlinConstraintSystemCompleter(
|
||||
|
||||
private fun shouldForceCallableReferenceOrLambdaResolution(
|
||||
completionMode: ConstraintSystemCompletionMode,
|
||||
variableForFixation: VariableFixationFinder.VariableForFixation?
|
||||
variableForFixation: VariableFixationFinder.VariableForFixation
|
||||
): Boolean {
|
||||
if (completionMode == ConstraintSystemCompletionMode.PARTIAL) return false
|
||||
if (variableForFixation != null && variableForFixation.hasProperConstraint) return false
|
||||
|
||||
return true
|
||||
return !variableForFixation.hasProperConstraint || variableForFixation.hasOnlyTrivialProperConstraint
|
||||
}
|
||||
|
||||
// true if we do analyze
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
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.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.typeUtil.isNothing
|
||||
import org.jetbrains.kotlin.types.typeUtil.isNullableNothing
|
||||
|
||||
class TrivialConstraintTypeInferenceOracle {
|
||||
// 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
|
||||
return constraint.kind == ConstraintKind.LOWER && constraint.type.isNothingOrNullableNothing()
|
||||
}
|
||||
}
|
||||
|
||||
private fun UnwrappedType.isNothingOrNullableNothing(): Boolean =
|
||||
isNothing() || isNullableNothing()
|
||||
+22
-4
@@ -27,13 +27,19 @@ import org.jetbrains.kotlin.types.TypeConstructor
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||
|
||||
class VariableFixationFinder {
|
||||
class VariableFixationFinder(
|
||||
private val trivialConstraintTypeInferenceOracle: TrivialConstraintTypeInferenceOracle
|
||||
) {
|
||||
interface Context {
|
||||
val notFixedTypeVariables: Map<TypeConstructor, VariableWithConstraints>
|
||||
val postponedTypeVariables: List<NewTypeVariable>
|
||||
}
|
||||
|
||||
data class VariableForFixation(val variable: TypeConstructor, val hasProperConstraint: Boolean)
|
||||
data class VariableForFixation(
|
||||
val variable: TypeConstructor,
|
||||
val hasProperConstraint: Boolean,
|
||||
val hasOnlyTrivialProperConstraint: Boolean = false
|
||||
)
|
||||
|
||||
fun findFirstVariableForFixation(
|
||||
c: Context,
|
||||
@@ -46,6 +52,7 @@ class VariableFixationFinder {
|
||||
private enum class TypeVariableFixationReadiness {
|
||||
FORBIDDEN,
|
||||
WITHOUT_PROPER_ARGUMENT_CONSTRAINT, // proper constraint from arguments -- not from upper bound for type parameters
|
||||
WITH_TRIVIAL_OR_NON_PROPER_CONSTRAINTS, // proper trivial constraint from arguments, Nothing <: T
|
||||
WITH_COMPLEX_DEPENDENCY, // if type variable T has constraint with non fixed type variable inside (non-top-level): T <: Foo<S>
|
||||
RELATED_TO_ANY_OUTPUT_TYPE,
|
||||
READY_FOR_FIXATION,
|
||||
@@ -58,6 +65,7 @@ class VariableFixationFinder {
|
||||
!notFixedTypeVariables.contains(variable) ||
|
||||
dependencyProvider.isVariableRelatedToTopLevelType(variable) -> TypeVariableFixationReadiness.FORBIDDEN
|
||||
!variableHasProperArgumentConstraints(variable) -> TypeVariableFixationReadiness.WITHOUT_PROPER_ARGUMENT_CONSTRAINT
|
||||
variableHasTrivialOrNonProperConstraints(variable) -> TypeVariableFixationReadiness.WITH_TRIVIAL_OR_NON_PROPER_CONSTRAINTS
|
||||
hasDependencyToOtherTypeVariables(variable) -> TypeVariableFixationReadiness.WITH_COMPLEX_DEPENDENCY
|
||||
dependencyProvider.isVariableRelatedToAnyOutputType(variable) -> TypeVariableFixationReadiness.RELATED_TO_ANY_OUTPUT_TYPE
|
||||
else -> TypeVariableFixationReadiness.READY_FOR_FIXATION
|
||||
@@ -65,12 +73,12 @@ class VariableFixationFinder {
|
||||
|
||||
private fun Context.findTypeVariableForFixation(
|
||||
allTypeVariables: List<TypeConstructor>,
|
||||
postponedKtPrimitives: List<PostponedResolvedAtom>,
|
||||
postponedArguments: List<PostponedResolvedAtom>,
|
||||
completionMode: ConstraintSystemCompletionMode,
|
||||
topLevelType: UnwrappedType
|
||||
): VariableForFixation? {
|
||||
val dependencyProvider = TypeVariableDependencyInformationProvider(
|
||||
notFixedTypeVariables, postponedKtPrimitives, topLevelType.takeIf { completionMode == PARTIAL }
|
||||
notFixedTypeVariables, postponedArguments, topLevelType.takeIf { completionMode == PARTIAL }
|
||||
)
|
||||
|
||||
val candidate = allTypeVariables.maxBy { getTypeVariableReadiness(it, dependencyProvider) } ?: return null
|
||||
@@ -79,6 +87,9 @@ class VariableFixationFinder {
|
||||
return when (candidateReadiness) {
|
||||
TypeVariableFixationReadiness.FORBIDDEN -> null
|
||||
TypeVariableFixationReadiness.WITHOUT_PROPER_ARGUMENT_CONSTRAINT -> VariableForFixation(candidate, false)
|
||||
TypeVariableFixationReadiness.WITH_TRIVIAL_OR_NON_PROPER_CONSTRAINTS ->
|
||||
VariableForFixation(candidate, hasProperConstraint = true, hasOnlyTrivialProperConstraint = true)
|
||||
|
||||
else -> VariableForFixation(candidate, true)
|
||||
}
|
||||
}
|
||||
@@ -92,6 +103,13 @@ class VariableFixationFinder {
|
||||
return false
|
||||
}
|
||||
|
||||
private fun Context.variableHasTrivialOrNonProperConstraints(variable: TypeConstructor): Boolean {
|
||||
return notFixedTypeVariables[variable]?.constraints?.all { constraint ->
|
||||
val isProperConstraint = isProperArgumentConstraint(constraint)
|
||||
isProperConstraint && trivialConstraintTypeInferenceOracle.isTrivialConstraint(constraint) || !isProperConstraint
|
||||
} ?: false
|
||||
}
|
||||
|
||||
private fun Context.variableHasProperArgumentConstraints(variable: TypeConstructor): Boolean =
|
||||
notFixedTypeVariables[variable]?.constraints?.any { isProperArgumentConstraint(it) } ?: false
|
||||
|
||||
|
||||
Reference in New Issue
Block a user