Raw FIR: generate data-class component1, component2, ... functions

This commit is contained in:
Mikhail Glukhikh
2019-04-18 18:26:40 +03:00
parent bb7dcd9945
commit f9feeac5e1
7 changed files with 128 additions and 0 deletions
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.FirTypeProjection
import org.jetbrains.kotlin.fir.types.impl.*
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.lexer.KtTokens.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
@@ -551,6 +552,48 @@ class RawFirBuilder(val session: FirSession, val stubMode: Boolean) {
)
}
if (classOrObject.hasModifier(KtTokens.DATA_KEYWORD) && firPrimaryConstructor != null) {
var componentIndex = 1
val zippedParameters =
classOrObject.primaryConstructorParameters.zip(firClass.declarations.filterIsInstance<FirProperty>())
for ((ktParameter, firProperty) in zippedParameters) {
if (!ktParameter.hasValOrVar()) continue
val name = Name.identifier("component$componentIndex")
componentIndex++
val symbol = FirFunctionSymbol(callableIdForName(name))
firClass.addDeclaration(
FirMemberFunctionImpl(
session, ktParameter, symbol, name,
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, ktParameter)
).apply {
val componentFunction = this
body = FirSingleExpressionBlock(
this@RawFirBuilder.session,
FirReturnExpressionImpl(
this@RawFirBuilder.session, ktParameter,
FirQualifiedAccessExpressionImpl(this@RawFirBuilder.session, ktParameter).apply {
val parameterName = ktParameter.nameAsSafeName
calleeReference = FirResolvedCallableReferenceImpl(
this@RawFirBuilder.session, ktParameter,
parameterName, firProperty.symbol
)
}
).apply {
target = FirFunctionTarget(null)
target.bind(componentFunction)
}
)
}
)
}
}
firClass
}
}
@@ -13,6 +13,18 @@ FILE: destructuring.kt
public? final? val third: String = R|<local>/third|
public? get(): String
public final fun component1(): <implicit> {
^component1 R|/Some.first|
}
public final fun component2(): <implicit> {
^component2 R|/Some.second|
}
public final fun component3(): <implicit> {
^component3 R|/Some.third|
}
}
public? final? fun foo(some: Some): kotlin/Unit {
lval <destruct>: <implicit> = some#
@@ -35,6 +35,14 @@ FILE: for.kt
public? final? val y: Int = R|<local>/y|
public? get(): Int
public final fun component1(): <implicit> {
^component1 R|/Some.x|
}
public final fun component2(): <implicit> {
^component2 R|/Some.y|
}
}
public? final? fun baz(set: Set<Some>): kotlin/Unit {
lval <range>: <implicit> = set#
@@ -10,6 +10,14 @@ FILE: lambda.kt
public? final? val y: Int = R|<local>/y|
public? get(): Int
public final fun component1(): <implicit> {
^component1 R|/Tuple.x|
}
public final fun component2(): <implicit> {
^component2 R|/Tuple.y|
}
}
public? final? inline fun use(f: ( (Tuple) -> Int )): <implicit> {
^use f#(Tuple#(Int(1), Int(2)))
@@ -0,0 +1,11 @@
data class D(val x: Int, val y: String)
fun foo(list: List<D>) {
for ((x, y) in list) {
}
val (x, y) = list.first()
list.forEach { (x, y) ->
println(x)
println(y)
}
}
@@ -0,0 +1,41 @@
FILE: components.kt
public final data class D : R|kotlin/Any| {
public constructor(x: R|kotlin/Int|, y: R|kotlin/String|): R|D| {
super<R|kotlin/Any|>()
}
public final val x: R|kotlin/Int| = R|<local>/x|
public get(): R|kotlin/Int|
public final val y: R|kotlin/String| = R|<local>/y|
public get(): R|kotlin/String|
public final fun component1(): R|kotlin/Int| {
^component1 R|/D.x|
}
public final fun component2(): R|kotlin/String| {
^component2 R|/D.y|
}
}
public final fun foo(list: R|kotlin/collections/List<D>|): R|kotlin/Unit| {
lval <range>: R|kotlin/collections/List<D>| = R|<local>/list|
lval <iterator>: R|kotlin/collections/Iterator<D>| = R|<local>/<range>|.R|FakeOverride<kotlin/collections/List.iterator: R|kotlin/collections/Iterator<D>|>|()
while(R|<local>/<iterator>|.R|FakeOverride<kotlin/collections/Iterator.hasNext: R|kotlin/Boolean|>|()) {
lval <destruct>: R|D| = R|<local>/<iterator>|.R|FakeOverride<kotlin/collections/Iterator.next: R|D|>|()
lval x: R|kotlin/Int| = R|<local>/<destruct>|.R|/D.component1|()
lval y: R|kotlin/String| = R|<local>/<destruct>|.R|/D.component2|()
}
lval <destruct>: <ERROR TYPE REF: Ambiguity: first, [kotlin/collections/first, kotlin/collections/first]> = R|<local>/list|.<Ambiguity: first, [kotlin/collections/first, kotlin/collections/first]>#()
lval x: <ERROR TYPE REF: Ambiguity: component1, [kotlin/collections/component1, kotlin/collections/component1, kotlin/collections/component1, kotlin/collections/component1, kotlin/collections/component1, kotlin/collections/component1, kotlin/collections/component1, kotlin/collections/component1, kotlin/collections/component1, kotlin/collections/component1, kotlin/collections/component1, kotlin/collections/component1, kotlin/collections/component1, kotlin/collections/component1, kotlin/collections/component1]> = R|<local>/<destruct>|.component1()
lval y: <ERROR TYPE REF: Ambiguity: component2, [kotlin/collections/component2, kotlin/collections/component2, kotlin/collections/component2, kotlin/collections/component2, kotlin/collections/component2, kotlin/collections/component2, kotlin/collections/component2, kotlin/collections/component2, kotlin/collections/component2, kotlin/collections/component2, kotlin/collections/component2, kotlin/collections/component2, kotlin/collections/component2, kotlin/collections/component2, kotlin/collections/component2]> = R|<local>/<destruct>|.component2()
R|<local>/list|.R|kotlin/collections/forEach|<R|D|>(<L> = forEach@fun <anonymous>(<destruct>: R|D|): R|kotlin/Unit| {
lval x: R|kotlin/Int| = R|<local>/<destruct>|.R|/D.component1|()
lval y: R|kotlin/String| = R|<local>/<destruct>|.R|/D.component2|()
R|kotlin/io/println|(R|<local>/x|)
R|kotlin/io/println|(R|<local>/y|)
}
)
}
@@ -34,6 +34,11 @@ public class FirResolveTestCaseWithStdlibGenerated extends AbstractFirResolveTes
runTest("compiler/fir/resolve/testData/resolve/stdlib/arrayFirstOrNull.kt");
}
@TestMetadata("components.kt")
public void testComponents() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/stdlib/components.kt");
}
@TestMetadata("concurrent.kt")
public void testConcurrent() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/stdlib/concurrent.kt");