[FIR] Split functions & constructors processing

This commit is contained in:
simon.ogorodnik
2020-04-09 22:34:23 +03:00
parent 7a1ecabe0a
commit c2ea0676e4
9 changed files with 260 additions and 99 deletions
@@ -190,7 +190,7 @@ abstract class AbstractFirTypeEnhancementTest : KtUsefulTestCase() {
for (declaration in javaClass.declarations) { for (declaration in javaClass.declarations) {
if (declaration in renderedDeclarations) continue if (declaration in renderedDeclarations) continue
when (declaration) { when (declaration) {
is FirJavaConstructor -> enhancementScope.processFunctionsByName(javaClass.name) { symbol -> is FirJavaConstructor -> enhancementScope.processDeclaredConstructors { symbol ->
val enhanced = symbol.fir val enhanced = symbol.fir
if (enhanced !in renderedDeclarations) { if (enhanced !in renderedDeclarations) {
enhanced.accept(renderer, null) enhanced.accept(renderer, null)
@@ -82,9 +82,9 @@ class JavaClassEnhancementScope(
} }
private fun enhance( private fun enhance(
original: FirCallableSymbol<*>, original: FirVariableSymbol<*>,
name: Name name: Name
): FirCallableSymbol<*> { ): FirVariableSymbol<*> {
when (val firElement = original.fir) { when (val firElement = original.fir) {
is FirField -> { is FirField -> {
if (firElement.returnTypeRef !is FirJavaTypeRef) return original if (firElement.returnTypeRef !is FirJavaTypeRef) return original
@@ -139,7 +139,7 @@ class JavaClassEnhancementScope(
private fun enhance( private fun enhance(
original: FirFunctionSymbol<*>, original: FirFunctionSymbol<*>,
name: Name name: Name?
): FirFunctionSymbol<*> { ): FirFunctionSymbol<*> {
val firMethod = original.fir val firMethod = original.fir
@@ -152,7 +152,7 @@ class JavaClassEnhancementScope(
private fun enhanceMethod( private fun enhanceMethod(
firMethod: FirFunction<*>, firMethod: FirFunction<*>,
methodId: CallableId, methodId: CallableId,
name: Name name: Name?
): FirFunctionSymbol<*> { ): FirFunctionSymbol<*> {
val memberContext = context.copyWithNewDefaultTypeQualifiers(typeQualifierResolver, jsr305State, firMethod.annotations) val memberContext = context.copyWithNewDefaultTypeQualifiers(typeQualifierResolver, jsr305State, firMethod.annotations)
@@ -241,7 +241,7 @@ class JavaClassEnhancementScope(
session = this@JavaClassEnhancementScope.session session = this@JavaClassEnhancementScope.session
returnTypeRef = newReturnTypeRef returnTypeRef = newReturnTypeRef
receiverTypeRef = newReceiverTypeRef receiverTypeRef = newReceiverTypeRef
this.name = name this.name = name!!
status = firMethod.status status = firMethod.status
symbol = FirNamedFunctionSymbol(methodId) symbol = FirNamedFunctionSymbol(methodId)
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
@@ -402,4 +402,13 @@ class JavaClassEnhancementScope(
) )
} }
override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) {
useSiteMemberScope.processDeclaredConstructors process@{ original ->
val function = enhancements.getOrPut(original) { enhance(original, name = null) }
processor(function as FirConstructorSymbol)
}
}
} }
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -17,11 +18,11 @@ import org.jetbrains.kotlin.name.Name
class JvmMappedScope( class JvmMappedScope(
private val declaredMemberScope: FirScope, private val declaredMemberScope: FirScope,
private val javaMappedClassUseSiteScope: FirScope, private val javaMappedClassUseSiteScope: FirScope,
private val whiteListSignaturesByName: Map<Name, List<String>> private val signatures: Signatures
) : FirScope() { ) : FirScope() {
override fun processFunctionsByName(name: Name, processor: (FirFunctionSymbol<*>) -> Unit) { override fun processFunctionsByName(name: Name, processor: (FirFunctionSymbol<*>) -> Unit) {
val whiteListSignatures = whiteListSignaturesByName[name] val whiteListSignatures = signatures.whiteListSignaturesByName[name]
?: return declaredMemberScope.processFunctionsByName(name, processor) ?: return declaredMemberScope.processFunctionsByName(name, processor)
javaMappedClassUseSiteScope.processFunctionsByName(name) { symbol -> javaMappedClassUseSiteScope.processFunctionsByName(name) { symbol ->
val jvmSignature = symbol.fir.computeJvmDescriptor() val jvmSignature = symbol.fir.computeJvmDescriptor()
@@ -36,6 +37,22 @@ class JvmMappedScope(
declaredMemberScope.processFunctionsByName(name, processor) declaredMemberScope.processFunctionsByName(name, processor)
} }
override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) {
val constructorBlackList = signatures.constructorBlackList
if (constructorBlackList.isNotEmpty()) {
javaMappedClassUseSiteScope.processDeclaredConstructors { symbol ->
val jvmSignature = symbol.fir.computeJvmDescriptor()
.replace("kotlin/Any", "java/lang/Object")
.replace("kotlin/String", "java/lang/String")
if (jvmSignature !in constructorBlackList) {
processor(symbol)
}
}
}
declaredMemberScope.processDeclaredConstructors(processor)
}
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) { override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
declaredMemberScope.processPropertiesByName(name, processor) declaredMemberScope.processPropertiesByName(name, processor)
} }
@@ -45,15 +62,27 @@ class JvmMappedScope(
} }
companion object { companion object {
fun prepareSignatures(klass: FirRegularClass): Map<Name, List<String>> { data class Signatures(val whiteListSignaturesByName: Map<Name, Set<String>>, val constructorBlackList: Set<String>) {
fun isEmpty() = whiteListSignaturesByName.isEmpty() && constructorBlackList.isEmpty()
fun isNotEmpty() = !isEmpty()
}
fun prepareSignatures(klass: FirRegularClass): Signatures {
val signaturePrefix = klass.symbol.classId.toString() val signaturePrefix = klass.symbol.classId.toString()
val filteredSignatures = JvmBuiltInsSettings.WHITE_LIST_METHOD_SIGNATURES.filter { signature -> val whiteListSignaturesByName = mutableMapOf<Name, MutableSet<String>>()
JvmBuiltInsSettings.WHITE_LIST_METHOD_SIGNATURES.filter { signature ->
signature.startsWith(signaturePrefix) signature.startsWith(signaturePrefix)
}.map { signature -> }.map { signature ->
// +1 to delete dot before function name // +1 to delete dot before function name
signature.substring(signaturePrefix.length + 1) signature.substring(signaturePrefix.length + 1)
}.forEach {
whiteListSignaturesByName.getOrPut(Name.identifier(it.substringBefore("("))) { mutableSetOf() }.add(it)
} }
return filteredSignatures.groupBy { Name.identifier(it.substringBefore("(")) }
val constructorBlackList = JvmBuiltInsSettings.BLACK_LIST_CONSTRUCTOR_SIGNATURES
.filter { it.startsWith(signaturePrefix) }
.mapTo(mutableSetOf()) { it.substring(signaturePrefix.length + 1) }
return Signatures(whiteListSignaturesByName, constructorBlackList)
} }
} }
} }
@@ -308,12 +308,10 @@ class FirCallResolver(
val candidateFactory = CandidateFactory(this, callInfo) val candidateFactory = CandidateFactory(this, callInfo)
val candidates = mutableListOf<Candidate>() val candidates = mutableListOf<Candidate>()
scope.processFunctionsByName(className) { scope.processDeclaredConstructors {
if (it is FirConstructorSymbol) { val candidate = candidateFactory.createCandidate(it, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER)
val candidate = candidateFactory.createCandidate(it, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER) candidate.typeArgumentMapping = TypeArgumentMapping.Mapped(typeArguments)
candidate.typeArgumentMapping = TypeArgumentMapping.Mapped(typeArguments) candidates += candidate
candidates += candidate
}
} }
return callResolver.selectDelegatingConstructorCall(delegatedConstructorCall, className, candidates) return callResolver.selectDelegatingConstructorCall(delegatedConstructorCall, className, candidates)
} }
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.resolve.calls
import com.intellij.openapi.progress.ProcessCanceledException import com.intellij.openapi.progress.ProcessCanceledException
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.buildConstructedClassTypeParameterRef
import org.jetbrains.kotlin.fir.declarations.builder.buildConstructor import org.jetbrains.kotlin.fir.declarations.builder.buildConstructor
import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameter import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameter
import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.*
@@ -16,7 +17,7 @@ import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.impl.FirClassSubstitutionScope import org.jetbrains.kotlin.fir.scopes.impl.FirClassSubstitutionScope
import org.jetbrains.kotlin.fir.scopes.impl.withReplacedConeType import org.jetbrains.kotlin.fir.scopes.impl.withReplacedConeType
import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope import org.jetbrains.kotlin.fir.scopes.scope
import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.ConeClassLikeType import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.ConeKotlinType
@@ -24,6 +25,9 @@ import org.jetbrains.kotlin.fir.types.coneTypeUnsafe
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.addToStdlib.safeAs
private operator fun <T> Pair<T, *>?.component1() = this?.first
private operator fun <T> Pair<*, T>?.component2() = this?.second
internal fun FirScope.processFunctionsAndConstructorsByName( internal fun FirScope.processFunctionsAndConstructorsByName(
name: Name, name: Name,
session: FirSession, session: FirSession,
@@ -32,34 +36,38 @@ internal fun FirScope.processFunctionsAndConstructorsByName(
processor: (FirCallableSymbol<*>) -> Unit processor: (FirCallableSymbol<*>) -> Unit
) { ) {
// TODO: Handle case with two or more accessible classifiers // TODO: Handle case with two or more accessible classifiers
val matchedClassSymbol = getFirstClassifierOrNull(name) as? FirClassLikeSymbol<*> val classifierInfo = getFirstClassifierOrNull(name)
if (classifierInfo != null) {
val (matchedClassifierSymbol, substitutor) = classifierInfo
val matchedClassSymbol = matchedClassifierSymbol as? FirClassLikeSymbol<*>
processConstructors(
matchedClassSymbol,
processor,
session,
bodyResolveComponents.scopeSession,
noInnerConstructors
)
processSyntheticConstructors( processConstructors(
matchedClassSymbol, matchedClassSymbol,
processor, substitutor,
bodyResolveComponents processor,
) session,
bodyResolveComponents.scopeSession,
noInnerConstructors
)
processSyntheticConstructors(
matchedClassSymbol,
processor,
bodyResolveComponents
)
}
processFunctionsByName(name) { processFunctionsByName(name) {
if (it !is FirConstructorSymbol) { processor(it)
processor(it)
}
} }
} }
private fun FirScope.getFirstClassifierOrNull(name: Name): FirClassifierSymbol<*>? { private fun FirScope.getFirstClassifierOrNull(name: Name): Pair<FirClassifierSymbol<*>, ConeSubstitutor>? {
var result: FirClassifierSymbol<*>? = null var result: Pair<FirClassifierSymbol<*>, ConeSubstitutor>? = null
processClassifiersByName(name) { processClassifiersByNameWithSubstitution(name) { symbol, substitution ->
if (result == null) { if (result == null) {
result = it result = symbol to substitution
} }
} }
@@ -127,6 +135,7 @@ private fun FirTypeAliasSymbol.findSAMConstructorForTypeAlias(
private fun processConstructors( private fun processConstructors(
matchedSymbol: FirClassLikeSymbol<*>?, matchedSymbol: FirClassLikeSymbol<*>?,
substitutor: ConeSubstitutor,
processor: (FirFunctionSymbol<*>) -> Unit, processor: (FirFunctionSymbol<*>) -> Unit,
session: FirSession, session: FirSession,
scopeSession: ScopeSession, scopeSession: ScopeSession,
@@ -145,18 +154,15 @@ private fun processConstructors(
) ?: return ) ?: return
} else basicScope } else basicScope
} }
is FirClassSymbol -> (matchedSymbol.fir as FirClass<*>).unsubstitutedScope(session, scopeSession) is FirClassSymbol ->
} (matchedSymbol.fir as FirClass<*>).scope(
substitutor, session, scopeSession, false,
val constructorName = when (matchedSymbol) { )
is FirTypeAliasSymbol -> finalExpansionName(matchedSymbol, session) ?: return
is FirRegularClassSymbol -> matchedSymbol.fir.name
else -> return
} }
//TODO: why don't we use declared member scope at this point? //TODO: why don't we use declared member scope at this point?
scope?.processFunctionsByName(constructorName) { scope?.processDeclaredConstructors {
if (!noInner || (it as? FirConstructorSymbol)?.fir?.isInner != true) { if (!noInner || !it.fir.isInner) {
processor(it) processor(it)
} }
} }
@@ -169,29 +175,37 @@ private fun processConstructors(
} }
private class TypeAliasConstructorsSubstitutingScope( private class TypeAliasConstructorsSubstitutingScope(
private val typeAliasConstructorsSubstitutor: TypeAliasConstructorsSubstitutor<FirConstructor>, private val typeAliasSymbol: FirTypeAliasSymbol,
private val copyFactory: ConstructorCopyFactory<FirConstructor>,
private val delegatingScope: FirScope private val delegatingScope: FirScope
) : FirScope() { ) : FirScope() {
override fun processFunctionsByName(name: Name, processor: (FirFunctionSymbol<*>) -> Unit) {
delegatingScope.processFunctionsByName(name) {
val toProcess = if (it is FirConstructorSymbol) {
typeAliasConstructorsSubstitutor.substitute(it.fir).symbol
} else {
it
}
processor(toProcess) override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) {
delegatingScope.processDeclaredConstructors {
val typeParameters = typeAliasSymbol.fir.typeParameters
if (typeParameters.isEmpty()) processor(it)
else {
processor(it.fir.copyFactory(
null,
null,
typeParameters.map { buildConstructedClassTypeParameterRef { symbol = it.symbol } }
).symbol)
}
} }
} }
} }
private typealias ConstructorCopyFactory2<F> =
F.(newReturnType: ConeKotlinType?, newValueParameterTypes: List<ConeKotlinType?>?, newTypeParameters: List<FirTypeParameter>) -> F
private typealias ConstructorCopyFactory<F> = private typealias ConstructorCopyFactory<F> =
F.(newReturnType: ConeKotlinType?, newValueParameterTypes: List<ConeKotlinType?>, newTypeParameters: List<FirTypeParameter>) -> F F.(newReturnType: ConeKotlinType?, newValueParameterTypes: List<ConeKotlinType?>?, newTypeParameters: List<FirTypeParameterRef>) -> F
private class TypeAliasConstructorsSubstitutor<F : FirFunction<F>>( private class TypeAliasConstructorsSubstitutor<F : FirFunction<F>>(
private val typeAliasSymbol: FirTypeAliasSymbol, private val typeAliasSymbol: FirTypeAliasSymbol,
private val substitutor: ConeSubstitutor, private val substitutor: ConeSubstitutor,
private val copyFactory: ConstructorCopyFactory<F> private val copyFactory: ConstructorCopyFactory2<F>
) { ) {
fun substitute(baseFunction: F): F { fun substitute(baseFunction: F): F {
val typeParameters = typeAliasSymbol.fir.typeParameters val typeParameters = typeAliasSymbol.fir.typeParameters
@@ -217,20 +231,16 @@ private fun prepareSubstitutingScopeForTypeAliasConstructors(
session: FirSession, session: FirSession,
delegatingScope: FirScope delegatingScope: FirScope
): FirScope? { ): FirScope? {
val typeAliasConstructorsSubstitutor = val copyFactory2: ConstructorCopyFactory<FirConstructor> = factory@ { newReturnType, newParameterTypes, newTypeParameters ->
prepareSubstitutorForTypeAliasConstructors<FirConstructor>( buildConstructor {
typeAliasSymbol, source = this@factory.source
expandedType, this.session = session
session returnTypeRef = this@factory.returnTypeRef.withReplacedConeType(newReturnType)
) factory@{ newReturnType, newParameterTypes, newTypeParameters -> receiverTypeRef = this@factory.receiverTypeRef
buildConstructor { status = this@factory.status
source = this@factory.source symbol = FirConstructorSymbol(this@factory.symbol.callableId, overriddenSymbol = this@factory.symbol)
this.session = session resolvePhase = this@factory.resolvePhase
returnTypeRef = this@factory.returnTypeRef.withReplacedConeType(newReturnType) if (newParameterTypes != null) {
receiverTypeRef = this@factory.receiverTypeRef
status = this@factory.status
symbol = FirConstructorSymbol(this@factory.symbol.callableId, overriddenSymbol = this@factory.symbol)
resolvePhase = this@factory.resolvePhase
valueParameters += valueParameters +=
this@factory.valueParameters.zip( this@factory.valueParameters.zip(
newParameterTypes newParameterTypes
@@ -247,12 +257,16 @@ private fun prepareSubstitutingScopeForTypeAliasConstructors(
isVararg = valueParameter.isVararg isVararg = valueParameter.isVararg
} }
} }
this.typeParameters += newTypeParameters } else {
valueParameters += this@factory.valueParameters
} }
} ?: return null this.typeParameters += newTypeParameters
}
}
return TypeAliasConstructorsSubstitutingScope( return TypeAliasConstructorsSubstitutingScope(
typeAliasConstructorsSubstitutor, typeAliasSymbol,
copyFactory2,
delegatingScope delegatingScope
) )
} }
@@ -261,7 +275,7 @@ private fun <F : FirFunction<F>> prepareSubstitutorForTypeAliasConstructors(
typeAliasSymbol: FirTypeAliasSymbol, typeAliasSymbol: FirTypeAliasSymbol,
expandedType: ConeClassLikeType, expandedType: ConeClassLikeType,
session: FirSession, session: FirSession,
copyFactory: ConstructorCopyFactory<F> copyFactory: ConstructorCopyFactory2<F>
): TypeAliasConstructorsSubstitutor<F>? { ): TypeAliasConstructorsSubstitutor<F>? {
val expandedClass = expandedType.lookupTag.toSymbol(session)?.fir as? FirRegularClass ?: return null val expandedClass = expandedType.lookupTag.toSymbol(session)?.fir as? FirRegularClass ?: return null
@@ -11,9 +11,6 @@ import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.declarations.FirValueParameter import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.declarations.builder.FirSimpleFunctionBuilder import org.jetbrains.kotlin.fir.declarations.builder.FirSimpleFunctionBuilder
import org.jetbrains.kotlin.fir.declarations.builder.FirValueParameterBuilder import org.jetbrains.kotlin.fir.declarations.builder.FirValueParameterBuilder
import org.jetbrains.kotlin.fir.declarations.builder.buildSimpleFunction
import org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl
import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl
import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.scopes.FirOverrideChecker import org.jetbrains.kotlin.fir.scopes.FirOverrideChecker
@@ -123,4 +120,8 @@ abstract class AbstractFirUseSiteMemberScope(
declaredMemberScope.processClassifiersByNameWithSubstitution(name, processor) declaredMemberScope.processClassifiersByNameWithSubstitution(name, processor)
superTypesScope.processClassifiersByNameWithSubstitution(name, processor) superTypesScope.processClassifiersByNameWithSubstitution(name, processor)
} }
override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) {
declaredMemberScope.processDeclaredConstructors(processor)
}
} }
@@ -9,10 +9,7 @@ import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
class FirClassDeclaredMemberScope( class FirClassDeclaredMemberScope(
@@ -33,7 +30,7 @@ class FirClassDeclaredMemberScope(
when (declaration) { when (declaration) {
is FirCallableMemberDeclaration<*> -> { is FirCallableMemberDeclaration<*> -> {
val name = when (declaration) { val name = when (declaration) {
is FirConstructor -> if (klass is FirRegularClass) klass.name else continue@loop is FirConstructor -> Name.special("<init>")
is FirVariable<*> -> declaration.name is FirVariable<*> -> declaration.name
is FirSimpleFunction -> declaration.name is FirSimpleFunction -> declaration.name
else -> continue@loop else -> continue@loop
@@ -54,6 +51,15 @@ class FirClassDeclaredMemberScope(
} }
} }
override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) {
val symbols = callablesIndex[Name.special("<init>")] ?: return
for (symbol in symbols) {
if (symbol is FirConstructorSymbol) {
processor(symbol)
}
}
}
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) { override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
val symbols = callablesIndex[name] ?: emptyList() val symbols = callablesIndex[name] ?: emptyList()
for (symbol in symbols) { for (symbol in symbols) {
@@ -40,6 +40,7 @@ class FirClassSubstitutionScope(
) : FirScope() { ) : FirScope() {
private val fakeOverrideFunctions = mutableMapOf<FirFunctionSymbol<*>, FirFunctionSymbol<*>>() private val fakeOverrideFunctions = mutableMapOf<FirFunctionSymbol<*>, FirFunctionSymbol<*>>()
private val fakeOverrideConstructors = mutableMapOf<FirConstructorSymbol, FirConstructorSymbol>()
private val fakeOverrideProperties = mutableMapOf<FirPropertySymbol, FirPropertySymbol>() private val fakeOverrideProperties = mutableMapOf<FirPropertySymbol, FirPropertySymbol>()
private val fakeOverrideFields = mutableMapOf<FirFieldSymbol, FirFieldSymbol>() private val fakeOverrideFields = mutableMapOf<FirFieldSymbol, FirFieldSymbol>()
private val fakeOverrideAccessors = mutableMapOf<FirAccessorSymbol, FirAccessorSymbol>() private val fakeOverrideAccessors = mutableMapOf<FirAccessorSymbol, FirAccessorSymbol>()
@@ -127,35 +128,66 @@ class FirClassSubstitutionScope(
} }
return createFakeOverrideFunction( return createFakeOverrideFunction(
session, member, original, newReceiverType, newReturnType, newParameterTypes, newTypeParameters, derivedClassId session,
member,
original,
newReceiverType,
newReturnType,
newParameterTypes,
newTypeParameters as List<FirTypeParameter>,
derivedClassId
) )
} }
private fun createFakeOverrideConstructor(original: FirConstructorSymbol): FirConstructorSymbol {
if (substitutor == ConeSubstitutor.Empty) return original
val constructor = original.fir
val (newTypeParameters, newSubstitutor) = createNewTypeParametersAndSubstitutor(constructor)
val returnType = constructor.returnTypeRef.coneTypeUnsafe<ConeKotlinType>()
val newReturnType = returnType.substitute(newSubstitutor)
val newParameterTypes = constructor.valueParameters.map {
it.returnTypeRef.coneTypeUnsafe<ConeKotlinType>().substitute(newSubstitutor)
}
if (newReturnType == null && newParameterTypes.all { it == null } && newTypeParameters === constructor.typeParameters) {
return original
}
return createFakeOverrideConstructor(FirConstructorSymbol(original.callableId, overriddenSymbol = original), session, constructor, null, newReturnType, newParameterTypes, newTypeParameters).symbol
}
// Returns a list of type parameters, and a substitutor that should be used for all other types // Returns a list of type parameters, and a substitutor that should be used for all other types
private fun createNewTypeParametersAndSubstitutor( private fun createNewTypeParametersAndSubstitutor(
member: FirCallableMemberDeclaration<*> member: FirTypeParameterRefsOwner
): Pair<List<FirTypeParameter>, ConeSubstitutor> { ): Pair<List<FirTypeParameterRef>, ConeSubstitutor> {
if (member.typeParameters.isEmpty()) return Pair(member.typeParameters, substitutor) if (member.typeParameters.isEmpty()) return Pair(member.typeParameters, substitutor)
val newTypeParameters = member.typeParameters.map { originalParameter -> val newTypeParameters = member.typeParameters.map { typeParameter ->
if (typeParameter !is FirTypeParameter) return@map null
FirTypeParameterBuilder().apply { FirTypeParameterBuilder().apply {
source = originalParameter.source source = typeParameter.source
session = originalParameter.session session = typeParameter.session
name = originalParameter.name name = typeParameter.name
symbol = FirTypeParameterSymbol() symbol = FirTypeParameterSymbol()
variance = originalParameter.variance variance = typeParameter.variance
isReified = originalParameter.isReified isReified = typeParameter.isReified
annotations += originalParameter.annotations annotations += typeParameter.annotations
} }
} }
val substitutionMapForNewParameters = member.typeParameters.zip(newTypeParameters).map { val substitutionMapForNewParameters = member.typeParameters.zip(newTypeParameters).mapNotNull { (original, new) ->
Pair(it.first.symbol, ConeTypeParameterTypeImpl(it.second.symbol.toLookupTag(), isNullable = false)) if (new != null)
Pair(original.symbol, ConeTypeParameterTypeImpl(new.symbol.toLookupTag(), isNullable = false))
else null
}.toMap() }.toMap()
val additionalSubstitutor = substitutorByMap(substitutionMapForNewParameters) val additionalSubstitutor = substitutorByMap(substitutionMapForNewParameters)
for ((newTypeParameter, oldTypeParameter) in newTypeParameters.zip(member.typeParameters)) { for ((newTypeParameter, oldTypeParameter) in newTypeParameters.zip(member.typeParameters)) {
for (boundTypeRef in oldTypeParameter.bounds) { if (newTypeParameter == null) continue
val original = oldTypeParameter as FirTypeParameter
for (boundTypeRef in original.bounds) {
val typeForBound = boundTypeRef.coneTypeUnsafe<ConeKotlinType>() val typeForBound = boundTypeRef.coneTypeUnsafe<ConeKotlinType>()
val substitutedBound = typeForBound.substitute() val substitutedBound = typeForBound.substitute()
newTypeParameter.bounds += newTypeParameter.bounds +=
@@ -171,7 +203,10 @@ class FirClassSubstitutionScope(
// While common Ir contracts expect them to be different // While common Ir contracts expect them to be different
// if (!wereChangesInTypeParameters) return Pair(member.typeParameters, substitutor) // if (!wereChangesInTypeParameters) return Pair(member.typeParameters, substitutor)
return Pair(newTypeParameters.map { it.build() }, ChainedSubstitutor(substitutor, additionalSubstitutor)) return Pair(
newTypeParameters.mapIndexed { index, builder -> builder?.build() ?: member.typeParameters[index] },
ChainedSubstitutor(substitutor, additionalSubstitutor)
)
} }
private fun createFakeOverrideProperty(original: FirPropertySymbol): FirPropertySymbol { private fun createFakeOverrideProperty(original: FirPropertySymbol): FirPropertySymbol {
@@ -193,7 +228,16 @@ class FirClassSubstitutionScope(
return original return original
} }
return createFakeOverrideProperty(session, member, original, newReceiverType, newReturnType, newTypeParameters, derivedClassId) @Suppress("UNCHECKED_CAST")
return createFakeOverrideProperty(
session,
member,
original,
newReceiverType,
newReturnType,
newTypeParameters as List<FirTypeParameter>,
derivedClassId
)
} }
private fun createFakeOverrideField(original: FirFieldSymbol): FirFieldSymbol { private fun createFakeOverrideField(original: FirFieldSymbol): FirFieldSymbol {
@@ -369,6 +413,61 @@ class FirClassSubstitutionScope(
delegateGetter = function delegateGetter = function
}.symbol }.symbol
} }
private fun createFakeOverrideConstructor(
fakeOverrideSymbol: FirConstructorSymbol,
session: FirSession,
baseConstructor: FirConstructor,
newReceiverType: ConeKotlinType? = null,
newReturnType: ConeKotlinType? = null,
newParameterTypes: List<ConeKotlinType?>? = null,
newTypeParameters: List<FirTypeParameterRef>? = null
): FirConstructor {
// TODO: consider using here some light-weight functions instead of pseudo-real FirMemberFunctionImpl
// As second alternative, we can invent some light-weight kind of FirRegularClass
return buildConstructor {
source = baseConstructor.source
this.session = session
returnTypeRef = baseConstructor.returnTypeRef.withReplacedReturnType(newReturnType)
receiverTypeRef = baseConstructor.receiverTypeRef?.withReplacedConeType(newReceiverType)
status = baseConstructor.status
symbol = fakeOverrideSymbol
annotations += baseConstructor.annotations
resolvePhase = baseConstructor.resolvePhase
valueParameters += baseConstructor.valueParameters.zip(
newParameterTypes ?: List(baseConstructor.valueParameters.size) { null }
) { valueParameter, newType ->
buildValueParameter {
source = valueParameter.source
this.session = session
returnTypeRef = valueParameter.returnTypeRef.withReplacedConeType(newType)
name = valueParameter.name
symbol = FirVariableSymbol(valueParameter.symbol.callableId)
defaultValue = valueParameter.defaultValue
isCrossinline = valueParameter.isCrossinline
isNoinline = valueParameter.isNoinline
isVararg = valueParameter.isVararg
}
}
// TODO: Fix the hack for org.jetbrains.kotlin.fir.backend.Fir2IrVisitor.addFakeOverrides
// We might have added baseFunction.typeParameters in case new ones are null
// But it fails at org.jetbrains.kotlin.ir.AbstractIrTextTestCase.IrVerifier.elementsAreUniqueChecker
// because it shares the same declarations of type parameters between two different two functions
if (newTypeParameters != null) {
typeParameters += newTypeParameters
}
}
}
}
override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) {
useSiteMemberScope.processDeclaredConstructors process@{ original ->
val constructor = fakeOverrideConstructors.getOrPut(original) { createFakeOverrideConstructor(original) }
processor(constructor)
}
} }
} }
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.scopes
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -26,6 +27,10 @@ abstract class FirScope {
name: Name, name: Name,
processor: (FirVariableSymbol<*>) -> Unit processor: (FirVariableSymbol<*>) -> Unit
) {} ) {}
open fun processDeclaredConstructors(
processor: (FirConstructorSymbol) -> Unit
) {}
} }
enum class ProcessorAction { enum class ProcessorAction {