[Analysis API] implement better rendering for chained KtSubstitutor

This commit is contained in:
Ilya Kirillov
2023-09-20 16:30:46 +02:00
committed by Space Team
parent e2d248b76d
commit 1107e728a2
5 changed files with 38 additions and 3 deletions
@@ -44,6 +44,7 @@ import org.jetbrains.kotlin.fir.resolve.getSymbolByLookupTag
import org.jetbrains.kotlin.fir.resolve.inference.ConeTypeParameterBasedTypeVariable import org.jetbrains.kotlin.fir.resolve.inference.ConeTypeParameterBasedTypeVariable
import org.jetbrains.kotlin.fir.scopes.impl.originalConstructorIfTypeAlias import org.jetbrains.kotlin.fir.scopes.impl.originalConstructorIfTypeAlias
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider 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.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap
import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.resolve.toSymbol
@@ -505,6 +506,7 @@ internal class KtSymbolByFirBuilder constructor(
if (substitutor == ConeSubstitutor.Empty) return KtSubstitutor.Empty(token) if (substitutor == ConeSubstitutor.Empty) return KtSubstitutor.Empty(token)
return when (substitutor) { return when (substitutor) {
is ConeSubstitutorByMap -> KtFirMapBackedSubstitutor(substitutor, this@KtSymbolByFirBuilder) is ConeSubstitutorByMap -> KtFirMapBackedSubstitutor(substitutor, this@KtSymbolByFirBuilder)
is ChainedSubstitutor -> KtFirChainedSubstitutor(substitutor, this@KtSymbolByFirBuilder)
else -> KtFirGenericSubstitutor(substitutor, this@KtSymbolByFirBuilder) else -> KtFirGenericSubstitutor(substitutor, this@KtSymbolByFirBuilder)
} }
} }
@@ -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.KtAnalysisApiInternals
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder 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.impl.base.KtMapBackedSubstitutor
import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion
import org.jetbrains.kotlin.analysis.api.symbols.KtTypeParameterSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtTypeParameterSymbol
import org.jetbrains.kotlin.analysis.api.types.KtSubstitutor import org.jetbrains.kotlin.analysis.api.types.KtSubstitutor
import org.jetbrains.kotlin.analysis.api.types.KtType 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.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap
@@ -50,3 +52,19 @@ internal class KtFirMapBackedSubstitutor(
return result return result
} }
} }
@OptIn(KtAnalysisApiInternals::class)
internal class KtFirChainedSubstitutor(
substitutor: ChainedSubstitutor,
builder: KtSymbolByFirBuilder,
) : AbstractKtFirSubstitutor<ChainedSubstitutor>(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)
}
}
@@ -21,3 +21,15 @@ interface KtMapBackedSubstitutor : KtSubstitutor {
*/ */
fun getAsMap(): Map<KtTypeParameterSymbol, KtType> fun getAsMap(): Map<KtTypeParameterSymbol, KtType>
} }
/**
* 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
}
@@ -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.KtCall
import org.jetbrains.kotlin.analysis.api.calls.KtCallableMemberCall import org.jetbrains.kotlin.analysis.api.calls.KtCallableMemberCall
import org.jetbrains.kotlin.analysis.api.diagnostics.KtDiagnostic 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.impl.base.KtMapBackedSubstitutor
import org.jetbrains.kotlin.analysis.api.renderer.declarations.impl.KtDeclarationRendererForSource import org.jetbrains.kotlin.analysis.api.renderer.declarations.impl.KtDeclarationRendererForSource
import org.jetbrains.kotlin.analysis.api.renderer.declarations.modifiers.renderers.KtRendererKeywordFilter import org.jetbrains.kotlin.analysis.api.renderer.declarations.modifiers.renderers.KtRendererKeywordFilter
@@ -31,9 +32,10 @@ import kotlin.reflect.KVisibility
import kotlin.reflect.full.memberProperties import kotlin.reflect.full.memberProperties
@OptIn(KtAnalysisApiInternals::class) @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('/', '.') fun KtType.render() = asStringForDebugging().replace('/', '.')
return when (this) { return when (this) {
null -> "null"
is KtFunctionLikeSymbol -> buildString { is KtFunctionLikeSymbol -> buildString {
append( append(
when (this@with) { 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() } .joinToString(prefix = "{", postfix = "}") { (k, v) -> stringRepresentation(k) + " = " + v.asStringForDebugging() }
"<map substitutor: $mappingText>" "<map substitutor: $mappingText>"
} }
is KtChainedSubstitutor -> "${stringRepresentation(first)} then ${stringRepresentation(second)}"
is KtSubstitutor -> "<complex substitutor>" is KtSubstitutor -> "<complex substitutor>"
is KtDiagnostic -> "$severity<$factoryName: $defaultMessage>" is KtDiagnostic -> "$severity<$factoryName: $defaultMessage>"
is KtType -> render() is KtType -> render()
@@ -206,7 +206,7 @@ fun substitutorByMap(substitution: Map<FirTypeParameterSymbol, ConeKotlinType>,
return ConeSubstitutorByMap(substitution, useSiteSession) 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? { override fun substituteOrNull(type: ConeKotlinType): ConeKotlinType? {
first.substituteOrNull(type)?.let { return second.substituteOrSelf(it) } first.substituteOrNull(type)?.let { return second.substituteOrSelf(it) }
return second.substituteOrNull(type) return second.substituteOrNull(type)