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.
/*
* Copyright 2000-2018 JetBrains s.r.o. 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.resolve.calls.inference.model.NewTypeVariable
import org.jetbrains.kotlin.resolve.calls.inference.model.NotEnoughInformationForTypeParameter
import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints
import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class KotlinConstraintSystemCompleter(
private val resultTypeResolver: ResultTypeResolver,
private val variableFixationFinder: VariableFixationFinder
) {
enum class ConstraintSystemCompletionMode {
FULL,
PARTIAL
}
interface Context : VariableFixationFinder.Context, ResultTypeResolver.Context {
override val notFixedTypeVariables: Map
override val postponedTypeVariables: List
// type can be proper if it not contains not fixed type variables
fun canBeProper(type: UnwrappedType): Boolean
fun containsOnlyFixedOrPostponedVariables(type: UnwrappedType): Boolean
// mutable operations
fun addError(error: KotlinCallDiagnostic)
fun fixVariable(variable: NewTypeVariable, resultType: UnwrappedType)
}
fun runCompletion(
c: Context,
completionMode: ConstraintSystemCompletionMode,
topLevelAtoms: List,
topLevelType: UnwrappedType,
analyze: (PostponedResolvedAtom) -> Unit
) {
runCompletion(c, completionMode, topLevelAtoms, topLevelType, collectVariablesFromContext = false, analyze = analyze)
}
fun completeConstraintSystem(c: Context, topLevelType: UnwrappedType) {
runCompletion(c, ConstraintSystemCompletionMode.FULL, emptyList(), topLevelType, collectVariablesFromContext = true) {
error("Shouldn't be called in complete constraint system mode")
}
}
private fun runCompletion(
c: Context,
completionMode: ConstraintSystemCompletionMode,
topLevelAtoms: List,
topLevelType: UnwrappedType,
collectVariablesFromContext: Boolean,
analyze: (PostponedResolvedAtom) -> Unit
) {
while (true) {
if (analyzePostponeArgumentIfPossible(c, topLevelAtoms, analyze)) continue
val allTypeVariables = getOrderedAllTypeVariables(c, collectVariablesFromContext, topLevelAtoms)
val postponedKtPrimitives = getOrderedNotAnalyzedPostponedArguments(topLevelAtoms)
val variableForFixation = variableFixationFinder.findFirstVariableForFixation(
c, allTypeVariables, postponedKtPrimitives, completionMode, topLevelType
)
if (shouldForceCallableReferenceOrLambdaResolution(completionMode, variableForFixation)) {
if (forcePostponedAtomResolution(topLevelAtoms, analyze)) continue
if (forcePostponedAtomResolution(topLevelAtoms, analyze)) continue
}
if (variableForFixation != null) {
if (variableForFixation.hasProperConstraint || completionMode == ConstraintSystemCompletionMode.FULL) {
val variableWithConstraints = c.notFixedTypeVariables[variableForFixation.variable]!!
fixVariable(c, topLevelType, variableWithConstraints, postponedKtPrimitives)
if (!variableForFixation.hasProperConstraint) {
c.addError(NotEnoughInformationForTypeParameter(variableWithConstraints.typeVariable))
}
continue
}
}
break
}
if (completionMode == ConstraintSystemCompletionMode.FULL) {
// force resolution for all not-analyzed argument's
getOrderedNotAnalyzedPostponedArguments(topLevelAtoms).forEach(analyze)
if (c.notFixedTypeVariables.isNotEmpty() && c.postponedTypeVariables.isEmpty()) {
runCompletion(c, completionMode, topLevelAtoms, topLevelType, analyze)
}
}
}
private fun shouldForceCallableReferenceOrLambdaResolution(
completionMode: ConstraintSystemCompletionMode,
variableForFixation: VariableFixationFinder.VariableForFixation?
): Boolean {
if (completionMode == ConstraintSystemCompletionMode.PARTIAL) return false
if (variableForFixation != null && variableForFixation.hasProperConstraint) return false
return true
}
// true if we do analyze
private fun analyzePostponeArgumentIfPossible(
c: Context,
topLevelAtoms: List,
analyze: (PostponedResolvedAtom) -> Unit
): Boolean {
for (argument in getOrderedNotAnalyzedPostponedArguments(topLevelAtoms)) {
if (canWeAnalyzeIt(c, argument)) {
analyze(argument)
return true
}
}
return false
}
// true if we find some callable reference and run resolution for it. Note that such resolution can be unsuccessful
private inline fun forcePostponedAtomResolution(
topLevelAtoms: List,
analyze: (PostponedResolvedAtom) -> Unit
): Boolean {
val postponedArgument = getOrderedNotAnalyzedPostponedArguments(topLevelAtoms).firstIsInstanceOrNull() ?: return false
analyze(postponedArgument)
return true
}
private fun getOrderedNotAnalyzedPostponedArguments(topLevelAtoms: List): List {
fun ResolvedAtom.process(to: MutableList) {
to.addIfNotNull(this.safeAs()?.takeUnless { it.analyzed })
if (analyzed) {
subResolvedAtoms.forEach { it.process(to) }
}
}
val notAnalyzedArguments = arrayListOf()
for (primitive in topLevelAtoms) {
primitive.process(notAnalyzedArguments)
}
return notAnalyzedArguments
}
private fun getOrderedAllTypeVariables(
c: Context,
collectVariablesFromContext: Boolean,
topLevelAtoms: List
): List {
if (collectVariablesFromContext) return c.notFixedTypeVariables.keys.toList()
fun ResolvedAtom.process(to: LinkedHashSet) {
val typeVariables = when (this) {
is ResolvedCallAtom -> substitutor.freshVariables
is ResolvedCallableReferenceAtom -> candidate?.freshSubstitutor?.freshVariables.orEmpty()
is ResolvedLambdaAtom -> listOfNotNull(typeVariableForLambdaReturnType)
else -> emptyList()
}
typeVariables.mapNotNullTo(to) {
val typeConstructor = it.freshTypeConstructor
typeConstructor.takeIf { c.notFixedTypeVariables.containsKey(typeConstructor) }
}
if (analyzed) {
subResolvedAtoms.forEach { it.process(to) }
}
}
// Note that it's important to use Set here, because several atoms can share the same type variable
val result = linkedSetOf()
for (primitive in topLevelAtoms) {
primitive.process(result)
}
assert(result.size == c.notFixedTypeVariables.size) {
val notFoundTypeVariables = c.notFixedTypeVariables.keys.toMutableSet().removeAll(result)
"Not all type variables found: $notFoundTypeVariables"
}
return result.toList()
}
private fun canWeAnalyzeIt(c: Context, argument: PostponedResolvedAtom): Boolean {
if (argument.analyzed) return false
return argument.inputTypes.all { c.containsOnlyFixedOrPostponedVariables(it) }
}
private fun fixVariable(
c: Context,
topLevelType: UnwrappedType,
variableWithConstraints: VariableWithConstraints,
postponedResolveKtPrimitives: List
) {
val direction = TypeVariableDirectionCalculator(c, postponedResolveKtPrimitives, topLevelType).getDirection(variableWithConstraints)
fixVariable(c, variableWithConstraints, direction)
}
fun fixVariable(
c: Context,
variableWithConstraints: VariableWithConstraints,
direction: TypeVariableDirectionCalculator.ResolveDirection
) {
val resultType = resultTypeResolver.findResultType(c, variableWithConstraints, direction)
c.fixVariable(variableWithConstraints.typeVariable, resultType)
}
}