From 912676d8687d3e690f01214c16909e5033b61fe8 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Tue, 8 Sep 2020 15:04:39 +0300 Subject: [PATCH] [FIR] Introduce ResolutionContext and get rid of components in Candidate --- .../fir/serialization/FirElementSerializer.kt | 2 +- .../fir/resolve/BodyResolveComponents.kt | 7 +- .../kotlin/fir/resolve/calls/Arguments.kt | 64 ++++++++++++------- .../kotlin/fir/resolve/calls/Candidate.kt | 7 +- .../fir/resolve/calls/CandidateFactory.kt | 4 +- ...CreateFreshTypeVariableSubstitutorStage.kt | 4 +- .../resolve/calls/ResolutionStageRunner.kt | 7 +- .../fir/resolve/calls/ResolutionStages.kt | 63 ++++++++++-------- .../fir/resolve/calls/TypeArgumentMapping.kt | 4 +- .../inference/ConstraintSystemCompleter.kt | 3 +- .../fir/resolve/inference/FirCallCompleter.kt | 4 +- .../resolve/inference/InferenceComponents.kt | 8 +++ .../resolve/inference/PostponedArguments.kt | 13 ++-- .../inference/PostponedArgumentsAnalyzer.kt | 12 ++-- ...rCallCompletionResultsWriterTransformer.kt | 2 +- .../FirAbstractBodyResolveTransformer.kt | 5 +- .../api/resolver/SingleCandidateResolver.kt | 2 +- 17 files changed, 129 insertions(+), 82 deletions(-) diff --git a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirElementSerializer.kt b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirElementSerializer.kt index e120bad4f09..f938acc93e6 100644 --- a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirElementSerializer.kt +++ b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirElementSerializer.kt @@ -492,7 +492,7 @@ class FirElementSerializer private constructor( } if (parameter.isVararg) { - val varargElementType = parameter.returnTypeRef.coneType.varargElementType(session) + val varargElementType = parameter.returnTypeRef.coneType.varargElementType() if (useTypeTable()) { builder.varargElementTypeId = typeId(varargElementType) } else { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/BodyResolveComponents.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/BodyResolveComponents.kt index fc51c314b4d..ca7c766e381 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/BodyResolveComponents.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/BodyResolveComponents.kt @@ -10,10 +10,7 @@ import kotlinx.collections.immutable.persistentListOf import org.jetbrains.kotlin.fir.FirCallResolver import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.* -import org.jetbrains.kotlin.fir.resolve.calls.ImplicitDispatchReceiverValue -import org.jetbrains.kotlin.fir.resolve.calls.ImplicitExtensionReceiverValue -import org.jetbrains.kotlin.fir.resolve.calls.ImplicitReceiverValue -import org.jetbrains.kotlin.fir.resolve.calls.ResolutionStageRunner +import org.jetbrains.kotlin.fir.resolve.calls.* import org.jetbrains.kotlin.fir.resolve.dfa.FirDataFlowAnalyzer import org.jetbrains.kotlin.fir.resolve.inference.FirCallCompleter import org.jetbrains.kotlin.fir.resolve.inference.InferenceComponents @@ -59,6 +56,8 @@ interface BodyResolveComponents : SessionHolder { val integerLiteralTypeApproximator: IntegerLiteralTypeApproximationTransformer val integerOperatorsTypeUpdater: IntegerOperatorsTypeUpdater val outerClassManager: FirOuterClassManager + + val resolutionContext: ResolutionContext } typealias FirLocalScopes = PersistentList diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt index f5178aca604..7885cb140dc 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt @@ -36,6 +36,7 @@ fun Candidate.resolveArgumentExpression( expectedType: ConeKotlinType?, expectedTypeRef: FirTypeRef?, sink: CheckerSink, + context: ResolutionContext, isReceiver: Boolean, isDispatch: Boolean ) { @@ -45,6 +46,7 @@ fun Candidate.resolveArgumentExpression( argument as FirResolvable, expectedType, sink, + context, isReceiver, isDispatch ) @@ -62,6 +64,7 @@ fun Candidate.resolveArgumentExpression( nestedQualifier, expectedType, sink, + context, isReceiver, isDispatch, useNullableArgumentType = true @@ -86,13 +89,14 @@ fun Candidate.resolveArgumentExpression( argument, expectedType, sink, + context, isReceiver, isDispatch ) else - preprocessCallableReference(argument, expectedType) + preprocessCallableReference(argument, expectedType, context) // TODO:! - is FirAnonymousFunction -> preprocessLambdaArgument(csBuilder, argument, expectedType, expectedTypeRef) + is FirAnonymousFunction -> preprocessLambdaArgument(csBuilder, argument, expectedType, expectedTypeRef, context) // TODO:! //TODO: Collection literal is FirWrappedArgumentExpression -> resolveArgumentExpression( @@ -101,6 +105,7 @@ fun Candidate.resolveArgumentExpression( expectedType, expectedTypeRef, sink, + context, isReceiver, isDispatch ) @@ -110,10 +115,11 @@ fun Candidate.resolveArgumentExpression( expectedType, expectedTypeRef, sink, + context, isReceiver, isDispatch ) - else -> resolvePlainExpressionArgument(csBuilder, argument, expectedType, sink, isReceiver, isDispatch) + else -> resolvePlainExpressionArgument(csBuilder, argument, expectedType, sink, context, isReceiver, isDispatch) } } @@ -123,6 +129,7 @@ private fun Candidate.resolveBlockArgument( expectedType: ConeKotlinType?, expectedTypeRef: FirTypeRef?, sink: CheckerSink, + context: ResolutionContext, isReceiver: Boolean, isDispatch: Boolean ) { @@ -146,6 +153,7 @@ private fun Candidate.resolveBlockArgument( expectedType, expectedTypeRef, sink, + context, isReceiver, isDispatch ) @@ -157,6 +165,7 @@ fun Candidate.resolveSubCallArgument( argument: FirResolvable, expectedType: ConeKotlinType?, sink: CheckerSink, + context: ResolutionContext, isReceiver: Boolean, isDispatch: Boolean, useNullableArgumentType: Boolean = false @@ -166,6 +175,7 @@ fun Candidate.resolveSubCallArgument( argument as FirExpression, expectedType, sink, + context, isReceiver, isDispatch, useNullableArgumentType @@ -180,7 +190,7 @@ fun Candidate.resolveSubCallArgument( sink.components.returnTypeCalculator.tryCalculateReturnType(candidate.symbol.firUnsafe()).type } val argumentType = candidate.substitutor.substituteOrSelf(type) - resolvePlainArgumentType(csBuilder, argumentType, expectedType, sink, isReceiver, isDispatch, useNullableArgumentType) + resolvePlainArgumentType(csBuilder, argumentType, expectedType, sink, context, isReceiver, isDispatch, useNullableArgumentType) } fun Candidate.resolvePlainExpressionArgument( @@ -188,13 +198,14 @@ fun Candidate.resolvePlainExpressionArgument( argument: FirExpression, expectedType: ConeKotlinType?, sink: CheckerSink, + context: ResolutionContext, isReceiver: Boolean, isDispatch: Boolean, useNullableArgumentType: Boolean = false ) { if (expectedType == null) return val argumentType = argument.typeRef.coneTypeSafe() ?: return - resolvePlainArgumentType(csBuilder, argumentType, expectedType, sink, isReceiver, isDispatch, useNullableArgumentType) + resolvePlainArgumentType(csBuilder, argumentType, expectedType, sink, context, isReceiver, isDispatch, useNullableArgumentType) checkApplicabilityForIntegerOperatorCall(sink, argument) } @@ -210,6 +221,7 @@ fun Candidate.resolvePlainArgumentType( argumentType: ConeKotlinType, expectedType: ConeKotlinType?, sink: CheckerSink, + context: ResolutionContext, isReceiver: Boolean, isDispatch: Boolean, useNullableArgumentType: Boolean = false @@ -217,7 +229,7 @@ fun Candidate.resolvePlainArgumentType( val position = SimpleConstraintSystemConstraintPosition //TODO val session = sink.components.session - val capturedType = prepareCapturedType(argumentType) + val capturedType = prepareCapturedType(argumentType, context) val argumentTypeForApplicabilityCheck = if (useNullableArgumentType) @@ -230,24 +242,24 @@ fun Candidate.resolvePlainArgumentType( ) } -fun Candidate.prepareCapturedType(argumentType: ConeKotlinType): ConeKotlinType { - return captureTypeFromExpressionOrNull(argumentType) ?: argumentType +fun Candidate.prepareCapturedType(argumentType: ConeKotlinType, context: ResolutionContext): ConeKotlinType { + return captureTypeFromExpressionOrNull(argumentType, context) ?: argumentType } -private fun Candidate.captureTypeFromExpressionOrNull(argumentType: ConeKotlinType): ConeKotlinType? { +private fun Candidate.captureTypeFromExpressionOrNull(argumentType: ConeKotlinType, context: ResolutionContext): ConeKotlinType? { if (argumentType is ConeFlexibleType) { - return captureTypeFromExpressionOrNull(argumentType.lowerBound) + return captureTypeFromExpressionOrNull(argumentType.lowerBound, context) } if (argumentType !is ConeClassLikeType) return null - argumentType.fullyExpandedType(bodyResolveComponents.session).let { - if (it !== argumentType) return captureTypeFromExpressionOrNull(it) + argumentType.fullyExpandedType(context.session).let { + if (it !== argumentType) return captureTypeFromExpressionOrNull(it, context) } if (argumentType.typeArguments.isEmpty()) return null - return bodyResolveComponents.inferenceComponents.ctx.captureFromArguments( + return context.inferenceComponents.ctx.captureFromArguments( argumentType, CaptureStatus.FROM_EXPRESSION ) as? ConeKotlinType } @@ -289,47 +301,55 @@ internal fun Candidate.resolveArgument( argument: FirExpression, parameter: FirValueParameter?, isReceiver: Boolean, - sink: CheckerSink + sink: CheckerSink, + context: ResolutionContext ) { argument.resultType.ensureResolvedTypeDeclaration(sink.components.session) - val expectedType = prepareExpectedType(sink.components.session, argument, parameter) + val expectedType = prepareExpectedType(sink.components.session, argument, parameter, context) resolveArgumentExpression( this.system.getBuilder(), argument, expectedType, parameter?.returnTypeRef, sink, + context, isReceiver, false ) } -private fun Candidate.prepareExpectedType(session: FirSession, argument: FirExpression, parameter: FirValueParameter?): ConeKotlinType? { +private fun Candidate.prepareExpectedType( + session: FirSession, + argument: FirExpression, + parameter: FirValueParameter?, + context: ResolutionContext +): ConeKotlinType? { if (parameter == null) return null if (parameter.returnTypeRef is FirILTTypeRefPlaceHolder && argument.resultType is FirResolvedTypeRef) return argument.resultType.coneType val basicExpectedType = argument.getExpectedType(session, parameter/*, LanguageVersionSettings*/) - val expectedType = getExpectedTypeWithSAMConversion(session, argument, basicExpectedType) ?: basicExpectedType + val expectedType = getExpectedTypeWithSAMConversion(session, argument, basicExpectedType, context) ?: basicExpectedType return this.substitutor.substituteOrSelf(expectedType) } private fun Candidate.getExpectedTypeWithSAMConversion( session: FirSession, argument: FirExpression, - candidateExpectedType: ConeKotlinType + candidateExpectedType: ConeKotlinType, + context: ResolutionContext ): ConeKotlinType? { if (candidateExpectedType.isBuiltinFunctionalType(session)) return null // TODO: if (!callComponents.languageVersionSettings.supportsFeature(LanguageFeature.SamConversionPerArgument)) return null val firFunction = symbol.fir as? FirFunction<*> ?: return null - if (!samResolver.shouldRunSamConversionForFunction(firFunction)) return null + if (!context.bodyResolveComponents.samResolver.shouldRunSamConversionForFunction(firFunction)) return null if (!argument.isFunctional(session)) return null // TODO: resolvedCall.registerArgumentWithSamConversion(argument, SamConversionDescription(convertedTypeByOriginal, convertedTypeByCandidate!!)) - return samResolver.getFunctionTypeForPossibleSamType(candidateExpectedType).apply { + return context.bodyResolveComponents.samResolver.getFunctionTypeForPossibleSamType(candidateExpectedType).apply { usesSAM = true } } @@ -351,12 +371,12 @@ internal fun FirExpression.getExpectedType( } return if (parameter.isVararg && shouldUnwrapVarargType) { - parameter.returnTypeRef.coneType.varargElementType(session) + parameter.returnTypeRef.coneType.varargElementType() } else { parameter.returnTypeRef.coneType } } -fun ConeKotlinType.varargElementType(session: FirSession): ConeKotlinType { +fun ConeKotlinType.varargElementType(): ConeKotlinType { return this.arrayElementType() ?: error("Failed to extract! ${this.render()}!") } 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 cfe85493db8..bdf1c8f9bdf 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 @@ -17,6 +17,7 @@ import org.jetbrains.kotlin.fir.expressions.impl.FirExpressionStub import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents import org.jetbrains.kotlin.fir.resolve.DoubleColonLHS +import org.jetbrains.kotlin.fir.resolve.inference.InferenceComponents import org.jetbrains.kotlin.fir.resolve.inference.PostponedResolvedAtom import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol @@ -78,21 +79,19 @@ class Candidate( val dispatchReceiverValue: ReceiverValue?, val implicitExtensionReceiverValue: ImplicitReceiverValue<*>?, val explicitReceiverKind: ExplicitReceiverKind, - val bodyResolveComponents: BodyResolveComponents, + val constraintSystemFactory: InferenceComponents.ConstraintSystemFactory, private val baseSystem: ConstraintStorage, val callInfo: CallInfo ) { var systemInitialized: Boolean = false val system: NewConstraintSystemImpl by lazy { - val system = bodyResolveComponents.inferenceComponents.createConstraintSystem() + val system = constraintSystemFactory.createConstraintSystem() system.addOtherSystem(baseSystem) systemInitialized = true system } - val samResolver get() = bodyResolveComponents.samResolver - lateinit var substitutor: ConeSubstitutor lateinit var freshVariables: List var resultingTypeForCallableReference: ConeKotlinType? = null 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 60f2f896db1..60946001071 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 @@ -56,7 +56,7 @@ class CandidateFactory private constructor( ): Candidate { return Candidate( symbol, dispatchReceiverValue, implicitExtensionReceiverValue, - explicitReceiverKind, bodyResolveComponents, baseSystem, + explicitReceiverKind, bodyResolveComponents.inferenceComponents.constraintSystemFactory, baseSystem, builtInExtensionFunctionReceiverValue?.receiverExpression?.let { callInfo.withReceiverAsArgument(it) } ?: callInfo @@ -78,7 +78,7 @@ class CandidateFactory private constructor( dispatchReceiverValue = null, implicitExtensionReceiverValue = null, explicitReceiverKind = ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, - bodyResolveComponents, + bodyResolveComponents.inferenceComponents.constraintSystemFactory, baseSystem, callInfo ) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CreateFreshTypeVariableSubstitutorStage.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CreateFreshTypeVariableSubstitutorStage.kt index 45e837be44d..d93e497ad5d 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CreateFreshTypeVariableSubstitutorStage.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CreateFreshTypeVariableSubstitutorStage.kt @@ -21,7 +21,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition internal object CreateFreshTypeVariableSubstitutorStage : ResolutionStage() { - override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) { + override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) { val declaration = candidate.symbol.fir if (declaration !is FirTypeParameterRefsOwner || declaration.typeParameters.isEmpty()) { candidate.substitutor = ConeSubstitutor.Empty @@ -66,7 +66,7 @@ internal object CreateFreshTypeVariableSubstitutorStage : ResolutionStage() { getTypePreservingFlexibilityWrtTypeVariable( typeArgument.typeRef.coneType, typeParameter, - candidate.bodyResolveComponents.inferenceComponents.ctx + context.bodyResolveComponents.inferenceComponents.ctx ), SimpleConstraintSystemConstraintPosition // TODO ) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStageRunner.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStageRunner.kt index ce3781e57e4..9ea6cd41a87 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStageRunner.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStageRunner.kt @@ -5,7 +5,6 @@ package org.jetbrains.kotlin.fir.resolve.calls -import org.jetbrains.kotlin.fir.resolve.inference.InferenceComponents import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability import org.jetbrains.kotlin.resolve.calls.tower.isSuccess import kotlin.coroutines.Continuation @@ -14,15 +13,15 @@ import kotlin.coroutines.EmptyCoroutineContext import kotlin.coroutines.intrinsics.createCoroutineUnintercepted import kotlin.coroutines.resume -class ResolutionStageRunner(val components: InferenceComponents) { +class ResolutionStageRunner(private val context: ResolutionContext) { fun processCandidate(candidate: Candidate, stopOnFirstError: Boolean = true): CandidateApplicability { - val sink = CheckerSinkImpl(components, stopOnFirstError = stopOnFirstError) + val sink = CheckerSinkImpl(context.bodyResolveComponents.inferenceComponents, stopOnFirstError = stopOnFirstError) var finished = false sink.continuation = suspend { candidate.callInfo.callKind.resolutionSequence.forEachIndexed { index, stage -> if (index < candidate.passedStages) return@forEachIndexed candidate.passedStages++ - stage.check(candidate, sink, candidate.callInfo) + stage.check(candidate, candidate.callInfo, sink, context) } }.createCoroutineUnintercepted(completion = object : Continuation { override val context: CoroutineContext diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt index ce0f7a19fee..9b08026ef74 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier import org.jetbrains.kotlin.fir.references.FirSuperReference import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.inference.* +import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculator import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol import org.jetbrains.kotlin.fir.symbols.SyntheticSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol @@ -29,14 +30,25 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystem import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.* +data class ResolutionContext( + val session: FirSession, + val bodyResolveComponents: BodyResolveComponents +) { + val inferenceComponents: InferenceComponents + get() = bodyResolveComponents.inferenceComponents + + val returnTypeCalculator: ReturnTypeCalculator + get() = bodyResolveComponents.returnTypeCalculator +} + abstract class ResolutionStage { - abstract suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) + abstract suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) } abstract class CheckerStage : ResolutionStage() internal object CheckExplicitReceiverConsistency : ResolutionStage() { - override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) { + override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) { val receiverKind = candidate.explicitReceiverKind val explicitReceiver = callInfo.explicitReceiver // TODO: add invoke cases @@ -71,7 +83,7 @@ internal sealed class CheckReceivers : ResolutionStage() { return this == DISPATCH_RECEIVER || this == BOTH_RECEIVERS } - override fun Candidate.getReceiverType(): ConeKotlinType? { + override fun Candidate.getReceiverType(context: ResolutionContext): ConeKotlinType? { return dispatchReceiverValue?.type } } @@ -85,25 +97,25 @@ internal sealed class CheckReceivers : ResolutionStage() { return this == EXTENSION_RECEIVER || this == BOTH_RECEIVERS } - override fun Candidate.getReceiverType(): ConeKotlinType? { + override fun Candidate.getReceiverType(context: ResolutionContext): ConeKotlinType? { val callableSymbol = symbol as? FirCallableSymbol<*> ?: return null val callable = callableSymbol.fir val receiverType = callable.receiverTypeRef?.coneType if (receiverType != null) return receiverType val returnTypeRef = callable.returnTypeRef as? FirResolvedTypeRef ?: return null - if (!returnTypeRef.type.isExtensionFunctionType(bodyResolveComponents.session)) return null + if (!returnTypeRef.type.isExtensionFunctionType(context.session)) return null return (returnTypeRef.type.typeArguments.firstOrNull() as? ConeKotlinTypeProjection)?.type } } - abstract fun Candidate.getReceiverType(): ConeKotlinType? + abstract fun Candidate.getReceiverType(context: ResolutionContext): ConeKotlinType? abstract fun ExplicitReceiverKind.shouldBeCheckedAgainstExplicit(): Boolean abstract fun ExplicitReceiverKind.shouldBeCheckedAgainstImplicit(): Boolean - override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) { - val expectedReceiverType = candidate.getReceiverType() + override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) { + val expectedReceiverType = candidate.getReceiverType(context) val explicitReceiverExpression = callInfo.explicitReceiver val explicitReceiverKind = candidate.explicitReceiverKind @@ -118,6 +130,7 @@ internal sealed class CheckReceivers : ResolutionStage() { expectedType = candidate.substitutor.substituteOrSelf(expectedReceiverType), expectedTypeRef = explicitReceiverExpression.typeRef, sink = sink, + context = context, isReceiver = true, isDispatch = this is Dispatch ) @@ -130,6 +143,7 @@ internal sealed class CheckReceivers : ResolutionStage() { argumentType = argumentExtensionReceiverValue.type, expectedType = candidate.substitutor.substituteOrSelf(expectedReceiverType.type), sink = sink, + context = context, isReceiver = true, isDispatch = this is Dispatch ) @@ -148,7 +162,7 @@ private fun FirExpression.isSuperReferenceExpression(): Boolean { } internal object MapArguments : ResolutionStage() { - override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) { + override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) { val symbol = candidate.symbol as? FirFunctionSymbol<*> ?: return sink.reportDiagnostic(HiddenCandidate) val function = symbol.fir @@ -161,7 +175,7 @@ internal object MapArguments : ResolutionStage() { } internal object CheckArguments : CheckerStage() { - override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) { + override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) { val argumentMapping = candidate.argumentMapping ?: error("Argument should be already mapped while checking arguments!") for (argument in callInfo.arguments) { @@ -170,7 +184,8 @@ internal object CheckArguments : CheckerStage() { argument, parameter, isReceiver = false, - sink = sink + sink = sink, + context = context ) if (candidate.system.hasContradiction) { sink.yieldDiagnostic(InapplicableCandidate) @@ -181,11 +196,11 @@ internal object CheckArguments : CheckerStage() { } internal object EagerResolveOfCallableReferences : CheckerStage() { - override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) { + override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) { if (candidate.postponedAtoms.isEmpty()) return for (atom in candidate.postponedAtoms) { if (atom is ResolvedCallableReferenceAtom) { - if (!candidate.bodyResolveComponents.callResolver.resolveCallableReference(candidate.csBuilder, atom)) { + if (!context.bodyResolveComponents.callResolver.resolveCallableReference(candidate.csBuilder, atom)) { sink.yieldDiagnostic(InapplicableCandidate) } } @@ -194,10 +209,10 @@ internal object EagerResolveOfCallableReferences : CheckerStage() { } internal object CheckCallableReferenceExpectedType : CheckerStage() { - override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) { + override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) { val outerCsBuilder = callInfo.outerCSBuilder ?: return val expectedType = callInfo.expectedType - val candidateSymbol = candidate.symbol as? FirCallableSymbol<*> ?: return + if (candidate.symbol !is FirCallableSymbol<*>) return val resultingReceiverType = when (callInfo.lhs) { is DoubleColonLHS.Type -> callInfo.lhs.type.takeIf { callInfo.explicitReceiver !is FirResolvedQualifier } @@ -206,7 +221,7 @@ internal object CheckCallableReferenceExpectedType : CheckerStage() { val fir: FirCallableDeclaration<*> = candidate.symbol.fir - val returnTypeRef = candidate.bodyResolveComponents.returnTypeCalculator.tryCalculateReturnType(fir) + val returnTypeRef = context.bodyResolveComponents.returnTypeCalculator.tryCalculateReturnType(fir) // If the expected type is a suspend function type and the current argument of interest is a function reference, we need to do // "suspend conversion." Here, during resolution, we bypass constraint system by making resulting type be KSuspendFunction. // Then, during conversion, we need to create an adapter function and replace the function reference created here with an adapted @@ -215,9 +230,8 @@ internal object CheckCallableReferenceExpectedType : CheckerStage() { val requireSuspendConversion = expectedType?.isSuspendFunctionType(callInfo.session) == true val resultingType: ConeKotlinType = when (fir) { is FirFunction -> callInfo.session.createAdaptedKFunctionType( - callInfo.session, - fir, resultingReceiverType, returnTypeRef, - expectedParameterTypes = expectedType?.typeArguments, + fir, + resultingReceiverType, returnTypeRef, expectedParameterTypes = expectedType?.typeArguments, isSuspend = (fir as? FirSimpleFunction)?.isSuspend == true || requireSuspendConversion, expectedReturnType = extractInputOutputTypesFromCallableReferenceExpectedType(expectedType, callInfo.session)?.outputType ) @@ -272,7 +286,6 @@ private fun createKPropertyType( } private fun FirSession.createAdaptedKFunctionType( - session: FirSession, function: FirFunction<*>, receiverType: ConeKotlinType?, returnTypeRef: FirResolvedTypeRef, @@ -326,7 +339,7 @@ private fun FirSession.createAdaptedKFunctionType( lastVarargParameter != null ) { val varargArrayType = lastVarargParameter.returnTypeRef.coneType - val varargElementType = varargArrayType.varargElementType(session) + val varargElementType = varargArrayType.varargElementType() val expectedParameterType = (expectedParameterTypes[parameterTypes.size + shift] as? ConeKotlinTypeProjection)?.type // Expect an array or potentially array (i.e., type variable). Pass vararg parameter as-is. if (expectedParameterType.isPotentiallyArray()) { @@ -355,7 +368,7 @@ private fun FirSession.createAdaptedKFunctionType( } internal object DiscriminateSynthetics : CheckerStage() { - override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) { + override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) { if (candidate.symbol is SyntheticSymbol) { sink.reportDiagnostic(ResolvedWithLowPriority) } @@ -363,7 +376,7 @@ internal object DiscriminateSynthetics : CheckerStage() { } internal object CheckVisibility : CheckerStage() { - override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) { + override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) { val visibilityChecker = callInfo.session.visibilityChecker val symbol = candidate.symbol val declaration = symbol.fir @@ -406,7 +419,7 @@ internal object CheckLowPriorityInOverloadResolution : CheckerStage() { private val LOW_PRIORITY_IN_OVERLOAD_RESOLUTION_CLASS_ID: ClassId = ClassId(FqName("kotlin.internal"), Name.identifier("LowPriorityInOverloadResolution")) - override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) { + override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) { val annotations = when (val fir = candidate.symbol.fir) { is FirSimpleFunction -> fir.annotations is FirProperty -> fir.annotations @@ -427,7 +440,7 @@ internal object CheckLowPriorityInOverloadResolution : CheckerStage() { internal object PostponedVariablesInitializerResolutionStage : ResolutionStage() { val BUILDER_INFERENCE_CLASS_ID: ClassId = ClassId.fromString("kotlin/BuilderInference") - override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) { + override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) { val argumentMapping = candidate.argumentMapping ?: return // TODO: convert type argument mapping to map [FirTypeParameterSymbol, FirTypedProjection?] if (candidate.typeArgumentMapping is TypeArgumentMapping.Mapped) return diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TypeArgumentMapping.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TypeArgumentMapping.kt index 1cc970118bf..54acef27b0b 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TypeArgumentMapping.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TypeArgumentMapping.kt @@ -24,7 +24,7 @@ sealed class TypeArgumentMapping { } internal object MapTypeArguments : ResolutionStage() { - override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) { + override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) { val typeArguments = callInfo.typeArguments if (typeArguments.isEmpty()) { candidate.typeArgumentMapping = TypeArgumentMapping.NoExplicitArguments @@ -43,7 +43,7 @@ internal object MapTypeArguments : ResolutionStage() { } internal object NoTypeArguments : ResolutionStage() { - override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) { + override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) { if (callInfo.typeArguments.isNotEmpty()) { sink.yieldDiagnostic(InapplicableCandidate) } 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 9481c1dbc5c..4f4f218b96e 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 @@ -81,7 +81,6 @@ class ConstraintSystemCompleter(private val components: BodyResolveComponents) { c: ConstraintSystemCompletionContext, variableForFixation: VariableFixationFinder.VariableForFixation, postponedAtoms: List, - /*diagnosticsHolder: KotlinDiagnosticsHolder,*/ analyze: (PostponedResolvedAtom) -> Unit ): Boolean { val variable = variableForFixation.variable as ConeTypeVariableTypeConstructor @@ -111,7 +110,7 @@ class ConstraintSystemCompleter(private val components: BodyResolveComponents) { isSuitable = { isBuiltinFunctionalType(components.session) }, typeVariableCreator = { ConeTypeVariableForLambdaReturnType(postponedAtom.atom, "_R") }, newAtomCreator = { returnTypeVariable, expectedType -> - postponedAtom.transformToResolvedLambda(csBuilder, expectedType, returnTypeVariable) + postponedAtom.transformToResolvedLambda(csBuilder, components.resolutionContext, expectedType, returnTypeVariable) } ) } 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 79115057883..3e19bb2dc1c 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 @@ -122,7 +122,9 @@ class FirCallCompleter( fun createPostponedArgumentsAnalyzer(): PostponedArgumentsAnalyzer { val lambdaAnalyzer = LambdaAnalyzerImpl() return PostponedArgumentsAnalyzer( - lambdaAnalyzer, inferenceComponents, + resolutionContext, + lambdaAnalyzer, + inferenceComponents, transformer.components.callResolver ) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/InferenceComponents.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/InferenceComponents.kt index c4ec0cb66b4..96c169fce0e 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/InferenceComponents.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/InferenceComponents.kt @@ -43,7 +43,15 @@ class InferenceComponents( } } + val constraintSystemFactory = ConstraintSystemFactory() + fun createConstraintSystem(): NewConstraintSystemImpl { return NewConstraintSystemImpl(injector, ctx) } + + inner class ConstraintSystemFactory { + fun createConstraintSystem(): NewConstraintSystemImpl { + return this@InferenceComponents.createConstraintSystem() + } + } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArguments.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArguments.kt index 13ae56bd2f4..08a4a468c52 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArguments.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArguments.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess import org.jetbrains.kotlin.fir.resolve.calls.Candidate +import org.jetbrains.kotlin.fir.resolve.calls.ResolutionContext import org.jetbrains.kotlin.fir.resolve.createFunctionalType import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder @@ -20,6 +21,7 @@ fun Candidate.preprocessLambdaArgument( argument: FirAnonymousFunction, expectedType: ConeKotlinType?, expectedTypeRef: FirTypeRef?, + context: ResolutionContext, forceResolution: Boolean = false, returnTypeVariable: ConeTypeVariableForLambdaReturnType? = null ): PostponedResolvedAtom { @@ -28,8 +30,8 @@ fun Candidate.preprocessLambdaArgument( } val resolvedArgument = - extractLambdaInfoFromFunctionalType(expectedType, expectedTypeRef, argument, returnTypeVariable, bodyResolveComponents, this) - ?: extraLambdaInfo(expectedType, argument, csBuilder, bodyResolveComponents.session, this) + extractLambdaInfoFromFunctionalType(expectedType, expectedTypeRef, argument, returnTypeVariable, context.bodyResolveComponents, this) + ?: extraLambdaInfo(expectedType, argument, csBuilder, context.session, this) if (expectedType != null) { // TODO: add SAM conversion processing @@ -47,10 +49,11 @@ fun Candidate.preprocessLambdaArgument( fun Candidate.preprocessCallableReference( argument: FirCallableReferenceAccess, - expectedType: ConeKotlinType? + expectedType: ConeKotlinType?, + context: ResolutionContext ) { - val lhs = bodyResolveComponents.doubleColonExpressionResolver.resolveDoubleColonLHS(argument) - postponedAtoms += ResolvedCallableReferenceAtom(argument, expectedType, lhs, bodyResolveComponents.session) + val lhs = context.bodyResolveComponents.doubleColonExpressionResolver.resolveDoubleColonLHS(argument) + postponedAtoms += ResolvedCallableReferenceAtom(argument, expectedType, lhs, context.session) } private fun extraLambdaInfo( diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArgumentsAnalyzer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArgumentsAnalyzer.kt index 116205b44f8..baccad4b886 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArgumentsAnalyzer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArgumentsAnalyzer.kt @@ -44,6 +44,7 @@ interface LambdaAnalyzer { } class PostponedArgumentsAnalyzer( + private val resolutionContext: ResolutionContext, private val lambdaAnalyzer: LambdaAnalyzer, private val components: InferenceComponents, private val callResolver: FirCallResolver @@ -53,14 +54,13 @@ class PostponedArgumentsAnalyzer( c: PostponedArgumentsAnalyzerContext, argument: PostponedResolvedAtom, candidate: Candidate - //diagnosticsHolder: KotlinDiagnosticsHolder ) { return when (argument) { is ResolvedLambdaAtom -> - analyzeLambda(c, argument, candidate/*, diagnosticsHolder*/) + analyzeLambda(c, argument, candidate) is LambdaWithTypeVariableAsExpectedTypeAtom -> - analyzeLambda(c, argument.transformToResolvedLambda(c.getBuilder()), candidate/*, diagnosticsHolder*/) + analyzeLambda(c, argument.transformToResolvedLambda(c.getBuilder(), resolutionContext), candidate) is ResolvedCallableReferenceAtom -> processCallableReference(argument, candidate) @@ -163,6 +163,7 @@ class PostponedArgumentsAnalyzer( lambda.returnType.let(::substitute), lambda.atom.returnTypeRef, // TODO: proper ref checkerSink, + context = resolutionContext, isReceiver = false, isDispatch = false ) @@ -181,7 +182,7 @@ class PostponedArgumentsAnalyzer( fun LambdaWithTypeVariableAsExpectedTypeAtom.transformToResolvedLambda( csBuilder: ConstraintSystemBuilder, - /*diagnosticHolder: KotlinDiagnosticsHolder,*/ + context: ResolutionContext, expectedType: ConeKotlinType? = null, returnTypeVariable: ConeTypeVariableForLambdaReturnType? = null ): ResolvedLambdaAtom { @@ -192,8 +193,9 @@ fun LambdaWithTypeVariableAsExpectedTypeAtom.transformToResolvedLambda( atom, fixedExpectedType, expectedTypeRef, + context, forceResolution = true, - returnTypeVariable + returnTypeVariable = returnTypeVariable ) as ResolvedLambdaAtom analyzed = true return resolvedAtom 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 2da1104e6e2..3c8145fc6be 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 @@ -352,7 +352,7 @@ class FirCallCompletionResultsWriterTransformer( private fun Candidate.createArgumentsMapping(): ExpectedArgumentType? { return argumentMapping?.map { (argument, valueParameter) -> val expectedType = if (valueParameter.isVararg) { - valueParameter.returnTypeRef.substitute(this).varargElementType(session) + valueParameter.returnTypeRef.substitute(this).varargElementType() } else { valueParameter.returnTypeRef.substitute(this) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirAbstractBodyResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirAbstractBodyResolveTransformer.kt index 6a8c9935543..a792ceb1009 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirAbstractBodyResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirAbstractBodyResolveTransformer.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.resolve.transformers.body.resolve import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.resolve.* +import org.jetbrains.kotlin.fir.resolve.calls.ResolutionContext import org.jetbrains.kotlin.fir.resolve.calls.ResolutionStageRunner import org.jetbrains.kotlin.fir.resolve.dfa.FirDataFlowAnalyzer import org.jetbrains.kotlin.fir.resolve.inference.FirCallCompleter @@ -92,6 +93,8 @@ abstract class FirAbstractBodyResolveTransformer(phase: FirResolvePhase) : FirAb val transformer: FirBodyResolveTransformer, val context: BodyResolveContext ) : BodyResolveComponents { + override val resolutionContext: ResolutionContext = ResolutionContext(session, this@BodyResolveTransformerComponents) + override val fileImportsScope: List get() = context.fileImportsScope override val towerDataElements: List get() = context.towerDataContext.towerDataElements override val localScopes: FirLocalScopes get() = context.towerDataContext.localScopes @@ -109,7 +112,7 @@ abstract class FirAbstractBodyResolveTransformer(phase: FirResolvePhase) : FirAb override val symbolProvider: FirSymbolProvider = session.firSymbolProvider override val inferenceComponents: InferenceComponents = inferenceComponents(session, returnTypeCalculator, scopeSession) - override val resolutionStageRunner: ResolutionStageRunner = ResolutionStageRunner(inferenceComponents) + override val resolutionStageRunner: ResolutionStageRunner = ResolutionStageRunner(resolutionContext) override val samResolver: FirSamResolver = FirSamResolverImpl(session, scopeSession) private val qualifiedResolver: FirQualifiedNameResolver = FirQualifiedNameResolver(this) override val callResolver: FirCallResolver = FirCallResolver( diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/resolver/SingleCandidateResolver.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/resolver/SingleCandidateResolver.kt index 4e222f47afc..0f8729df000 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/resolver/SingleCandidateResolver.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/resolver/SingleCandidateResolver.kt @@ -47,7 +47,7 @@ class SingleCandidateResolver( stubBodyResolveTransformer, bodyResolveComponents, ) - private val resolutionStageRunner = ResolutionStageRunner(bodyResolveComponents.inferenceComponents) + private val resolutionStageRunner = ResolutionStageRunner(ResolutionContext(firSession, bodyResolveComponents)) fun resolveSingleCandidate( resolutionParameters: ResolutionParameters