FIR: copy constructor for typealias'ed inner/nested class
This commit is contained in:
committed by
Denis Zharkov
parent
5e5712afbb
commit
8c88670185
+48
-5
@@ -9,6 +9,7 @@ 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.buildConstructorCopy
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameter
|
||||
import org.jetbrains.kotlin.fir.resolve.*
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
@@ -42,7 +43,7 @@ internal fun FirScope.processConstructorsByName(
|
||||
substitutor,
|
||||
processor,
|
||||
session,
|
||||
bodyResolveComponents.scopeSession,
|
||||
bodyResolveComponents,
|
||||
includeInnerConstructors
|
||||
)
|
||||
|
||||
@@ -135,7 +136,7 @@ private fun processConstructors(
|
||||
substitutor: ConeSubstitutor,
|
||||
processor: (FirFunctionSymbol<*>) -> Unit,
|
||||
session: FirSession,
|
||||
scopeSession: ScopeSession,
|
||||
bodyResolveComponents: BodyResolveComponents,
|
||||
includeInnerConstructors: Boolean
|
||||
) {
|
||||
try {
|
||||
@@ -144,7 +145,7 @@ private fun processConstructors(
|
||||
is FirTypeAliasSymbol -> {
|
||||
matchedSymbol.ensureResolved(FirResolvePhase.TYPES, session)
|
||||
val type = matchedSymbol.fir.expandedTypeRef.coneTypeUnsafe<ConeClassLikeType>().fullyExpandedType(session)
|
||||
val basicScope = type.scope(session, scopeSession)
|
||||
val basicScope = type.scope(session, bodyResolveComponents.scopeSession)
|
||||
|
||||
if (basicScope != null && type.typeArguments.isNotEmpty()) {
|
||||
prepareSubstitutingScopeForTypeAliasConstructors(
|
||||
@@ -154,14 +155,16 @@ private fun processConstructors(
|
||||
}
|
||||
is FirClassSymbol ->
|
||||
(matchedSymbol.fir as FirClass<*>).scopeForClass(
|
||||
substitutor, session, scopeSession
|
||||
substitutor, session, bodyResolveComponents.scopeSession
|
||||
)
|
||||
}
|
||||
|
||||
//TODO: why don't we use declared member scope at this point?
|
||||
scope?.processDeclaredConstructors {
|
||||
if (includeInnerConstructors || !it.fir.isInner) {
|
||||
processor(it)
|
||||
val constructorSymbolToProcess =
|
||||
prepareCopyConstructorForTypealiasNestedClass(matchedSymbol, it, session, bodyResolveComponents) ?: it
|
||||
processor(constructorSymbolToProcess)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -289,3 +292,43 @@ private fun <F : FirFunction<F>> prepareSubstitutorForTypeAliasConstructors(
|
||||
|
||||
return TypeAliasConstructorsSubstitutor(typeAliasSymbol, substitutor, copyFactory)
|
||||
}
|
||||
|
||||
private fun prepareCopyConstructorForTypealiasNestedClass(
|
||||
matchedSymbol: FirClassLikeSymbol<*>,
|
||||
originalSymbol: FirConstructorSymbol,
|
||||
session: FirSession,
|
||||
bodyResolveComponents: BodyResolveComponents,
|
||||
): FirConstructorSymbol? {
|
||||
// If the matched symbol is a type alias, and the expanded type is a nested class, e.g.,
|
||||
//
|
||||
// class Outer {
|
||||
// inner class Inner
|
||||
// }
|
||||
// typealias OI = Outer.Inner
|
||||
// fun foo() { Outer().OI() }
|
||||
//
|
||||
// the chances are that `processor` belongs to [ScopeTowerLevel] (to resolve type aliases at top-level), which treats
|
||||
// the explicit receiver (`Outer()`) as an extension receiver, whereas the constructor of the nested class may regard
|
||||
// the same explicit receiver as a dispatch receiver (hence inconsistent receiver).
|
||||
// Here, we add a copy of the nested class constructor, along with the outer type as an extension receiver, so that it
|
||||
// can be seen as if resolving:
|
||||
//
|
||||
// fun Outer.OI(): OI = ...
|
||||
//
|
||||
if (originalSymbol.callableId.classId?.isNestedClass == true && matchedSymbol is FirTypeAliasSymbol) {
|
||||
val innerTypeRef = originalSymbol.fir.returnTypeRef
|
||||
val innerType = innerTypeRef.coneType.fullyExpandedType(session) as? ConeClassLikeType
|
||||
if (innerType != null) {
|
||||
val outerType = bodyResolveComponents.outerClassManager.outerType(innerType)
|
||||
if (outerType != null) {
|
||||
val extCopy = buildConstructorCopy(originalSymbol.fir) {
|
||||
origin = FirDeclarationOrigin.Synthetic
|
||||
receiverTypeRef = innerTypeRef.withReplacedConeType(outerType)
|
||||
symbol = FirConstructorSymbol(originalSymbol.callableId, overriddenSymbol = originalSymbol)
|
||||
}
|
||||
return extCopy.symbol
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
+23
@@ -85,3 +85,26 @@ inline fun buildConstructor(init: FirConstructorBuilder.() -> Unit): FirConstruc
|
||||
}
|
||||
return FirConstructorBuilder().apply(init).build()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
inline fun buildConstructorCopy(original: FirConstructor, init: FirConstructorBuilder.() -> Unit): FirConstructor {
|
||||
contract {
|
||||
callsInPlace(init, kotlin.contracts.InvocationKind.EXACTLY_ONCE)
|
||||
}
|
||||
val copyBuilder = FirConstructorBuilder()
|
||||
copyBuilder.source = original.source
|
||||
copyBuilder.session = original.session
|
||||
copyBuilder.resolvePhase = original.resolvePhase
|
||||
copyBuilder.origin = original.origin
|
||||
copyBuilder.returnTypeRef = original.returnTypeRef
|
||||
copyBuilder.receiverTypeRef = original.receiverTypeRef
|
||||
copyBuilder.typeParameters.addAll(original.typeParameters)
|
||||
copyBuilder.valueParameters.addAll(original.valueParameters)
|
||||
copyBuilder.status = original.status
|
||||
copyBuilder.containerSource = original.containerSource
|
||||
copyBuilder.annotations.addAll(original.annotations)
|
||||
copyBuilder.symbol = original.symbol
|
||||
copyBuilder.delegatedConstructor = original.delegatedConstructor
|
||||
copyBuilder.body = original.body
|
||||
return copyBuilder.apply(init).build()
|
||||
}
|
||||
|
||||
+1
@@ -81,6 +81,7 @@ object BuilderConfigurator : AbstractBuilderConfigurator<FirTreeBuilder>(FirTree
|
||||
|
||||
builder(constructor, "FirConstructorImpl") {
|
||||
openBuilder()
|
||||
withCopy()
|
||||
}
|
||||
|
||||
builder(field) {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
class Outer(val x: String) {
|
||||
inner class Inner(val y: String) {
|
||||
val z = x + y
|
||||
|
||||
+5
-5
@@ -7,7 +7,7 @@ class Outer {
|
||||
|
||||
typealias OI = Outer.Inner
|
||||
|
||||
fun test1(x: Outer) = x.<!UNRESOLVED_REFERENCE!>OI<!>()
|
||||
fun test1(x: Outer) = x.OI()
|
||||
|
||||
|
||||
class Generic<T> {
|
||||
@@ -17,8 +17,8 @@ class Generic<T> {
|
||||
typealias GI<T> = Generic<T>.Inner
|
||||
typealias GIntI = Generic<Int>.Inner
|
||||
|
||||
fun test2(x: Generic<Int>) = x.<!UNRESOLVED_REFERENCE!>GI<!>()
|
||||
fun <T> test3(x: Generic<T>) = x.<!UNRESOLVED_REFERENCE!>GI<!>()
|
||||
fun <T> test4(x: Generic<List<T>>) = x.<!UNRESOLVED_REFERENCE!>GI<!>()
|
||||
fun <T> test5(x: Generic<T>) = x.<!UNRESOLVED_REFERENCE!>GIntI<!>()
|
||||
fun test2(x: Generic<Int>) = x.GI()
|
||||
fun <T> test3(x: Generic<T>) = x.GI()
|
||||
fun <T> test4(x: Generic<List<T>>) = x.GI()
|
||||
fun <T> test5(x: Generic<T>) = x.<!INAPPLICABLE_CANDIDATE!>GIntI<!>()
|
||||
fun Generic<Int>.test6() = GIntI()
|
||||
+2
-2
@@ -26,9 +26,9 @@ class Outer {
|
||||
}
|
||||
typealias Test5 = Outer.Inner
|
||||
|
||||
val test5 = Test5()
|
||||
val test5 = <!UNRESOLVED_REFERENCE!>Test5<!>()
|
||||
val test5a = Outer.<!UNRESOLVED_REFERENCE!>Inner<!>()
|
||||
val test5b = Outer.<!UNRESOLVED_REFERENCE!>TestInner<!>()
|
||||
val test5c = Outer().<!UNRESOLVED_REFERENCE!>TestInner<!>()
|
||||
val test5d = Outer().Inner()
|
||||
val test5e = Outer().<!UNRESOLVED_REFERENCE!>Test5<!>()
|
||||
val test5e = Outer().Test5()
|
||||
|
||||
+4
-3
@@ -81,7 +81,8 @@ FILE fqName:<root> fileName:/kt16905.kt
|
||||
overridden:
|
||||
public open fun toString (): kotlin.String declared in kotlin.Any
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
|
||||
FUN name:test visibility:public modality:FINAL <> () returnType:IrErrorType
|
||||
FUN name:test visibility:public modality:FINAL <> () returnType:<root>.Outer.Inner
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun test (): IrErrorType declared in <root>'
|
||||
ERROR_CALL 'Unresolved reference: <Unresolved name: OI>#' type=IrErrorType
|
||||
RETURN type=kotlin.Nothing from='public final fun test (): <root>.Outer.Inner declared in <root>'
|
||||
CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.Outer.Inner' type=<root>.Outer.Inner origin=null
|
||||
$outer: CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.Outer' type=<root>.Outer origin=null
|
||||
|
||||
Reference in New Issue
Block a user