K2: Fix PCLA breaking change when using a bare type on a type variable

See the change at docs/fir/pcla.md and the kdoc
at `getAndSemiFixCurrentResultIfTypeVariable` for clarification

^KT-64840 Fixed
This commit is contained in:
Denis.Zharkov
2024-03-08 19:38:58 +01:00
committed by Space Team
parent 141be17b4b
commit 232c3aeadc
10 changed files with 78 additions and 33 deletions
@@ -37,6 +37,19 @@ abstract class FirInferenceSession {
open fun addSubtypeConstraintIfCompatible(lowerType: ConeKotlinType, upperType: ConeKotlinType, element: FirElement) {}
/**
* For non-trivial inference session (currently PCLA-only), if the type is a type variable that might be fixed,
* fix it and return a fixation result.
*
* Type variable might be fixed if it doesn't belong to an outer CS and have proper constraints.
*
* By semi-fixation we mean that only the relevant EQUALITY constraint is added,
* [org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintSystemCompletionContext.fixVariable] is not expected to be called.
*
* NB: The callee must pay attention that exactly current common CS will be modified.
*/
open fun getAndSemiFixCurrentResultIfTypeVariable(type: ConeKotlinType): ConeKotlinType? = null
companion object {
val DEFAULT: FirInferenceSession = object : FirInferenceSession() {
override fun <T> processPartiallyResolvedCall(
@@ -135,7 +135,7 @@ class FirPCLAInferenceSession(
val system = (this as? FirResolvable)?.candidate()?.system ?: currentCommonSystem
if (resolutionMode is ResolutionMode.ReceiverResolution) {
fixVariablesForMemberScope(resolvedType, system)?.let { additionalBindings += it }
fixCurrentResultIfTypeVariableAndReturnBinding(resolvedType, system)?.let { additionalBindings += it }
}
val substitutor = system.buildCurrentSubstitutor(additionalBindings) as ConeSubstitutor
@@ -146,19 +146,22 @@ class FirPCLAInferenceSession(
}
}
fun fixVariablesForMemberScope(
override fun getAndSemiFixCurrentResultIfTypeVariable(type: ConeKotlinType): ConeKotlinType? =
fixCurrentResultIfTypeVariableAndReturnBinding(type, currentCommonSystem)?.second
fun fixCurrentResultIfTypeVariableAndReturnBinding(
type: ConeKotlinType,
myCs: NewConstraintSystemImpl,
): Pair<ConeTypeVariableTypeConstructor, ConeKotlinType>? {
return when (type) {
is ConeFlexibleType -> fixVariablesForMemberScope(type.lowerBound, myCs)
is ConeDefinitelyNotNullType -> fixVariablesForMemberScope(type.original, myCs)
is ConeTypeVariableType -> fixVariablesForMemberScope(type, myCs)
is ConeFlexibleType -> fixCurrentResultIfTypeVariableAndReturnBinding(type.lowerBound, myCs)
is ConeDefinitelyNotNullType -> fixCurrentResultIfTypeVariableAndReturnBinding(type.original, myCs)
is ConeTypeVariableType -> fixCurrentResultForNestedTypeVariable(type, myCs)
else -> null
}
}
private fun fixVariablesForMemberScope(
private fun fixCurrentResultForNestedTypeVariable(
type: ConeTypeVariableType,
myCs: NewConstraintSystemImpl,
): Pair<ConeTypeVariableTypeConstructor, ConeKotlinType>? {
@@ -120,7 +120,7 @@ class PostponedArgumentsAnalyzer(
// TODO: Fix variables for context receivers, too (KT-64859)
buildMap {
lambda.receiver
?.let { pclaInferenceSession.fixVariablesForMemberScope(it, candidate.system) }
?.let { pclaInferenceSession.fixCurrentResultIfTypeVariableAndReturnBinding(it, candidate.system) }
?.let(this::plusAssign)
}
}
@@ -867,7 +867,10 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT
val firClass = type.lookupTag.toSymbol(session)?.fir ?: return this
if (firClass.typeParameters.isEmpty()) return this
val originalType = argument.unwrapExpression().resolvedType
val originalType = argument.unwrapExpression().resolvedType.let {
components.context.inferenceSession.getAndSemiFixCurrentResultIfTypeVariable(it) ?: it
}
val outerClasses by lazy(LazyThreadSafetyMode.NONE) { firClass.symbol.getClassAndItsOuterClassesWhenLocal(session) }
val newType = components.computeRepresentativeTypeForBareType(type, originalType)
?: if (