diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/java/AbstractFirTypeEnhancementTest.kt b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/java/AbstractFirTypeEnhancementTest.kt index 25cfc909f53..94b403c794e 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/java/AbstractFirTypeEnhancementTest.kt +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/java/AbstractFirTypeEnhancementTest.kt @@ -190,7 +190,7 @@ abstract class AbstractFirTypeEnhancementTest : KtUsefulTestCase() { for (declaration in javaClass.declarations) { if (declaration in renderedDeclarations) continue when (declaration) { - is FirJavaConstructor -> enhancementScope.processFunctionsByName(javaClass.name) { symbol -> + is FirJavaConstructor -> enhancementScope.processDeclaredConstructors { symbol -> val enhanced = symbol.fir if (enhanced !in renderedDeclarations) { enhanced.accept(renderer, null) diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassEnhancementScope.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassEnhancementScope.kt index 06014e0d6e4..568f1ed297f 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassEnhancementScope.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassEnhancementScope.kt @@ -82,9 +82,9 @@ class JavaClassEnhancementScope( } private fun enhance( - original: FirCallableSymbol<*>, + original: FirVariableSymbol<*>, name: Name - ): FirCallableSymbol<*> { + ): FirVariableSymbol<*> { when (val firElement = original.fir) { is FirField -> { if (firElement.returnTypeRef !is FirJavaTypeRef) return original @@ -139,7 +139,7 @@ class JavaClassEnhancementScope( private fun enhance( original: FirFunctionSymbol<*>, - name: Name + name: Name? ): FirFunctionSymbol<*> { val firMethod = original.fir @@ -152,7 +152,7 @@ class JavaClassEnhancementScope( private fun enhanceMethod( firMethod: FirFunction<*>, methodId: CallableId, - name: Name + name: Name? ): FirFunctionSymbol<*> { val memberContext = context.copyWithNewDefaultTypeQualifiers(typeQualifierResolver, jsr305State, firMethod.annotations) @@ -241,7 +241,7 @@ class JavaClassEnhancementScope( session = this@JavaClassEnhancementScope.session returnTypeRef = newReturnTypeRef receiverTypeRef = newReceiverTypeRef - this.name = name + this.name = name!! status = firMethod.status symbol = FirNamedFunctionSymbol(methodId) 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) + } + } + } diff --git a/compiler/fir/jvm/src/org/jetbrains/kotlin/fir/scopes/jvm/JvmMappedScope.kt b/compiler/fir/jvm/src/org/jetbrains/kotlin/fir/scopes/jvm/JvmMappedScope.kt index 6eed8645764..eeab37135eb 100644 --- a/compiler/fir/jvm/src/org/jetbrains/kotlin/fir/scopes/jvm/JvmMappedScope.kt +++ b/compiler/fir/jvm/src/org/jetbrains/kotlin/fir/scopes/jvm/JvmMappedScope.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.scopes.FirScope 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.FirVariableSymbol import org.jetbrains.kotlin.name.Name @@ -17,11 +18,11 @@ import org.jetbrains.kotlin.name.Name class JvmMappedScope( private val declaredMemberScope: FirScope, private val javaMappedClassUseSiteScope: FirScope, - private val whiteListSignaturesByName: Map> + private val signatures: Signatures ) : FirScope() { override fun processFunctionsByName(name: Name, processor: (FirFunctionSymbol<*>) -> Unit) { - val whiteListSignatures = whiteListSignaturesByName[name] + val whiteListSignatures = signatures.whiteListSignaturesByName[name] ?: return declaredMemberScope.processFunctionsByName(name, processor) javaMappedClassUseSiteScope.processFunctionsByName(name) { symbol -> val jvmSignature = symbol.fir.computeJvmDescriptor() @@ -36,6 +37,22 @@ class JvmMappedScope( 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) { declaredMemberScope.processPropertiesByName(name, processor) } @@ -45,15 +62,27 @@ class JvmMappedScope( } companion object { - fun prepareSignatures(klass: FirRegularClass): Map> { + data class Signatures(val whiteListSignaturesByName: Map>, val constructorBlackList: Set) { + fun isEmpty() = whiteListSignaturesByName.isEmpty() && constructorBlackList.isEmpty() + fun isNotEmpty() = !isEmpty() + } + + fun prepareSignatures(klass: FirRegularClass): Signatures { val signaturePrefix = klass.symbol.classId.toString() - val filteredSignatures = JvmBuiltInsSettings.WHITE_LIST_METHOD_SIGNATURES.filter { signature -> + val whiteListSignaturesByName = mutableMapOf>() + JvmBuiltInsSettings.WHITE_LIST_METHOD_SIGNATURES.filter { signature -> signature.startsWith(signaturePrefix) }.map { signature -> // +1 to delete dot before function name 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) } } } \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt index d1ae3658f02..0a6fde15bd9 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt @@ -308,12 +308,10 @@ class FirCallResolver( val candidateFactory = CandidateFactory(this, callInfo) val candidates = mutableListOf() - scope.processFunctionsByName(className) { - if (it is FirConstructorSymbol) { - val candidate = candidateFactory.createCandidate(it, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER) - candidate.typeArgumentMapping = TypeArgumentMapping.Mapped(typeArguments) - candidates += candidate - } + scope.processDeclaredConstructors { + val candidate = candidateFactory.createCandidate(it, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER) + candidate.typeArgumentMapping = TypeArgumentMapping.Mapped(typeArguments) + candidates += candidate } return callResolver.selectDelegatingConstructorCall(delegatedConstructorCall, className, candidates) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConstructorProcessing.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConstructorProcessing.kt index 2219fd30045..f5fb8595b3d 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConstructorProcessing.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConstructorProcessing.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.resolve.calls import com.intellij.openapi.progress.ProcessCanceledException import org.jetbrains.kotlin.fir.FirSession 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.buildValueParameter 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.impl.FirClassSubstitutionScope 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.types.ConeClassLikeType 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.utils.addToStdlib.safeAs +private operator fun Pair?.component1() = this?.first +private operator fun Pair<*, T>?.component2() = this?.second + internal fun FirScope.processFunctionsAndConstructorsByName( name: Name, session: FirSession, @@ -32,34 +36,38 @@ internal fun FirScope.processFunctionsAndConstructorsByName( processor: (FirCallableSymbol<*>) -> Unit ) { // 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( - matchedClassSymbol, - processor, - bodyResolveComponents - ) + processConstructors( + matchedClassSymbol, + substitutor, + processor, + session, + bodyResolveComponents.scopeSession, + noInnerConstructors + ) + + processSyntheticConstructors( + matchedClassSymbol, + processor, + bodyResolveComponents + ) + } processFunctionsByName(name) { - if (it !is FirConstructorSymbol) { - processor(it) - } + processor(it) } } -private fun FirScope.getFirstClassifierOrNull(name: Name): FirClassifierSymbol<*>? { - var result: FirClassifierSymbol<*>? = null - processClassifiersByName(name) { +private fun FirScope.getFirstClassifierOrNull(name: Name): Pair, ConeSubstitutor>? { + var result: Pair, ConeSubstitutor>? = null + processClassifiersByNameWithSubstitution(name) { symbol, substitution -> if (result == null) { - result = it + result = symbol to substitution } } @@ -127,6 +135,7 @@ private fun FirTypeAliasSymbol.findSAMConstructorForTypeAlias( private fun processConstructors( matchedSymbol: FirClassLikeSymbol<*>?, + substitutor: ConeSubstitutor, processor: (FirFunctionSymbol<*>) -> Unit, session: FirSession, scopeSession: ScopeSession, @@ -145,18 +154,15 @@ private fun processConstructors( ) ?: return } else basicScope } - is FirClassSymbol -> (matchedSymbol.fir as FirClass<*>).unsubstitutedScope(session, scopeSession) - } - - val constructorName = when (matchedSymbol) { - is FirTypeAliasSymbol -> finalExpansionName(matchedSymbol, session) ?: return - is FirRegularClassSymbol -> matchedSymbol.fir.name - else -> return + is FirClassSymbol -> + (matchedSymbol.fir as FirClass<*>).scope( + substitutor, session, scopeSession, false, + ) } //TODO: why don't we use declared member scope at this point? - scope?.processFunctionsByName(constructorName) { - if (!noInner || (it as? FirConstructorSymbol)?.fir?.isInner != true) { + scope?.processDeclaredConstructors { + if (!noInner || !it.fir.isInner) { processor(it) } } @@ -169,29 +175,37 @@ private fun processConstructors( } private class TypeAliasConstructorsSubstitutingScope( - private val typeAliasConstructorsSubstitutor: TypeAliasConstructorsSubstitutor, + private val typeAliasSymbol: FirTypeAliasSymbol, + private val copyFactory: ConstructorCopyFactory, private val delegatingScope: 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.(newReturnType: ConeKotlinType?, newValueParameterTypes: List?, newTypeParameters: List) -> F + private typealias ConstructorCopyFactory = - F.(newReturnType: ConeKotlinType?, newValueParameterTypes: List, newTypeParameters: List) -> F + F.(newReturnType: ConeKotlinType?, newValueParameterTypes: List?, newTypeParameters: List) -> F private class TypeAliasConstructorsSubstitutor>( private val typeAliasSymbol: FirTypeAliasSymbol, private val substitutor: ConeSubstitutor, - private val copyFactory: ConstructorCopyFactory + private val copyFactory: ConstructorCopyFactory2 ) { fun substitute(baseFunction: F): F { val typeParameters = typeAliasSymbol.fir.typeParameters @@ -217,20 +231,16 @@ private fun prepareSubstitutingScopeForTypeAliasConstructors( session: FirSession, delegatingScope: FirScope ): FirScope? { - val typeAliasConstructorsSubstitutor = - prepareSubstitutorForTypeAliasConstructors( - typeAliasSymbol, - expandedType, - session - ) factory@{ newReturnType, newParameterTypes, newTypeParameters -> - buildConstructor { - source = this@factory.source - this.session = session - returnTypeRef = this@factory.returnTypeRef.withReplacedConeType(newReturnType) - receiverTypeRef = this@factory.receiverTypeRef - status = this@factory.status - symbol = FirConstructorSymbol(this@factory.symbol.callableId, overriddenSymbol = this@factory.symbol) - resolvePhase = this@factory.resolvePhase + val copyFactory2: ConstructorCopyFactory = factory@ { newReturnType, newParameterTypes, newTypeParameters -> + buildConstructor { + source = this@factory.source + this.session = session + returnTypeRef = this@factory.returnTypeRef.withReplacedConeType(newReturnType) + receiverTypeRef = this@factory.receiverTypeRef + status = this@factory.status + symbol = FirConstructorSymbol(this@factory.symbol.callableId, overriddenSymbol = this@factory.symbol) + resolvePhase = this@factory.resolvePhase + if (newParameterTypes != null) { valueParameters += this@factory.valueParameters.zip( newParameterTypes @@ -247,12 +257,16 @@ private fun prepareSubstitutingScopeForTypeAliasConstructors( isVararg = valueParameter.isVararg } } - this.typeParameters += newTypeParameters + } else { + valueParameters += this@factory.valueParameters } - } ?: return null + this.typeParameters += newTypeParameters + } + } return TypeAliasConstructorsSubstitutingScope( - typeAliasConstructorsSubstitutor, + typeAliasSymbol, + copyFactory2, delegatingScope ) } @@ -261,7 +275,7 @@ private fun > prepareSubstitutorForTypeAliasConstructors( typeAliasSymbol: FirTypeAliasSymbol, expandedType: ConeClassLikeType, session: FirSession, - copyFactory: ConstructorCopyFactory + copyFactory: ConstructorCopyFactory2 ): TypeAliasConstructorsSubstitutor? { val expandedClass = expandedType.lookupTag.toSymbol(session)?.fir as? FirRegularClass ?: return null diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/AbstractFirUseSiteMemberScope.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/AbstractFirUseSiteMemberScope.kt index c1975084aeb..dac8dee122f 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/AbstractFirUseSiteMemberScope.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/AbstractFirUseSiteMemberScope.kt @@ -11,9 +11,6 @@ import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.declarations.FirValueParameter import org.jetbrains.kotlin.fir.declarations.builder.FirSimpleFunctionBuilder 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.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.scopes.FirOverrideChecker @@ -123,4 +120,8 @@ abstract class AbstractFirUseSiteMemberScope( declaredMemberScope.processClassifiersByNameWithSubstitution(name, processor) superTypesScope.processClassifiersByNameWithSubstitution(name, processor) } + + override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) { + declaredMemberScope.processDeclaredConstructors(processor) + } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirClassDeclaredMemberScope.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirClassDeclaredMemberScope.kt index 20422369113..c9134e4d28a 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirClassDeclaredMemberScope.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirClassDeclaredMemberScope.kt @@ -9,10 +9,7 @@ import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.scopes.FirScope -import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol -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.fir.symbols.impl.* import org.jetbrains.kotlin.name.Name class FirClassDeclaredMemberScope( @@ -33,7 +30,7 @@ class FirClassDeclaredMemberScope( when (declaration) { is FirCallableMemberDeclaration<*> -> { val name = when (declaration) { - is FirConstructor -> if (klass is FirRegularClass) klass.name else continue@loop + is FirConstructor -> Name.special("") is FirVariable<*> -> declaration.name is FirSimpleFunction -> declaration.name else -> continue@loop @@ -54,6 +51,15 @@ class FirClassDeclaredMemberScope( } } + override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) { + val symbols = callablesIndex[Name.special("")] ?: return + for (symbol in symbols) { + if (symbol is FirConstructorSymbol) { + processor(symbol) + } + } + } + override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) { val symbols = callablesIndex[name] ?: emptyList() for (symbol in symbols) { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirClassSubstitutionScope.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirClassSubstitutionScope.kt index e8f601288ca..c37d247e4b1 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirClassSubstitutionScope.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirClassSubstitutionScope.kt @@ -40,6 +40,7 @@ class FirClassSubstitutionScope( ) : FirScope() { private val fakeOverrideFunctions = mutableMapOf, FirFunctionSymbol<*>>() + private val fakeOverrideConstructors = mutableMapOf() private val fakeOverrideProperties = mutableMapOf() private val fakeOverrideFields = mutableMapOf() private val fakeOverrideAccessors = mutableMapOf() @@ -127,35 +128,66 @@ class FirClassSubstitutionScope( } return createFakeOverrideFunction( - session, member, original, newReceiverType, newReturnType, newParameterTypes, newTypeParameters, derivedClassId + session, + member, + original, + newReceiverType, + newReturnType, + newParameterTypes, + newTypeParameters as List, + 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() + val newReturnType = returnType.substitute(newSubstitutor) + + val newParameterTypes = constructor.valueParameters.map { + it.returnTypeRef.coneTypeUnsafe().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 private fun createNewTypeParametersAndSubstitutor( - member: FirCallableMemberDeclaration<*> - ): Pair, ConeSubstitutor> { + member: FirTypeParameterRefsOwner + ): Pair, ConeSubstitutor> { 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 { - source = originalParameter.source - session = originalParameter.session - name = originalParameter.name + source = typeParameter.source + session = typeParameter.session + name = typeParameter.name symbol = FirTypeParameterSymbol() - variance = originalParameter.variance - isReified = originalParameter.isReified - annotations += originalParameter.annotations + variance = typeParameter.variance + isReified = typeParameter.isReified + annotations += typeParameter.annotations } } - val substitutionMapForNewParameters = member.typeParameters.zip(newTypeParameters).map { - Pair(it.first.symbol, ConeTypeParameterTypeImpl(it.second.symbol.toLookupTag(), isNullable = false)) + val substitutionMapForNewParameters = member.typeParameters.zip(newTypeParameters).mapNotNull { (original, new) -> + if (new != null) + Pair(original.symbol, ConeTypeParameterTypeImpl(new.symbol.toLookupTag(), isNullable = false)) + else null }.toMap() val additionalSubstitutor = substitutorByMap(substitutionMapForNewParameters) 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() val substitutedBound = typeForBound.substitute() newTypeParameter.bounds += @@ -171,7 +203,10 @@ class FirClassSubstitutionScope( // While common Ir contracts expect them to be different // 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 { @@ -193,7 +228,16 @@ class FirClassSubstitutionScope( return original } - return createFakeOverrideProperty(session, member, original, newReceiverType, newReturnType, newTypeParameters, derivedClassId) + @Suppress("UNCHECKED_CAST") + return createFakeOverrideProperty( + session, + member, + original, + newReceiverType, + newReturnType, + newTypeParameters as List, + derivedClassId + ) } private fun createFakeOverrideField(original: FirFieldSymbol): FirFieldSymbol { @@ -369,6 +413,61 @@ class FirClassSubstitutionScope( delegateGetter = function }.symbol } + + private fun createFakeOverrideConstructor( + fakeOverrideSymbol: FirConstructorSymbol, + session: FirSession, + baseConstructor: FirConstructor, + newReceiverType: ConeKotlinType? = null, + newReturnType: ConeKotlinType? = null, + newParameterTypes: List? = null, + newTypeParameters: List? = 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) + } } } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirScope.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirScope.kt index 81263dd689d..a3a523e07d2 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirScope.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirScope.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.scopes import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor 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.FirVariableSymbol import org.jetbrains.kotlin.name.Name @@ -26,6 +27,10 @@ abstract class FirScope { name: Name, processor: (FirVariableSymbol<*>) -> Unit ) {} + + open fun processDeclaredConstructors( + processor: (FirConstructorSymbol) -> Unit + ) {} } enum class ProcessorAction {