JVM_IR: collect free type parameters when serializing FIR metadata

The "free" in "createFreeFakeLambdaDescriptor" and such refers to the
fact that there are no references to type parameters from outside the
current declaration. This is necessary because at the point where the
metadata is written, the type parameters may not even be in scope (e.g.
local delegated properties are serialized at class level, but may refer
to function-scope type parameters).
This commit is contained in:
pyos
2020-09-15 18:35:05 +02:00
committed by Mikhail Glukhikh
parent aa58ed9234
commit 6e143a2656
3 changed files with 32 additions and 17 deletions
@@ -44,61 +44,79 @@ class FirMetadataSerializer(
}
}
private fun FirTypeRef.approximated(toSuper: Boolean): FirTypeRef {
private fun FirTypeRef.approximated(toSuper: Boolean, typeParameterSet: MutableCollection<FirTypeParameter>): FirTypeRef {
val approximatedType = if (toSuper)
approximator.approximateToSuperType(coneType, TypeApproximatorConfiguration.PublicDeclaration)
else
approximator.approximateToSubType(coneType, TypeApproximatorConfiguration.PublicDeclaration)
return withReplacedConeType(approximatedType as? ConeKotlinType)
return withReplacedConeType(approximatedType as? ConeKotlinType).apply { coneType.collectTypeParameters(typeParameterSet) }
}
private fun ConeKotlinType.collectTypeParameters(c: MutableCollection<FirTypeParameter>) {
when (this) {
is ConeFlexibleType -> {
lowerBound.collectTypeParameters(c)
upperBound.collectTypeParameters(c)
}
is ConeClassLikeType ->
for (projection in type.typeArguments) {
if (projection is ConeKotlinTypeProjection) {
projection.type.collectTypeParameters(c)
}
}
is ConeTypeParameterType -> c.add(lookupTag.typeParameterSymbol.fir)
else -> Unit
}
}
private fun FirFunction<*>.copyToFreeAnonymousFunction(): FirAnonymousFunction {
val function = this
return buildAnonymousFunction {
val typeParameterSet = function.typeParameters.filterIsInstanceTo(mutableSetOf<FirTypeParameter>())
session = function.session
origin = FirDeclarationOrigin.Source
symbol = FirAnonymousFunctionSymbol()
returnTypeRef = function.returnTypeRef.approximated(toSuper = true)
receiverTypeRef = function.receiverTypeRef?.approximated(toSuper = false)
returnTypeRef = function.returnTypeRef.approximated(toSuper = true, typeParameterSet)
receiverTypeRef = function.receiverTypeRef?.approximated(toSuper = false, typeParameterSet)
isLambda = (function as? FirAnonymousFunction)?.isLambda == true
valueParameters.addAll(function.valueParameters.map {
buildValueParameterCopy(it) {
returnTypeRef = it.returnTypeRef.approximated(toSuper = false)
returnTypeRef = it.returnTypeRef.approximated(toSuper = false, typeParameterSet)
}
})
// TODO need containers' type parameters too
function.typeParameters.filterIsInstanceTo(typeParameters)
typeParameters += typeParameterSet
}
}
private fun FirPropertyAccessor.copyToFreeAccessor(): FirPropertyAccessor {
val accessor = this
return buildPropertyAccessor {
val typeParameterSet = accessor.typeParameters.toMutableSet()
session = accessor.session
origin = FirDeclarationOrigin.Source
returnTypeRef = accessor.returnTypeRef.approximated(toSuper = true)
returnTypeRef = accessor.returnTypeRef.approximated(toSuper = true, typeParameterSet)
symbol = FirPropertyAccessorSymbol()
isGetter = accessor.isGetter
status = accessor.status
accessor.valueParameters.mapTo(valueParameters) {
buildValueParameterCopy(it) {
returnTypeRef = it.returnTypeRef.approximated(toSuper = false)
returnTypeRef = it.returnTypeRef.approximated(toSuper = false, typeParameterSet)
}
}
annotations += accessor.annotations
// TODO need containers' type parameters too
typeParameters += accessor.typeParameters
typeParameters += typeParameterSet
}
}
private fun FirProperty.copyToFreeProperty(): FirProperty {
val property = this
return buildProperty {
val typeParameterSet = property.typeParameters.toMutableSet()
session = property.session
origin = FirDeclarationOrigin.Source
symbol = FirPropertySymbol(property.symbol.callableId)
returnTypeRef = property.returnTypeRef.approximated(toSuper = true)
receiverTypeRef = property.receiverTypeRef?.approximated(toSuper = false)
returnTypeRef = property.returnTypeRef.approximated(toSuper = true, typeParameterSet)
receiverTypeRef = property.receiverTypeRef?.approximated(toSuper = false, typeParameterSet)
name = property.name
initializer = property.initializer
delegate = property.delegate
@@ -111,8 +129,7 @@ class FirMetadataSerializer(
isLocal = property.isLocal
status = property.status
annotations += property.annotations
// TODO need containers' type parameters too
typeParameters += property.typeParameters
typeParameters += typeParameterSet
}.apply {
delegateFieldSymbol?.fir = this
}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JS_IR_ES6
// TODO: muted automatically, investigate should it be ran for JS or not
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// WITH_REFLECT