~ mostly ok
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/ConstraintSystemCompleter.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/ConstraintSystemCompleter.kt index ca16682..eba7b7f 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/ConstraintSystemCompleter.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/ConstraintSystemCompleter.kt
@@ -383,10 +383,10 @@ result.addAll(notFixedTypeVariables.filter { context.inferenceSession.isSyntheticTypeVariable(it.value.typeVariable) }.keys.asIterable()) } - require(result.size == notFixedTypeVariables.size) { - val notFoundTypeVariables = notFixedTypeVariables.keys.toMutableSet().apply { removeAll(result) } - "Not all type variables found: $notFoundTypeVariables" - } +// require(result.size == notFixedTypeVariables.size) { +// val notFoundTypeVariables = notFixedTypeVariables.keys.toMutableSet().apply { removeAll(result) } +// "Not all type variables found: $notFoundTypeVariables" +// } return result.toList() }
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..05e5b72 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 @@ -83,6 +82,18 @@ call.replaceLambdaArgumentInvocationKinds(session) } + if (inferenceSession.customCompletionHandling(call, resolutionMode, completionMode) { chosenCompletionMode -> + runCompletionForCall( + candidate, + chosenCompletionMode, + call, + initialType + ) + } + ) { + return call + } + return when (completionMode) { ConstraintSystemCompletionMode.FULL -> { if (inferenceSession.shouldRunCompletion(call)) { @@ -91,7 +102,7 @@ .buildAbstractResultingSubstitutor(session.typeContext) as ConeSubstitutor val completedCall = call.transformSingle( FirCallCompletionResultsWriterTransformer( - session, finalSubstitutor, + session, components.scopeSession, finalSubstitutor, components.returnTypeCalculator, session.typeApproximator, components.dataFlowAnalyzer, @@ -110,13 +121,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 +214,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..1c4e18a 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,27 @@ 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.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 +34,73 @@ private val postponedArgumentsAnalyzer: PostponedArgumentsAnalyzer, ) : FirInferenceSessionForChainedResolve(resolutionContext) { - private val currentConstraintSystem = components.session.inferenceComponents.createConstraintSystem() - override val currentConstraintStorage: ConstraintStorage get() = currentConstraintSystem.currentStorage() + private 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 - } + override fun <R> onCandidatesResolution(call: FirFunctionCall, candidatesResolutionCallback: () -> R): R { + return if (!call.isAnyOfDelegateOperators()) + candidatesResolutionCallback() + else + resolutionContext.bodyResolveContext.withOuterConstraintStorage( + currentConstraintSystem.currentStorage(), + candidatesResolutionCallback + ) } - private fun integrateResolvedCall(storage: ConstraintStorage) { - registerSyntheticVariables(storage) - val stubToTypeVariableSubstitutor = createToSyntheticTypeVariableSubstitutor() - integrateConstraints( - currentConstraintSystem, - storage, - stubToTypeVariableSubstitutor, - false - ) - } + override fun <T> customCompletionHandling( + call: T, + resolutionMode: ResolutionMode, + completionMode: ConstraintSystemCompletionMode, + runCompletionCallback: (ConstraintSystemCompletionMode) -> Unit, + ): Boolean where T : FirResolvable, T : FirStatement { + val candidate = call.candidate + val isProvideDelegateOperator = call.isOperatorCallWithName { it == OperatorNameConventions.PROVIDE_DELEGATE } + if (!candidate.isSuccessful && isProvideDelegateOperator) return 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()) - } - } + // Do not run completion for provideDelegate/getValue/setValue because they might affect each other + if (completionMode == ConstraintSystemCompletionMode.FULL && resolutionMode == ResolutionMode.ContextDependentDelegate) return false - override fun <T> addPartiallyResolvedCall(call: T) where T : FirResolvable, T : FirStatement { - super.addPartiallyResolvedCall(call) - if (call.candidate.isSuccessful) { - integrateResolvedCall(call.candidate.system.currentStorage()) - } - } + if (resolutionMode != ResolutionMode.ContextDependentDelegate && !call.isAnyOfDelegateOperators()) return false - override fun <T> shouldRunCompletion(call: T): Boolean where T : FirResolvable, T : FirStatement { - val callee = call.calleeReference as? FirNamedReferenceWithCandidate ?: return true + partiallyResolvedCalls.add(call to call.candidate) + currentConstraintSystem = call.candidate.system - if (callee.candidate.system.hasContradiction) return true - - val hasStubType = - callee.candidate.chosenExtensionReceiver?.typeRef?.coneType?.containsStubType() ?: false - || callee.candidate.dispatchReceiver?.typeRef?.coneType?.containsStubType() ?: false - - if (!hasStubType) { - return true + if (isProvideDelegateOperator) { + val innerSet = candidate.freshVariables.mapTo(mutableSetOf()) { it.typeConstructor } + currentConstraintSystem.withDisallowingOnlyThisTypeVariablesForProperTypes(innerSet) { + runCompletionCallback(ConstraintSystemCompletionMode.FULL) + } + } else { + runCompletionCallback(ConstraintSystemCompletionMode.PARTIAL) } - 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 true } - 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 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) - ) - } fun completeCandidates(): List<FirResolvable> { - val commonSystem = components.session.inferenceComponents.createConstraintSystem() + val commonSystem = currentConstraintSystem val notCompletedCalls = partiallyResolvedCalls.mapNotNull { partiallyResolvedCall -> partiallyResolvedCall.first.takeIf { resolvable -> @@ -171,20 +108,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 +141,32 @@ } } - resultingConstraintSystem = commonSystem return notCompletedCalls } - fun createFinalSubstitutor(): ConeSubstitutor { - val stubTypeSubstitutor = createNonFixedTypeToVariableSubstitutor() + fun createFinalSubstitutor(): ConeSubstitutor = + currentConstraintSystem.asReadOnlyStorage() + .buildAbstractResultingSubstitutor(components.session.typeContext) as ConeSubstitutor - val typeContext = components.session.typeContext - val resultSubstitutor = resultingConstraintSystem.asReadOnlyStorage() - .buildAbstractResultingSubstitutor(typeContext) as ConeSubstitutor - return ChainedSubstitutor(stubTypeSubstitutor, resultSubstitutor) - .replaceStubsAndTypeVariablesToErrors(typeContext, stubTypesByTypeVariable.values.map { it.constructor }) - } + override fun hasSyntheticTypeVariables(): Boolean = false - private val stubTypesByTypeVariable: MutableMap<ConeTypeVariable, ConeStubType> = mutableMapOf() - private val syntheticTypeVariableByTypeVariable = mutableMapOf<TypeVariableMarker, ConeTypeVariable>() - - 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 isSyntheticTypeVariable(typeVariable: TypeVariableMarker): Boolean = false 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 + TODO("Not yet implemented") } - 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 + override fun fixSyntheticTypeVariableWithNotEnoughInformation( + typeVariable: TypeVariableMarker, + completionContext: ConstraintSystemCompletionContext ) { - 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) - } - } + error("") } + + + override fun <T> addCompletedCall(call: T, candidate: Candidate) where T : FirResolvable, T : FirStatement {} + override fun <T> addPartiallyResolvedCall(call: T) where T : FirResolvable, T : FirStatement { + error("") + } + override fun <T> shouldRunCompletion(call: T): Boolean where T : FirResolvable, T : FirStatement = true }
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..0db5b017 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,13 @@ } abstract fun <T> shouldRunCompletion(call: T): Boolean where T : FirResolvable, T : FirStatement - abstract val currentConstraintStorage: ConstraintStorage + + open fun <T> customCompletionHandling( + call: T, + resolutionMode: ResolutionMode, + completionMode: ConstraintSystemCompletionMode, + runCompletionCallback: (ConstraintSystemCompletionMode) -> Unit, + ): 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 +56,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..b5a4cc0 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,9 @@ @set:PrivateForInline var inferenceSession: FirInferenceSession = FirInferenceSession.DEFAULT + @set:PrivateForInline + var outerConstraintStorage: ConstraintStorage = ConstraintStorage.Empty + val anonymousFunctionsAnalyzedInDependentContext: MutableSet<FirFunctionSymbol<*>> = mutableSetOf() var containingClassDeclarations: ArrayDeque<FirRegularClass> = ArrayDeque() @@ -832,6 +838,21 @@ } @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 94f7754..63492a1 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,11 @@ 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.FirStubTypeTransformer +import org.jetbrains.kotlin.fir.resolve.inference.FirDelegatedPropertyInferenceSession 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 @@ -45,8 +46,10 @@ import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef import org.jetbrains.kotlin.fir.types.impl.FirImplicitTypeRefImplWithoutSource +import org.jetbrains.kotlin.fir.visitors.FirDefaultTransformer 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,8 +291,7 @@ val finalSubstitutor = createFinalSubstitutor() - val stubTypeCompletionResultsWriter = FirStubTypeTransformer(finalSubstitutor) - property.transformSingle(stubTypeCompletionResultsWriter, null) + property.applyFinalSubstitutor(finalSubstitutor) property.replaceReturnTypeRef( property.returnTypeRef.approximateDeclarationType( session, @@ -315,6 +317,26 @@ dataFlowAnalyzer.exitDelegateExpression(delegate) } + private fun FirProperty.applyFinalSubstitutor( + finalSubstitutor: ConeSubstitutor, + ) { + val substitutorTypeRefTransformer = ApplyingSubstitutorTypeRefTransformer(finalSubstitutor) + + transformReturnTypeRef(substitutorTypeRefTransformer, null) + + getter?.transformTypeWithPropertyType(returnTypeRef) + setter?.transformTypeWithPropertyType(returnTypeRef) + } + + private class ApplyingSubstitutorTypeRefTransformer(private val substitutor: ConeSubstitutor) : FirDefaultTransformer<Nothing?>() { + override fun <E : FirElement> transformElement(element: E, data: Nothing?): E = element + + override fun transformResolvedTypeRef(resolvedTypeRef: FirResolvedTypeRef, data: Nothing?): FirTypeRef = + substitutor.substituteOrNull(resolvedTypeRef.type)?.let { + resolvedTypeRef.withReplacedConeType(it) + } ?: resolvedTypeRef + } + override fun transformPropertyAccessor(propertyAccessor: FirPropertyAccessor, data: ResolutionMode): FirStatement { return propertyAccessor.also { transformProperty(it.propertySymbol.fir, data) @@ -334,18 +356,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)) } } @@ -362,22 +376,17 @@ // 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 30e83fa..e7a4679d 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
@@ -434,7 +434,11 @@ } 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/ConstraintStorage.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/ConstraintStorage.kt index be56d0df..7f15e0d 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/ConstraintStorage.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/ConstraintStorage.kt
@@ -44,6 +44,7 @@ val hasContradiction: Boolean val fixedTypeVariables: Map<TypeConstructorMarker, KotlinTypeMarker> val postponedTypeVariables: List<TypeVariableMarker> + val typeVariablesThatMightNeedResultsRefinement: Set<TypeConstructorMarker> val builtFunctionalTypesForPostponedArgumentsByTopLevelTypeVariables: Map<Pair<TypeConstructorMarker, List<Pair<TypeConstructorMarker, Int>>>, KotlinTypeMarker> val builtFunctionalTypesForPostponedArgumentsByExpectedTypeVariables: Map<TypeConstructorMarker, KotlinTypeMarker> val constraintsFromAllForkPoints: List<Pair<IncorporationConstraintPosition, ForkPointData>> @@ -58,6 +59,7 @@ override val hasContradiction: Boolean get() = false override val fixedTypeVariables: Map<TypeConstructorMarker, KotlinTypeMarker> get() = emptyMap() override val postponedTypeVariables: List<TypeVariableMarker> get() = emptyList() + override val typeVariablesThatMightNeedResultsRefinement: Set<TypeConstructorMarker> get() = emptySet() override val builtFunctionalTypesForPostponedArgumentsByTopLevelTypeVariables: Map<Pair<TypeConstructorMarker, List<Pair<TypeConstructorMarker, Int>>>, KotlinTypeMarker> = emptyMap() override val builtFunctionalTypesForPostponedArgumentsByExpectedTypeVariables: Map<TypeConstructorMarker, KotlinTypeMarker> = emptyMap() override val constraintsFromAllForkPoints: List<Pair<IncorporationConstraintPosition, ForkPointData>> = emptyList()
diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/MutableConstraintStorage.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/MutableConstraintStorage.kt index a1706f5..b48b799 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/MutableConstraintStorage.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/MutableConstraintStorage.kt
@@ -235,6 +235,7 @@ override val hasContradiction: Boolean get() = errors.any { !it.applicability.isSuccess } override val fixedTypeVariables: MutableMap<TypeConstructorMarker, KotlinTypeMarker> = LinkedHashMap() override val postponedTypeVariables: MutableList<TypeVariableMarker> = SmartList() + override val typeVariablesThatMightNeedResultsRefinement: MutableSet<TypeConstructorMarker> = mutableSetOf() override val builtFunctionalTypesForPostponedArgumentsByTopLevelTypeVariables: MutableMap<Pair<TypeConstructorMarker, List<Pair<TypeConstructorMarker, Int>>>, KotlinTypeMarker> = LinkedHashMap() override val builtFunctionalTypesForPostponedArgumentsByExpectedTypeVariables: MutableMap<TypeConstructorMarker, KotlinTypeMarker> =
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..a38daf6 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
@@ -42,10 +42,31 @@ 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 + + storage.typeVariablesThatMightNeedResultsRefinement.addAll(typeVariables) + + block() + + typeVariablesAreDisallowedForProperTypes = null + properTypesCache.clear() + notProperTypesCache.clear() + } + private enum class State { BUILDING, TRANSACTION, @@ -294,6 +315,7 @@ storage.fixedTypeVariables.putAll(otherSystem.fixedTypeVariables) storage.postponedTypeVariables.addAll(otherSystem.postponedTypeVariables) storage.constraintsFromAllForkPoints.addAll(otherSystem.constraintsFromAllForkPoints) + storage.typeVariablesThatMightNeedResultsRefinement.addAll(otherSystem.typeVariablesThatMightNeedResultsRefinement) } // ResultTypeResolver.Context, ConstraintSystemBuilder @@ -317,6 +339,9 @@ it if (typeToCheck == null) return@contains false + if (typeVariablesAreDisallowedForProperTypes != null) { + return@contains typeVariablesAreDisallowedForProperTypes!!.contains(typeToCheck.typeConstructor()) + } storage.allTypeVariables.containsKey(typeToCheck.typeConstructor()) } @@ -486,6 +511,14 @@ storage.fixedTypeVariables[freshTypeConstructor] = resultType + val substitutorForFixedVariables = typeSubstitutorByTypeConstructor(mapOf(freshTypeConstructor to resultType)) + + storage.typeVariablesThatMightNeedResultsRefinement.forEach { otherVariable -> + storage.fixedTypeVariables[otherVariable]?.let { + storage.fixedTypeVariables[otherVariable] = substitutorForFixedVariables.safeSubstitute(it) + } + } + // Substitute freshly fixed type variable into missed constraints substituteMissedConstraints()