Skip to content

Commit

Permalink
FIR: Merge both synthetic type alias constructor kinds
Browse files Browse the repository at this point in the history
  • Loading branch information
dzharkov committed Nov 6, 2020
1 parent f9aab77 commit d58e66e
Showing 1 changed file with 59 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,22 @@ private fun FirTypeAliasSymbol.findSAMConstructorForTypeAlias(
).fir
}

private fun prepareSubstitutorForTypeAliasConstructors(
expandedType: ConeClassLikeType,
session: FirSession
): ConeSubstitutor? {
val expandedClass = expandedType.lookupTag.toSymbol(session)?.fir as? FirRegularClass ?: return null

val resultingTypeArguments = expandedType.typeArguments.map {
// We don't know how to handle cases like yet
// typealias A = ArrayList<*>()
it as? ConeKotlinType ?: return null
}
return substitutorByMap(
expandedClass.typeParameters.map { it.symbol }.zip(resultingTypeArguments).toMap()
)
}

private fun processConstructors(
matchedSymbol: FirClassLikeSymbol<*>?,
substitutor: ConeSubstitutor,
Expand All @@ -158,10 +174,13 @@ private fun processConstructors(
val type = matchedSymbol.fir.expandedTypeRef.coneTypeUnsafe<ConeClassLikeType>().fullyExpandedType(session)
val basicScope = type.scope(session, bodyResolveComponents.scopeSession, FakeOverrideTypeCalculator.DoNothing)

if (basicScope != null && type.typeArguments.isNotEmpty()) {
val outerType = bodyResolveComponents.outerClassManager.outerType(type)

if (basicScope != null && (matchedSymbol.fir.typeParameters.isNotEmpty() || outerType != null)) {
TypeAliasConstructorsSubstitutingScope(
matchedSymbol,
basicScope
basicScope,
outerType
)
} else basicScope
}
Expand All @@ -174,9 +193,7 @@ private fun processConstructors(
//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)
processor(it)
}
}
}
Expand All @@ -187,83 +204,53 @@ private fun processConstructors(

private class TypeAliasConstructorsSubstitutingScope(
private val typeAliasSymbol: FirTypeAliasSymbol,
private val delegatingScope: FirScope
private val delegatingScope: FirScope,
private val outerType: ConeClassLikeType?,
) : FirScope() {

override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) {
delegatingScope.processDeclaredConstructors { originalConstructorSymbol ->
init {
require(outerType != null || typeAliasSymbol.fir.typeParameters.isNotEmpty())
}

override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) {
delegatingScope.processDeclaredConstructors wrapper@{ 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(
expandedType: ConeClassLikeType,
session: FirSession
): ConeSubstitutor? {
val expandedClass = expandedType.lookupTag.toSymbol(session)?.fir as? FirRegularClass ?: return null
processor(
buildConstructorCopy(originalConstructorSymbol.fir) {
symbol = FirConstructorSymbol(originalConstructorSymbol.callableId)
origin = FirDeclarationOrigin.Synthetic

val resultingTypeArguments = expandedType.typeArguments.map {
// We don't know how to handle cases like yet
// typealias A = ArrayList<*>()
it as? ConeKotlinType ?: return null
}
return substitutorByMap(
expandedClass.typeParameters.map { it.symbol }.zip(resultingTypeArguments).toMap()
)
}
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)
}

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)
}.apply {
originalConstructorIfTypeAlias = originalSymbol.fir
}
return extCopy.symbol
}
originalConstructorIfTypeAlias = originalConstructorSymbol.fir
}.symbol
)
}
}
return null
}

private object TypeAliasConstructorKey : FirDeclarationDataKey()
Expand Down

0 comments on commit d58e66e

Please sign in to comment.