Implement inferring materialized self types through a default type in ResultTypeResolver

This commit is contained in:
Victor Petukhov
2021-07-07 14:00:09 +03:00
parent 3787099a38
commit c2cf2f36cd
13 changed files with 103 additions and 60 deletions
@@ -5,9 +5,7 @@
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(
@@ -49,10 +47,27 @@ fun ConstraintStorage.buildNotFixedVariablesToNonSubtypableTypesSubstitutor(
)
}
fun TypeSystemInferenceExtensionContext.hasDeclaredUpperBoundSelfTypes(constraint: Constraint): Boolean {
val typeConstructor = constraint.type.typeConstructor()
fun TypeSystemInferenceExtensionContext.hasRecursiveTypeParametersWithGivenSelfType(selfTypeConstructor: TypeConstructorMarker) =
selfTypeConstructor.getParameters().any { it.hasRecursiveBounds(selfTypeConstructor) }
return constraint.position.from is DeclaredUpperBoundConstraintPosition<*>
&& (typeConstructor.getParameters().any { it.hasRecursiveBounds(typeConstructor) }
|| typeConstructor.getTypeParameterClassifier()?.hasRecursiveBounds() == true)
fun TypeSystemInferenceExtensionContext.isRecursiveTypeParameter(typeConstructor: TypeConstructorMarker) =
typeConstructor.getTypeParameterClassifier()?.hasRecursiveBounds() == true
fun TypeSystemInferenceExtensionContext.extractTypeForGivenRecursiveTypeParameter(
type: KotlinTypeMarker,
typeParameter: TypeParameterMarker
): KotlinTypeMarker? {
for (argument in type.getArguments()) {
if (argument.isStarProjection()) continue
val typeConstructor = argument.getType().typeConstructor()
if (typeConstructor is TypeVariableTypeConstructorMarker
&& typeConstructor.typeParameter == typeParameter
&& typeConstructor.typeParameter?.hasRecursiveBounds(type.typeConstructor()) == true
) {
return type
}
extractTypeForGivenRecursiveTypeParameter(argument.getType(), typeParameter)?.let { return it }
}
return null
}
@@ -21,7 +21,7 @@ import kotlin.math.max
class ConstraintInjector(
val constraintIncorporator: ConstraintIncorporator,
val typeApproximator: AbstractTypeApproximator,
val languageVersionSettings: LanguageVersionSettings,
private val languageVersionSettings: LanguageVersionSettings,
) {
private val ALLOWED_DEPTH_DELTA_FOR_INCORPORATION = 1
@@ -5,11 +5,10 @@
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.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.extractTypeForGivenRecursiveTypeParameter
import org.jetbrains.kotlin.resolve.calls.inference.model.*
import org.jetbrains.kotlin.types.AbstractTypeApproximator
import org.jetbrains.kotlin.types.AbstractTypeChecker
@@ -27,13 +26,36 @@ class ResultTypeResolver(
fun isReified(variable: TypeVariableMarker): Boolean
}
private fun Context.getDefaultTypeForSelfType(
constraints: List<Constraint>,
typeVariable: TypeVariableMarker
): KotlinTypeMarker? {
val typeVariableConstructor = typeVariable.freshTypeConstructor() as TypeVariableTypeConstructorMarker
val typesForRecursiveTypeParameters = constraints.mapNotNull { constraint ->
if (constraint.position.from !is DeclaredUpperBoundConstraintPosition<*>) return@mapNotNull null
val typeParameter = typeVariableConstructor.typeParameter ?: return@mapNotNull null
extractTypeForGivenRecursiveTypeParameter(constraint.type, typeParameter)
}.takeIf { it.isNotEmpty() } ?: return null
return createCapturedStarProjectionForSelfType(typeVariableConstructor, typesForRecursiveTypeParameters)
}
@OptIn(ExperimentalStdlibApi::class)
private fun Context.getDefaultType(
direction: ResolveDirection,
constraints: List<Constraint>,
typeVariable: TypeVariableMarker
): KotlinTypeMarker {
getDefaultTypeForSelfType(constraints, typeVariable)?.let { return it }
return if (direction == ResolveDirection.TO_SUBTYPE) nothingType() else nullableAnyType()
}
fun findResultType(c: Context, variableWithConstraints: VariableWithConstraints, direction: ResolveDirection): KotlinTypeMarker {
findResultTypeOrNull(c, variableWithConstraints, direction)?.let { return it }
// no proper constraints
return run {
if (direction == ResolveDirection.TO_SUBTYPE) c.nothingType() else c.nullableAnyType()
}
return c.getDefaultType(direction, variableWithConstraints.constraints, variableWithConstraints.typeVariable)
}
private fun findResultTypeOrNull(
@@ -214,12 +236,8 @@ class ResultTypeResolver(
}
private fun Context.findSuperType(variableWithConstraints: VariableWithConstraints): KotlinTypeMarker? {
val isTypeInferenceForSelfTypesSupported =
languageVersionSettings.supportsFeature(LanguageFeature.TypeInferenceOnCallsWithSelfTypes)
val upperConstraints = variableWithConstraints.constraints.filter {
it.kind == ConstraintKind.UPPER
&& ((isTypeInferenceForSelfTypesSupported && hasDeclaredUpperBoundSelfTypes(it)) || isProperTypeForFixation(it.type))
}
val upperConstraints =
variableWithConstraints.constraints.filter { it.kind == ConstraintKind.UPPER && this@findSuperType.isProperTypeForFixation(it.type) }
if (upperConstraints.isNotEmpty()) {
val intersectionUpperType = intersectTypes(upperConstraints.map { it.type })
val resultIsActuallyIntersection = intersectionUpperType.typeConstructor().isIntersection()
@@ -246,7 +264,7 @@ class ResultTypeResolver(
return typeApproximator.approximateToSubType(
upperType,
TypeApproximatorConfiguration.InternalAndSelfTypesApproximation
TypeApproximatorConfiguration.InternalTypesApproximation
) ?: upperType
}
return null
@@ -8,7 +8,8 @@ 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.hasRecursiveTypeParametersWithGivenSelfType
import org.jetbrains.kotlin.resolve.calls.inference.isRecursiveTypeParameter
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
@@ -66,7 +67,7 @@ class VariableFixationFinder(
): TypeVariableFixationReadiness = when {
!notFixedTypeVariables.contains(variable) ||
dependencyProvider.isVariableRelatedToTopLevelType(variable) -> TypeVariableFixationReadiness.FORBIDDEN
isTypeInferenceForSelfTypesSupported && hasDeclaredUpperBoundSelfTypes(variable) ->
isTypeInferenceForSelfTypesSupported && hasOnlyDeclaredUpperBoundSelfTypes(variable) ->
TypeVariableFixationReadiness.READY_FOR_FIXATION_DECLARED_UPPER_BOUND_WITH_SELF_TYPES
!variableHasProperArgumentConstraints(variable) -> TypeVariableFixationReadiness.WITHOUT_PROPER_ARGUMENT_CONSTRAINT
hasDependencyToOtherTypeVariables(variable) -> TypeVariableFixationReadiness.WITH_COMPLEX_DEPENDENCY
@@ -174,9 +175,13 @@ class VariableFixationFinder(
}
}
private fun Context.hasDeclaredUpperBoundSelfTypes(variable: TypeConstructorMarker): Boolean {
private fun Context.hasOnlyDeclaredUpperBoundSelfTypes(variable: TypeConstructorMarker): Boolean {
val constraints = notFixedTypeVariables[variable]?.constraints ?: return false
return constraints.isNotEmpty() && constraints.all(::hasDeclaredUpperBoundSelfTypes)
return constraints.isNotEmpty() && constraints.all {
val typeConstructor = it.type.typeConstructor()
it.position.from is DeclaredUpperBoundConstraintPosition<*>
&& (hasRecursiveTypeParametersWithGivenSelfType(typeConstructor) || isRecursiveTypeParameter(typeConstructor))
}
}
}
@@ -404,17 +404,6 @@ abstract class AbstractTypeApproximator(
if (argument.isStarProjection()) continue
val argumentTypeConstructor = argument.getType().typeConstructor()
val isTypeInferenceForSelfTypesSupported =
languageVersionSettings.supportsFeature(LanguageFeature.TypeInferenceOnCallsWithSelfTypes)
if (isTypeInferenceForSelfTypesSupported && 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,7 +24,6 @@ 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 =
@@ -74,12 +73,6 @@ 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