~
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt index 460eb3f..83150b7 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt
@@ -30,7 +30,7 @@ import org.jetbrains.kotlin.resolve.calls.tower.isSuccess class Candidate( - override val symbol: FirBasedSymbol<*>, + override var symbol: FirBasedSymbol<*>, // Here we may have an ExpressionReceiverValue // - in case a use-site receiver is explicit // - in some cases with static entities, no matter is a use-site receiver explicit or not
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateFactory.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateFactory.kt index 90bb08a..09d81e3 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateFactory.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateFactory.kt
@@ -39,7 +39,7 @@ callInfo.arguments.forEach { system.addSubsystemFromExpression(it) } - system.addOtherSystem(context.bodyResolveContext.inferenceSession.currentConstraintStorage) + system.addOtherSystem(context.bodyResolveContext.outerConstraintStorage) return system.asReadOnlyStorage() } }
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirBuilderInferenceSession.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirBuilderInferenceSession.kt index 43ff953..9828fdc 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirBuilderInferenceSession.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirBuilderInferenceSession.kt
@@ -10,8 +10,8 @@ import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.hasAnnotation -import org.jetbrains.kotlin.fir.expressions.* -import org.jetbrains.kotlin.fir.render +import org.jetbrains.kotlin.fir.expressions.FirResolvable +import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.resolve.calls.Candidate import org.jetbrains.kotlin.fir.resolve.calls.ImplicitExtensionReceiverValue import org.jetbrains.kotlin.fir.resolve.calls.ResolutionContext @@ -19,7 +19,6 @@ import org.jetbrains.kotlin.fir.resolve.substitution.ChainedSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.replaceStubsAndTypeVariablesToErrors -import org.jetbrains.kotlin.fir.resolve.transformers.FirCallCompletionResultsWriterTransformer import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.visitors.FirDefaultTransformer import org.jetbrains.kotlin.fir.visitors.transformSingle @@ -27,7 +26,9 @@ import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder import org.jetbrains.kotlin.resolve.calls.inference.buildAbstractResultingSubstitutor import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintSystemCompletionMode -import org.jetbrains.kotlin.resolve.calls.inference.model.* +import org.jetbrains.kotlin.resolve.calls.inference.model.BuilderInferencePosition +import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage +import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl import org.jetbrains.kotlin.resolve.calls.inference.registerTypeVariableIfNotPresent import org.jetbrains.kotlin.resolve.descriptorUtil.BUILDER_INFERENCE_ANNOTATION_FQ_NAME import org.jetbrains.kotlin.types.model.TypeConstructorMarker @@ -45,9 +46,6 @@ private val commonCalls: MutableList<Pair<FirStatement, Candidate>> = mutableListOf() private var lambdaImplicitReceivers: MutableList<ImplicitExtensionReceiverValue> = mutableListOf() - override val currentConstraintStorage: ConstraintStorage - get() = ConstraintStorage.Empty - override fun hasSyntheticTypeVariables(): Boolean = false override fun isSyntheticTypeVariable(typeVariable: TypeVariableMarker): Boolean {
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt index 4081787..d53671e 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt
@@ -33,7 +33,6 @@ import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl import org.jetbrains.kotlin.fir.visitors.transformSingle -import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.calls.inference.addEqualityConstraintIfCompatible import org.jetbrains.kotlin.resolve.calls.inference.addSubtypeConstraintIfCompatible import org.jetbrains.kotlin.resolve.calls.inference.buildAbstractResultingSubstitutor @@ -42,6 +41,7 @@ import org.jetbrains.kotlin.types.model.StubTypeMarker import org.jetbrains.kotlin.types.model.TypeVariableMarker import org.jetbrains.kotlin.types.model.safeSubstitute +import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.utils.addToStdlib.runIf class FirCallCompleter( @@ -83,6 +83,25 @@ call.replaceLambdaArgumentInvocationKinds(session) } + if (inferenceSession.skipCompletion(call, resolutionMode, completionMode)) { + if (candidate.callInfo.name == OperatorNameConventions.PROVIDE_DELEGATE && resolutionMode != ResolutionMode.ContextDependentDelegate) { + val inferenceSession = inferenceSession as FirDelegatedPropertyInferenceSession + + val innerSet = candidate.freshVariables.mapTo(mutableSetOf()) { it.typeConstructor } + inferenceSession.currentConstraintSystem.withDisallowingOnlyThisTypeVariablesForProperTypes(innerSet) { + runCompletionForCall(candidate, ConstraintSystemCompletionMode.FULL, call, initialType, analyzer) + } + } else { + runCompletionForCall(candidate, ConstraintSystemCompletionMode.PARTIAL, call, initialType, analyzer) + } + // Running completion at least partially is required to filter out some of the candidates of subsequent calls, + // thus avoiding resolution ambiguity for them. + // Can't use `completionCall` in case it's FULL, because we can't force getValue() completion until BI lambdas in delegate expression are completed + // But those lambdas cannot be found at getValeu() calls as they don't belong there + + return call + } + return when (completionMode) { ConstraintSystemCompletionMode.FULL -> { if (inferenceSession.shouldRunCompletion(call)) { @@ -91,7 +110,7 @@ .buildAbstractResultingSubstitutor(session.typeContext) as ConeSubstitutor val completedCall = call.transformSingle( FirCallCompletionResultsWriterTransformer( - session, finalSubstitutor, + session, components.scopeSession, finalSubstitutor, components.returnTypeCalculator, session.typeApproximator, components.dataFlowAnalyzer, @@ -111,12 +130,6 @@ ConstraintSystemCompletionMode.PARTIAL -> { runCompletionForCall(candidate, completionMode, call, initialType, analyzer) - // Add top-level delegate call as partially resolved to inference session - if (resolutionMode is ResolutionMode.ContextDependentDelegate) { - require(inferenceSession is FirDelegatedPropertyInferenceSession) - inferenceSession.addPartiallyResolvedCall(call) - } - call } @@ -210,7 +223,7 @@ mode: FirCallCompletionResultsWriterTransformer.Mode = FirCallCompletionResultsWriterTransformer.Mode.Normal ): FirCallCompletionResultsWriterTransformer { return FirCallCompletionResultsWriterTransformer( - session, substitutor, components.returnTypeCalculator, + session, components.scopeSession, substitutor, components.returnTypeCalculator, session.typeApproximator, components.dataFlowAnalyzer, components.integerLiteralAndOperatorApproximationTransformer,
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirDelegatedPropertyInferenceSession.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirDelegatedPropertyInferenceSession.kt index a40d858..d66b3d6 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirDelegatedPropertyInferenceSession.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirDelegatedPropertyInferenceSession.kt
@@ -6,22 +6,28 @@ package org.jetbrains.kotlin.fir.resolve.inference import org.jetbrains.kotlin.fir.declarations.FirProperty +import org.jetbrains.kotlin.fir.expressions.FirFunctionCall +import org.jetbrains.kotlin.fir.expressions.FirFunctionCallOrigin import org.jetbrains.kotlin.fir.expressions.FirResolvable import org.jetbrains.kotlin.fir.expressions.FirStatement -import org.jetbrains.kotlin.fir.resolve.calls.* -import org.jetbrains.kotlin.fir.resolve.inference.model.ConeFixVariableConstraintPosition -import org.jetbrains.kotlin.fir.resolve.substitution.* +import org.jetbrains.kotlin.fir.resolve.ResolutionMode +import org.jetbrains.kotlin.fir.resolve.calls.Candidate +import org.jetbrains.kotlin.fir.resolve.calls.InferenceError +import org.jetbrains.kotlin.fir.resolve.calls.ResolutionContext +import org.jetbrains.kotlin.fir.resolve.calls.candidate +import org.jetbrains.kotlin.fir.resolve.substitution.ChainedSubstitutor +import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.types.* +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder -import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem import org.jetbrains.kotlin.resolve.calls.inference.buildAbstractResultingSubstitutor import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintSystemCompletionContext import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintSystemCompletionMode -import org.jetbrains.kotlin.resolve.calls.inference.model.BuilderInferencePosition import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl -import org.jetbrains.kotlin.resolve.calls.inference.registerTypeVariableIfNotPresent -import org.jetbrains.kotlin.types.model.* +import org.jetbrains.kotlin.types.model.TypeConstructorMarker +import org.jetbrains.kotlin.types.model.TypeVariableMarker +import org.jetbrains.kotlin.util.OperatorNameConventions class FirDelegatedPropertyInferenceSession( val property: FirProperty, @@ -29,141 +35,81 @@ private val postponedArgumentsAnalyzer: PostponedArgumentsAnalyzer, ) : FirInferenceSessionForChainedResolve(resolutionContext) { - private val currentConstraintSystem = components.session.inferenceComponents.createConstraintSystem() - override val currentConstraintStorage: ConstraintStorage get() = currentConstraintSystem.currentStorage() + var currentConstraintSystem = components.session.inferenceComponents.createConstraintSystem() + val currentConstraintStorage: ConstraintStorage get() = currentConstraintSystem.currentStorage() private val unitType: ConeClassLikeType = components.session.builtinTypes.unitType.type - private lateinit var resultingConstraintSystem: NewConstraintSystem - - private fun ConeKotlinType.containsStubType(): Boolean { - return this.contains { - it is ConeStubTypeForChainInference - } - } - - private fun integrateResolvedCall(storage: ConstraintStorage) { - registerSyntheticVariables(storage) - val stubToTypeVariableSubstitutor = createToSyntheticTypeVariableSubstitutor() - integrateConstraints( - currentConstraintSystem, - storage, - stubToTypeVariableSubstitutor, - false - ) - } override fun <T> addCompletedCall(call: T, candidate: Candidate) where T : FirResolvable, T : FirStatement { - partiallyResolvedCalls += call to candidate - if (candidate.isSuccessful) { - integrateResolvedCall(candidate.system.asReadOnlyStorage()) - } + // TODO } override fun <T> addPartiallyResolvedCall(call: T) where T : FirResolvable, T : FirStatement { - super.addPartiallyResolvedCall(call) - if (call.candidate.isSuccessful) { - integrateResolvedCall(call.candidate.system.currentStorage()) - } + // TODO } - override fun <T> shouldRunCompletion(call: T): Boolean where T : FirResolvable, T : FirStatement { - val callee = call.calleeReference as? FirNamedReferenceWithCandidate ?: return true + override fun <T> shouldRunCompletion(call: T): Boolean where T : FirResolvable, T : FirStatement = true - if (callee.candidate.system.hasContradiction) return true + override fun <R> onCandidatesResolution(call: FirFunctionCall, candidatesResolutionCallback: () -> R): R { + return if (!call.isAnyOfDelegateOperators()) + candidatesResolutionCallback() + else + resolutionContext.bodyResolveContext.withOuterConstraintStorage( + currentConstraintSystem.currentStorage(), + candidatesResolutionCallback + ) + } - val hasStubType = - callee.candidate.chosenExtensionReceiver?.typeRef?.coneType?.containsStubType() ?: false - || callee.candidate.dispatchReceiver?.typeRef?.coneType?.containsStubType() ?: false + override fun <T> skipCompletion( + call: T, + resolutionMode: ResolutionMode, + completionMode: ConstraintSystemCompletionMode + ): Boolean where T : FirResolvable, T : FirStatement { + if (!call.candidate.isSuccessful && call.isOperatorCallWithName { it == OperatorNameConventions.PROVIDE_DELEGATE }) return false + // Do not run completion for provideDelegate/getValue/setValue because they might affect each other + if (completionMode == ConstraintSystemCompletionMode.FULL && resolutionMode == ResolutionMode.ContextDependentDelegate) return false - if (!hasStubType) { + if (resolutionMode == ResolutionMode.ContextDependentDelegate || call.isAnyOfDelegateOperators()) { + partiallyResolvedCalls.add(call to call.candidate) + currentConstraintSystem = call.candidate.system return true } - val system = call.candidate.system - - val storage = system.getBuilder().currentStorage() - - if (call.hasPostponed()) return true - - return storage.notFixedTypeVariables.keys.all { - val variable = storage.allTypeVariables[it] - val isPostponed = variable != null && variable in storage.postponedTypeVariables - isPostponed || isSyntheticTypeVariable(variable!!) || - components.callCompleter.completer.variableFixationFinder.isTypeVariableHasProperConstraint(system, it) - } + return false } - private fun FirStatement.hasPostponed(): Boolean { - var result = false - processAllContainingCallCandidates(processBlocks = false) { - result = result || it.hasPostponed() - } - return result + private fun <T> T.isAnyOfDelegateOperators(): Boolean where T : FirResolvable, T : FirStatement = isOperatorCallWithName { + it == OperatorNameConventions.PROVIDE_DELEGATE || it == OperatorNameConventions.GET_VALUE || it == OperatorNameConventions.SET_VALUE } - private fun Candidate.hasPostponed(): Boolean { - return postponedAtoms.any { !it.analyzed } + private fun <T> T.isOperatorCallWithName(predicate: (Name) -> Boolean): Boolean where T : FirResolvable, T : FirStatement { + if (this !is FirFunctionCall) return false + val name = calleeReference.name + if (!predicate(name)) return false + + return origin == FirFunctionCallOrigin.Operator } + override fun inferPostponedVariables( lambda: ResolvedLambdaAtom, constraintSystemBuilder: ConstraintSystemBuilder, completionMode: ConstraintSystemCompletionMode ): Map<ConeTypeVariableTypeConstructor, ConeKotlinType>? = null - private fun createNonFixedTypeToVariableSubstitutor(): NotFixedTypeToVariableSubstitutorForDelegateInference { - val typeContext = components.session.typeContext - - val bindings = mutableMapOf<TypeVariableMarker, ConeKotlinType>() - for ((variable, synthetic) in syntheticTypeVariableByTypeVariable) { - bindings[synthetic] = variable.defaultType(typeContext) as ConeKotlinType - } - - return NotFixedTypeToVariableSubstitutorForDelegateInference(bindings, typeContext) - } - - - /* - * This creates Stub-preserving substitution to synthetic type variables - * Stub(R) => Stub(_R) - * R => _R - */ - private fun createToSyntheticTypeVariableSubstitutor(): ConeSubstitutor { - - val typeContext = components.session.typeContext - val bindings = mutableMapOf<TypeConstructorMarker, ConeKotlinType>() - for ((variable, syntheticVariable) in syntheticTypeVariableByTypeVariable) { - bindings[variable.freshTypeConstructor(typeContext)] = syntheticVariable.defaultType - } - - return typeContext.typeSubstitutorByTypeConstructor(bindings) - } - - override fun hasSyntheticTypeVariables(): Boolean { - return syntheticTypeVariableByTypeVariable.isNotEmpty() - } - - override fun isSyntheticTypeVariable(typeVariable: TypeVariableMarker): Boolean { - return typeVariable in syntheticTypeVariableByTypeVariable.values + override fun createSyntheticStubTypes(system: NewConstraintSystemImpl): Map<TypeConstructorMarker, ConeStubType> { + TODO("Not yet implemented") } override fun fixSyntheticTypeVariableWithNotEnoughInformation( typeVariable: TypeVariableMarker, completionContext: ConstraintSystemCompletionContext ) { - typeVariable as ConeTypeVariable - completionContext.fixVariable( - typeVariable, - ConeStubTypeForSyntheticFixation( - ConeStubTypeConstructor(typeVariable, isTypeVariableInSubtyping = false, isForFixation = true), - ConeNullability.create(typeVariable.defaultType.isMarkedNullable) - ), - ConeFixVariableConstraintPosition(typeVariable) - ) + error("") } fun completeCandidates(): List<FirResolvable> { - val commonSystem = components.session.inferenceComponents.createConstraintSystem() + val commonSystem = currentConstraintSystem val notCompletedCalls = partiallyResolvedCalls.mapNotNull { partiallyResolvedCall -> partiallyResolvedCall.first.takeIf { resolvable -> @@ -171,20 +117,6 @@ } } - val stubToTypeVariableSubstitutor = createNonFixedTypeToVariableSubstitutor() - - for ((call, candidate) in partiallyResolvedCalls) { - if (candidate.isSuccessful) { - integrateConstraints( - commonSystem, - candidate.system.asReadOnlyStorage(), - stubToTypeVariableSubstitutor, - call.candidate() != null - ) - } - } - - resolutionContext.bodyResolveContext.withInferenceSession(DEFAULT) { @Suppress("UNCHECKED_CAST") components.callCompleter.completer.complete( @@ -218,97 +150,20 @@ } } - resultingConstraintSystem = commonSystem return notCompletedCalls } fun createFinalSubstitutor(): ConeSubstitutor { - val stubTypeSubstitutor = createNonFixedTypeToVariableSubstitutor() - val typeContext = components.session.typeContext - val resultSubstitutor = resultingConstraintSystem.asReadOnlyStorage() + + val t = currentConstraintSystem.asReadOnlyStorage() .buildAbstractResultingSubstitutor(typeContext) as ConeSubstitutor - return ChainedSubstitutor(stubTypeSubstitutor, resultSubstitutor) - .replaceStubsAndTypeVariablesToErrors(typeContext, stubTypesByTypeVariable.values.map { it.constructor }) + + // TODO: TT?? + return ChainedSubstitutor(t, t) } - private val stubTypesByTypeVariable: MutableMap<ConeTypeVariable, ConeStubType> = mutableMapOf() - private val syntheticTypeVariableByTypeVariable = mutableMapOf<TypeVariableMarker, ConeTypeVariable>() + override fun hasSyntheticTypeVariables(): Boolean = false - private fun registerSyntheticVariables(storage: ConstraintStorage) { - for (variableWithConstraints in storage.notFixedTypeVariables.values) { - val variable = variableWithConstraints.typeVariable as ConeTypeVariable - - val syntheticVariable = syntheticTypeVariableByTypeVariable.getOrPut(variable) { - ConeTypeVariable("_" + variable.typeConstructor.name).also { - currentConstraintSystem.registerVariable(it) - } - } - - stubTypesByTypeVariable.getOrPut(variable) { - ConeStubTypeForChainInference( - syntheticVariable, - ConeNullability.create(syntheticVariable.defaultType.isMarkedNullable) - ) - } - } - } - - override fun createSyntheticStubTypes(system: NewConstraintSystemImpl): Map<TypeConstructorMarker, ConeStubType> { - - val bindings = mutableMapOf<TypeConstructorMarker, ConeStubType>() - registerSyntheticVariables(system.currentStorage()) - for (variable in system.postponedTypeVariables) { - variable as ConeTypeVariable - - bindings[variable.typeConstructor] = stubTypesByTypeVariable[variable]!! - } - - return bindings - } - - override fun registerStubTypes(map: Map<TypeVariableMarker, StubTypeMarker>) { -// @Suppress("UNCHECKED_CAST") -// stubTypesByTypeVariable.putAll(map as Map<ConeTypeVariable, ConeStubType>) - } - - - private fun integrateConstraints( - commonSystem: NewConstraintSystemImpl, - storage: ConstraintStorage, - nonFixedToVariablesSubstitutor: ConeSubstitutor, - shouldIntegrateAllConstraints: Boolean - ) { - if (shouldIntegrateAllConstraints) { - storage.notFixedTypeVariables.values.forEach { - if (isSyntheticTypeVariable(it.typeVariable)) return@forEach - commonSystem.registerTypeVariableIfNotPresent(it.typeVariable) - } - } - /* - * storage can contain the following substitutions: - * TypeVariable(A) -> ProperType - * TypeVariable(B) -> Special-Non-Fixed-Type - * - * while substitutor from parameter map non-fixed types to the original type variable - * */ - val callSubstitutor = - storage.buildAbstractResultingSubstitutor(commonSystem, transformTypeVariablesToErrorTypes = false) as ConeSubstitutor - - for (initialConstraint in storage.initialConstraints) { - integrateConstraintToSystem( - commonSystem, initialConstraint, callSubstitutor, nonFixedToVariablesSubstitutor, storage.fixedTypeVariables - ) - } - - if (shouldIntegrateAllConstraints) { - for ((variableConstructor, type) in storage.fixedTypeVariables) { - val typeVariable = storage.allTypeVariables.getValue(variableConstructor) - if (isSyntheticTypeVariable(typeVariable)) continue - - commonSystem.registerTypeVariableIfNotPresent(typeVariable) - commonSystem.addEqualityConstraint((typeVariable as ConeTypeVariable).defaultType, type, BuilderInferencePosition) - } - } - } + override fun isSyntheticTypeVariable(typeVariable: TypeVariableMarker): Boolean = false }
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirInferenceSession.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirInferenceSession.kt index 3e7f83d..4157308 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirInferenceSession.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirInferenceSession.kt
@@ -5,8 +5,10 @@ package org.jetbrains.kotlin.fir.resolve.inference +import org.jetbrains.kotlin.fir.expressions.FirFunctionCall import org.jetbrains.kotlin.fir.expressions.FirResolvable import org.jetbrains.kotlin.fir.expressions.FirStatement +import org.jetbrains.kotlin.fir.resolve.ResolutionMode import org.jetbrains.kotlin.fir.resolve.calls.Candidate import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.ConeStubType @@ -14,7 +16,6 @@ import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintSystemCompletionContext import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintSystemCompletionMode -import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl import org.jetbrains.kotlin.types.model.StubTypeMarker import org.jetbrains.kotlin.types.model.TypeConstructorMarker @@ -26,7 +27,11 @@ } abstract fun <T> shouldRunCompletion(call: T): Boolean where T : FirResolvable, T : FirStatement - abstract val currentConstraintStorage: ConstraintStorage + open fun <T> skipCompletion( + call: T, + resolutionMode: ResolutionMode, + completionMode: ConstraintSystemCompletionMode + ): Boolean where T : FirResolvable, T : FirStatement = false abstract fun <T> addPartiallyResolvedCall(call: T) where T : FirResolvable, T : FirStatement abstract fun <T> addCompletedCall(call: T, candidate: Candidate) where T : FirResolvable, T : FirStatement @@ -49,14 +54,12 @@ abstract fun clear() abstract fun createSyntheticStubTypes(system: NewConstraintSystemImpl): Map<TypeConstructorMarker, ConeStubType> + open fun <R> onCandidatesResolution(call: FirFunctionCall, candidatesResolutionCallback: () -> R) = candidatesResolutionCallback() } abstract class FirStubInferenceSession : FirInferenceSession() { override fun <T> shouldRunCompletion(call: T): Boolean where T : FirResolvable, T : FirStatement = true - override val currentConstraintStorage: ConstraintStorage - get() = ConstraintStorage.Empty - override fun <T> addPartiallyResolvedCall(call: T) where T : FirResolvable, T : FirStatement {} override fun <T> addCompletedCall(call: T, candidate: Candidate) where T : FirResolvable, T : FirStatement {}
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt index aa90ddd..4e2389f 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt
@@ -30,12 +30,16 @@ import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeTypeParameterInQualifiedAccess import org.jetbrains.kotlin.fir.resolve.inference.ResolvedLambdaAtom import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor +import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.* +import org.jetbrains.kotlin.fir.scopes.FakeOverrideTypeCalculator import org.jetbrains.kotlin.fir.scopes.impl.ConvertibleIntegerOperators.binaryOperatorsWithSignedArgument +import org.jetbrains.kotlin.fir.scopes.impl.FirClassSubstitutionScope import org.jetbrains.kotlin.fir.scopes.impl.isWrappedIntegerOperator import org.jetbrains.kotlin.fir.scopes.impl.isWrappedIntegerOperatorForUnsignedType import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.fir.types.* @@ -58,6 +62,7 @@ class FirCallCompletionResultsWriterTransformer( override val session: FirSession, + private val scopeSession: ScopeSession, private val finalSubstitutor: ConeSubstitutor, private val typeCalculator: ReturnTypeCalculator, private val typeApproximator: ConeTypeApproximator, @@ -101,6 +106,9 @@ qualifiedAccessExpression: T, calleeReference: FirNamedReferenceWithCandidate, ): T { val subCandidate = calleeReference.candidate + + subCandidate.refineSubstitutedSymbol() + val declaration = subCandidate.symbol.fir val typeArguments = computeTypeArguments(qualifiedAccessExpression, subCandidate) val typeRef = if (declaration is FirCallableDeclaration) { @@ -134,6 +142,12 @@ } } + if (mode == Mode.DelegatedPropertyCompletion) { + // Update type for `$delegateField` in `$$delegateField.get/setValue()` calls inside accessors + val typeUpdater = TypeUpdaterForDelegateArguments() + qualifiedAccessExpression.transformExplicitReceiver(typeUpdater, null) + } + var dispatchReceiver = subCandidate.dispatchReceiverExpression() var extensionReceiver = subCandidate.chosenExtensionReceiverExpression() if (!declaration.isWrappedIntegerOperator()) { @@ -169,18 +183,58 @@ return qualifiedAccessExpression } + private fun Candidate.refineSubstitutedSymbol() { + val updatedSymbol = symbol.refineSubstitutedSymbol() ?: return + val oldSymbol = symbol + symbol = updatedSymbol + + if (updatedSymbol !is FirFunctionSymbol) return + require(oldSymbol is FirFunctionSymbol) + + val oldArgumentMapping = argumentMapping ?: return + val oldValueParametersToNewMap = oldSymbol.valueParameterSymbols.zip(updatedSymbol.valueParameterSymbols).toMap() + + argumentMapping = oldArgumentMapping.mapValuesTo(linkedMapOf()) { + oldValueParametersToNewMap[it.value.symbol]!!.fir + } + + substitutor = substitutorByMap( + updatedSymbol.typeParameterSymbols.zip(freshVariables).associate { (typeParameter, typeVariable) -> + typeParameter to typeVariable.defaultType + }, + session, + ) + } + + private fun FirBasedSymbol<*>.refineSubstitutedSymbol(): FirBasedSymbol<*>? { + val fir = fir + if (fir !is FirCallableDeclaration) return null + + val dispatchReceiverType = fir.dispatchReceiverType ?: return null + val updatedDispatchReceiverType = finalSubstitutor.substituteOrNull(dispatchReceiverType) ?: return null + + val scope = + updatedDispatchReceiverType.scope( + session, + scopeSession, + FakeOverrideTypeCalculator.DoNothing, + FirResolvePhase.STATUS + ) as? FirClassSubstitutionScope ?: return null + + return when (val original = fir.originalForSubstitutionOverride) { + is FirSimpleFunction -> scope.createSubstitutionOverrideFunction(original.symbol) + is FirProperty -> scope.createSubstitutionOverrideProperty(original.symbol) + is FirConstructor -> scope.createSubstitutionOverrideConstructor(original.symbol) + else -> error("!!!") + } + } + override fun transformQualifiedAccessExpression( qualifiedAccessExpression: FirQualifiedAccessExpression, data: ExpectedArgumentType?, ): FirStatement { val calleeReference = qualifiedAccessExpression.calleeReference as? FirNamedReferenceWithCandidate - ?: return run { - if (mode == Mode.DelegatedPropertyCompletion) { - val typeUpdater = TypeUpdaterForDelegateArguments() - qualifiedAccessExpression.transformSingle(typeUpdater, null) - } - qualifiedAccessExpression - } + ?: return qualifiedAccessExpression val result = prepareQualifiedTransform(qualifiedAccessExpression, calleeReference) val typeRef = result.typeRef as FirResolvedTypeRef val subCandidate = calleeReference.candidate @@ -190,11 +244,6 @@ result.replaceTypeRef(resultType) session.lookupTracker?.recordTypeResolveAsLookup(resultType, qualifiedAccessExpression.source, context.file.source) - if (mode == Mode.DelegatedPropertyCompletion) { - val typeUpdater = TypeUpdaterForDelegateArguments() - result.transformExplicitReceiver(typeUpdater, null) - } - return result } @@ -242,12 +291,6 @@ result.replaceTypeRef(resultType) session.lookupTracker?.recordTypeResolveAsLookup(resultType, functionCall.source, context.file.source) - if (mode == Mode.DelegatedPropertyCompletion) { - val typeUpdater = TypeUpdaterForDelegateArguments() - result.argumentList.transformArguments(typeUpdater, null) - result.transformExplicitReceiver(typeUpdater, null) - } - if (enableArrayOfCallTransformation) { return arrayOfCallTransformer.transformFunctionCall(result, session) }
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/BodyResolveContext.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/BodyResolveContext.kt index 08f0a05..4d67a23 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/BodyResolveContext.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/BodyResolveContext.kt
@@ -7,13 +7,15 @@ import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.ClassKind -import org.jetbrains.kotlin.fir.* +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.correspondingProperty import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor import org.jetbrains.kotlin.fir.declarations.utils.isCompanion import org.jetbrains.kotlin.fir.declarations.utils.isInner import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess import org.jetbrains.kotlin.fir.expressions.FirWhenExpression +import org.jetbrains.kotlin.fir.languageVersionSettings import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.calls.ImplicitExtensionReceiverValue import org.jetbrains.kotlin.fir.resolve.calls.ImplicitReceiverValue @@ -38,6 +40,7 @@ import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.SpecialNames.UNDERSCORE_FOR_UNUSED_VAR +import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage import org.jetbrains.kotlin.util.PrivateForInline class BodyResolveContext( @@ -87,6 +90,12 @@ @set:PrivateForInline var inferenceSession: FirInferenceSession = FirInferenceSession.DEFAULT + @set:PrivateForInline + var currentDelegatedPropertyInferenceSession: FirDelegatedPropertyInferenceSession? = null + + @set:PrivateForInline + var outerConstraintStorage: ConstraintStorage = ConstraintStorage.Empty + val anonymousFunctionsAnalyzedInDependentContext: MutableSet<FirFunctionSymbol<*>> = mutableSetOf() var containingClassDeclarations: ArrayDeque<FirRegularClass> = ArrayDeque() @@ -814,6 +823,7 @@ } } + @OptIn(PrivateForInline::class) inline fun <T> forPropertyDelegateAccessors( property: FirProperty, resolutionContext: ResolutionContext, @@ -826,12 +836,35 @@ callCompleter.createPostponedArgumentsAnalyzer(resolutionContext) ) +// val oldSession = this.currentDelegatedPropertyInferenceSession +// this.currentDelegatedPropertyInferenceSession = inferenceSession +// try { +// inferenceSession.f() +// } finally { +// this.currentDelegatedPropertyInferenceSession = oldSession +// } + withInferenceSession(inferenceSession) { inferenceSession.f() } } @OptIn(PrivateForInline::class) + inline fun <T> withOuterConstraintStorage( + storage: ConstraintStorage, + f: () -> T + ): T { + val oldStorage = this.outerConstraintStorage + this.outerConstraintStorage = storage + return try { + f() + } finally { + this.outerConstraintStorage = oldStorage + } + } + + + @OptIn(PrivateForInline::class) inline fun <T> withConstructor(constructor: FirConstructor, f: () -> T): T = withContainer(constructor, f)
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt index b23fb7b..7fad5ae 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt
@@ -32,10 +32,12 @@ import org.jetbrains.kotlin.fir.resolve.calls.candidate import org.jetbrains.kotlin.fir.resolve.dfa.FirControlFlowGraphReferenceImpl import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeLocalVariableNoTypeOrInitializer +import org.jetbrains.kotlin.fir.resolve.inference.FirDelegatedPropertyInferenceSession import org.jetbrains.kotlin.fir.resolve.inference.FirStubTypeTransformer import org.jetbrains.kotlin.fir.resolve.inference.ResolvedLambdaAtom import org.jetbrains.kotlin.fir.resolve.inference.extractLambdaInfoFromFunctionType -import org.jetbrains.kotlin.fir.resolve.substitution.createTypeSubstitutorByTypeConstructor +import org.jetbrains.kotlin.fir.resolve.substitution.ChainedSubstitutor +import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.transformers.FirCallCompletionResultsWriterTransformer import org.jetbrains.kotlin.fir.resolve.transformers.FirStatusResolver import org.jetbrains.kotlin.fir.resolve.transformers.contracts.runContractResolveForFunction @@ -47,6 +49,7 @@ import org.jetbrains.kotlin.fir.types.impl.FirImplicitTypeRefImplWithoutSource import org.jetbrains.kotlin.fir.visitors.FirTransformer import org.jetbrains.kotlin.fir.visitors.transformSingle +import org.jetbrains.kotlin.resolve.calls.inference.buildCurrentSubstitutor open class FirDeclarationsResolveTransformer( transformer: FirAbstractBodyResolveTransformerDispatcher @@ -288,6 +291,7 @@ val finalSubstitutor = createFinalSubstitutor() + // TODO: Replace just property/accessors return types instead val stubTypeCompletionResultsWriter = FirStubTypeTransformer(finalSubstitutor) property.transformSingle(stubTypeCompletionResultsWriter, null) property.replaceReturnTypeRef( @@ -334,18 +338,10 @@ if (delegateExpression is FirResolvable) { val calleeReference = delegateExpression.calleeReference if (calleeReference is FirNamedReferenceWithCandidate) { - val system = calleeReference.candidate.system - system.notFixedTypeVariables.forEach { - system.markPostponedVariable(it.value.typeVariable) - } - val typeVariableTypeToStubType = context.inferenceSession.createSyntheticStubTypes(system) - - val substitutor = createTypeSubstitutorByTypeConstructor( - typeVariableTypeToStubType, session.typeContext, approximateIntegerLiterals = true - ) val delegateExpressionTypeRef = delegateExpression.typeRef - val stubTypeSubstituted = substitutor.substituteOrNull(delegateExpressionTypeRef.coneType) - delegateExpression.replaceTypeRef(delegateExpressionTypeRef.withReplacedConeType(stubTypeSubstituted)) + val returnTypeSubstitutedWithTypeVariables = + calleeReference.candidate.substitutor.substituteOrNull(delegateExpressionTypeRef.coneType) + delegateExpression.replaceTypeRef(delegateExpressionTypeRef.withReplacedConeType(returnTypeSubstitutedWithTypeVariables)) } } @@ -356,28 +352,23 @@ // TODO: this generates some nodes in the control flow graph which we don't want if we // end up not selecting this option, KT-59684 transformer.expressionsTransformer.transformFunctionCallInternal( - provideDelegateCall, ResolutionMode.ContextIndependent, provideDelegate = true + provideDelegateCall, ResolutionMode.ContextIndependent, skipExplicitReceiverTransformation = true ) // If we got successful candidate for provideDelegate, let's select it val provideDelegateCandidate = provideDelegateCall.candidate() if (provideDelegateCandidate != null && provideDelegateCandidate.isSuccessful) { - val system = provideDelegateCandidate.system - system.notFixedTypeVariables.forEach { - system.markPostponedVariable(it.value.typeVariable) - } - val typeVariableTypeToStubType = context.inferenceSession.createSyntheticStubTypes(system) - val substitutor = createTypeSubstitutorByTypeConstructor( - typeVariableTypeToStubType, session.typeContext, approximateIntegerLiterals = true + val substitutor = ChainedSubstitutor( + provideDelegateCandidate.substitutor, + (context.inferenceSession as FirDelegatedPropertyInferenceSession).currentConstraintStorage.buildCurrentSubstitutor( + session.typeContext, emptyMap() + ) as ConeSubstitutor ) - val stubTypeSubstituted = substitutor.substituteOrSelf( - provideDelegateCandidate.substitutor.substituteOrSelf( - components.typeFromCallee(provideDelegateCall).type - ) - ) + val toTypeVariableSubstituted = + substitutor.substituteOrSelf(components.typeFromCallee(provideDelegateCall).type) - provideDelegateCall.replaceTypeRef(provideDelegateCall.typeRef.resolvedTypeFromPrototype(stubTypeSubstituted)) + provideDelegateCall.replaceTypeRef(provideDelegateCall.typeRef.resolvedTypeFromPrototype(toTypeVariableSubstituted)) return provideDelegateCall }
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt index a7f640b..98ea5a4 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt
@@ -393,12 +393,14 @@ } override fun transformFunctionCall(functionCall: FirFunctionCall, data: ResolutionMode): FirStatement = - transformFunctionCallInternal(functionCall, data, provideDelegate = false) + transformFunctionCallInternal(functionCall, data, skipExplicitReceiverTransformation = false) internal fun transformFunctionCallInternal( functionCall: FirFunctionCall, data: ResolutionMode, - provideDelegate: Boolean, + // Currently, it's only `true` for provideDelegate calls, because delegateExpression is already resolved as that stage. + // See also FirDeclarationsResolveTransformer.transformWrappedDelegateExpression + skipExplicitReceiverTransformation: Boolean, ): FirStatement = whileAnalysing(session, functionCall) { val calleeReference = functionCall.calleeReference @@ -420,16 +422,12 @@ functionCall.transformAnnotations(transformer, data) functionCall.replaceLambdaArgumentInvocationKinds(session) functionCall.transformTypeArguments(transformer, ResolutionMode.ContextIndependent) + val initialExplicitReceiver = functionCall.explicitReceiver val withTransformedArguments = if (!resolvingAugmentedAssignment) { dataFlowAnalyzer.enterCallArguments(functionCall, functionCall.arguments) - // In provideDelegate mode the explicitReceiver is already resolved - // E.g. we have val some by someDelegate - // At 1st stage of delegate inference we resolve someDelegate itself, - // at 2nd stage in provideDelegate mode we are trying to resolve someDelegate.provideDelegate(), - // and 'someDelegate' explicit receiver is resolved at 1st stage - // See also FirDeclarationsResolveTransformer.transformWrappedDelegateExpression - val withResolvedExplicitReceiver = if (provideDelegate) functionCall else transformExplicitReceiver(functionCall) + val withResolvedExplicitReceiver = + if (skipExplicitReceiverTransformation) functionCall else transformExplicitReceiver(functionCall) withResolvedExplicitReceiver.also { it.replaceArgumentList(it.argumentList.transform(this, ResolutionMode.ContextDependent)) dataFlowAnalyzer.exitCallArguments() @@ -437,7 +435,12 @@ } else { functionCall } - val resultExpression = callResolver.resolveCallAndSelectCandidate(withTransformedArguments) + + + + val resultExpression = context.inferenceSession.onCandidatesResolution(withTransformedArguments) { + callResolver.resolveCallAndSelectCandidate(withTransformedArguments) + } val resultExplicitReceiver = resultExpression.explicitReceiver?.unwrapSmartcastExpression() if (initialExplicitReceiver !== resultExplicitReceiver && resultExplicitReceiver is FirQualifiedAccessExpression) { // name.invoke() case
diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/VariableFixationFinder.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/VariableFixationFinder.kt index 4f725e3..37434e0 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/VariableFixationFinder.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/VariableFixationFinder.kt
@@ -27,6 +27,7 @@ val fixedTypeVariables: Map<TypeConstructorMarker, KotlinTypeMarker> val postponedTypeVariables: List<TypeVariableMarker> val constraintsFromAllForkPoints: MutableList<Pair<IncorporationConstraintPosition, ForkPointData>> + val typeVariablesAreDisallowedForProperTypes: Set<TypeConstructorMarker>? fun isReified(variable: TypeVariableMarker): Boolean } @@ -182,7 +183,13 @@ && !c.isNullabilityConstraint private fun Context.isProperType(type: KotlinTypeMarker): Boolean = - isProperTypeForFixation(type) { t -> !t.contains { notFixedTypeVariables.containsKey(it.typeConstructor()) } } + isProperTypeForFixation(type) { t -> !t.contains { isNotFixedRelevantVariable(it) } } + + private fun Context.isNotFixedRelevantVariable(it: KotlinTypeMarker): Boolean { + if (!notFixedTypeVariables.containsKey(it.typeConstructor())) return false + if (typeVariablesAreDisallowedForProperTypes == null) return true + return typeVariablesAreDisallowedForProperTypes!!.contains(it.typeConstructor()) + } private fun Context.isReified(variable: TypeConstructorMarker): Boolean = notFixedTypeVariables[variable]?.typeVariable?.let { isReified(it) } ?: false
diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt index a47f80a..130b55b 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt
@@ -30,8 +30,7 @@ ConstraintSystemBuilder, ConstraintInjector.Context, ResultTypeResolver.Context, - PostponedArgumentsAnalyzerContext -{ + PostponedArgumentsAnalyzerContext { private val utilContext = constraintInjector.constraintIncorporator.utilContext private val postponedComputationsAfterAllVariablesAreFixed = mutableListOf<() -> Unit>() @@ -42,10 +41,29 @@ private val properTypesCache: MutableSet<KotlinTypeMarker> = SmartSet.create() private val notProperTypesCache: MutableSet<KotlinTypeMarker> = SmartSet.create() private val intersectionTypesCache: MutableMap<Collection<KotlinTypeMarker>, EmptyIntersectionTypeInfo?> = mutableMapOf() + override var typeVariablesAreDisallowedForProperTypes: Set<TypeConstructorMarker>? = null + private var couldBeResolvedWithUnrestrictedBuilderInference: Boolean = false override var atCompletionState: Boolean = false + fun withDisallowingOnlyThisTypeVariablesForProperTypes(typeVariables: Set<TypeConstructorMarker>, block: () -> Unit) { + properTypesCache.clear() + notProperTypesCache.clear() + + require(typeVariablesAreDisallowedForProperTypes == null) { + "Currently there should be no nested withDisallowingOnlyThisTypeVariablesForProperTypes calls" + } + + typeVariablesAreDisallowedForProperTypes = typeVariables + + block() + + typeVariablesAreDisallowedForProperTypes = null + properTypesCache.clear() + notProperTypesCache.clear() + } + private enum class State { BUILDING, TRANSACTION, @@ -149,7 +167,8 @@ pathToExpectedType: List<Pair<TypeConstructorMarker, Int>>, builtFunctionalType: KotlinTypeMarker ) { - storage.builtFunctionalTypesForPostponedArgumentsByTopLevelTypeVariables[topLevelVariable to pathToExpectedType] = builtFunctionalType + storage.builtFunctionalTypesForPostponedArgumentsByTopLevelTypeVariables[topLevelVariable to pathToExpectedType] = + builtFunctionalType } override fun putBuiltFunctionalExpectedTypeForPostponedArgument( @@ -317,6 +336,9 @@ it if (typeToCheck == null) return@contains false + if (typeVariablesAreDisallowedForProperTypes != null) { + return@contains typeVariablesAreDisallowedForProperTypes!!.contains(typeToCheck.typeConstructor()) + } storage.allTypeVariables.containsKey(typeToCheck.typeConstructor()) }