All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jetbrains.kotlin.resolve.calls.inference.components.VariableFixationFinder.kt Maven / Gradle / Ivy
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
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.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
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtomMarker
import org.jetbrains.kotlin.types.model.*
class VariableFixationFinder(
private val trivialConstraintTypeInferenceOracle: TrivialConstraintTypeInferenceOracle,
private val languageVersionSettings: LanguageVersionSettings,
) {
interface Context : TypeSystemInferenceExtensionContext {
val notFixedTypeVariables: Map
val fixedTypeVariables: Map
val postponedTypeVariables: List
fun isReified(variable: TypeVariableMarker): Boolean
}
data class VariableForFixation(
val variable: TypeConstructorMarker,
val hasProperConstraint: Boolean,
val hasOnlyTrivialProperConstraint: Boolean = false
)
fun findFirstVariableForFixation(
c: Context,
allTypeVariables: List,
postponedKtPrimitives: List,
completionMode: ConstraintSystemCompletionMode,
topLevelType: KotlinTypeMarker,
): VariableForFixation? = c.findTypeVariableForFixation(allTypeVariables, postponedKtPrimitives, completionMode, topLevelType)
enum class TypeVariableFixationReadiness {
FORBIDDEN,
WITHOUT_PROPER_ARGUMENT_CONSTRAINT, // proper constraint from arguments -- not from upper bound for type parameters
READY_FOR_FIXATION_DECLARED_UPPER_BOUND_WITH_SELF_TYPES,
WITH_COMPLEX_DEPENDENCY, // if type variable T has constraint with non fixed type variable inside (non-top-level): T <: Foo
WITH_TRIVIAL_OR_NON_PROPER_CONSTRAINTS, // proper trivial constraint from arguments, Nothing <: T
RELATED_TO_ANY_OUTPUT_TYPE,
FROM_INCORPORATION_OF_DECLARED_UPPER_BOUND,
READY_FOR_FIXATION_UPPER,
READY_FOR_FIXATION_LOWER,
READY_FOR_FIXATION,
READY_FOR_FIXATION_REIFIED,
}
private val inferenceCompatibilityModeEnabled: Boolean
get() = languageVersionSettings.supportsFeature(LanguageFeature.InferenceCompatibility)
private val isTypeInferenceForSelfTypesSupported: Boolean
get() = languageVersionSettings.supportsFeature(LanguageFeature.TypeInferenceOnCallsWithSelfTypes)
private fun Context.getTypeVariableReadiness(
variable: TypeConstructorMarker,
dependencyProvider: TypeVariableDependencyInformationProvider,
): TypeVariableFixationReadiness = when {
!notFixedTypeVariables.contains(variable) ||
dependencyProvider.isVariableRelatedToTopLevelType(variable) -> TypeVariableFixationReadiness.FORBIDDEN
isTypeInferenceForSelfTypesSupported && areAllProperConstraintsSelfTypeBased(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
dependencyProvider.isVariableRelatedToAnyOutputType(variable) -> TypeVariableFixationReadiness.RELATED_TO_ANY_OUTPUT_TYPE
variableHasOnlyIncorporatedConstraintsFromDeclaredUpperBound(variable) ->
TypeVariableFixationReadiness.FROM_INCORPORATION_OF_DECLARED_UPPER_BOUND
isReified(variable) -> TypeVariableFixationReadiness.READY_FOR_FIXATION_REIFIED
inferenceCompatibilityModeEnabled -> {
when {
variableHasLowerNonNothingProperConstraint(variable) -> TypeVariableFixationReadiness.READY_FOR_FIXATION_LOWER
else -> TypeVariableFixationReadiness.READY_FOR_FIXATION_UPPER
}
}
else -> TypeVariableFixationReadiness.READY_FOR_FIXATION
}
fun isTypeVariableHasProperConstraint(
context: Context,
typeVariable: TypeConstructorMarker,
): Boolean {
return with(context) {
val dependencyProvider = TypeVariableDependencyInformationProvider(
notFixedTypeVariables, emptyList(), topLevelType = null, context
)
when (getTypeVariableReadiness(typeVariable, dependencyProvider)) {
TypeVariableFixationReadiness.FORBIDDEN, TypeVariableFixationReadiness.WITHOUT_PROPER_ARGUMENT_CONSTRAINT -> false
else -> true
}
}
}
private fun Context.variableHasTrivialOrNonProperConstraints(variable: TypeConstructorMarker): Boolean {
return notFixedTypeVariables[variable]?.constraints?.all { constraint ->
val isProperConstraint = isProperArgumentConstraint(constraint)
isProperConstraint && trivialConstraintTypeInferenceOracle.isNotInterestingConstraint(constraint) || !isProperConstraint
} ?: false
}
private fun Context.variableHasOnlyIncorporatedConstraintsFromDeclaredUpperBound(variable: TypeConstructorMarker): Boolean {
val constraints = notFixedTypeVariables[variable]?.constraints ?: return false
return constraints.filter { isProperArgumentConstraint(it) }.all { it.position.isFromDeclaredUpperBound }
}
private fun Context.findTypeVariableForFixation(
allTypeVariables: List,
postponedArguments: List,
completionMode: ConstraintSystemCompletionMode,
topLevelType: KotlinTypeMarker,
): VariableForFixation? {
if (allTypeVariables.isEmpty()) return null
val dependencyProvider = TypeVariableDependencyInformationProvider(
notFixedTypeVariables, postponedArguments, topLevelType.takeIf { completionMode == PARTIAL }, this
)
val candidate =
allTypeVariables.maxByOrNull { getTypeVariableReadiness(it, dependencyProvider) } ?: return null
return when (getTypeVariableReadiness(candidate, dependencyProvider)) {
TypeVariableFixationReadiness.FORBIDDEN -> null
TypeVariableFixationReadiness.WITHOUT_PROPER_ARGUMENT_CONSTRAINT -> VariableForFixation(candidate, false)
TypeVariableFixationReadiness.WITH_TRIVIAL_OR_NON_PROPER_CONSTRAINTS ->
VariableForFixation(candidate, hasProperConstraint = true, hasOnlyTrivialProperConstraint = true)
else -> VariableForFixation(candidate, true)
}
}
private fun Context.hasDependencyToOtherTypeVariables(typeVariable: TypeConstructorMarker): Boolean {
for (constraint in notFixedTypeVariables[typeVariable]?.constraints ?: return false) {
val dependencyPresenceCondition = { type: KotlinTypeMarker ->
type.typeConstructor() != typeVariable && notFixedTypeVariables.containsKey(type.typeConstructor())
}
if (constraint.type.lowerBoundIfFlexible().argumentsCount() != 0 && constraint.type.contains(dependencyPresenceCondition))
return true
}
return false
}
private fun Context.variableHasProperArgumentConstraints(variable: TypeConstructorMarker): Boolean {
val constraints = notFixedTypeVariables[variable]?.constraints ?: return false
// temporary hack to fail calls which contain callable references resolved though OI with uninferred type parameters
val areThereConstraintsWithUninferredTypeParameter = constraints.any { c -> c.type.contains { it.isUninferredParameter() } }
return constraints.any { isProperArgumentConstraint(it) } && !areThereConstraintsWithUninferredTypeParameter
}
private fun Context.isProperArgumentConstraint(c: Constraint) =
isProperType(c.type)
&& c.position.initialConstraint.position !is DeclaredUpperBoundConstraintPosition<*>
&& !c.isNullabilityConstraint
private fun Context.isProperType(type: KotlinTypeMarker): Boolean =
isProperTypeForFixation(type) { t -> !t.contains { notFixedTypeVariables.containsKey(it.typeConstructor()) } }
private fun Context.isReified(variable: TypeConstructorMarker): Boolean =
notFixedTypeVariables[variable]?.typeVariable?.let { isReified(it) } ?: false
private fun Context.variableHasLowerNonNothingProperConstraint(variable: TypeConstructorMarker): Boolean {
val constraints = notFixedTypeVariables[variable]?.constraints ?: return false
return constraints.any {
it.kind.isLower() && isProperArgumentConstraint(it) && !it.type.typeConstructor().isNothingConstructor()
}
}
private fun Context.isSelfTypeConstraint(constraint: Constraint): Boolean {
val typeConstructor = constraint.type.typeConstructor()
return constraint.position.from is DeclaredUpperBoundConstraintPosition<*>
&& (hasRecursiveTypeParametersWithGivenSelfType(typeConstructor) || isRecursiveTypeParameter(typeConstructor))
}
private fun Context.areAllProperConstraintsSelfTypeBased(variable: TypeConstructorMarker): Boolean {
val constraints = notFixedTypeVariables[variable]?.constraints?.takeIf { it.isNotEmpty() } ?: return false
var hasSelfTypeConstraint = false
var hasOtherProperConstraint = false
for (constraint in constraints) {
if (isSelfTypeConstraint(constraint)) {
hasSelfTypeConstraint = true
}
if (isProperArgumentConstraint(constraint)) {
hasOtherProperConstraint = true
}
if (hasSelfTypeConstraint && hasOtherProperConstraint) break
}
return hasSelfTypeConstraint && !hasOtherProperConstraint
}
}
inline fun TypeSystemInferenceExtensionContext.isProperTypeForFixation(type: KotlinTypeMarker, isProper: (KotlinTypeMarker) -> Boolean) =
isProper(type) && extractProjectionsForAllCapturedTypes(type).all(isProper)
@OptIn(ExperimentalStdlibApi::class)
fun TypeSystemInferenceExtensionContext.extractProjectionsForAllCapturedTypes(baseType: KotlinTypeMarker): Set {
val simpleBaseType = baseType.asSimpleType()
return buildSet {
val projectionType = if (simpleBaseType is CapturedTypeMarker) {
val typeArgument = simpleBaseType.typeConstructorProjection().takeIf { !it.isStarProjection() } ?: return@buildSet
typeArgument.getType().also(::add)
} else baseType
val argumentsCount = projectionType.argumentsCount().takeIf { it != 0 } ?: return@buildSet
for (i in 0 until argumentsCount) {
val typeArgument = projectionType.getArgument(i).takeIf { !it.isStarProjection() } ?: continue
addAll(extractProjectionsForAllCapturedTypes(typeArgument.getType()))
}
}
}
fun TypeSystemInferenceExtensionContext.containsTypeVariable(type: KotlinTypeMarker, typeVariable: TypeConstructorMarker): Boolean {
if (type.contains { it.typeConstructor().unwrapStubTypeVariableConstructor() == typeVariable }) return true
val typeProjections = extractProjectionsForAllCapturedTypes(type)
return typeProjections.any { typeProjectionsType ->
typeProjectionsType.contains { it.typeConstructor().unwrapStubTypeVariableConstructor() == typeVariable }
}
}