diff --git a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10TypeProvider.kt b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10TypeProvider.kt index 3bd4dc170d2..4d82238cc18 100644 --- a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10TypeProvider.kt +++ b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10TypeProvider.kt @@ -5,21 +5,26 @@ package org.jetbrains.kotlin.analysis.api.descriptors.components +import org.jetbrains.kotlin.analysis.api.assertIsValidAndAccessible import org.jetbrains.kotlin.analysis.api.components.KtBuiltinTypes import org.jetbrains.kotlin.analysis.api.components.KtTypeProvider import org.jetbrains.kotlin.analysis.api.descriptors.Fe10AnalysisContext import org.jetbrains.kotlin.analysis.api.descriptors.KtFe10AnalysisSession import org.jetbrains.kotlin.analysis.api.descriptors.Fe10AnalysisFacade.AnalysisMode import org.jetbrains.kotlin.analysis.api.descriptors.components.base.Fe10KtAnalysisSessionComponent +import org.jetbrains.kotlin.analysis.api.descriptors.symbols.base.KtFe10Symbol +import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.KtFe10DescSymbol import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.classId import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.getSymbolDescriptor import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.isInterfaceLike import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.toKtType +import org.jetbrains.kotlin.analysis.api.descriptors.symbols.psiBased.base.KtFe10PsiSymbol import org.jetbrains.kotlin.analysis.api.descriptors.symbols.psiBased.base.getResolutionScope import org.jetbrains.kotlin.analysis.api.descriptors.types.base.KtFe10Type import org.jetbrains.kotlin.analysis.api.descriptors.utils.PublicApproximatorConfiguration import org.jetbrains.kotlin.analysis.api.descriptors.utils.cached import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol +import org.jetbrains.kotlin.analysis.api.symbols.markers.KtPossibleMemberSymbol import org.jetbrains.kotlin.analysis.api.symbols.nameOrAnonymous import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken import org.jetbrains.kotlin.analysis.api.types.KtType @@ -39,7 +44,6 @@ import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.checker.NewCapturedType import org.jetbrains.kotlin.types.checker.NewTypeVariableConstructor import org.jetbrains.kotlin.types.typeUtil.isNothing -import org.jetbrains.kotlin.types.typeUtil.supertypes import org.jetbrains.kotlin.util.containingNonLocalDeclaration internal class KtFe10TypeProvider( @@ -115,6 +119,19 @@ internal class KtFe10TypeProvider( return TypeUtils.getAllSupertypes(type.type).map { it.toKtType(analysisContext) } } + override fun getDispatchReceiverType(symbol: KtPossibleMemberSymbol): KtType? { + assertIsValidAndAccessible() + require(symbol is KtFe10Symbol) + + val descriptor = when (symbol) { + is KtFe10DescSymbol<*> -> symbol.descriptor as? CallableDescriptor + is KtFe10PsiSymbol<*, *> -> symbol.descriptor as? CallableDescriptor + else -> error("No callable descriptor on $symbol") + } + + return descriptor?.dispatchReceiverParameter?.type?.toKtType(analysisContext) + } + private fun areTypesCompatible(a: KotlinType, b: KotlinType): Boolean { if (a.isNothing() || b.isNothing() || TypeUtils.equalTypes(a, b) || (a.isNullable() && b.isNullable())) { return true diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirTypeProvider.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirTypeProvider.kt index 207259868b6..057ec61ca01 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirTypeProvider.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirTypeProvider.kt @@ -9,10 +9,12 @@ import org.jetbrains.kotlin.analysis.api.components.KtBuiltinTypes import org.jetbrains.kotlin.analysis.api.components.KtTypeProvider import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirNamedClassOrObjectSymbol +import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirSymbol import org.jetbrains.kotlin.analysis.api.fir.types.KtFirType import org.jetbrains.kotlin.analysis.api.fir.types.PublicTypeApproximator import org.jetbrains.kotlin.analysis.api.fir.utils.toConeNullability import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol +import org.jetbrains.kotlin.analysis.api.symbols.markers.KtPossibleMemberSymbol import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken import org.jetbrains.kotlin.analysis.api.types.KtType import org.jetbrains.kotlin.analysis.api.types.KtTypeNullability @@ -25,6 +27,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.ConeTypeCompatibilityChecker import org.jetbrains.kotlin.fir.analysis.checkers.ConeTypeCompatibilityChecker.isCompatible import org.jetbrains.kotlin.fir.analysis.checkers.fullyExpandedClass import org.jetbrains.kotlin.fir.analysis.checkers.typeParameterSymbols +import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess @@ -183,5 +186,17 @@ internal class KtFirTypeProvider( .drop(1) .mapTo(mutableListOf()) { it.asKtType() } } + + override fun getDispatchReceiverType(symbol: KtPossibleMemberSymbol): KtType? { + require(symbol is KtFirSymbol<*>) + + return symbol.firRef.withFir { declaration -> + check(declaration is FirCallableDeclaration) { + "Fir declaration should be FirCallableDeclaration; instead it was ${declaration::class}" + } + + declaration.dispatchReceiverType?.asKtType() + } + } } diff --git a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/fir/AbstractResolveCallTest.kt b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/fir/AbstractResolveCallTest.kt index 48489999645..651c1e739bd 100644 --- a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/fir/AbstractResolveCallTest.kt +++ b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/fir/AbstractResolveCallTest.kt @@ -37,7 +37,7 @@ abstract class AbstractResolveCallTest(configurator: FrontendApiTestConfigurator val actual = executeOnPooledThreadInReadAction { analyseForTest(expression) { - resolveCall(expression)?.stringRepresentation() + resolveCall(expression)?.let { stringRepresentation(it) } } } ?: "null" testServices.assertions.assertEqualsToTestDataFileSibling(actual) @@ -62,8 +62,8 @@ abstract class AbstractResolveCallTest(configurator: FrontendApiTestConfigurator } -private fun KtCall.stringRepresentation(): String { - fun KtType.render() = substitutor.substituteOrSelf(this).asStringForDebugging().replace('/', '.') +private fun KtAnalysisSession.stringRepresentation(call: KtCall): String { + fun KtType.render() = call.substitutor.substituteOrSelf(this).asStringForDebugging().replace('/', '.') fun Any.stringValue(): String = when (this) { is KtFunctionLikeSymbol -> buildString { append( @@ -81,7 +81,9 @@ private fun KtCall.stringRepresentation(): String { append(": ${receiver.type.render()}") if (valueParameters.isNotEmpty()) append(", ") } - (this@stringValue as? KtPossibleMemberSymbol)?.dispatchType?.let { dispatchReceiverType -> + + @Suppress("DEPRECATION") + (this@stringValue as? KtPossibleMemberSymbol)?.getDispatchReceiverType()?.let { dispatchReceiverType -> append(": ${dispatchReceiverType.render()}") if (valueParameters.isNotEmpty()) append(", ") } @@ -108,7 +110,7 @@ private fun KtCall.stringRepresentation(): String { else -> error("unexpected parameter type ${this::class}") } - val callInfoClass = this::class + val callInfoClass = call::class return buildString { append(callInfoClass.simpleName!!) append(":\n") @@ -118,7 +120,7 @@ private fun KtCall.stringRepresentation(): String { .filter { it.name != "token" } .joinTo(this, separator = "\n") { parameter -> val name = parameter.name!!.removePrefix("_") - val value = propertyByName[name]!!.javaGetter!!(this@stringRepresentation)?.stringValue() + val value = propertyByName[name]!!.javaGetter!!(call)?.stringValue() "$name = $value" } } diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/components/KtTypeProvider.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/components/KtTypeProvider.kt index 963754c10b0..7d0e9e50549 100644 --- a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/components/KtTypeProvider.kt +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/components/KtTypeProvider.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.analysis.api.components import org.jetbrains.kotlin.analysis.api.ValidityTokenOwner import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol +import org.jetbrains.kotlin.analysis.api.symbols.markers.KtPossibleMemberSymbol import org.jetbrains.kotlin.analysis.api.types.KtFlexibleType import org.jetbrains.kotlin.analysis.api.types.KtType import org.jetbrains.kotlin.analysis.api.types.KtTypeNullability @@ -37,6 +38,7 @@ public abstract class KtTypeProvider : KtAnalysisSessionComponent() { public abstract fun getAllSuperTypes(type: KtType, shouldApproximate: Boolean): List + public abstract fun getDispatchReceiverType(symbol: KtPossibleMemberSymbol): KtType? } public interface KtTypeProviderMixIn : KtAnalysisSessionMixIn { @@ -118,6 +120,21 @@ public interface KtTypeProviderMixIn : KtAnalysisSessionMixIn { */ public fun KtType.getAllSuperTypes(shouldApproximate: Boolean = false): List = analysisSession.typeProvider.getAllSuperTypes(this, shouldApproximate) + + /** + * This function is provided for a few use-cases where it's hard to go without it. + * + * **Please avoid using it**; it will probably be removed in the future. + * + * The function is instantly deprecated, so it's not shown in the completion. + * + * @receiver A target callable symbol. + * @return A dispatch receiver type for this symbol if it has any. + */ + @Suppress("DeprecatedCallableAddReplaceWith") + @Deprecated("Avoid using this function") + public fun KtPossibleMemberSymbol.getDispatchReceiverType(): KtType? = + analysisSession.typeProvider.getDispatchReceiverType(this) } @Suppress("PropertyName")