FIR: support don't use builder inference if possible

In this commit we upgrade FIR builder inference logic from
the compiler version to 1.7. FIR-based compiler now works with
"don't use builder inference" flag always ON and supports switching
the flag "use builder inference only if needed". To do it,
ContraintSystemCompleter (FIR) and KotlinConstraintSystemCompleter (FE 1.0)
are made similar with extracting some common parts into
ConstraintSystemCompletionContext.

Test status: one BB test fails after this commit (KT-49285).
Also we have a crush in DFA logic in FIR bootstrap test and somehow
questionable behavior in FIR diagnostic test. However,
two BB tests were fixed, the 3rd case from KT-49925 were also fixed.

#KT-49925 Fixed
This commit is contained in:
Mikhail Glukhikh
2021-12-23 12:16:01 +03:00
committed by teamcity
parent d2bfb7153e
commit e8be9d4861
36 changed files with 638 additions and 475 deletions
@@ -126,6 +126,7 @@ digraph complexPostponedCfg_kt {
35 -> {36} [color=green];
36 -> {37};
37 -> {38};
38 -> {10} [color=red];
38 -> {22} [color=green];
39 -> {40};
40 -> {41};
@@ -9,7 +9,7 @@ FILE: builderInferenceAndCoercionToUnit.kt
}
public final fun test(strings: R|kotlin/collections/List<kotlin/String>|): R|kotlin/Unit| {
lval dropDown: R|DropDownComponent<kotlin/String>| = R|/DropDownComponent.DropDownComponent|<R|kotlin/String|>(initialValues = R|kotlin/collections/buildList|<R|kotlin/String|>(<L> = buildList@fun R|kotlin/collections/MutableList<kotlin/String>|.<anonymous>(): R|kotlin/Unit| <inline=Inline, kind=EXACTLY_ONCE> {
lval dropDown: R|DropDownComponent<kotlin/Any>| = R|/DropDownComponent.DropDownComponent|<R|kotlin/Any|>(initialValues = R|kotlin/collections/buildList|<R|kotlin/Any|>(<L> = buildList@fun R|kotlin/collections/MutableList<kotlin/Any>|.<anonymous>(): R|kotlin/Unit| <inline=Inline, kind=EXACTLY_ONCE> {
this@R|special/anonymous|.R|SubstitutionOverride<kotlin/collections/MutableList.addAll: R|kotlin/Boolean|>|(R|<local>/strings|)
}
))
@@ -28,8 +28,8 @@ FILE: buildListLazy.kt
this@R|special/anonymous|.R|kotlin/collections/plusAssign|<R|NameAndSafeValue|>(R|/NameAndSafeValue.NameAndSafeValue|(R|<local>/name|, R|<local>/value|))
}
)
this@R|special/anonymous|.<Inapplicable(INAPPLICABLE): kotlin/collections/sortBy>#<R|NameAndSafeValue|, R|ERROR CLASS: Cannot infer argument for type parameter R|>(<L> = sortBy@fun <anonymous>(it: R|NameAndSafeValue|): <ERROR TYPE REF: Cannot infer argument for type parameter R> <inline=CrossInline, kind=UNKNOWN> {
^ R|<local>/it|.<Unresolved name: name>#
this@R|special/anonymous|.R|kotlin/collections/sortBy|<R|NameAndSafeValue|, R|kotlin/String|>(<L> = sortBy@fun <anonymous>(it: R|NameAndSafeValue|): R|kotlin/String?| <inline=CrossInline, kind=UNKNOWN> {
^ R|<local>/it|.R|/NameAndSafeValue.name|
}
)
}
@@ -7,6 +7,6 @@ private val environment: List<NameAndSafeValue> by lazy {
getEnv().forEach { (name, value) ->
this += NameAndSafeValue(name, value)
}
sortBy { <!ARGUMENT_TYPE_MISMATCH!>it.<!UNRESOLVED_REFERENCE!>name<!><!> }
sortBy { it.name }
}
}
@@ -497,6 +497,9 @@ internal object PostponedVariablesInitializerResolutionStage : ResolutionStage()
if (!parameter.hasBuilderInferenceAnnotation()) continue
val type = parameter.returnTypeRef.coneType
val receiverType = type.receiverType(callInfo.session) ?: continue
val dontUseBuilderInferenceIfPossible =
context.session.languageVersionSettings.supportsFeature(LanguageFeature.UseBuilderInferenceOnlyIfNeeded)
if (dontUseBuilderInferenceIfPossible) continue
for (freshVariable in candidate.freshVariables) {
if (candidate.csBuilder.isPostponedTypeVariable(freshVariable)) continue
@@ -5,10 +5,12 @@
package org.jetbrains.kotlin.fir.resolve.inference
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate
@@ -34,10 +36,11 @@ import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.cast
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class ConstraintSystemCompleter(private val components: BodyResolveComponents, private val context: BodyResolveContext) {
class ConstraintSystemCompleter(components: BodyResolveComponents, private val context: BodyResolveContext) {
private val inferenceComponents = components.session.inferenceComponents
val variableFixationFinder = inferenceComponents.variableFixationFinder
private val postponedArgumentsInputTypesResolver = inferenceComponents.postponedArgumentInputTypesResolver
private val languageVersionSettings = components.session.languageVersionSettings
fun complete(
c: ConstraintSystemCompletionContext,
@@ -47,35 +50,56 @@ class ConstraintSystemCompleter(private val components: BodyResolveComponents, p
context: ResolutionContext,
collectVariablesFromContext: Boolean = false,
analyze: (PostponedResolvedAtom) -> Unit
) = with(c) {
val topLevelTypeVariables = candidateReturnType.extractTypeVariables()
) = c.runCompletion(completionMode, topLevelAtoms, candidateReturnType, context, collectVariablesFromContext, analyze)
c.processForkConstraints()
private fun ConstraintSystemCompletionContext.runCompletion(
completionMode: ConstraintSystemCompletionMode,
topLevelAtoms: List<FirStatement>,
topLevelType: ConeKotlinType,
context: ResolutionContext,
collectVariablesFromContext: Boolean = false,
analyze: (PostponedResolvedAtom) -> Unit
) {
val topLevelTypeVariables = topLevelType.extractTypeVariables()
// NB: it's called in ConstraintSystemForks resolution stage by FE 1.0
processForkConstraints()
completion@ while (true) {
val postponedArguments = getOrderedNotAnalyzedPostponedArguments(topLevelAtoms) // TODO: This is very slow
// TODO: This is very slow
val postponedArguments = getOrderedNotAnalyzedPostponedArguments(topLevelAtoms)
if (completionMode == ConstraintSystemCompletionMode.UNTIL_FIRST_LAMBDA && hasLambdaToAnalyze(postponedArguments)) return
if (completionMode == ConstraintSystemCompletionMode.UNTIL_FIRST_LAMBDA && hasLambdaToAnalyze(
languageVersionSettings,
postponedArguments
)
) return
// Stage 1
if (analyzeArgumentWithFixedParameterTypes(postponedArguments, analyze))
// Stage 1: analyze postponed arguments with fixed parameter types
if (analyzeArgumentWithFixedParameterTypes(languageVersionSettings, postponedArguments, analyze))
continue
val someVariableIsReadyForFixation = isAnyVariableReadyForFixation(
completionMode, topLevelAtoms, candidateReturnType, collectVariablesFromContext, postponedArguments
)
val isThereAnyReadyForFixationVariable = variableFixationFinder.findFirstVariableForFixation(
this,
getOrderedAllTypeVariables(collectVariablesFromContext, topLevelAtoms),
postponedArguments,
completionMode,
topLevelType
) != null
if (postponedArguments.isEmpty() && !someVariableIsReadyForFixation)
// If there aren't any postponed arguments and ready for fixation variables, then completion isn't needed: nothing to do
if (postponedArguments.isEmpty() && !isThereAnyReadyForFixationVariable)
break
val postponedArgumentsWithRevisableType = postponedArguments
.filterIsInstance<PostponedAtomWithRevisableExpectedType>()
// NB: FE 1.0 does not perform this check
.filter { it.revisedExpectedType == null }
val dependencyProvider =
TypeVariableDependencyInformationProvider(notFixedTypeVariables, postponedArguments, candidateReturnType, this)
TypeVariableDependencyInformationProvider(notFixedTypeVariables, postponedArguments, topLevelType, this)
// Stage 2
val newExpectedTypeWasBuilt = postponedArgumentsInputTypesResolver.collectParameterTypesAndBuildNewExpectedTypes(
// Stage 2: collect parameter types for postponed arguments
val wasBuiltNewExpectedTypeForSomeArgument = postponedArgumentsInputTypesResolver.collectParameterTypesAndBuildNewExpectedTypes(
this,
postponedArgumentsWithRevisableType,
completionMode,
@@ -83,19 +107,21 @@ class ConstraintSystemCompleter(private val components: BodyResolveComponents, p
topLevelTypeVariables
)
if (newExpectedTypeWasBuilt)
if (wasBuiltNewExpectedTypeForSomeArgument)
continue
if (completionMode == ConstraintSystemCompletionMode.FULL) {
// Stage 3
// Stage 3: fix variables for parameter types of all postponed arguments
for (argument in postponedArguments) {
val variableWasFixed = postponedArgumentsInputTypesResolver.fixNextReadyVariableForParameterTypeIfNeeded(
this,
argument,
postponedArguments,
candidateReturnType,
topLevelType,
dependencyProvider,
) { // atom provided here is used only inside constraint positions, omitting right now
) {
// NB: FE 1.0 calls findResolvedAtomBy here
// atom provided here is used only inside constraint positions, omitting right now
null
}
@@ -103,10 +129,11 @@ class ConstraintSystemCompleter(private val components: BodyResolveComponents, p
continue@completion
}
// Stage 4
// Stage 4: create atoms with revised expected types if needed
for (argument in postponedArgumentsWithRevisableType) {
val argumentWasTransformed =
transformToAtomWithNewFunctionalExpectedType(this, context, argument)
val argumentWasTransformed = transformToAtomWithNewFunctionalExpectedType(
this, context, argument
)
if (argumentWasTransformed)
continue@completion
@@ -114,17 +141,27 @@ class ConstraintSystemCompleter(private val components: BodyResolveComponents, p
}
// Stage 5: analyze the next ready postponed argument
if (analyzeNextReadyPostponedArgument(postponedArguments, completionMode, analyze))
if (analyzeNextReadyPostponedArgument(languageVersionSettings, postponedArguments, completionMode, analyze))
continue
// Stage 6: fix type variables fix if possible or report not enough information (if completion mode is full)
val variableWasFixed = fixVariablesOrReportNotEnoughInformation(
completionMode, topLevelAtoms, candidateReturnType, collectVariablesFromContext, postponedArguments
// Stage 6: fix next ready type variable with proper constraints
if (fixNextReadyVariable(completionMode, topLevelAtoms, topLevelType, collectVariablesFromContext, postponedArguments))
continue
// Stage 7: try to complete call with the builder inference if there are uninferred type variables
val areThereAppearedProperConstraintsForSomeVariable = tryToCompleteWithBuilderInference(
completionMode, topLevelAtoms, topLevelType, postponedArguments, collectVariablesFromContext, analyze
)
if (variableWasFixed)
if (areThereAppearedProperConstraintsForSomeVariable)
continue
// Stage 7: force analysis of remaining not analyzed postponed arguments and rerun stages if there are
// Stage 8: report "not enough information" for uninferred type variables
reportNotEnoughTypeInformation(
completionMode, topLevelAtoms, topLevelType, collectVariablesFromContext, postponedArguments
)
// Stage 9: force analysis of remaining not analyzed postponed arguments and rerun stages if there are
if (completionMode == ConstraintSystemCompletionMode.FULL) {
if (analyzeRemainingNotAnalyzedPostponedArgument(postponedArguments, analyze))
continue
@@ -134,37 +171,44 @@ class ConstraintSystemCompleter(private val components: BodyResolveComponents, p
}
}
private fun ConstraintSystemCompletionContext.analyzeArgumentWithFixedParameterTypes(
postponedArguments: List<PostponedResolvedAtom>,
analyze: (PostponedResolvedAtom) -> Unit
): Boolean {
val argumentWithFixedOrPostponedInputTypes = findPostponedArgumentWithFixedOrPostponedInputTypes(postponedArguments)
if (argumentWithFixedOrPostponedInputTypes != null) {
analyze(argumentWithFixedOrPostponedInputTypes)
return true
}
return false
}
private fun ConstraintSystemCompletionContext.findPostponedArgumentWithFixedOrPostponedInputTypes(postponedArguments: List<PostponedResolvedAtom>) =
postponedArguments.firstOrNull { argument -> argument.inputTypes.all { containsOnlyFixedOrPostponedVariables(it) } }
private fun ConstraintSystemCompletionContext.isAnyVariableReadyForFixation(
private fun ConstraintSystemCompletionContext.tryToCompleteWithBuilderInference(
completionMode: ConstraintSystemCompletionMode,
topLevelAtoms: List<FirStatement>,
topLevelType: ConeKotlinType,
collectVariablesFromContext: Boolean,
postponedArguments: List<PostponedResolvedAtom>,
collectVariablesFromContext: Boolean,
analyze: (PostponedResolvedAtom) -> Unit
): Boolean {
return variableFixationFinder.findFirstVariableForFixation(
this,
getOrderedAllTypeVariables(this, topLevelAtoms, collectVariablesFromContext),
postponedArguments,
completionMode,
topLevelType
) != null
if (completionMode == ConstraintSystemCompletionMode.PARTIAL) return false
// If we use the builder inference anyway (if the annotation is presented), then we are already analysed builder inference lambdas
if (!languageVersionSettings.supportsFeature(LanguageFeature.UseBuilderInferenceOnlyIfNeeded)) return false
val lambdaArguments = postponedArguments.filterIsInstance<ResolvedLambdaAtom>().takeIf { it.isNotEmpty() } ?: return false
// We assume useBuilderInferenceWithoutAnnotation = true for FIR
for (argument in lambdaArguments) {
val notFixedInputTypeVariables = argument.inputTypes
.map { it.extractTypeVariables() }.flatten().filter { it !in fixedTypeVariables }
if (notFixedInputTypeVariables.isEmpty()) continue
for (variable in notFixedInputTypeVariables) {
getBuilder().markPostponedVariable(notFixedTypeVariables.getValue(variable).typeVariable)
}
analyze(argument)
}
val variableForFixation = variableFixationFinder.findFirstVariableForFixation(
this, getOrderedAllTypeVariables(collectVariablesFromContext, topLevelAtoms), postponedArguments, completionMode, topLevelType
)
// continue completion (rerun stages) only if ready for fixation variables with proper constraints have appeared
// (after analysing a lambda with the builder inference)
// otherwise we don't continue and report "not enough type information" error
return variableForFixation?.hasProperConstraint == true
}
private fun transformToAtomWithNewFunctionalExpectedType(
@@ -186,81 +230,73 @@ class ConstraintSystemCompleter(private val components: BodyResolveComponents, p
return true
}
private fun ConstraintSystemCompletionContext.analyzeNextReadyPostponedArgument(
postponedArguments: List<PostponedResolvedAtom>,
completionMode: ConstraintSystemCompletionMode,
analyze: (PostponedResolvedAtom) -> Unit,
): Boolean {
if (completionMode == ConstraintSystemCompletionMode.FULL) {
val argumentWithTypeVariableAsExpectedType = findPostponedArgumentWithRevisableExpectedType(postponedArguments)
if (argumentWithTypeVariableAsExpectedType != null) {
analyze(argumentWithTypeVariableAsExpectedType)
return true
}
}
return analyzeArgumentWithFixedParameterTypes(postponedArguments, analyze)
}
// Avoiding smart cast from filterIsInstanceOrNull looks dirty
private fun findPostponedArgumentWithRevisableExpectedType(postponedArguments: List<PostponedResolvedAtom>): PostponedResolvedAtom? =
postponedArguments.firstOrNull { argument -> argument is PostponedAtomWithRevisableExpectedType }
private fun ConstraintSystemCompletionContext.fixVariablesOrReportNotEnoughInformation(
private fun ConstraintSystemCompletionContext.fixNextReadyVariable(
completionMode: ConstraintSystemCompletionMode,
topLevelAtoms: List<FirStatement>,
topLevelType: ConeKotlinType,
collectVariablesFromContext: Boolean,
postponedArguments: List<PostponedResolvedAtom>,
): Boolean {
while (true) {
val variableForFixation = variableFixationFinder.findFirstVariableForFixation(
this,
getOrderedAllTypeVariables(this, topLevelAtoms, collectVariablesFromContext),
postponedArguments,
completionMode,
topLevelType
) ?: break
val variableForFixation = variableFixationFinder.findFirstVariableForFixation(
this,
getOrderedAllTypeVariables(collectVariablesFromContext, topLevelAtoms),
postponedArguments,
completionMode,
topLevelType
) ?: return false
if (!variableForFixation.hasProperConstraint && completionMode == ConstraintSystemCompletionMode.PARTIAL)
break
val variableWithConstraints = notFixedTypeVariables.getValue(variableForFixation.variable)
when {
variableForFixation.hasProperConstraint -> {
fixVariable(this, topLevelType, variableWithConstraints, postponedArguments)
return true
}
context.inferenceSession.isSyntheticTypeVariable(variableWithConstraints.typeVariable) -> {
context.inferenceSession.fixSyntheticTypeVariableWithNotEnoughInformation(
variableWithConstraints.typeVariable as ConeTypeVariable,
this
)
return true
}
else -> {
processVariableWhenNotEnoughInformation(this, variableWithConstraints, topLevelAtoms)
}
val variableWithConstraints = notFixedTypeVariables.getValue(variableForFixation.variable)
if (!variableForFixation.hasProperConstraint) {
if (context.inferenceSession.isSyntheticTypeVariable(variableWithConstraints.typeVariable)) {
context.inferenceSession.fixSyntheticTypeVariableWithNotEnoughInformation(
variableWithConstraints.typeVariable as ConeTypeVariable,
this
)
return true
}
return false
}
return false
fixVariable(this, topLevelType, variableWithConstraints, postponedArguments)
return true
}
private fun processVariableWhenNotEnoughInformation(
c: ConstraintSystemCompletionContext,
private fun ConstraintSystemCompletionContext.reportNotEnoughTypeInformation(
completionMode: ConstraintSystemCompletionMode,
topLevelAtoms: List<FirStatement>,
topLevelType: ConeKotlinType,
collectVariablesFromContext: Boolean,
postponedArguments: List<PostponedResolvedAtom>,
) {
while (true) {
val variableForFixation = variableFixationFinder.findFirstVariableForFixation(
this, getOrderedAllTypeVariables(collectVariablesFromContext, topLevelAtoms),
postponedArguments, completionMode, topLevelType,
) ?: break
assert(!variableForFixation.hasProperConstraint) {
"At this stage there should be no remaining variables with proper constraints"
}
if (completionMode == ConstraintSystemCompletionMode.PARTIAL) break
val variableWithConstraints = notFixedTypeVariables.getValue(variableForFixation.variable)
processVariableWhenNotEnoughInformation(variableWithConstraints, topLevelAtoms)
}
}
private fun ConstraintSystemCompletionContext.processVariableWhenNotEnoughInformation(
variableWithConstraints: VariableWithConstraints,
topLevelAtoms: List<FirStatement>,
) {
val typeVariable = variableWithConstraints.typeVariable
val resolvedAtom =
findResolvedAtomBy(typeVariable, topLevelAtoms) ?: topLevelAtoms.firstOrNull()
val resolvedAtom = findResolvedAtomBy(typeVariable, topLevelAtoms) ?: topLevelAtoms.firstOrNull()
if (resolvedAtom != null) {
c.addError(
NotEnoughInformationForTypeParameter(typeVariable, resolvedAtom, c.couldBeResolvedWithUnrestrictedBuilderInference())
addError(
NotEnoughInformationForTypeParameter(typeVariable, resolvedAtom, couldBeResolvedWithUnrestrictedBuilderInference())
)
}
@@ -274,84 +310,19 @@ class ConstraintSystemCompleter(private val components: BodyResolveComponents, p
else -> createCannotInferErrorType("Cannot infer type variable $typeVariable")
}
c.fixVariable(typeVariable, resultErrorType, ConeFixVariableConstraintPosition(typeVariable))
fixVariable(typeVariable, resultErrorType, ConeFixVariableConstraintPosition(typeVariable))
}
private fun createCannotInferErrorType(message: String, isUninferredParameter: Boolean = false) =
ConeClassErrorType(
ConeSimpleDiagnostic(
message,
DiagnosticKind.CannotInferParameterType,
),
isUninferredParameter,
)
private fun findResolvedAtomBy(
typeVariable: TypeVariableMarker,
private fun ConstraintSystemCompletionContext.getOrderedAllTypeVariables(
collectVariablesFromContext: Boolean,
topLevelAtoms: List<FirStatement>
): FirStatement? {
fun FirStatement.findFirstAtomContainingVariable(): FirStatement? {
var result: FirStatement? = null
fun suggestElement(element: FirElement) {
if (result == null && element is FirStatement) {
result = element
}
}
this@findFirstAtomContainingVariable.processAllContainingCallCandidates(processBlocks = true) { candidate ->
if (typeVariable in candidate.freshVariables) {
suggestElement(candidate.callInfo.callSite)
}
for (postponedAtom in candidate.postponedAtoms) {
if (postponedAtom is ResolvedLambdaAtom) {
if (postponedAtom.typeVariableForLambdaReturnType == typeVariable) {
suggestElement(postponedAtom.atom)
}
}
}
}
return result
}
return topLevelAtoms.firstNotNullOfOrNull(FirStatement::findFirstAtomContainingVariable)
}
private fun analyzeRemainingNotAnalyzedPostponedArgument(
postponedArguments: List<PostponedResolvedAtom>,
analyze: (PostponedResolvedAtom) -> Unit
): Boolean {
val remainingNotAnalyzedPostponedArgument = postponedArguments.firstOrNull { !it.analyzed }
if (remainingNotAnalyzedPostponedArgument != null) {
analyze(remainingNotAnalyzedPostponedArgument)
return true
}
return false
}
private fun ConstraintSystemCompletionContext.hasLambdaToAnalyze(
postponedArguments: List<PostponedResolvedAtom>
): Boolean {
return analyzeArgumentWithFixedParameterTypes(postponedArguments) {}
}
private fun getOrderedAllTypeVariables(
c: ConstraintSystemCompletionContext,
topLevelAtoms: List<FirStatement>,
collectVariablesFromContext: Boolean
): List<TypeConstructorMarker> = with(c) {
): List<TypeConstructorMarker> {
if (collectVariablesFromContext) {
return c.notFixedTypeVariables.keys.toList()
return notFixedTypeVariables.keys.toList()
}
val result = LinkedHashSet<TypeConstructorMarker>(c.notFixedTypeVariables.size)
val result = LinkedHashSet<TypeConstructorMarker>(notFixedTypeVariables.size)
fun ConeTypeVariable?.toTypeConstructor(): TypeConstructorMarker? =
this?.typeConstructor?.takeIf { it in c.notFixedTypeVariables.keys }
this?.typeConstructor?.takeIf { it in notFixedTypeVariables.keys }
// TODO: non-top-level variables?
fun PostponedAtomWithRevisableExpectedType.collectNotFixedVariables() {
@@ -372,33 +343,35 @@ class ConstraintSystemCompleter(private val components: BodyResolveComponents, p
}
for (postponedAtom in candidate.postponedAtoms) {
when {
postponedAtom is ResolvedLambdaAtom -> {
when (postponedAtom) {
is ResolvedLambdaAtom -> {
result.addIfNotNull(postponedAtom.typeVariableForLambdaReturnType.toTypeConstructor())
}
postponedAtom is LambdaWithTypeVariableAsExpectedTypeAtom -> {
is LambdaWithTypeVariableAsExpectedTypeAtom -> {
postponedAtom.collectNotFixedVariables()
}
postponedAtom is ResolvedCallableReferenceAtom -> {
is ResolvedCallableReferenceAtom -> {
if (postponedAtom.mightNeedAdditionalResolution) {
postponedAtom.collectNotFixedVariables()
}
}
// ResolvedCallAtom?
// ResolvedCallableReferenceArgumentAtom?
}
}
}
}
for (topLevel in topLevelAtoms) {
topLevel.collectAllTypeVariables()
for (topLevelAtom in topLevelAtoms) {
topLevelAtom.collectAllTypeVariables()
}
if (context.inferenceSession.hasSyntheticTypeVariables()) {
result.addAll(c.notFixedTypeVariables.filter { context.inferenceSession.isSyntheticTypeVariable(it.value.typeVariable) }.keys.asIterable())
result.addAll(notFixedTypeVariables.filter { context.inferenceSession.isSyntheticTypeVariable(it.value.typeVariable) }.keys.asIterable())
}
require(result.size == c.notFixedTypeVariables.size) {
val notFoundTypeVariables = c.notFixedTypeVariables.keys.toMutableSet().apply { removeAll(result) }
require(result.size == notFixedTypeVariables.size) {
val notFoundTypeVariables = notFixedTypeVariables.keys.toMutableSet().apply { removeAll(result) }
"Not all type variables found: $notFoundTypeVariables"
}
@@ -417,21 +390,69 @@ class ConstraintSystemCompleter(private val components: BodyResolveComponents, p
c.fixVariable(variable, resultType, ConeFixVariableConstraintPosition(variable)) // TODO: obtain atom for diagnostics
}
private fun getOrderedNotAnalyzedPostponedArguments(topLevelAtoms: List<FirStatement>): List<PostponedResolvedAtom> {
val notAnalyzedArguments = arrayListOf<PostponedResolvedAtom>()
for (primitive in topLevelAtoms) {
primitive.processAllContainingCallCandidates(
// TODO: remove this argument and relevant parameter
// Currently, it's used because otherwise problem happens with a lambda in a try-block (see tryWithLambdaInside test)
processBlocks = true
) { candidate ->
candidate.postponedAtoms.forEach {
notAnalyzedArguments.addIfNotNull(it.safeAs<PostponedResolvedAtom>()?.takeUnless { it.analyzed })
companion object {
private fun getOrderedNotAnalyzedPostponedArguments(topLevelAtoms: List<FirStatement>): List<PostponedResolvedAtom> {
val notAnalyzedArguments = arrayListOf<PostponedResolvedAtom>()
for (primitive in topLevelAtoms) {
primitive.processAllContainingCallCandidates(
// TODO: remove this argument and relevant parameter
// Currently, it's used because otherwise problem happens with a lambda in a try-block (see tryWithLambdaInside test)
processBlocks = true
) { candidate ->
candidate.postponedAtoms.forEach { atom ->
notAnalyzedArguments.addIfNotNull(atom.safeAs<PostponedResolvedAtom>()?.takeUnless { it.analyzed })
}
}
}
return notAnalyzedArguments
}
return notAnalyzedArguments
private fun findResolvedAtomBy(
typeVariable: TypeVariableMarker,
topLevelAtoms: List<FirStatement>
): FirStatement? {
fun FirStatement.findFirstAtomContainingVariable(): FirStatement? {
var result: FirStatement? = null
fun suggestElement(element: FirElement) {
if (result == null && element is FirStatement) {
result = element
}
}
this@findFirstAtomContainingVariable.processAllContainingCallCandidates(processBlocks = true) { candidate ->
if (typeVariable in candidate.freshVariables) {
suggestElement(candidate.callInfo.callSite)
}
for (postponedAtom in candidate.postponedAtoms) {
if (postponedAtom is ResolvedLambdaAtom) {
if (postponedAtom.typeVariableForLambdaReturnType == typeVariable) {
suggestElement(postponedAtom.atom)
}
}
}
}
return result
}
return topLevelAtoms.firstNotNullOfOrNull(FirStatement::findFirstAtomContainingVariable)
}
private fun createCannotInferErrorType(message: String, isUninferredParameter: Boolean = false) =
ConeClassErrorType(
ConeSimpleDiagnostic(
message,
DiagnosticKind.CannotInferParameterType,
),
isUninferredParameter,
)
}
}