Support type inference for self type materialization calls

This commit is contained in:
Victor Petukhov
2021-06-30 16:21:58 +03:00
parent 44cf4be1e5
commit 51c5a54e31
21 changed files with 183 additions and 89 deletions
@@ -5,7 +5,9 @@
package org.jetbrains.kotlin.resolve.calls.inference
import org.jetbrains.kotlin.resolve.calls.inference.model.Constraint
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
import org.jetbrains.kotlin.resolve.calls.inference.model.DeclaredUpperBoundConstraintPosition
import org.jetbrains.kotlin.types.model.*
fun ConstraintStorage.buildCurrentSubstitutor(
@@ -46,3 +48,11 @@ fun ConstraintStorage.buildNotFixedVariablesToNonSubtypableTypesSubstitutor(
notFixedTypeVariables.mapValues { context.createStubTypeForTypeVariablesInSubtyping(it.value.typeVariable) }
)
}
fun TypeSystemInferenceExtensionContext.hasDeclaredUpperBoundSelfTypes(constraint: Constraint): Boolean {
val typeConstructor = constraint.type.typeConstructor()
return constraint.position.from is DeclaredUpperBoundConstraintPosition<*>
&& (typeConstructor.getParameters().any { it.hasRecursiveBounds(typeConstructor) }
|| typeConstructor.getTypeParameterClassifier()?.hasRecursiveBounds() == true)
}
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.resolve.calls.inference.components
import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator
import org.jetbrains.kotlin.resolve.calls.inference.components.TypeVariableDirectionCalculator.ResolveDirection
import org.jetbrains.kotlin.resolve.calls.inference.hasDeclaredUpperBoundSelfTypes
import org.jetbrains.kotlin.resolve.calls.inference.model.*
import org.jetbrains.kotlin.types.AbstractTypeApproximator
import org.jetbrains.kotlin.types.AbstractTypeChecker
@@ -210,8 +211,9 @@ class ResultTypeResolver(
}
private fun Context.findSuperType(variableWithConstraints: VariableWithConstraints): KotlinTypeMarker? {
val upperConstraints =
variableWithConstraints.constraints.filter { it.kind == ConstraintKind.UPPER && this@findSuperType.isProperTypeForFixation(it.type) }
val upperConstraints = variableWithConstraints.constraints.filter {
it.kind == ConstraintKind.UPPER && (hasDeclaredUpperBoundSelfTypes(it) || isProperTypeForFixation(it.type))
}
if (upperConstraints.isNotEmpty()) {
val intersectionUpperType = intersectTypes(upperConstraints.map { it.type })
val resultIsActuallyIntersection = intersectionUpperType.typeConstructor().isIntersection()
@@ -238,7 +240,7 @@ class ResultTypeResolver(
return typeApproximator.approximateToSubType(
upperType,
TypeApproximatorConfiguration.InternalTypesApproximation
TypeApproximatorConfiguration.InternalAndSelfTypesApproximation
) ?: upperType
}
return null
@@ -8,6 +8,7 @@ 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.inference.components.ConstraintSystemCompletionMode.PARTIAL
import org.jetbrains.kotlin.resolve.calls.inference.hasDeclaredUpperBoundSelfTypes
import org.jetbrains.kotlin.resolve.calls.inference.model.Constraint
import org.jetbrains.kotlin.resolve.calls.inference.model.DeclaredUpperBoundConstraintPosition
import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints
@@ -48,6 +49,7 @@ class VariableFixationFinder(
FROM_INCORPORATION_OF_DECLARED_UPPER_BOUND,
READY_FOR_FIXATION_UPPER,
READY_FOR_FIXATION_LOWER,
READY_FOR_FIXATION_DECLARED_UPPER_BOUND_WITH_SELF_TYPES,
READY_FOR_FIXATION,
READY_FOR_FIXATION_REIFIED,
}
@@ -61,6 +63,7 @@ class VariableFixationFinder(
): TypeVariableFixationReadiness = when {
!notFixedTypeVariables.contains(variable) ||
dependencyProvider.isVariableRelatedToTopLevelType(variable) -> TypeVariableFixationReadiness.FORBIDDEN
hasDeclaredUpperBoundSelfTypes(variable) -> TypeVariableFixationReadiness.READY_FOR_FIXATION_DECLARED_UPPER_BOUND_WITH_SELF_TYPES
!variableHasProperArgumentConstraints(variable) -> TypeVariableFixationReadiness.WITHOUT_PROPER_ARGUMENT_CONSTRAINT
hasDependencyToOtherTypeVariables(variable) -> TypeVariableFixationReadiness.WITH_COMPLEX_DEPENDENCY
variableHasTrivialOrNonProperConstraints(variable) -> TypeVariableFixationReadiness.WITH_TRIVIAL_OR_NON_PROPER_CONSTRAINTS
@@ -166,6 +169,11 @@ class VariableFixationFinder(
it.kind.isLower() && isProperArgumentConstraint(it) && !it.type.typeConstructor().isNothingConstructor()
}
}
private fun Context.hasDeclaredUpperBoundSelfTypes(variable: TypeConstructorMarker): Boolean {
val constraints = notFixedTypeVariables[variable]?.constraints ?: return false
return constraints.isNotEmpty() && constraints.all(::hasDeclaredUpperBoundSelfTypes)
}
}
inline fun TypeSystemInferenceExtensionContext.isProperTypeForFixation(type: KotlinTypeMarker, isProper: (KotlinTypeMarker) -> Boolean) =
@@ -404,6 +404,15 @@ abstract class AbstractTypeApproximator(
if (argument.isStarProjection()) continue
val argumentTypeConstructor = argument.getType().typeConstructor()
if (argumentTypeConstructor is TypeVariableTypeConstructorMarker && conf.selfTypesWithTypeVariablesToCapturedStarProjection) {
// If we have Self<TypeVariable(T)> where T is bounded by Self<T>, we approximate it to CapturedType(*) to satisfy constraints
if (argumentTypeConstructor.typeParameter?.hasRecursiveBounds(type.typeConstructor()) == true) {
return createCapturedStarProjectionForSelfType(argumentTypeConstructor, type)
}
}
val effectiveVariance = AbstractTypeChecker.effectiveVariance(parameter.getVariance(), argument.getVariance())
val argumentType = newArguments[index]?.getType() ?: argument.getType()
@@ -24,6 +24,7 @@ open class TypeApproximatorConfiguration {
open val intersection: IntersectionStrategy = IntersectionStrategy.TO_COMMON_SUPERTYPE
open val intersectionTypesInContravariantPositions = false
open val localTypes = false
open val selfTypesWithTypeVariablesToCapturedStarProjection = false
open val typeVariable: (TypeVariableTypeConstructorMarker) -> Boolean = { false }
open fun capturedType(ctx: TypeSystemInferenceExtensionContext, type: CapturedTypeMarker): Boolean =
@@ -73,6 +74,12 @@ open class TypeApproximatorConfiguration {
override val intersectionTypesInContravariantPositions: Boolean get() = true
}
object InternalAndSelfTypesApproximation : AbstractCapturedTypesApproximation(CaptureStatus.FROM_EXPRESSION) {
override val integerLiteralType: Boolean get() = true
override val intersectionTypesInContravariantPositions: Boolean get() = true
override val selfTypesWithTypeVariablesToCapturedStarProjection = true
}
object FinalApproximationAfterResolutionAndInference :
AbstractCapturedTypesApproximation(CaptureStatus.FROM_EXPRESSION) {
override val integerLiteralType: Boolean get() = true