From 6342eb96c03f5eae47fe7900373aeeeb11592839 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Wed, 22 Dec 2021 09:59:50 +0300 Subject: [PATCH] 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 --- .../inference/problems/expectedType.fir.txt | 4 +- .../fir/resolve/substitution/Substitutors.kt | 2 +- .../AbstractManyCandidatesInferenceSession.kt | 37 ++++++++++++++++--- .../inference/FirBuilderInferenceSession.kt | 5 ++- .../FirDelegatedPropertyInferenceSession.kt | 5 ++- 5 files changed, 43 insertions(+), 10 deletions(-) diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/inference/problems/expectedType.fir.txt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/inference/problems/expectedType.fir.txt index 88e022bc5e3..5640cd80021 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/inference/problems/expectedType.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/inference/problems/expectedType.fir.txt @@ -61,8 +61,8 @@ FILE: expectedType.kt public final val property: R|FirProperty| = R|/property| public get(): R|FirProperty| - public final val expectedType: R|ConeKotlinType?|by #( = myLazy@fun (): R|ConeKotlinType| { - ^ this@R|/Session|.R|/Session.property|.R|/FirProperty.returnTypeRef|.#() + public final val expectedType: R|ConeKotlinType?|by R|/myLazy|( = myLazy@fun (): R|ConeKotlinType?| { + ^ this@R|/Session|.R|/Session.property|.R|/FirProperty.returnTypeRef|.R|/coneTypeSafe|() } ) public get(): R|ConeKotlinType?| { diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/substitution/Substitutors.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/substitution/Substitutors.kt index 5fd020112d2..d143765b01f 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/substitution/Substitutors.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/substitution/Substitutors.kt @@ -219,7 +219,7 @@ internal class TypeSubstitutorByTypeConstructor( // Note: builder inference uses TypeSubstitutorByTypeConstructor for not fixed type substitution class NotFixedTypeToVariableSubstitutorForDelegateInference( - private val bindings: Map, + val bindings: Map, typeContext: ConeTypeContext ) : AbstractConeSubstitutor(typeContext) { override fun substituteType(type: ConeKotlinType): ConeKotlinType? { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/AbstractManyCandidatesInferenceSession.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/AbstractManyCandidatesInferenceSession.kt index 7dc48cc2425..db910c8edc3 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/AbstractManyCandidatesInferenceSession.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/AbstractManyCandidatesInferenceSession.kt @@ -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, ): 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 + ): 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 + } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirBuilderInferenceSession.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirBuilderInferenceSession.kt index bc830a1f31e..8dbdfacf812 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirBuilderInferenceSession.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirBuilderInferenceSession.kt @@ -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 } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirDelegatedPropertyInferenceSession.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirDelegatedPropertyInferenceSession.kt index 7d684ff5f87..0a6128491f7 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirDelegatedPropertyInferenceSession.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirDelegatedPropertyInferenceSession.kt @@ -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 } }