diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt index 9c9a07669ae..8faadc1c8da 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -499,6 +499,15 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.PLUGIN_AMBIGUOUS_INTERCEPTED_SYMBOL) { firDiagnostic -> + PluginAmbiguousInterceptedSymbolImpl( + firDiagnostic.a.map { string -> + string + }, + firDiagnostic as KtPsiDiagnostic, + token, + ) + } add(FirErrors.RESOLUTION_TO_CLASSIFIER) { firDiagnostic -> ResolutionToClassifierImpl( firSymbolBuilder.classifierBuilder.buildClassLikeSymbol(firDiagnostic.a), diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt index 683f13e9781..008f6ac53cb 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt @@ -396,6 +396,11 @@ sealed interface KtFirDiagnostic : KtDiagnosticWithPsi { val classSymbol: KtClassLikeSymbol } + interface PluginAmbiguousInterceptedSymbol : KtFirDiagnostic { + override val diagnosticClass get() = PluginAmbiguousInterceptedSymbol::class + val names: List + } + interface ResolutionToClassifier : KtFirDiagnostic { override val diagnosticClass get() = ResolutionToClassifier::class val classSymbol: KtClassLikeSymbol diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index b7b8ee1752d..6ab5ea0c54d 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -459,6 +459,12 @@ internal class InnerClassConstructorNoReceiverImpl( token: KtLifetimeToken, ) : KtAbstractFirDiagnostic(firDiagnostic, token), KtFirDiagnostic.InnerClassConstructorNoReceiver +internal class PluginAmbiguousInterceptedSymbolImpl( + override val names: List, + firDiagnostic: KtPsiDiagnostic, + token: KtLifetimeToken, +) : KtAbstractFirDiagnostic(firDiagnostic, token), KtFirDiagnostic.PluginAmbiguousInterceptedSymbol + internal class ResolutionToClassifierImpl( override val classSymbol: KtClassLikeSymbol, firDiagnostic: KtPsiDiagnostic, diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index 503a34f0d8e..d0b1fa27dd1 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -210,6 +210,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { val INNER_CLASS_CONSTRUCTOR_NO_RECEIVER by error { parameter("classSymbol") } + val PLUGIN_AMBIGUOUS_INTERCEPTED_SYMBOL by error { + parameter>("names") + } val RESOLUTION_TO_CLASSIFIER by error { parameter("classSymbol") } diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index c05840cc830..c23ef35ec7e 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -200,6 +200,7 @@ object FirErrors { val INTERFACE_AS_FUNCTION: KtDiagnosticFactory1 by error1() val EXPECT_CLASS_AS_FUNCTION: KtDiagnosticFactory1 by error1() val INNER_CLASS_CONSTRUCTOR_NO_RECEIVER: KtDiagnosticFactory1 by error1() + val PLUGIN_AMBIGUOUS_INTERCEPTED_SYMBOL: KtDiagnosticFactory1> by error1>() val RESOLUTION_TO_CLASSIFIER: KtDiagnosticFactory1 by error1() val AMBIGUOUS_ALTERED_ASSIGN: KtDiagnosticFactory1> by error1>() val FORBIDDEN_BINARY_MOD: KtDiagnosticFactory2, String> by error2, String>(SourceElementPositioningStrategies.OPERATOR_MODIFIER) diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt index 12962cd574d..b0290b04aa9 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt @@ -64,6 +64,7 @@ val FIR_NON_SUPPRESSIBLE_ERROR_NAMES: Set = setOf( "INTERFACE_AS_FUNCTION", "EXPECT_CLASS_AS_FUNCTION", "INNER_CLASS_CONSTRUCTOR_NO_RECEIVER", + "PLUGIN_AMBIGUOUS_INTERCEPTED_SYMBOL", "RESOLUTION_TO_CLASSIFIER", "AMBIGUOUS_ALTERED_ASSIGN", "FORBIDDEN_BINARY_MOD", diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt index cc1a8679acb..2b09c651d0c 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt @@ -510,6 +510,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OVERRIDING_FINAL_ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PACKAGE_CANNOT_BE_IMPORTED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PACKAGE_OR_CLASSIFIER_REDECLARATION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PLATFORM_CLASS_MAPPED_TO_KOTLIN +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PLUGIN_AMBIGUOUS_INTERCEPTED_SYMBOL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.POTENTIALLY_NON_REPORTED_ANNOTATION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PRE_RELEASE_CLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED @@ -882,6 +883,11 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() { "Multiple extensions attempted to alter this assignment at the same time. Extensions: {0}", COLLECTION(NULLABLE_STRING) ) + map.put( + PLUGIN_AMBIGUOUS_INTERCEPTED_SYMBOL, + "Multiple extensions attempted to modify this function call. Extensions: {0}", + COLLECTION(NULLABLE_STRING) + ) map.put(DEPRECATED_BINARY_MOD, "Convention for ''{0}'' is prohibited. Use ''{1}''.", SYMBOL, STRING) map.put(FORBIDDEN_BINARY_MOD, "Deprecated convention for ''{0}''. Use ''{1}''.", SYMBOL, STRING) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt index da526d9de79..38568986466 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt @@ -397,6 +397,8 @@ private fun mapInapplicableCandidateError( // Reported later is TypeParameterAsExpression -> null + is AmbiguousInterceptedSymbol -> FirErrors.PLUGIN_AMBIGUOUS_INTERCEPTED_SYMBOL.createOn(source, rootCause.pluginNames) + else -> genericDiagnostic } }.distinct() diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/extensions/FirExtensionRegistrar.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/extensions/FirExtensionRegistrar.kt index e3b097d9417..c1b5af1c5c3 100644 --- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/extensions/FirExtensionRegistrar.kt +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/extensions/FirExtensionRegistrar.kt @@ -38,6 +38,8 @@ abstract class FirExtensionRegistrar : FirExtensionRegistrarAdapter() { FirFunctionTypeKindExtension::class, @OptIn(FirExtensionApiInternals::class) FirMetadataSerializerPlugin::class, + @OptIn(FirExtensionApiInternals::class) + FirFunctionCallRefinementExtension::class, ) internal val ALLOWED_EXTENSIONS_FOR_LIBRARY_SESSION = listOf( @@ -122,6 +124,12 @@ abstract class FirExtensionRegistrar : FirExtensionRegistrarAdapter() { registerExtension(FirMetadataSerializerPlugin::class, this) } + @FirExtensionApiInternals + @JvmName("plusFunctionCallRefinementExtension") + operator fun (FirFunctionCallRefinementExtension.Factory).unaryPlus() { + registerExtension(FirFunctionCallRefinementExtension::class, this) + } + // ------------------ reference methods ------------------ @JvmName("plusStatusTransformerExtension") @@ -195,6 +203,12 @@ abstract class FirExtensionRegistrar : FirExtensionRegistrarAdapter() { FirMetadataSerializerPlugin.Factory { this.invoke(it) }.unaryPlus() } + @FirExtensionApiInternals + @JvmName("plusFunctionCallRefinementExtension") + operator fun ((FirSession) -> FirFunctionCallRefinementExtension).unaryPlus() { + FirFunctionCallRefinementExtension.Factory { this.invoke(it) }.unaryPlus() + } + // ------------------ utilities ------------------ @JvmName("bindLeft") diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirFunctionCallRefinementExtension.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirFunctionCallRefinementExtension.kt new file mode 100644 index 00000000000..e64c70f7385 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirFunctionCallRefinementExtension.kt @@ -0,0 +1,90 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.extensions + +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.declarations.FirDeclaration +import org.jetbrains.kotlin.fir.declarations.FirDeclarationDataKey +import org.jetbrains.kotlin.fir.declarations.FirDeclarationDataRegistry +import org.jetbrains.kotlin.fir.expressions.FirFunctionCall +import org.jetbrains.kotlin.fir.resolve.calls.CallInfo +import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol +import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef +import kotlin.reflect.KClass + +/** + * This extension integrates with call resolution mechanism: + * resolution and completion of the receiver + * resolution of arguments + * resolution of the call itself + * - [intercept] is called + * resolution of the outer call + * completion of the call + * - [transform] is called + * completion of the outer call + * + * !!!! This extension is highly unstable and not recommended to use !!!! + */ +@FirExtensionApiInternals +abstract class FirFunctionCallRefinementExtension(session: FirSession) : FirExtension(session) { + companion object { + val NAME = FirExtensionPointName("FunctionCallRefinementExtension") + } + + final override val name: FirExtensionPointName + get() = NAME + + + final override val extensionType: KClass = FirFunctionCallRefinementExtension::class + + /** + * Allows a call to be completed with a more specific type than the declared return type of function + * ``` + * interface Container { } + * fun Container.add(item: String): Container + * ``` + * at call site `Container` can be modified to become `Container` + * ``` + * container.add("A") + * ``` + * this `NewLocalType` can be created in [intercept]. It must be later saved into FIR tree in [transform] + * Generated declarations should be local because this [FirExtension] works at body resolve stage and thus cannot create new top level declarations + * + * When [intercept] returns non-null value, a copy will be created from FirFunction that [symbol] + * points to. Copy will be used in call completion instead of original function. + * + * @return null if plugin is not interested in a [symbol] + */ + abstract fun intercept(callInfo: CallInfo, symbol: FirNamedFunctionSymbol): CallReturnType? + + /** + * + * Data can be associated with [FirNamedFunctionSymbol] in [callback] + */ + class CallReturnType(val typeRef: FirResolvedTypeRef, val callback: ((FirNamedFunctionSymbol) -> Unit)? = null) + + /** + * @param call to a function that was created with modified [FirResolvedTypeRef] as a result of [intercept]. + * This function doesn't exist in FIR, it is needed to complete the call. + * @param originalSymbol [intercept] is called with symbol to a declaration that exists somewhere in FIR: library, project code. + * The same symbol is [originalSymbol]. + * [transform] needs to generate call to [let] with the same return type as [call] + * and put all generated declarations used in [FirResolvedTypeRef] in statements. + */ + abstract fun transform(call: FirFunctionCall, originalSymbol: FirNamedFunctionSymbol): FirFunctionCall + + fun interface Factory : FirExtension.Factory +} + +@OptIn(FirExtensionApiInternals::class) +val FirExtensionService.callRefinementExtensions: List by FirExtensionService.registeredExtensions() + +@OptIn(FirExtensionApiInternals::class) +internal class OriginalCallData(val originalSymbol: FirNamedFunctionSymbol, val extension: FirFunctionCallRefinementExtension) + +internal object OriginalCallDataKey : FirDeclarationDataKey() + +internal var FirDeclaration.originalCallDataForPluginRefinedCall: OriginalCallData? by FirDeclarationDataRegistry.data(OriginalCallDataKey) \ No newline at end of file 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 cb6e2a62c7c..bb0d2ba743d 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 @@ -12,9 +12,13 @@ import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.declarations.builder.buildErrorFunction import org.jetbrains.kotlin.fir.declarations.builder.buildErrorProperty +import org.jetbrains.kotlin.fir.declarations.builder.buildSimpleFunctionCopy import org.jetbrains.kotlin.fir.declarations.fullyExpandedClass import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic import org.jetbrains.kotlin.fir.expressions.* +import org.jetbrains.kotlin.fir.extensions.* +import org.jetbrains.kotlin.fir.extensions.OriginalCallData +import org.jetbrains.kotlin.fir.extensions.originalCallDataForPluginRefinedCall import org.jetbrains.kotlin.fir.resolve.isIntegerLiteralOrOperatorCall import org.jetbrains.kotlin.fir.resolve.toFirRegularClass import org.jetbrains.kotlin.fir.scopes.FirScope @@ -31,6 +35,8 @@ class CandidateFactory private constructor( val context: ResolutionContext, private val baseSystem: ConstraintStorage ) { + @OptIn(FirExtensionApiInternals::class) + private val callRefinementExtensions = context.session.extensionService.callRefinementExtensions.takeIf { it.isNotEmpty() } companion object { private fun buildBaseSystem(context: ResolutionContext, callInfo: CallInfo): ConstraintStorage { @@ -58,8 +64,21 @@ class CandidateFactory private constructor( objectsByName: Boolean = false, isFromOriginalTypeInPresenceOfSmartCast: Boolean = false, ): Candidate { + var pluginAmbiguity: AmbiguousInterceptedSymbol? = null + @Suppress("NAME_SHADOWING") - val symbol = symbol.unwrapIntegerOperatorSymbolIfNeeded(callInfo) + @OptIn(FirExtensionApiInternals::class) + val symbol = if ( + callRefinementExtensions != null && + callInfo.callKind == CallKind.Function && + symbol is FirNamedFunctionSymbol + ) { + val result = symbol.replaceFromPluginsIfNeeded(callRefinementExtensions, callInfo) + pluginAmbiguity = result.second + result.first + } else { + symbol.unwrapIntegerOperatorSymbolIfNeeded(callInfo) + } val result = Candidate( symbol, @@ -81,6 +100,10 @@ class CandidateFactory private constructor( context.bodyResolveContext.inferenceSession, ) + if (pluginAmbiguity != null) { + result.addDiagnostic(pluginAmbiguity) + } + // The counterpart in FE 1.0 checks if the given descriptor is VariableDescriptor yet not PropertyDescriptor. // Here, we explicitly check if the referred declaration/symbol is value parameter, local variable, enum entry, or backing field. val callSite = callInfo.callSite @@ -122,6 +145,48 @@ class CandidateFactory private constructor( return result } + @OptIn(FirExtensionApiInternals::class) + private fun FirNamedFunctionSymbol.replaceFromPluginsIfNeeded( + callRefinementExtensions: List, + callInfo: CallInfo, + ): Pair, AmbiguousInterceptedSymbol?> { + var pluginAmbiguity: AmbiguousInterceptedSymbol? = null + fun process( + result: FirFunctionCallRefinementExtension.CallReturnType, + extension: FirFunctionCallRefinementExtension + ): FirNamedFunctionSymbol { + val newSymbol = FirNamedFunctionSymbol(callableId) + val function = buildSimpleFunctionCopy(fir) { + body = null + this.symbol = newSymbol + returnTypeRef = result.typeRef + } + function.originalCallDataForPluginRefinedCall = OriginalCallData(this, extension) + result.callback?.invoke(newSymbol) + return newSymbol + } + + val variants = callRefinementExtensions.mapNotNull { extension -> + val result = extension.intercept(callInfo, this) + result?.let { it to extension } + } + val firBasedSymbol = when (variants.size) { + 0 -> { + unwrapIntegerOperatorSymbolIfNeeded(callInfo) + } + 1 -> { + val (result, extension) = variants[0] + process(result, extension) + } + else -> { + pluginAmbiguity = + AmbiguousInterceptedSymbol(variants.map { it.second::class.qualifiedName ?: it.second.javaClass.name }) + unwrapIntegerOperatorSymbolIfNeeded(callInfo) + } + } + return Pair(firBasedSymbol, pluginAmbiguity) + } + private fun FirBasedSymbol<*>.isRegularClassWithoutCompanion(session: FirSession): Boolean { val referencedClass = (this as? FirClassLikeSymbol<*>)?.fullyExpandedClass(session) ?: return false return referencedClass.classKind != ClassKind.OBJECT && referencedClass.companionObjectSymbol == null diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/CompletionModeCalculator.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/CompletionModeCalculator.kt index 9e56c0db3d1..814ec734c44 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/CompletionModeCalculator.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/CompletionModeCalculator.kt @@ -5,9 +5,11 @@ package org.jetbrains.kotlin.fir.resolve.inference +import org.jetbrains.kotlin.fir.extensions.originalCallDataForPluginRefinedCall 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.toRegularClassSymbol 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.components.TrivialConstraintTypeInferenceOracle @@ -33,6 +35,9 @@ fun Candidate.computeCompletionMode( // Full if return type for call has no type variables csBuilder.isProperType(currentReturnType) -> ConstraintSystemCompletionMode.FULL + // Plugins need fully complete calls. Calls that cannot be completed should not be modified, forcing completion will produce type inference error + currentReturnType.toRegularClassSymbol(components.session)?.fir?.originalCallDataForPluginRefinedCall != null -> ConstraintSystemCompletionMode.FULL + else -> CalculatorForNestedCall( this, currentReturnType, csBuilder, components.trivialConstraintTypeInferenceOracle ).computeCompletionMode() 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 483361541eb..c4e4618574c 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 @@ -19,9 +19,7 @@ import org.jetbrains.kotlin.fir.expressions.FirOperation.* import org.jetbrains.kotlin.fir.expressions.builder.* import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedArgumentList import org.jetbrains.kotlin.fir.expressions.impl.toAnnotationArgumentMapping -import org.jetbrains.kotlin.fir.extensions.assignAltererExtensions -import org.jetbrains.kotlin.fir.extensions.expressionResolutionExtensions -import org.jetbrains.kotlin.fir.extensions.extensionService +import org.jetbrains.kotlin.fir.extensions.* import org.jetbrains.kotlin.fir.references.* import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference import org.jetbrains.kotlin.fir.references.builder.buildExplicitSuperReference @@ -62,6 +60,8 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT private val expressionResolutionExtensions = session.extensionService.expressionResolutionExtensions.takeIf { it.isNotEmpty() } private val assignAltererExtensions = session.extensionService.assignAltererExtensions.takeIf { it.isNotEmpty() } + @OptIn(FirExtensionApiInternals::class) + private val callRefinementExtensions = session.extensionService.callRefinementExtensions.takeIf { it.isNotEmpty() } init { @Suppress("LeakingThis") @@ -462,10 +462,20 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT resultExpression, data, skipEvenPartialCompletion = choosingOptionForAugmentedAssignment, ) - val result = completeInference.transformToIntegerOperatorCallOrApproximateItIfNeeded(data) + var result = completeInference.transformToIntegerOperatorCallOrApproximateItIfNeeded(data) if (!choosingOptionForAugmentedAssignment) { dataFlowAnalyzer.exitFunctionCall(result, data.forceFullCompletion) } + @OptIn(FirExtensionApiInternals::class) + if (callRefinementExtensions != null) { + val reference = result.calleeReference + if (reference is FirResolvedNamedReference) { + val callData = reference.resolvedSymbol.fir.originalCallDataForPluginRefinedCall + if (callData != null) { + result = callData.extension.transform(result, callData.originalSymbol) + } + } + } addReceiversFromExtensions(result) diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionDiagnostic.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionDiagnostic.kt index 5c62f82d11d..3ab694c0dd7 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionDiagnostic.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionDiagnostic.kt @@ -165,4 +165,6 @@ class TypeVariableAsExplicitReceiver( val typeParameter: FirTypeParameter, ) : ResolutionDiagnostic(RESOLVED_WITH_ERROR) -object CallToDeprecatedOverrideOfHidden : ResolutionDiagnostic(RESOLVED) \ No newline at end of file +object CallToDeprecatedOverrideOfHidden : ResolutionDiagnostic(RESOLVED) + +class AmbiguousInterceptedSymbol(val pluginNames: List) : ResolutionDiagnostic(RESOLVED_WITH_ERROR) \ No newline at end of file