FIR: support copy functions in data classes

This commit is contained in:
Mikhail Glukhikh
2019-05-16 11:14:43 +03:00
parent d9261acdfc
commit 2bf80ff64e
17 changed files with 341 additions and 16 deletions
@@ -9,21 +9,24 @@ import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.FirFunctionTarget
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirConstructor
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.impl.FirClassImpl
import org.jetbrains.kotlin.fir.declarations.impl.FirMemberFunctionImpl
import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl
import org.jetbrains.kotlin.fir.expressions.impl.FirFunctionCallImpl
import org.jetbrains.kotlin.fir.expressions.impl.FirQualifiedAccessExpressionImpl
import org.jetbrains.kotlin.fir.expressions.impl.FirReturnExpressionImpl
import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock
import org.jetbrains.kotlin.fir.references.FirResolvedCallableReferenceImpl
import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.impl.FirImplicitTypeRefImpl
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtTypeReference
internal fun KtClassOrObject.generateComponentFunctions(
session: FirSession, firClass: FirClassImpl, packageFqName: FqName, classFqName: FqName
@@ -67,4 +70,64 @@ internal fun KtClassOrObject.generateComponentFunctions(
}
)
}
}
private val copyName = Name.identifier("copy")
internal fun KtClassOrObject.generateCopyFunction(
session: FirSession, firClass: FirClassImpl, packageFqName: FqName, classFqName: FqName,
firPrimaryConstructor: FirConstructor,
toFirOrErrorTypeRef: KtTypeReference?.() -> FirTypeRef
) {
val symbol = FirFunctionSymbol(CallableId(packageFqName, classFqName, copyName))
firClass.addDeclaration(
FirMemberFunctionImpl(
session, this, symbol, copyName,
Visibilities.PUBLIC, Modality.FINAL,
isExpect = false, isActual = false,
isOverride = false, isOperator = false,
isInfix = false, isInline = false,
isTailRec = false, isExternal = false,
isSuspend = false, receiverTypeRef = null,
returnTypeRef = FirImplicitTypeRefImpl(session, this)
).apply {
val copyFunction = this
val zippedParameters =
primaryConstructorParameters.zip(firClass.declarations.filterIsInstance<FirProperty>())
for ((ktParameter, firProperty) in zippedParameters) {
val name = ktParameter.nameAsSafeName
valueParameters += FirValueParameterImpl(
session, ktParameter, name,
ktParameter.typeReference.toFirOrErrorTypeRef(),
FirQualifiedAccessExpressionImpl(session, ktParameter).apply {
calleeReference = FirResolvedCallableReferenceImpl(session, ktParameter, name, firProperty.symbol)
},
isCrossinline = false, isNoinline = false, isVararg = false
)
}
body = FirSingleExpressionBlock(
session,
FirReturnExpressionImpl(
session, this@generateCopyFunction,
FirFunctionCallImpl(session, this@generateCopyFunction).apply {
calleeReference = FirResolvedCallableReferenceImpl(
session, this@generateCopyFunction, firClass.name,
firPrimaryConstructor.symbol
)
}.apply {
for ((ktParameter, firParameter) in primaryConstructorParameters.zip(valueParameters)) {
this.arguments += FirQualifiedAccessExpressionImpl(session, ktParameter).apply {
calleeReference = FirResolvedCallableReferenceImpl(
session, ktParameter, firParameter.name, firParameter.symbol
)
}
}
}
).apply {
target = FirFunctionTarget(null)
target.bind(copyFunction)
}
)
}
)
}
@@ -547,6 +547,10 @@ class RawFirBuilder(val session: FirSession, val stubMode: Boolean) {
if (classOrObject.hasModifier(DATA_KEYWORD) && firPrimaryConstructor != null) {
classOrObject.generateComponentFunctions(session, firClass, packageFqName, className)
classOrObject.generateCopyFunction(session, firClass, packageFqName, className, firPrimaryConstructor) {
toFirOrErrorType()
}
// TODO: equals, hashCode, toString
}
firClass
@@ -29,6 +29,10 @@ FILE: annotated.kt
super<kotlin/Any>()
}
public final fun copy(): <implicit> {
^copy R|/Two.Two|()
}
}
public? final? fun bar(two: Two): kotlin/Unit {
lval <destruct>: <implicit> = two#
@@ -25,6 +25,10 @@ FILE: destructuring.kt
^component3 R|/Some.third|
}
public final fun copy(first: Int = R|/Some.first|, second: Double = R|/Some.second|, third: String = R|/Some.third|): <implicit> {
^copy R|/Some.Some|(R|<local>/first|, R|<local>/second|, R|<local>/third|)
}
}
public? final? fun foo(some: Some): kotlin/Unit {
lval <destruct>: <implicit> = some#
@@ -43,6 +43,10 @@ FILE: for.kt
^component2 R|/Some.y|
}
public final fun copy(x: Int = R|/Some.x|, y: Int = R|/Some.y|): <implicit> {
^copy R|/Some.Some|(R|<local>/x|, R|<local>/y|)
}
}
public? final? fun baz(set: Set<Some>): kotlin/Unit {
lval <range>: <implicit> = set#
@@ -18,6 +18,10 @@ FILE: lambda.kt
^component2 R|/Tuple.y|
}
public final fun copy(x: Int = R|/Tuple.x|, y: Int = R|/Tuple.y|): <implicit> {
^copy R|/Tuple.Tuple|(R|<local>/x|, R|<local>/y|)
}
}
public? final? inline fun use(f: ( (Tuple) -> Int )): <implicit> {
^use f#(Tuple#(Int(1), Int(2)))