diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/ConstraintSystemCompleter.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/ConstraintSystemCompleter.kt index 74ff67772e4..b8db4f0e088 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/ConstraintSystemCompleter.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/ConstraintSystemCompleter.kt @@ -50,7 +50,7 @@ class ConstraintSystemCompleter(private val components: BodyResolveComponents) { val postponedAtoms = getOrderedNotAnalyzedPostponedArguments(topLevelAtoms) val variableForFixation = variableFixationFinder.findFirstVariableForFixation( - c, allTypeVariables, postponedAtoms, completionMode, candidateReturnType + c, allTypeVariables, postponedAtoms, completionMode, candidateReturnType, inferenceCompatibilityMode = true ) ?: break if ( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/CoroutineInferenceSession.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/CoroutineInferenceSession.kt index 7dce885fdeb..e5b845273ab 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/CoroutineInferenceSession.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/CoroutineInferenceSession.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.resolve.calls.inference import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.impl.* @@ -81,7 +82,13 @@ class CoroutineInferenceSession( return !storage.notFixedTypeVariables.keys.any { val variable = storage.allTypeVariables[it] 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() } } diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/VariableFixationFinder.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/VariableFixationFinder.kt index b5165624d5a..41f331e319b 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/VariableFixationFinder.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/VariableFixationFinder.kt @@ -32,8 +32,10 @@ class VariableFixationFinder( allTypeVariables: List, postponedKtPrimitives: List, completionMode: ConstraintSystemCompletionMode, - topLevelType: KotlinTypeMarker - ): VariableForFixation? = c.findTypeVariableForFixation(allTypeVariables, postponedKtPrimitives, completionMode, topLevelType) + topLevelType: KotlinTypeMarker, + inferenceCompatibilityMode: Boolean = false, + ): VariableForFixation? = + c.findTypeVariableForFixation(allTypeVariables, postponedKtPrimitives, completionMode, topLevelType, inferenceCompatibilityMode) enum class TypeVariableFixationReadiness { FORBIDDEN, @@ -44,12 +46,14 @@ class VariableFixationFinder( FROM_INCORPORATION_OF_DECLARED_UPPER_BOUND, READY_FOR_FIXATION_UPPER, READY_FOR_FIXATION_LOWER, + READY_FOR_FIXATION, READY_FOR_FIXATION_REIFIED, } private fun Context.getTypeVariableReadiness( variable: TypeConstructorMarker, - dependencyProvider: TypeVariableDependencyInformationProvider + dependencyProvider: TypeVariableDependencyInformationProvider, + inferenceCompatibilityMode: Boolean ): TypeVariableFixationReadiness = when { !notFixedTypeVariables.contains(variable) || dependencyProvider.isVariableRelatedToTopLevelType(variable) -> TypeVariableFixationReadiness.FORBIDDEN @@ -60,16 +64,25 @@ class VariableFixationFinder( variableHasOnlyIncorporatedConstraintsFromDeclaredUpperBound(variable) -> TypeVariableFixationReadiness.FROM_INCORPORATION_OF_DECLARED_UPPER_BOUND isReified(variable) -> TypeVariableFixationReadiness.READY_FOR_FIXATION_REIFIED - !variableHasLowerProperConstraint(variable) -> TypeVariableFixationReadiness.READY_FOR_FIXATION_UPPER - else -> TypeVariableFixationReadiness.READY_FOR_FIXATION_LOWER + inferenceCompatibilityMode -> { + 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) { val dependencyProvider = TypeVariableDependencyInformationProvider( notFixedTypeVariables, emptyList(), topLevelType = null, context ) - when (getTypeVariableReadiness(typeVariable, dependencyProvider)) { + when (getTypeVariableReadiness(typeVariable, dependencyProvider, inferenceCompatibilityMode)) { TypeVariableFixationReadiness.FORBIDDEN, TypeVariableFixationReadiness.WITHOUT_PROPER_ARGUMENT_CONSTRAINT -> false else -> true } @@ -93,7 +106,8 @@ class VariableFixationFinder( allTypeVariables: List, postponedArguments: List, completionMode: ConstraintSystemCompletionMode, - topLevelType: KotlinTypeMarker + topLevelType: KotlinTypeMarker, + inferenceCompatibilityMode: Boolean, ): VariableForFixation? { if (allTypeVariables.isEmpty()) return null @@ -101,9 +115,10 @@ class VariableFixationFinder( 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.WITHOUT_PROPER_ARGUMENT_CONSTRAINT -> VariableForFixation(candidate, false) TypeVariableFixationReadiness.WITH_TRIVIAL_OR_NON_PROPER_CONSTRAINTS -> diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/KotlinConstraintSystemCompleter.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/KotlinConstraintSystemCompleter.kt index 550788962a2..dcfa97d5e65 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/KotlinConstraintSystemCompleter.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/KotlinConstraintSystemCompleter.kt @@ -5,6 +5,8 @@ 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.inference.model.* import org.jetbrains.kotlin.resolve.calls.model.* @@ -19,6 +21,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs class KotlinConstraintSystemCompleter( private val resultTypeResolver: ResultTypeResolver, val variableFixationFinder: VariableFixationFinder, + val languageVersionSettings: LanguageVersionSettings, ) { private val postponedArgumentInputTypesResolver = PostponedArgumentInputTypesResolver(resultTypeResolver, variableFixationFinder) @@ -104,7 +107,8 @@ class KotlinConstraintSystemCompleter( postponedArguments, topLevelType, topLevelAtoms, - dependencyProvider + dependencyProvider, + inferenceCompatibilityMode = isInferenceCompatibilityModeEnabled(), ) if (wasFixedSomeVariable) @@ -257,7 +261,8 @@ class KotlinConstraintSystemCompleter( getOrderedAllTypeVariables(collectVariablesFromContext, topLevelAtoms), postponedArguments, completionMode, - topLevelType + topLevelType, + inferenceCompatibilityMode = isInferenceCompatibilityModeEnabled(), ) ?: break if (!variableForFixation.hasProperConstraint && completionMode == ConstraintSystemCompletionMode.PARTIAL) @@ -363,9 +368,17 @@ class KotlinConstraintSystemCompleter( collectVariablesFromContext: Boolean, postponedArguments: List ) = variableFixationFinder.findFirstVariableForFixation( - this, getOrderedAllTypeVariables(collectVariablesFromContext, topLevelAtoms), postponedArguments, completionMode, topLevelType + this, + getOrderedAllTypeVariables(collectVariablesFromContext, topLevelAtoms), + postponedArguments, + completionMode, + topLevelType, + inferenceCompatibilityMode = isInferenceCompatibilityModeEnabled(), ) != null + private fun isInferenceCompatibilityModeEnabled(): Boolean = + languageVersionSettings.supportsFeature(LanguageFeature.InferenceCompatibility) + companion object { fun getOrderedNotAnalyzedPostponedArguments(topLevelAtoms: List): List { fun ResolvedAtom.process(to: MutableList) { diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/PostponedArgumentInputTypesResolver.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/PostponedArgumentInputTypesResolver.kt index a1acc521990..6c7928aea90 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/PostponedArgumentInputTypesResolver.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/PostponedArgumentInputTypesResolver.kt @@ -454,13 +454,21 @@ class PostponedArgumentInputTypesResolver( postponedArguments: List, topLevelType: UnwrappedType, topLevelAtoms: List, - dependencyProvider: TypeVariableDependencyInformationProvider + dependencyProvider: TypeVariableDependencyInformationProvider, + inferenceCompatibilityMode: Boolean = false, ): Boolean { val expectedType = argument.run { safeAs()?.revisedExpectedType ?: expectedType } if (expectedType != null && expectedType.isFunctionOrKFunctionTypeWithAnySuspendability) { val wasFixedSomeVariable = - c.fixNextReadyVariableForParameterType(expectedType, postponedArguments, topLevelType, topLevelAtoms, dependencyProvider) + c.fixNextReadyVariableForParameterType( + expectedType, + postponedArguments, + topLevelType, + topLevelAtoms, + dependencyProvider, + inferenceCompatibilityMode + ) if (wasFixedSomeVariable) return true @@ -474,12 +482,13 @@ class PostponedArgumentInputTypesResolver( postponedArguments: List, topLevelType: UnwrappedType, topLevelAtoms: List, - dependencyProvider: TypeVariableDependencyInformationProvider + dependencyProvider: TypeVariableDependencyInformationProvider, + inferenceCompatibilityMode: Boolean, ): Boolean { val relatedVariables = type.getPureArgumentsForFunctionalTypeOrSubtype() .flatMap { getAllDeeplyRelatedTypeVariables(it, dependencyProvider) } val variableForFixation = variableFixationFinder.findFirstVariableForFixation( - this, relatedVariables, postponedArguments, ConstraintSystemCompletionMode.FULL, topLevelType + this, relatedVariables, postponedArguments, ConstraintSystemCompletionMode.FULL, topLevelType, inferenceCompatibilityMode ) if (variableForFixation == null || !variableForFixation.hasProperConstraint) diff --git a/compiler/testData/diagnostics/tests/inference/regressions/kt41394.kt b/compiler/testData/diagnostics/tests/inference/regressions/kt41394.kt index 9ec5b6d6359..8f6d0d7fc37 100644 --- a/compiler/testData/diagnostics/tests/inference/regressions/kt41394.kt +++ b/compiler/testData/diagnostics/tests/inference/regressions/kt41394.kt @@ -1,12 +1,11 @@ // FIR_IDENTICAL // !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_ANONYMOUS_PARAMETER -// !LANGUAGE: +NewInference +// !LANGUAGE: +InferenceCompatibility -fun foo(x: T, fn: (VR?/*T?*/, T) -> Unit) {} +fun foo(x: T, fn: (VR?, T) -> Unit) {} fun takeInt(x: Int) {} fun main(x: Int) { 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` } \ No newline at end of file