FIR: implement early type alias expansion

This commit is contained in:
Simon Ogorodnik
2018-03-21 18:30:28 +03:00
committed by Mikhail Glukhikh
parent d15fb1963b
commit 25ae12fe07
16 changed files with 187 additions and 90 deletions
@@ -8,9 +8,12 @@ package org.jetbrains.kotlin.descriptors
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirRenderer
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.resolve.FirProvider
import org.jetbrains.kotlin.fir.resolve.FirTypeResolver
import org.jetbrains.kotlin.fir.scopes.impl.*
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
import org.jetbrains.kotlin.fir.transformSingle
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeImpl
@@ -21,8 +24,6 @@ import org.jetbrains.kotlin.fir.visitors.compose
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
fun FirElement.render(): String = buildString { this@render.accept(FirRenderer(this)) }
class FirTypeResolveTransformer(val superTypesOnly: Boolean = false) : FirTransformer<Nothing?>() {
override fun <E : FirElement> transformElement(element: E, data: Nothing?): CompositeTransformResult<E> {
return if (superTypesOnly) {
@@ -94,11 +95,15 @@ class FirTypeResolveTransformer(val superTypesOnly: Boolean = false) : FirTransf
override fun transformType(type: FirType, data: Nothing?): CompositeTransformResult<FirType> {
val typeResolver = FirTypeResolver.getInstance(type.session)
type.transformChildren(this, data)
type.transformChildren(this, null)
return transformType(type, typeResolver.resolveType(type, scope))
}
private fun transformType(type: FirType, resolvedType: ConeKotlinType): CompositeTransformResult<FirType> {
return FirResolvedTypeImpl(
type.session,
type.psi,
typeResolver.resolveType(type, scope),
resolvedType,
false,
type.annotations
).compose()
@@ -109,16 +114,27 @@ class FirTypeResolveTransformer(val superTypesOnly: Boolean = false) : FirTransf
}
override fun transformTypeProjectionWithVariance(
typeProjectionWithVariance: FirTypeProjectionWithVariance,
data: Nothing?
): CompositeTransformResult<FirTypeProjection> {
typeProjectionWithVariance.transformChildren(this, data)
return typeProjectionWithVariance.compose()
}
private inner class SuperTypeResolver : FirTransformer<Nothing?>() {
override fun <E : FirElement> transformElement(element: E, data: Nothing?): CompositeTransformResult<E> {
return element.compose()
}
override fun transformType(type: FirType, data: Nothing?): CompositeTransformResult<FirType> {
val transformedType = this@FirTypeResolveTransformer.transformType(type, data).single as FirResolvedType
val typeResolver = FirTypeResolver.getInstance(type.session)
val symbol = typeResolver.resolveToSymbol(type, scope)
val myTransformer = this@FirTypeResolveTransformer
val classId = (transformedType.type as? ConeClassLikeType)?.symbol?.classId ?: return transformedType.compose()
val firProvider = FirProvider.getInstance(transformedType.session)
if (type !is FirUserType) return myTransformer.transformType(type, data)
val classId = (symbol as? ConeClassLikeSymbol)?.classId ?: return myTransformer.transformType(type, data)
val firProvider = FirProvider.getInstance(type.session)
val classes = generateSequence(classId) { it.outerClassId }.toList()
@@ -132,7 +148,9 @@ class FirTypeResolveTransformer(val superTypesOnly: Boolean = false) : FirTransf
firProvider.getFirClassifierByFqName(it)!!.transformSingle(transformer, data)
}
return transformedType.compose()
type.transformChildren(myTransformer, null)
return myTransformer.transformType(type, typeResolver.resolveUserType(type, symbol, scope))
}
}
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.resolve
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.FirNamedDeclaration
import org.jetbrains.kotlin.fir.service
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
import org.jetbrains.kotlin.name.ClassId
@@ -18,7 +19,7 @@ interface FirProvider {
fun getFirClassifierContainerFile(fqName: ClassId): FirFile
fun getFirClassifierBySymbol(symbol: ConeSymbol): FirMemberDeclaration?
fun getFirClassifierBySymbol(symbol: ConeSymbol): FirNamedDeclaration?
companion object {
fun getInstance(session: FirSession): FirProvider = session.service()
@@ -7,15 +7,16 @@ package org.jetbrains.kotlin.fir.resolve
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.service
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.FirQualifierPart
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
interface FirQualifierResolver {
fun resolveTypeWithPrefix(parts: List<FirQualifierPart>, prefix: ClassId): ConeKotlinType?
fun resolveSymbolWithPrefix(parts: List<FirQualifierPart>, prefix: ClassId): ConeSymbol?
fun resolveType(parts: List<FirQualifierPart>): ConeKotlinType?
fun resolveSymbol(parts: List<FirQualifierPart>): ConeSymbol?
companion object {
fun getInstance(session: FirSession): FirQualifierResolver = session.service()
@@ -8,14 +8,19 @@ package org.jetbrains.kotlin.fir.resolve
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.service
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
import org.jetbrains.kotlin.fir.types.FirType
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.FirUserType
interface FirTypeResolver {
fun resolveType(type: FirType, scope: FirScope): ConeKotlinType
fun resolveToSymbol(type: FirType, scope: FirScope): ConeSymbol?
companion object {
fun getInstance(session: FirSession): FirTypeResolver = session.service()
}
fun resolveUserType(type: FirUserType, symbol: ConeSymbol?, scope: FirScope): ConeKotlinType
}
@@ -17,9 +17,9 @@ import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
class FirProviderImpl(val session: FirSession) : FirProvider {
override fun getFirClassifierBySymbol(symbol: ConeSymbol): FirMemberDeclaration? {
override fun getFirClassifierBySymbol(symbol: ConeSymbol): FirNamedDeclaration? {
return when(symbol) {
is FirBasedSymbol<*> -> symbol.fir as? FirMemberDeclaration
is FirBasedSymbol<*> -> symbol.fir as? FirNamedDeclaration
is ConeClassLikeSymbol -> getFirClassifierByFqName(symbol.classId)
else -> error("!")
}
@@ -11,6 +11,8 @@ import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.FirTypeAlias
import org.jetbrains.kotlin.fir.resolve.FirProvider
import org.jetbrains.kotlin.fir.resolve.FirQualifierResolver
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
import org.jetbrains.kotlin.fir.symbols.toSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.*
@@ -20,43 +22,7 @@ import org.jetbrains.kotlin.types.Variance
class FirQualifierResolverImpl(val session: FirSession) : FirQualifierResolver {
private fun List<FirQualifierPart>.toTypeProjections() = flatMap {
it.typeArguments.map {
when (it) {
is FirStarProjection -> StarProjection
is FirTypeProjectionWithVariance -> {
val type = (it.type as FirResolvedType).type
when (it.variance) {
Variance.INVARIANT -> type
Variance.IN_VARIANCE -> ConeKotlinTypeProjectionInImpl(type)
Variance.OUT_VARIANCE -> ConeKotlinTypeProjectionOutImpl(type)
}
}
else -> error("!")
}
}
}
private fun FirMemberDeclaration.toConeKotlinType(fqName: ClassId, parts: List<FirQualifierPart>): ConeKotlinType? {
return when (this) {
is FirClass -> {
ConeClassTypeImpl(fqName.toSymbol(), parts.toTypeProjections())
}
is FirTypeAlias -> {
val expansion = expandedType.coneTypeSafe<ConeClassLikeType>()
?: return ConeKotlinErrorType("Couldn't resolve expansion")
ConeAbbreviatedTypeImpl(
abbreviationSymbol = fqName.toSymbol(),
typeArguments = parts.toTypeProjections(),
directExpansion = expansion
)
}
else -> error("!")
}
}
override fun resolveTypeWithPrefix(parts: List<FirQualifierPart>, prefix: ClassId): ConeKotlinType? {
override fun resolveSymbolWithPrefix(parts: List<FirQualifierPart>, prefix: ClassId): ConeSymbol? {
val firProvider = FirProvider.getInstance(session)
val fqName = ClassId(
@@ -64,12 +30,12 @@ class FirQualifierResolverImpl(val session: FirSession) : FirQualifierResolver {
parts.drop(1).fold(prefix.relativeClassName) { prefix, suffix -> prefix.child(suffix.name) },
false
)
val foundClassifier = firProvider.getFirClassifierByFqName(fqName)
firProvider.getFirClassifierByFqName(fqName) ?: return null
return foundClassifier?.toConeKotlinType(fqName, parts)
return ConeClassLikeSymbol(fqName)
}
override fun resolveType(parts: List<FirQualifierPart>): ConeKotlinType? {
override fun resolveSymbol(parts: List<FirQualifierPart>): ConeSymbol? {
val firProvider = FirProvider.getInstance(session)
if (parts.isNotEmpty()) {
@@ -84,7 +50,7 @@ class FirQualifierResolverImpl(val session: FirSession) : FirQualifierResolver {
val foundClassifier = firProvider.getFirClassifierByFqName(fqName)
if (foundClassifier != null) {
return foundClassifier.toConeKotlinType(fqName, parts)
return ConeClassLikeSymbol(fqName)
}
}
return null
@@ -5,40 +5,107 @@
package org.jetbrains.kotlin.fir.resolve.impl
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirTypeAlias
import org.jetbrains.kotlin.fir.declarations.FirTypeParameter
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.resolve.FirProvider
import org.jetbrains.kotlin.fir.resolve.FirQualifierResolver
import org.jetbrains.kotlin.fir.resolve.FirTypeResolver
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.ConeKotlinErrorType
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.fir.types.impl.*
import org.jetbrains.kotlin.types.Variance
class FirTypeResolverImpl : FirTypeResolver {
override fun resolveType(type: FirType, scope: FirScope): ConeKotlinType {
private fun List<FirQualifierPart>.toTypeProjections() = flatMap {
it.typeArguments.map {
when (it) {
is FirStarProjection -> StarProjection
is FirTypeProjectionWithVariance -> {
val type = (it.type as FirResolvedType).type
when (it.variance) {
Variance.INVARIANT -> type
Variance.IN_VARIANCE -> ConeKotlinTypeProjectionInImpl(type)
Variance.OUT_VARIANCE -> ConeKotlinTypeProjectionOutImpl(type)
}
}
else -> error("!")
}
}
}
private fun ConeSymbol.toConeKotlinType(parts: List<FirQualifierPart>, session: FirSession): ConeKotlinType? {
val firProvider = FirProvider.getInstance(session)
val fir = firProvider.getFirClassifierBySymbol(this) ?: return null
return when (fir) {
is FirTypeParameter -> {
ConeTypeParameterTypeImpl(this as ConeTypeParameterSymbol)
}
is FirClass -> {
ConeClassTypeImpl(this as ConeClassLikeSymbol, parts.toTypeProjections())
}
is FirTypeAlias -> {
val coneTypeSafe = fir.expandedType.coneTypeSafe<ConeClassLikeType>()
val expansion = if (coneTypeSafe != null) coneTypeSafe else {
return ConeKotlinErrorType("Couldn't resolve expansion")
}
ConeAbbreviatedTypeImpl(
abbreviationSymbol = this as ConeClassLikeSymbol,
typeArguments = parts.toTypeProjections(),
directExpansion = expansion
)
}
else -> error("!")
}
}
override fun resolveToSymbol(type: FirType, scope: FirScope): ConeSymbol? {
return when (type) {
is FirResolvedType -> type.type
is FirResolvedType -> type.coneTypeSafe<ConeSymbolBasedType>()?.symbol
is FirUserType -> {
val qualifierResolver = FirQualifierResolver.getInstance(type.session)
var resolvedType: ConeKotlinType? = null
var resolvedSymbol: ConeSymbol? = null
scope.processClassifiersByName(type.qualifier.first().name) { symbol ->
resolvedType = when (symbol) {
resolvedSymbol = when (symbol) {
is ConeClassLikeSymbol -> {
qualifierResolver.resolveTypeWithPrefix(type.qualifier, symbol.classId)
qualifierResolver.resolveSymbolWithPrefix(type.qualifier, symbol.classId)
}
is ConeTypeParameterSymbol -> {
assert(type.qualifier.size == 1)
ConeTypeParameterTypeImpl(symbol)
symbol
}
else -> error("!")
}
resolvedType == null
resolvedSymbol == null
}
// TODO: Imports
resolvedType ?: qualifierResolver.resolveType(type.qualifier) ?: ConeKotlinErrorType("Failed to resolve qualified type")
resolvedSymbol ?: qualifierResolver.resolveSymbol(type.qualifier)
}
else -> null
}
}
override fun resolveUserType(type: FirUserType, symbol: ConeSymbol?, scope: FirScope): ConeKotlinType {
symbol ?: return ConeKotlinErrorType("Symbol not found")
return symbol.toConeKotlinType(type.qualifier, type.session) ?: ConeKotlinErrorType("Failed to resolve qualified type")
}
override fun resolveType(type: FirType, scope: FirScope): ConeKotlinType {
return when (type) {
is FirResolvedType -> type.type
is FirUserType -> {
resolveUserType(type, resolveToSymbol(type, scope), scope)
}
is FirErrorType -> {
ConeKotlinErrorType(type.reason)
@@ -18,6 +18,8 @@ import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.utils.Printer
fun FirElement.render(): String = buildString { this@render.accept(FirRenderer(this)) }
class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
private val printer = Printer(builder)