From 1107e728a24b5ff16a479a5beb24362410b817bd Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Wed, 20 Sep 2023 16:30:46 +0200 Subject: [PATCH] [Analysis API] implement better rendering for chained `KtSubstitutor` --- .../analysis/api/fir/KtSymbolByFirBuilder.kt | 2 ++ .../analysis/api/fir/types/KtFirSubstitutor.kt | 18 ++++++++++++++++++ ...kedSubstitutor.kt => substitutorMarkers.kt} | 14 +++++++++++++- .../base/test/cases/components/testUtils.kt | 5 ++++- .../fir/resolve/substitution/Substitutors.kt | 2 +- 5 files changed, 38 insertions(+), 3 deletions(-) rename analysis/analysis-api-impl-base/src/org/jetbrains/kotlin/analysis/api/impl/base/{KtMapBackedSubstitutor.kt => substitutorMarkers.kt} (70%) diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/KtSymbolByFirBuilder.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/KtSymbolByFirBuilder.kt index 7cb91f22f7a..ce881bb366a 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/KtSymbolByFirBuilder.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/KtSymbolByFirBuilder.kt @@ -44,6 +44,7 @@ import org.jetbrains.kotlin.fir.resolve.getSymbolByLookupTag import org.jetbrains.kotlin.fir.resolve.inference.ConeTypeParameterBasedTypeVariable import org.jetbrains.kotlin.fir.scopes.impl.originalConstructorIfTypeAlias import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider +import org.jetbrains.kotlin.fir.resolve.substitution.ChainedSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap import org.jetbrains.kotlin.fir.resolve.toSymbol @@ -505,6 +506,7 @@ internal class KtSymbolByFirBuilder constructor( if (substitutor == ConeSubstitutor.Empty) return KtSubstitutor.Empty(token) return when (substitutor) { is ConeSubstitutorByMap -> KtFirMapBackedSubstitutor(substitutor, this@KtSymbolByFirBuilder) + is ChainedSubstitutor -> KtFirChainedSubstitutor(substitutor, this@KtSymbolByFirBuilder) else -> KtFirGenericSubstitutor(substitutor, this@KtSymbolByFirBuilder) } } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/types/KtFirSubstitutor.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/types/KtFirSubstitutor.kt index f7e4cef3fa6..deade9e59ea 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/types/KtFirSubstitutor.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/types/KtFirSubstitutor.kt @@ -7,12 +7,14 @@ package org.jetbrains.kotlin.analysis.api.fir.types import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder +import org.jetbrains.kotlin.analysis.api.impl.base.KtChainedSubstitutor import org.jetbrains.kotlin.analysis.api.impl.base.KtMapBackedSubstitutor import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion import org.jetbrains.kotlin.analysis.api.symbols.KtTypeParameterSymbol import org.jetbrains.kotlin.analysis.api.types.KtSubstitutor import org.jetbrains.kotlin.analysis.api.types.KtType +import org.jetbrains.kotlin.fir.resolve.substitution.ChainedSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap @@ -49,4 +51,20 @@ internal class KtFirMapBackedSubstitutor( return result } +} + +@OptIn(KtAnalysisApiInternals::class) +internal class KtFirChainedSubstitutor( + substitutor: ChainedSubstitutor, + builder: KtSymbolByFirBuilder, +) : AbstractKtFirSubstitutor(substitutor, builder), KtChainedSubstitutor { + override val first + get(): KtSubstitutor { + return builder.typeBuilder.buildSubstitutor(substitutor.first) + } + + override val second + get(): KtSubstitutor { + return builder.typeBuilder.buildSubstitutor(substitutor.second) + } } \ No newline at end of file diff --git a/analysis/analysis-api-impl-base/src/org/jetbrains/kotlin/analysis/api/impl/base/KtMapBackedSubstitutor.kt b/analysis/analysis-api-impl-base/src/org/jetbrains/kotlin/analysis/api/impl/base/substitutorMarkers.kt similarity index 70% rename from analysis/analysis-api-impl-base/src/org/jetbrains/kotlin/analysis/api/impl/base/KtMapBackedSubstitutor.kt rename to analysis/analysis-api-impl-base/src/org/jetbrains/kotlin/analysis/api/impl/base/substitutorMarkers.kt index 15fc9b5b47f..9a06248cf12 100644 --- a/analysis/analysis-api-impl-base/src/org/jetbrains/kotlin/analysis/api/impl/base/KtMapBackedSubstitutor.kt +++ b/analysis/analysis-api-impl-base/src/org/jetbrains/kotlin/analysis/api/impl/base/substitutorMarkers.kt @@ -20,4 +20,16 @@ interface KtMapBackedSubstitutor : KtSubstitutor { * Substitution rules in a form of a `Map` */ fun getAsMap(): Map -} \ No newline at end of file +} + + +/** + * A [KtSubstitutor] which substitution logic can be represented as subsequent invocation of two substitutors [first] and [second] + * This is an implementation detail, + * and Analysis API clients should not depend on the fact if some [KtSubstitutor] is [KtChainedSubstitutor] or not. + */ +@KtAnalysisApiInternals +interface KtChainedSubstitutor : KtSubstitutor { + val first: KtSubstitutor + val second: KtSubstitutor +} diff --git a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/testUtils.kt b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/testUtils.kt index c7191d2423f..4304e74c9d2 100644 --- a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/testUtils.kt +++ b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/testUtils.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.analysis.api.KtAnalysisSession import org.jetbrains.kotlin.analysis.api.calls.KtCall import org.jetbrains.kotlin.analysis.api.calls.KtCallableMemberCall import org.jetbrains.kotlin.analysis.api.diagnostics.KtDiagnostic +import org.jetbrains.kotlin.analysis.api.impl.base.KtChainedSubstitutor import org.jetbrains.kotlin.analysis.api.impl.base.KtMapBackedSubstitutor import org.jetbrains.kotlin.analysis.api.renderer.declarations.impl.KtDeclarationRendererForSource import org.jetbrains.kotlin.analysis.api.renderer.declarations.modifiers.renderers.KtRendererKeywordFilter @@ -31,9 +32,10 @@ import kotlin.reflect.KVisibility import kotlin.reflect.full.memberProperties @OptIn(KtAnalysisApiInternals::class) -internal fun KtAnalysisSession.stringRepresentation(any: Any): String = with(any) { +internal fun KtAnalysisSession.stringRepresentation(any: Any?): String = with(any) { fun KtType.render() = asStringForDebugging().replace('/', '.') return when (this) { + null -> "null" is KtFunctionLikeSymbol -> buildString { append( when (this@with) { @@ -84,6 +86,7 @@ internal fun KtAnalysisSession.stringRepresentation(any: Any): String = with(any .joinToString(prefix = "{", postfix = "}") { (k, v) -> stringRepresentation(k) + " = " + v.asStringForDebugging() } "" } + is KtChainedSubstitutor -> "${stringRepresentation(first)} then ${stringRepresentation(second)}" is KtSubstitutor -> "" is KtDiagnostic -> "$severity<$factoryName: $defaultMessage>" is KtType -> render() diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/substitution/Substitutors.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/substitution/Substitutors.kt index cb9e2658c67..79eb8c53751 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/substitution/Substitutors.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/substitution/Substitutors.kt @@ -206,7 +206,7 @@ fun substitutorByMap(substitution: Map, return ConeSubstitutorByMap(substitution, useSiteSession) } -data class ChainedSubstitutor(private val first: ConeSubstitutor, private val second: ConeSubstitutor) : ConeSubstitutor() { +data class ChainedSubstitutor(val first: ConeSubstitutor, val second: ConeSubstitutor) : ConeSubstitutor() { override fun substituteOrNull(type: ConeKotlinType): ConeKotlinType? { first.substituteOrNull(type)?.let { return second.substituteOrSelf(it) } return second.substituteOrNull(type)