[FIR] Extension point for function calls
This extension point allows changing the return type of call from a declared type to its subtype. With an idea that such a plugin needs the ability to control available (extension) properties for this type. A set of properties should be decided based on the resolved function, provided arguments, types, and resolved lambdas. It is not a goal to enable plugins to affect resolution in any way. Types are not intended to have any structured capabilities In other words. The goal was to come up with a way to enable a limited form of an "extensible records" mechanism through plugins. - It should give enough value for a practical use. (more info in the ticket). - It should have minimal effect on the compilation process This appears to be an extension point that solves this problem. ^KT-65859 Fixed
This commit is contained in:
committed by
Space Team
parent
4d04546652
commit
c49edfef04
+9
@@ -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),
|
||||
|
||||
+5
@@ -396,6 +396,11 @@ sealed interface KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
val classSymbol: KtClassLikeSymbol
|
||||
}
|
||||
|
||||
interface PluginAmbiguousInterceptedSymbol : KtFirDiagnostic<PsiElement> {
|
||||
override val diagnosticClass get() = PluginAmbiguousInterceptedSymbol::class
|
||||
val names: List<String>
|
||||
}
|
||||
|
||||
interface ResolutionToClassifier : KtFirDiagnostic<PsiElement> {
|
||||
override val diagnosticClass get() = ResolutionToClassifier::class
|
||||
val classSymbol: KtClassLikeSymbol
|
||||
|
||||
+6
@@ -459,6 +459,12 @@ internal class InnerClassConstructorNoReceiverImpl(
|
||||
token: KtLifetimeToken,
|
||||
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.InnerClassConstructorNoReceiver
|
||||
|
||||
internal class PluginAmbiguousInterceptedSymbolImpl(
|
||||
override val names: List<String>,
|
||||
firDiagnostic: KtPsiDiagnostic,
|
||||
token: KtLifetimeToken,
|
||||
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.PluginAmbiguousInterceptedSymbol
|
||||
|
||||
internal class ResolutionToClassifierImpl(
|
||||
override val classSymbol: KtClassLikeSymbol,
|
||||
firDiagnostic: KtPsiDiagnostic,
|
||||
|
||||
+3
@@ -210,6 +210,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val INNER_CLASS_CONSTRUCTOR_NO_RECEIVER by error<PsiElement> {
|
||||
parameter<FirRegularClassSymbol>("classSymbol")
|
||||
}
|
||||
val PLUGIN_AMBIGUOUS_INTERCEPTED_SYMBOL by error<PsiElement> {
|
||||
parameter<List<String>>("names")
|
||||
}
|
||||
val RESOLUTION_TO_CLASSIFIER by error<PsiElement> {
|
||||
parameter<FirRegularClassSymbol>("classSymbol")
|
||||
}
|
||||
|
||||
@@ -200,6 +200,7 @@ object FirErrors {
|
||||
val INTERFACE_AS_FUNCTION: KtDiagnosticFactory1<FirRegularClassSymbol> by error1<PsiElement, FirRegularClassSymbol>()
|
||||
val EXPECT_CLASS_AS_FUNCTION: KtDiagnosticFactory1<FirRegularClassSymbol> by error1<PsiElement, FirRegularClassSymbol>()
|
||||
val INNER_CLASS_CONSTRUCTOR_NO_RECEIVER: KtDiagnosticFactory1<FirRegularClassSymbol> by error1<PsiElement, FirRegularClassSymbol>()
|
||||
val PLUGIN_AMBIGUOUS_INTERCEPTED_SYMBOL: KtDiagnosticFactory1<List<String>> by error1<PsiElement, List<String>>()
|
||||
val RESOLUTION_TO_CLASSIFIER: KtDiagnosticFactory1<FirRegularClassSymbol> by error1<PsiElement, FirRegularClassSymbol>()
|
||||
val AMBIGUOUS_ALTERED_ASSIGN: KtDiagnosticFactory1<List<String?>> by error1<PsiElement, List<String?>>()
|
||||
val FORBIDDEN_BINARY_MOD: KtDiagnosticFactory2<FirBasedSymbol<*>, String> by error2<PsiElement, FirBasedSymbol<*>, String>(SourceElementPositioningStrategies.OPERATOR_MODIFIER)
|
||||
|
||||
+1
@@ -64,6 +64,7 @@ val FIR_NON_SUPPRESSIBLE_ERROR_NAMES: Set<String> = 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",
|
||||
|
||||
+6
@@ -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)
|
||||
|
||||
|
||||
+2
@@ -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()
|
||||
|
||||
+14
@@ -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")
|
||||
|
||||
+90
@@ -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<out FirExtension> = FirFunctionCallRefinementExtension::class
|
||||
|
||||
/**
|
||||
* Allows a call to be completed with a more specific type than the declared return type of function
|
||||
* ```
|
||||
* interface Container<out T> { }
|
||||
* fun Container<T>.add(item: String): Container<Any>
|
||||
* ```
|
||||
* at call site `Container<Any>` can be modified to become `Container<NewLocalType>`
|
||||
* ```
|
||||
* 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<FirFunctionCallRefinementExtension>
|
||||
}
|
||||
|
||||
@OptIn(FirExtensionApiInternals::class)
|
||||
val FirExtensionService.callRefinementExtensions: List<FirFunctionCallRefinementExtension> 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)
|
||||
+66
-1
@@ -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<FirFunctionCallRefinementExtension>,
|
||||
callInfo: CallInfo,
|
||||
): Pair<FirBasedSymbol<*>, 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
|
||||
|
||||
+5
@@ -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()
|
||||
|
||||
+14
-4
@@ -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)
|
||||
|
||||
|
||||
+3
-1
@@ -165,4 +165,6 @@ class TypeVariableAsExplicitReceiver(
|
||||
val typeParameter: FirTypeParameter,
|
||||
) : ResolutionDiagnostic(RESOLVED_WITH_ERROR)
|
||||
|
||||
object CallToDeprecatedOverrideOfHidden : ResolutionDiagnostic(RESOLVED)
|
||||
object CallToDeprecatedOverrideOfHidden : ResolutionDiagnostic(RESOLVED)
|
||||
|
||||
class AmbiguousInterceptedSymbol(val pluginNames: List<String>) : ResolutionDiagnostic(RESOLVED_WITH_ERROR)
|
||||
Reference in New Issue
Block a user