FIR: replace constraint with NotFixedTypeToVariableSubstitutor properly

In this commit we add nullability to upper type of a substituted
constraint in the situation like (Stub<_L> <: SomeType),
where _L is fixed to nullable Stub<_L>?.
We have to change this constraint to L <: SomeType? and not to
L <: SomeType as before, otherwise nullability become broken
(direct substitution of Stub<_L> to L is illegal here).

#KT-50470 Fixed
This commit is contained in:
Mikhail Glukhikh
2021-12-22 09:59:50 +03:00
committed by teamcity
parent dafc6d849c
commit 6342eb96c0
5 changed files with 43 additions and 10 deletions
@@ -61,8 +61,8 @@ FILE: expectedType.kt
public final val property: R|FirProperty| = R|<local>/property|
public get(): R|FirProperty|
public final val expectedType: R|ConeKotlinType?|by <Inapplicable(INAPPLICABLE): /myLazy>#<R|ConeKotlinType|>(<L> = myLazy@fun <anonymous>(): R|ConeKotlinType| <inline=NoInline> {
^ this@R|/Session|.R|/Session.property|.R|/FirProperty.returnTypeRef|.<Inapplicable(INAPPLICABLE): /coneTypeSafe>#<R|ConeKotlinType|>()
public final val expectedType: R|ConeKotlinType?|by R|/myLazy|<R|ConeKotlinType?|>(<L> = myLazy@fun <anonymous>(): R|ConeKotlinType?| <inline=NoInline> {
^ this@R|/Session|.R|/Session.property|.R|/FirProperty.returnTypeRef|.R|/coneTypeSafe|<R|ConeKotlinType|>()
}
)
public get(): R|ConeKotlinType?| {
@@ -219,7 +219,7 @@ internal class TypeSubstitutorByTypeConstructor(
// Note: builder inference uses TypeSubstitutorByTypeConstructor for not fixed type substitution
class NotFixedTypeToVariableSubstitutorForDelegateInference(
private val bindings: Map<TypeVariableMarker, ConeKotlinType>,
val bindings: Map<TypeVariableMarker, ConeKotlinType>,
typeContext: ConeTypeContext
) : AbstractConeSubstitutor(typeContext) {
override fun substituteType(type: ConeKotlinType): ConeKotlinType? {
@@ -13,14 +13,12 @@ import org.jetbrains.kotlin.fir.resolve.calls.ResolutionContext
import org.jetbrains.kotlin.fir.resolve.calls.candidate
import org.jetbrains.kotlin.fir.resolve.inference.model.ConeBuilderInferenceSubstitutionConstraintPosition
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintSystemCompletionContext
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind
import org.jetbrains.kotlin.resolve.calls.inference.model.InitialConstraint
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
import org.jetbrains.kotlin.types.model.StubTypeMarker
import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker
import org.jetbrains.kotlin.types.model.TypeVariableMarker
import org.jetbrains.kotlin.types.model.safeSubstitute
import org.jetbrains.kotlin.types.model.*
abstract class AbstractManyCandidatesInferenceSession(
protected val resolutionContext: ResolutionContext
@@ -60,8 +58,10 @@ abstract class AbstractManyCandidatesInferenceSession(
initialConstraint: InitialConstraint,
callSubstitutor: ConeSubstitutor,
nonFixedToVariablesSubstitutor: ConeSubstitutor,
fixedTypeVariables: Map<TypeConstructorMarker, KotlinTypeMarker>,
): Boolean {
val substitutedConstraintWith = initialConstraint.substitute(callSubstitutor).substitute(nonFixedToVariablesSubstitutor)
val substitutedConstraintWith =
initialConstraint.substitute(callSubstitutor).substitute(nonFixedToVariablesSubstitutor, fixedTypeVariables)
val lower = substitutedConstraintWith.a // TODO: SUB
val upper = substitutedConstraintWith.b // TODO: SUB
@@ -95,4 +95,31 @@ abstract class AbstractManyCandidatesInferenceSession(
ConeBuilderInferenceSubstitutionConstraintPosition(this) // TODO
)
}
protected fun InitialConstraint.substitute(
substitutor: TypeSubstitutorMarker,
fixedTypeVariables: Map<TypeConstructorMarker, KotlinTypeMarker>
): InitialConstraint {
val substituted = substitute(substitutor)
val a = a
// In situation when some type variable _T is fixed to Stub(_T)?,
// we are not allowed just to substitute Stub(_T) with T because nullabilities are different here!
// To compensate this, we have to substitute Stub(_T) <: SomeType constraint with T <: SomeType? adding nullability to upper type
if (a is ConeStubTypeForChainInference && substituted.a !is ConeStubTypeForChainInference) {
val constructor = a.constructor
val fixedTypeVariableType = fixedTypeVariables[constructor.variable.typeConstructor]
if (fixedTypeVariableType is ConeStubTypeForChainInference &&
fixedTypeVariableType.constructor === constructor &&
fixedTypeVariableType.isMarkedNullable
) {
return InitialConstraint(
substituted.a,
(substituted.b as ConeKotlinType).withNullability(ConeNullability.NULLABLE, resolutionContext.typeContext),
substituted.constraintKind,
substituted.position
)
}
}
return substituted
}
}
@@ -197,7 +197,10 @@ class FirBuilderInferenceSession(
for (initialConstraint in storage.initialConstraints) {
if (initialConstraint.position is BuilderInferencePosition) continue
if (integrateConstraintToSystem(commonSystem, initialConstraint, callSubstitutor, nonFixedToVariablesSubstitutor)) {
if (integrateConstraintToSystem(
commonSystem, initialConstraint, callSubstitutor, nonFixedToVariablesSubstitutor, storage.fixedTypeVariables
)
) {
introducedConstraint = true
}
}
@@ -300,7 +300,10 @@ class FirDelegatedPropertyInferenceSession(
var introducedConstraint = false
for (initialConstraint in storage.initialConstraints) {
if (integrateConstraintToSystem(commonSystem, initialConstraint, callSubstitutor, nonFixedToVariablesSubstitutor)) {
if (integrateConstraintToSystem(
commonSystem, initialConstraint, callSubstitutor, nonFixedToVariablesSubstitutor, storage.fixedTypeVariables
)
) {
introducedConstraint = true
}
}