FIR: Merge both synthetic type alias constructor kinds

This commit is contained in:
Denis Zharkov
2020-11-02 15:15:51 +03:00
parent f9aab77ce5
commit d58e66e79a
@@ -142,72 +142,6 @@ private fun FirTypeAliasSymbol.findSAMConstructorForTypeAlias(
).fir ).fir
} }
private fun processConstructors(
matchedSymbol: FirClassLikeSymbol<*>?,
substitutor: ConeSubstitutor,
processor: (FirFunctionSymbol<*>) -> Unit,
session: FirSession,
bodyResolveComponents: BodyResolveComponents,
includeInnerConstructors: Boolean
) {
try {
if (matchedSymbol != null) {
val scope = when (matchedSymbol) {
is FirTypeAliasSymbol -> {
matchedSymbol.ensureResolved(FirResolvePhase.TYPES, session)
val type = matchedSymbol.fir.expandedTypeRef.coneTypeUnsafe<ConeClassLikeType>().fullyExpandedType(session)
val basicScope = type.scope(session, bodyResolveComponents.scopeSession, FakeOverrideTypeCalculator.DoNothing)
if (basicScope != null && type.typeArguments.isNotEmpty()) {
TypeAliasConstructorsSubstitutingScope(
matchedSymbol,
basicScope
)
} else basicScope
}
is FirClassSymbol ->
(matchedSymbol.fir as FirClass<*>).scopeForClass(
substitutor, session, bodyResolveComponents.scopeSession
)
}
//TODO: why don't we use declared member scope at this point?
scope?.processDeclaredConstructors {
if (includeInnerConstructors || !it.fir.isInner) {
val constructorSymbolToProcess =
prepareCopyConstructorForTypealiasNestedClass(matchedSymbol, it, session, bodyResolveComponents) ?: it
processor(constructorSymbolToProcess)
}
}
}
} catch (e: Throwable) {
throw RuntimeException("While processing constructors", e)
}
}
private class TypeAliasConstructorsSubstitutingScope(
private val typeAliasSymbol: FirTypeAliasSymbol,
private val delegatingScope: FirScope
) : FirScope() {
override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) {
delegatingScope.processDeclaredConstructors { originalConstructorSymbol ->
val typeParameters = typeAliasSymbol.fir.typeParameters
if (typeParameters.isEmpty()) processor(originalConstructorSymbol)
else {
processor(
buildConstructorCopy(originalConstructorSymbol.fir) {
symbol = FirConstructorSymbol(originalConstructorSymbol.callableId, overriddenSymbol = originalConstructorSymbol)
origin = FirDeclarationOrigin.SubstitutionOverride
this.typeParameters += typeParameters.map { buildConstructedClassTypeParameterRef { symbol = it.symbol } }
}.symbol
)
}
}
}
}
private fun prepareSubstitutorForTypeAliasConstructors( private fun prepareSubstitutorForTypeAliasConstructors(
expandedType: ConeClassLikeType, expandedType: ConeClassLikeType,
session: FirSession session: FirSession
@@ -224,46 +158,99 @@ private fun prepareSubstitutorForTypeAliasConstructors(
) )
} }
private fun prepareCopyConstructorForTypealiasNestedClass( private fun processConstructors(
matchedSymbol: FirClassLikeSymbol<*>, matchedSymbol: FirClassLikeSymbol<*>?,
originalSymbol: FirConstructorSymbol, substitutor: ConeSubstitutor,
processor: (FirFunctionSymbol<*>) -> Unit,
session: FirSession, session: FirSession,
bodyResolveComponents: BodyResolveComponents, bodyResolveComponents: BodyResolveComponents,
): FirConstructorSymbol? { includeInnerConstructors: Boolean
// If the matched symbol is a type alias, and the expanded type is a nested class, e.g., ) {
// try {
// class Outer { if (matchedSymbol != null) {
// inner class Inner val scope = when (matchedSymbol) {
// } is FirTypeAliasSymbol -> {
// typealias OI = Outer.Inner matchedSymbol.ensureResolved(FirResolvePhase.TYPES, session)
// fun foo() { Outer().OI() } val type = matchedSymbol.fir.expandedTypeRef.coneTypeUnsafe<ConeClassLikeType>().fullyExpandedType(session)
// val basicScope = type.scope(session, bodyResolveComponents.scopeSession, FakeOverrideTypeCalculator.DoNothing)
// 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 val outerType = bodyResolveComponents.outerClassManager.outerType(type)
// 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 if (basicScope != null && (matchedSymbol.fir.typeParameters.isNotEmpty() || outerType != null)) {
// can be seen as if resolving: TypeAliasConstructorsSubstitutingScope(
// matchedSymbol,
// fun Outer.OI(): OI = ... basicScope,
// outerType
if (originalSymbol.callableId.classId?.isNestedClass == true && matchedSymbol is FirTypeAliasSymbol) { )
val innerTypeRef = originalSymbol.fir.returnTypeRef } else basicScope
val innerType = innerTypeRef.coneType.fullyExpandedType(session) as? ConeClassLikeType }
if (innerType != null) { is FirClassSymbol ->
val outerType = bodyResolveComponents.outerClassManager.outerType(innerType) (matchedSymbol.fir as FirClass<*>).scopeForClass(
if (outerType != null) { substitutor, session, bodyResolveComponents.scopeSession
val extCopy = buildConstructorCopy(originalSymbol.fir) { )
origin = FirDeclarationOrigin.Synthetic }
receiverTypeRef = innerTypeRef.withReplacedConeType(outerType)
symbol = FirConstructorSymbol(originalSymbol.callableId) //TODO: why don't we use declared member scope at this point?
}.apply { scope?.processDeclaredConstructors {
originalConstructorIfTypeAlias = originalSymbol.fir if (includeInnerConstructors || !it.fir.isInner) {
processor(it)
} }
return extCopy.symbol
} }
} }
} catch (e: Throwable) {
throw RuntimeException("While processing constructors", e)
}
}
private class TypeAliasConstructorsSubstitutingScope(
private val typeAliasSymbol: FirTypeAliasSymbol,
private val delegatingScope: FirScope,
private val outerType: ConeClassLikeType?,
) : FirScope() {
init {
require(outerType != null || typeAliasSymbol.fir.typeParameters.isNotEmpty())
}
override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) {
delegatingScope.processDeclaredConstructors wrapper@{ originalConstructorSymbol ->
val typeParameters = typeAliasSymbol.fir.typeParameters
processor(
buildConstructorCopy(originalConstructorSymbol.fir) {
symbol = FirConstructorSymbol(originalConstructorSymbol.callableId)
origin = FirDeclarationOrigin.Synthetic
this.typeParameters.clear()
this.typeParameters += typeParameters.map { buildConstructedClassTypeParameterRef { symbol = it.symbol } }
if (outerType != null) {
// 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 = ...
//
//
receiverTypeRef = originalConstructorSymbol.fir.returnTypeRef.withReplacedConeType(outerType)
}
}.apply {
originalConstructorIfTypeAlias = originalConstructorSymbol.fir
}.symbol
)
}
} }
return null
} }
private object TypeAliasConstructorKey : FirDeclarationDataKey() private object TypeAliasConstructorKey : FirDeclarationDataKey()