K2, Refactor: Move integrateConstraintToSystem to FirBuilderInferenceSession

integrateConstraintToSystem and substitute functions are only used in
the FirBuilderInferenceSession

Move is needed to specialize implementation for builder inference and
avoid an introduction of accidental usages from other inference sessions
This commit is contained in:
Simon Ogorodnik
2023-12-01 14:55:40 +01:00
committed by Space Team
parent 1df318ff28
commit fd1641ef35
2 changed files with 75 additions and 79 deletions
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.fir.resolve.calls.Candidate
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitExtensionReceiverValue
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.ChainedSubstitutor
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.substitution.replaceStubsAndTypeVariablesToErrors
@@ -27,12 +28,13 @@ import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
import org.jetbrains.kotlin.resolve.calls.inference.buildAbstractResultingSubstitutor
import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintSystemCompletionMode
import org.jetbrains.kotlin.resolve.calls.inference.model.BuilderInferencePosition
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
import org.jetbrains.kotlin.resolve.calls.inference.model.*
import org.jetbrains.kotlin.resolve.calls.inference.registerTypeVariableIfNotPresent
import org.jetbrains.kotlin.resolve.descriptorUtil.BUILDER_INFERENCE_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker
import org.jetbrains.kotlin.types.model.safeSubstitute
/**
* General documentation for builder inference algorithm is located at `/docs/fir/builder_inference.md`
@@ -249,6 +251,76 @@ class FirBuilderInferenceSession(
// TODO: support diagnostics, see [CoroutineInferenceSession#updateCalls]
}
}
private fun integrateConstraintToSystem(
commonSystem: NewConstraintSystemImpl,
initialConstraint: InitialConstraint,
callSubstitutor: ConeSubstitutor,
nonFixedToVariablesSubstitutor: ConeSubstitutor,
fixedTypeVariables: Map<TypeConstructorMarker, KotlinTypeMarker>,
): Boolean {
val substitutedConstraintWith =
initialConstraint.substitute(callSubstitutor).substitute(nonFixedToVariablesSubstitutor, fixedTypeVariables)
val lower = substitutedConstraintWith.a // TODO: SUB
val upper = substitutedConstraintWith.b // TODO: SUB
if (commonSystem.isProperType(lower) && (lower == upper || commonSystem.isProperType(upper))) return false
val position = substitutedConstraintWith.position
when (initialConstraint.constraintKind) {
ConstraintKind.LOWER -> error("LOWER constraint shouldn't be used, please use UPPER")
ConstraintKind.UPPER -> commonSystem.addSubtypeConstraint(lower, upper, position)
ConstraintKind.EQUALITY ->
with(commonSystem) {
addSubtypeConstraint(lower, upper, position)
addSubtypeConstraint(upper, lower, position)
}
}
return true
}
private fun InitialConstraint.substitute(substitutor: TypeSubstitutorMarker): InitialConstraint {
val lowerSubstituted = substitutor.safeSubstitute(resolutionContext.typeContext, this.a)
val upperSubstituted = substitutor.safeSubstitute(resolutionContext.typeContext, this.b)
if (lowerSubstituted == a && upperSubstituted == b) return this
return InitialConstraint(
lowerSubstituted,
upperSubstituted,
this.constraintKind,
ConeBuilderInferenceSubstitutionConstraintPosition(this)
)
}
private 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
}
}
class FirStubTypeTransformer(private val substitutor: ConeSubstitutor) : FirDefaultTransformer<Nothing?>() {
@@ -12,12 +12,6 @@ import org.jetbrains.kotlin.fir.resolve.ResolutionMode
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
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.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.*
abstract class FirInferenceSessionForChainedResolve(
@@ -46,74 +40,4 @@ abstract class FirInferenceSessionForChainedResolve(
partiallyResolvedCalls.clear()
completedCalls.clear()
}
protected fun integrateConstraintToSystem(
commonSystem: NewConstraintSystemImpl,
initialConstraint: InitialConstraint,
callSubstitutor: ConeSubstitutor,
nonFixedToVariablesSubstitutor: ConeSubstitutor,
fixedTypeVariables: Map<TypeConstructorMarker, KotlinTypeMarker>,
): Boolean {
val substitutedConstraintWith =
initialConstraint.substitute(callSubstitutor).substitute(nonFixedToVariablesSubstitutor, fixedTypeVariables)
val lower = substitutedConstraintWith.a // TODO: SUB
val upper = substitutedConstraintWith.b // TODO: SUB
if (commonSystem.isProperType(lower) && (lower == upper || commonSystem.isProperType(upper))) return false
val position = substitutedConstraintWith.position
when (initialConstraint.constraintKind) {
ConstraintKind.LOWER -> error("LOWER constraint shouldn't be used, please use UPPER")
ConstraintKind.UPPER -> commonSystem.addSubtypeConstraint(lower, upper, position)
ConstraintKind.EQUALITY ->
with(commonSystem) {
addSubtypeConstraint(lower, upper, position)
addSubtypeConstraint(upper, lower, position)
}
}
return true
}
protected fun InitialConstraint.substitute(substitutor: TypeSubstitutorMarker): InitialConstraint {
val lowerSubstituted = substitutor.safeSubstitute(resolutionContext.typeContext, this.a)
val upperSubstituted = substitutor.safeSubstitute(resolutionContext.typeContext, this.b)
if (lowerSubstituted == a && upperSubstituted == b) return this
return InitialConstraint(
lowerSubstituted,
upperSubstituted,
this.constraintKind,
ConeBuilderInferenceSubstitutionConstraintPosition(this)
)
}
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
}
}