[NI] Use compatibility mode for KT-41934

This commit is contained in:
Pavel Kirpichenkov
2020-09-18 12:12:42 +03:00
parent 1465e10f12
commit fdc134ff66
6 changed files with 65 additions and 22 deletions
@@ -50,7 +50,7 @@ class ConstraintSystemCompleter(private val components: BodyResolveComponents) {
val postponedAtoms = getOrderedNotAnalyzedPostponedArguments(topLevelAtoms) val postponedAtoms = getOrderedNotAnalyzedPostponedArguments(topLevelAtoms)
val variableForFixation = val variableForFixation =
variableFixationFinder.findFirstVariableForFixation( variableFixationFinder.findFirstVariableForFixation(
c, allTypeVariables, postponedAtoms, completionMode, candidateReturnType c, allTypeVariables, postponedAtoms, completionMode, candidateReturnType, inferenceCompatibilityMode = true
) ?: break ) ?: break
if ( if (
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.resolve.calls.inference package org.jetbrains.kotlin.resolve.calls.inference
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.impl.* import org.jetbrains.kotlin.descriptors.impl.*
@@ -81,7 +82,13 @@ class CoroutineInferenceSession(
return !storage.notFixedTypeVariables.keys.any { return !storage.notFixedTypeVariables.keys.any {
val variable = storage.allTypeVariables[it] val variable = storage.allTypeVariables[it]
val isPostponed = variable != null && variable in storage.postponedTypeVariables val isPostponed = variable != null && variable in storage.postponedTypeVariables
!isPostponed && !kotlinConstraintSystemCompleter.variableFixationFinder.isTypeVariableHasProperConstraint(system, it) val useInferenceCompatibilityMode =
topLevelCallContext.languageVersionSettings.supportsFeature(LanguageFeature.InferenceCompatibility)
!isPostponed && !kotlinConstraintSystemCompleter.variableFixationFinder.isTypeVariableHasProperConstraint(
system,
it,
useInferenceCompatibilityMode
)
} || candidate.getSubResolvedAtoms().any { it.hasPostponed() } } || candidate.getSubResolvedAtoms().any { it.hasPostponed() }
} }
@@ -32,8 +32,10 @@ class VariableFixationFinder(
allTypeVariables: List<TypeConstructorMarker>, allTypeVariables: List<TypeConstructorMarker>,
postponedKtPrimitives: List<PostponedResolvedAtomMarker>, postponedKtPrimitives: List<PostponedResolvedAtomMarker>,
completionMode: ConstraintSystemCompletionMode, completionMode: ConstraintSystemCompletionMode,
topLevelType: KotlinTypeMarker topLevelType: KotlinTypeMarker,
): VariableForFixation? = c.findTypeVariableForFixation(allTypeVariables, postponedKtPrimitives, completionMode, topLevelType) inferenceCompatibilityMode: Boolean = false,
): VariableForFixation? =
c.findTypeVariableForFixation(allTypeVariables, postponedKtPrimitives, completionMode, topLevelType, inferenceCompatibilityMode)
enum class TypeVariableFixationReadiness { enum class TypeVariableFixationReadiness {
FORBIDDEN, FORBIDDEN,
@@ -44,12 +46,14 @@ class VariableFixationFinder(
FROM_INCORPORATION_OF_DECLARED_UPPER_BOUND, FROM_INCORPORATION_OF_DECLARED_UPPER_BOUND,
READY_FOR_FIXATION_UPPER, READY_FOR_FIXATION_UPPER,
READY_FOR_FIXATION_LOWER, READY_FOR_FIXATION_LOWER,
READY_FOR_FIXATION,
READY_FOR_FIXATION_REIFIED, READY_FOR_FIXATION_REIFIED,
} }
private fun Context.getTypeVariableReadiness( private fun Context.getTypeVariableReadiness(
variable: TypeConstructorMarker, variable: TypeConstructorMarker,
dependencyProvider: TypeVariableDependencyInformationProvider dependencyProvider: TypeVariableDependencyInformationProvider,
inferenceCompatibilityMode: Boolean
): TypeVariableFixationReadiness = when { ): TypeVariableFixationReadiness = when {
!notFixedTypeVariables.contains(variable) || !notFixedTypeVariables.contains(variable) ||
dependencyProvider.isVariableRelatedToTopLevelType(variable) -> TypeVariableFixationReadiness.FORBIDDEN dependencyProvider.isVariableRelatedToTopLevelType(variable) -> TypeVariableFixationReadiness.FORBIDDEN
@@ -60,16 +64,25 @@ class VariableFixationFinder(
variableHasOnlyIncorporatedConstraintsFromDeclaredUpperBound(variable) -> variableHasOnlyIncorporatedConstraintsFromDeclaredUpperBound(variable) ->
TypeVariableFixationReadiness.FROM_INCORPORATION_OF_DECLARED_UPPER_BOUND TypeVariableFixationReadiness.FROM_INCORPORATION_OF_DECLARED_UPPER_BOUND
isReified(variable) -> TypeVariableFixationReadiness.READY_FOR_FIXATION_REIFIED isReified(variable) -> TypeVariableFixationReadiness.READY_FOR_FIXATION_REIFIED
!variableHasLowerProperConstraint(variable) -> TypeVariableFixationReadiness.READY_FOR_FIXATION_UPPER inferenceCompatibilityMode -> {
else -> TypeVariableFixationReadiness.READY_FOR_FIXATION_LOWER when {
variableHasLowerProperConstraint(variable) -> TypeVariableFixationReadiness.READY_FOR_FIXATION_LOWER
else -> TypeVariableFixationReadiness.READY_FOR_FIXATION_UPPER
}
}
else -> TypeVariableFixationReadiness.READY_FOR_FIXATION
} }
fun isTypeVariableHasProperConstraint(context: Context, typeVariable: TypeConstructorMarker): Boolean { fun isTypeVariableHasProperConstraint(
context: Context,
typeVariable: TypeConstructorMarker,
inferenceCompatibilityMode: Boolean = false
): Boolean {
return with(context) { return with(context) {
val dependencyProvider = TypeVariableDependencyInformationProvider( val dependencyProvider = TypeVariableDependencyInformationProvider(
notFixedTypeVariables, emptyList(), topLevelType = null, context notFixedTypeVariables, emptyList(), topLevelType = null, context
) )
when (getTypeVariableReadiness(typeVariable, dependencyProvider)) { when (getTypeVariableReadiness(typeVariable, dependencyProvider, inferenceCompatibilityMode)) {
TypeVariableFixationReadiness.FORBIDDEN, TypeVariableFixationReadiness.WITHOUT_PROPER_ARGUMENT_CONSTRAINT -> false TypeVariableFixationReadiness.FORBIDDEN, TypeVariableFixationReadiness.WITHOUT_PROPER_ARGUMENT_CONSTRAINT -> false
else -> true else -> true
} }
@@ -93,7 +106,8 @@ class VariableFixationFinder(
allTypeVariables: List<TypeConstructorMarker>, allTypeVariables: List<TypeConstructorMarker>,
postponedArguments: List<PostponedResolvedAtomMarker>, postponedArguments: List<PostponedResolvedAtomMarker>,
completionMode: ConstraintSystemCompletionMode, completionMode: ConstraintSystemCompletionMode,
topLevelType: KotlinTypeMarker topLevelType: KotlinTypeMarker,
inferenceCompatibilityMode: Boolean,
): VariableForFixation? { ): VariableForFixation? {
if (allTypeVariables.isEmpty()) return null if (allTypeVariables.isEmpty()) return null
@@ -101,9 +115,10 @@ class VariableFixationFinder(
notFixedTypeVariables, postponedArguments, topLevelType.takeIf { completionMode == PARTIAL }, this notFixedTypeVariables, postponedArguments, topLevelType.takeIf { completionMode == PARTIAL }, this
) )
val candidate = allTypeVariables.maxByOrNull { getTypeVariableReadiness(it, dependencyProvider) } ?: return null val candidate =
allTypeVariables.maxByOrNull { getTypeVariableReadiness(it, dependencyProvider, inferenceCompatibilityMode) } ?: return null
return when (getTypeVariableReadiness(candidate, dependencyProvider)) { return when (getTypeVariableReadiness(candidate, dependencyProvider, inferenceCompatibilityMode)) {
TypeVariableFixationReadiness.FORBIDDEN -> null TypeVariableFixationReadiness.FORBIDDEN -> null
TypeVariableFixationReadiness.WITHOUT_PROPER_ARGUMENT_CONSTRAINT -> VariableForFixation(candidate, false) TypeVariableFixationReadiness.WITHOUT_PROPER_ARGUMENT_CONSTRAINT -> VariableForFixation(candidate, false)
TypeVariableFixationReadiness.WITH_TRIVIAL_OR_NON_PROPER_CONSTRAINTS -> TypeVariableFixationReadiness.WITH_TRIVIAL_OR_NON_PROPER_CONSTRAINTS ->
@@ -5,6 +5,8 @@
package org.jetbrains.kotlin.resolve.calls.inference.components package org.jetbrains.kotlin.resolve.calls.inference.components
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.resolve.calls.components.transformToResolvedLambda import org.jetbrains.kotlin.resolve.calls.components.transformToResolvedLambda
import org.jetbrains.kotlin.resolve.calls.inference.model.* import org.jetbrains.kotlin.resolve.calls.inference.model.*
import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.model.*
@@ -19,6 +21,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class KotlinConstraintSystemCompleter( class KotlinConstraintSystemCompleter(
private val resultTypeResolver: ResultTypeResolver, private val resultTypeResolver: ResultTypeResolver,
val variableFixationFinder: VariableFixationFinder, val variableFixationFinder: VariableFixationFinder,
val languageVersionSettings: LanguageVersionSettings,
) { ) {
private val postponedArgumentInputTypesResolver = PostponedArgumentInputTypesResolver(resultTypeResolver, variableFixationFinder) private val postponedArgumentInputTypesResolver = PostponedArgumentInputTypesResolver(resultTypeResolver, variableFixationFinder)
@@ -104,7 +107,8 @@ class KotlinConstraintSystemCompleter(
postponedArguments, postponedArguments,
topLevelType, topLevelType,
topLevelAtoms, topLevelAtoms,
dependencyProvider dependencyProvider,
inferenceCompatibilityMode = isInferenceCompatibilityModeEnabled(),
) )
if (wasFixedSomeVariable) if (wasFixedSomeVariable)
@@ -257,7 +261,8 @@ class KotlinConstraintSystemCompleter(
getOrderedAllTypeVariables(collectVariablesFromContext, topLevelAtoms), getOrderedAllTypeVariables(collectVariablesFromContext, topLevelAtoms),
postponedArguments, postponedArguments,
completionMode, completionMode,
topLevelType topLevelType,
inferenceCompatibilityMode = isInferenceCompatibilityModeEnabled(),
) ?: break ) ?: break
if (!variableForFixation.hasProperConstraint && completionMode == ConstraintSystemCompletionMode.PARTIAL) if (!variableForFixation.hasProperConstraint && completionMode == ConstraintSystemCompletionMode.PARTIAL)
@@ -363,9 +368,17 @@ class KotlinConstraintSystemCompleter(
collectVariablesFromContext: Boolean, collectVariablesFromContext: Boolean,
postponedArguments: List<PostponedResolvedAtom> postponedArguments: List<PostponedResolvedAtom>
) = variableFixationFinder.findFirstVariableForFixation( ) = variableFixationFinder.findFirstVariableForFixation(
this, getOrderedAllTypeVariables(collectVariablesFromContext, topLevelAtoms), postponedArguments, completionMode, topLevelType this,
getOrderedAllTypeVariables(collectVariablesFromContext, topLevelAtoms),
postponedArguments,
completionMode,
topLevelType,
inferenceCompatibilityMode = isInferenceCompatibilityModeEnabled(),
) != null ) != null
private fun isInferenceCompatibilityModeEnabled(): Boolean =
languageVersionSettings.supportsFeature(LanguageFeature.InferenceCompatibility)
companion object { companion object {
fun getOrderedNotAnalyzedPostponedArguments(topLevelAtoms: List<ResolvedAtom>): List<PostponedResolvedAtom> { fun getOrderedNotAnalyzedPostponedArguments(topLevelAtoms: List<ResolvedAtom>): List<PostponedResolvedAtom> {
fun ResolvedAtom.process(to: MutableList<PostponedResolvedAtom>) { fun ResolvedAtom.process(to: MutableList<PostponedResolvedAtom>) {
@@ -454,13 +454,21 @@ class PostponedArgumentInputTypesResolver(
postponedArguments: List<PostponedResolvedAtom>, postponedArguments: List<PostponedResolvedAtom>,
topLevelType: UnwrappedType, topLevelType: UnwrappedType,
topLevelAtoms: List<ResolvedAtom>, topLevelAtoms: List<ResolvedAtom>,
dependencyProvider: TypeVariableDependencyInformationProvider dependencyProvider: TypeVariableDependencyInformationProvider,
inferenceCompatibilityMode: Boolean = false,
): Boolean { ): Boolean {
val expectedType = argument.run { safeAs<PostponedAtomWithRevisableExpectedType>()?.revisedExpectedType ?: expectedType } val expectedType = argument.run { safeAs<PostponedAtomWithRevisableExpectedType>()?.revisedExpectedType ?: expectedType }
if (expectedType != null && expectedType.isFunctionOrKFunctionTypeWithAnySuspendability) { if (expectedType != null && expectedType.isFunctionOrKFunctionTypeWithAnySuspendability) {
val wasFixedSomeVariable = val wasFixedSomeVariable =
c.fixNextReadyVariableForParameterType(expectedType, postponedArguments, topLevelType, topLevelAtoms, dependencyProvider) c.fixNextReadyVariableForParameterType(
expectedType,
postponedArguments,
topLevelType,
topLevelAtoms,
dependencyProvider,
inferenceCompatibilityMode
)
if (wasFixedSomeVariable) if (wasFixedSomeVariable)
return true return true
@@ -474,12 +482,13 @@ class PostponedArgumentInputTypesResolver(
postponedArguments: List<PostponedResolvedAtom>, postponedArguments: List<PostponedResolvedAtom>,
topLevelType: UnwrappedType, topLevelType: UnwrappedType,
topLevelAtoms: List<ResolvedAtom>, topLevelAtoms: List<ResolvedAtom>,
dependencyProvider: TypeVariableDependencyInformationProvider dependencyProvider: TypeVariableDependencyInformationProvider,
inferenceCompatibilityMode: Boolean,
): Boolean { ): Boolean {
val relatedVariables = type.getPureArgumentsForFunctionalTypeOrSubtype() val relatedVariables = type.getPureArgumentsForFunctionalTypeOrSubtype()
.flatMap { getAllDeeplyRelatedTypeVariables(it, dependencyProvider) } .flatMap { getAllDeeplyRelatedTypeVariables(it, dependencyProvider) }
val variableForFixation = variableFixationFinder.findFirstVariableForFixation( val variableForFixation = variableFixationFinder.findFirstVariableForFixation(
this, relatedVariables, postponedArguments, ConstraintSystemCompletionMode.FULL, topLevelType this, relatedVariables, postponedArguments, ConstraintSystemCompletionMode.FULL, topLevelType, inferenceCompatibilityMode
) )
if (variableForFixation == null || !variableForFixation.hasProperConstraint) if (variableForFixation == null || !variableForFixation.hasProperConstraint)
@@ -1,12 +1,11 @@
// FIR_IDENTICAL // FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_ANONYMOUS_PARAMETER // !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_ANONYMOUS_PARAMETER
// !LANGUAGE: +NewInference // !LANGUAGE: +InferenceCompatibility
fun <T, VR : T> foo(x: T, fn: (VR?/*T?*/, T) -> Unit) {} fun <T, VR : T> foo(x: T, fn: (VR?, T) -> Unit) {}
fun takeInt(x: Int) {} fun takeInt(x: Int) {}
fun main(x: Int) { fun main(x: Int) {
foo(x) { prev: Int?, new -> takeInt(new) } // `new` is `Int` in OI, `Int?` in NI foo(x) { prev: Int?, new -> takeInt(new) } // `new` is `Int` in OI, `Int?` in NI
// It seems, `VR` has been fixed to `Int?` instead of `Int`
} }