Extract anonymous class for property references (class, constructor, call to constructor, optional parameters)

This commit is contained in:
Tamas Vajk
2022-02-22 16:25:54 +01:00
committed by Ian Lynagh
parent d057530584
commit 4ce813a720
3 changed files with 207 additions and 3 deletions

View File

@@ -2528,8 +2528,7 @@ open class KotlinFileExtractor(
extractTypeAccess(e.classType, locId, callable, id, 0, exprParent.enclosingStmt)
}
is IrPropertyReference -> {
// TODO
logger.errorElement("Unhandled IrPropertyReference", e)
extractPropertyReference(e, parent, callable)
}
else -> {
logger.errorElement("Unrecognised IrExpression: " + e.javaClass, e)
@@ -2592,6 +2591,133 @@ open class KotlinFileExtractor(
}
}
private fun extractPropertyReference(
propertyReferenceExpr: IrPropertyReference,
parent: StmtExprParent,
callable: Label<out DbCallable>
) {
with("property reference", propertyReferenceExpr) {
/*
* Extract generated class:
* ```
* class C : kotlin.jvm.internal.PropertyReference, kotlin.reflect.KMutableProperty0<R> {
* private dispatchReceiver: TD
* constructor(dispatchReceiver: TD) {
* super()
* this.dispatchReceiver = dispatchReceiver
* }
*
* fun get(): R { return this.dispatchReceiver.FN1() }
*
* fun set(a0: R): Unit { return this.dispatchReceiver.FN2(a0) }
* }
* ```
*
* Variations:
* - KProperty vs KMutableProperty
* - KProperty0<> vs KProperty1<,>
* - no receiver vs dispatchReceiver vs extensionReceiver
**/
val target = propertyReferenceExpr.getter ?: run {
logger.errorElement("Expected to find getter for property reference.", propertyReferenceExpr)
return
}
val locId = tw.getLocation(propertyReferenceExpr)
val extensionParameter = target.owner.extensionReceiverParameter
val dispatchParameter = target.owner.dispatchReceiverParameter
var parameters = LinkedList<IrValueParameter>()
if (extensionParameter != null && propertyReferenceExpr.extensionReceiver == null) {
parameters.addFirst(extensionParameter)
}
if (dispatchParameter != null && propertyReferenceExpr.dispatchReceiver == null) {
parameters.addFirst(dispatchParameter)
}
val parameterTypes = parameters.map { it.type }
val kPropertyTypeArguments = parameterTypes + target.owner.returnType
val kPropertyType = propertyReferenceExpr.type
val javaResult = TypeResult(tw.getFreshIdLabel<DbClass>(), "", "")
val kotlinResult = TypeResult(tw.getFreshIdLabel<DbKt_notnull_type>(), "", "")
tw.writeKt_notnull_types(kotlinResult.id, javaResult.id)
val ids = LocallyVisibleFunctionLabels(
TypeResults(javaResult, kotlinResult),
tw.getFreshIdLabel(),
tw.getFreshIdLabel(), // not used
tw.getFreshIdLabel()
)
val currentDeclaration = declarationStack.peek()
// The base class could be `Any`. `PropertyReference` is used to keep symmetry with function references.
val baseClass = pluginContext.referenceClass(FqName("kotlin.jvm.internal.PropertyReference"))?.owner?.typeWith()
?: pluginContext.irBuiltIns.anyType
val id = extractGeneratedClass(ids, listOf(baseClass, kPropertyType), locId, currentDeclaration)
val helper = FunctionReferenceHelper(locId, ids)
val firstAssignmentStmtIdx = 1
val extensionParameterIndex: Int
val dispatchReceiver = propertyReferenceExpr.dispatchReceiver
val dispatchFieldId: Label<DbField>?
if (dispatchReceiver != null) {
dispatchFieldId = tw.getFreshIdLabel()
extensionParameterIndex = 1
extractField(dispatchFieldId, "<dispatchReceiver>", dispatchReceiver.type, id, locId, DescriptorVisibilities.PRIVATE, propertyReferenceExpr, false)
helper.extractParameterToFieldAssignmentInConstructor("<dispatchReceiver>", dispatchReceiver.type, dispatchFieldId, 0, firstAssignmentStmtIdx)
} else {
dispatchFieldId = null
extensionParameterIndex = 0
}
val extensionReceiver = propertyReferenceExpr.extensionReceiver
val extensionFieldId: Label<out DbField>?
if (extensionReceiver != null) {
extensionFieldId = tw.getFreshIdLabel()
extractField(extensionFieldId, "<extensionReceiver>", extensionReceiver.type, id, locId, DescriptorVisibilities.PRIVATE, propertyReferenceExpr, false)
helper.extractParameterToFieldAssignmentInConstructor( "<extensionReceiver>", extensionReceiver.type, extensionFieldId, 0 + extensionParameterIndex, firstAssignmentStmtIdx + extensionParameterIndex)
} else {
extensionFieldId = null
}
// todo: add get and set methods with body, call to reflection target (get and set), arguments
// todo: property ref
// Add constructor (property ref) call:
val exprParent = parent.expr(propertyReferenceExpr, callable)
val idCtorRef = tw.getFreshIdLabel<DbNewexpr>()
tw.writeExprs_newexpr(idCtorRef, ids.type.javaResult.id, exprParent.parent, exprParent.idx)
tw.writeExprsKotlinType(idCtorRef, ids.type.kotlinResult.id)
tw.writeHasLocation(idCtorRef, locId)
tw.writeCallableEnclosingExpr(idCtorRef, callable)
tw.writeStatementEnclosingExpr(idCtorRef, exprParent.enclosingStmt)
tw.writeCallableBinding(idCtorRef, ids.constructor)
extractTypeAccess(kPropertyType, locId, callable, idCtorRef, -3, exprParent.enclosingStmt)
// todo: property ref:
//tw.writeMemberRefBinding(idMemberRef, targetCallableId)
// constructor arguments:
if (dispatchReceiver != null) {
extractExpressionExpr(dispatchReceiver, callable, idCtorRef, 0, exprParent.enclosingStmt)
}
if (extensionReceiver != null) {
extractExpressionExpr(extensionReceiver, callable, idCtorRef, 0 + extensionParameterIndex, exprParent.enclosingStmt)
}
tw.writeIsAnonymClass(id, idCtorRef)
}
}
private fun extractFunctionReference(
functionReferenceExpr: IrFunctionReference,
parent: StmtExprParent,
@@ -2634,6 +2760,7 @@ open class KotlinFileExtractor(
val typeArguments = if (target is IrConstructorSymbol) {
(target.owner.returnType as? IrSimpleType)?.arguments
} else {
// todo: do we need to check the arguments of the extensionReceiver?
(functionReferenceExpr.dispatchReceiver?.type as? IrSimpleType)?.arguments
}
@@ -2661,11 +2788,12 @@ open class KotlinFileExtractor(
val ids = LocallyVisibleFunctionLabels(
TypeResults(javaResult, kotlinResult),
tw.getFreshIdLabel(),
tw.getFreshIdLabel(),
tw.getFreshIdLabel(), // not used
tw.getFreshIdLabel()
)
val currentDeclaration = declarationStack.peek()
// `FunctionReference` base class is required, because that's implementing `KFunction`.
val baseClass = pluginContext.referenceClass(FqName("kotlin.jvm.internal.FunctionReference"))?.owner?.typeWith()
?: pluginContext.irBuiltIns.anyType

View File

@@ -18,11 +18,33 @@ reflection.kt:
# 48| 0: [MethodAccess] println(...)
# 48| -1: [TypeAccess] ConsoleKt
# 48| 0: [MethodAccess] get(...)
# 48| -1: [ClassInstanceExpr] new (...)
# 48| -4: [AnonymousClass] new KProperty1<String,Character>(...) { ... }
# 48| 1: [Constructor]
# 48| 5: [BlockStmt] { ... }
# 48| 0: [SuperConstructorInvocationStmt] super(...)
# 48| -3: [TypeAccess] KProperty1<String,Character>
# 48| 0: [StringLiteral] abc
# 49| 1: [ExprStmt] <Expr>;
# 49| 0: [MethodAccess] println(...)
# 49| -1: [TypeAccess] ConsoleKt
# 49| 0: [MethodAccess] get(...)
# 49| -1: [ClassInstanceExpr] new (...)
# 49| -4: [AnonymousClass] new KProperty0<Character>(...) { ... }
# 49| 1: [Constructor]
#-----| 4: (Parameters)
# 49| 0: [Parameter] <extensionReceiver>
# 49| 5: [BlockStmt] { ... }
# 49| 0: [SuperConstructorInvocationStmt] super(...)
# 49| 1: [ExprStmt] <Expr>;
# 49| 0: [AssignExpr] ...=...
# 49| 0: [VarAccess] this.<extensionReceiver>
# 49| -1: [ThisAccess] this
# 49| 1: [VarAccess] <extensionReceiver>
# 49| 1: [FieldDeclaration] String <extensionReceiver>;
# 49| -1: [TypeAccess] String
# 49| -3: [TypeAccess] KProperty0<Character>
# 49| 0: [StringLiteral] abcd
# 3| 2: [Class] Reflection
# 3| 1: [Constructor] Reflection
# 3| 5: [BlockStmt] { ... }
@@ -55,6 +77,12 @@ reflection.kt:
# 6| -1: [VarAccess] ref
# 8| 2: [LocalVariableDeclStmt] var ...;
# 8| 1: [LocalVariableDeclExpr] x0
# 8| 0: [ClassInstanceExpr] new (...)
# 8| -4: [AnonymousClass] new KProperty1<C,Integer>(...) { ... }
# 8| 1: [Constructor]
# 8| 5: [BlockStmt] { ... }
# 8| 0: [SuperConstructorInvocationStmt] super(...)
# 8| -3: [TypeAccess] KProperty1<C,Integer>
# 9| 3: [LocalVariableDeclStmt] var ...;
# 9| 1: [LocalVariableDeclExpr] x1
# 9| 0: [MethodAccess] get(...)
@@ -98,8 +126,31 @@ reflection.kt:
# 12| 0: [VarAccess] x0
# 13| 7: [LocalVariableDeclStmt] var ...;
# 13| 1: [LocalVariableDeclExpr] x5
# 13| 0: [ClassInstanceExpr] new (...)
# 13| -4: [AnonymousClass] new KProperty0<Integer>(...) { ... }
# 13| 1: [Constructor]
#-----| 4: (Parameters)
# 13| 0: [Parameter] <dispatchReceiver>
# 13| 5: [BlockStmt] { ... }
# 13| 0: [SuperConstructorInvocationStmt] super(...)
# 13| 1: [ExprStmt] <Expr>;
# 13| 0: [AssignExpr] ...=...
# 13| 0: [VarAccess] this.<dispatchReceiver>
# 13| -1: [ThisAccess] this
# 13| 1: [VarAccess] <dispatchReceiver>
# 13| 1: [FieldDeclaration] C <dispatchReceiver>;
# 13| -1: [TypeAccess] C
# 13| -3: [TypeAccess] KProperty0<Integer>
# 13| 0: [ClassInstanceExpr] new C(...)
# 13| -3: [TypeAccess] C
# 15| 8: [LocalVariableDeclStmt] var ...;
# 15| 1: [LocalVariableDeclExpr] y0
# 15| 0: [ClassInstanceExpr] new (...)
# 15| -4: [AnonymousClass] new KMutableProperty1<C,Integer>(...) { ... }
# 15| 1: [Constructor]
# 15| 5: [BlockStmt] { ... }
# 15| 0: [SuperConstructorInvocationStmt] super(...)
# 15| -3: [TypeAccess] KMutableProperty1<C,Integer>
# 16| 9: [LocalVariableDeclStmt] var ...;
# 16| 1: [LocalVariableDeclExpr] y1
# 16| 0: [MethodAccess] set(...)
@@ -146,6 +197,23 @@ reflection.kt:
# 19| 0: [VarAccess] y0
# 20| 13: [LocalVariableDeclStmt] var ...;
# 20| 1: [LocalVariableDeclExpr] y5
# 20| 0: [ClassInstanceExpr] new (...)
# 20| -4: [AnonymousClass] new KMutableProperty0<Integer>(...) { ... }
# 20| 1: [Constructor]
#-----| 4: (Parameters)
# 20| 0: [Parameter] <dispatchReceiver>
# 20| 5: [BlockStmt] { ... }
# 20| 0: [SuperConstructorInvocationStmt] super(...)
# 20| 1: [ExprStmt] <Expr>;
# 20| 0: [AssignExpr] ...=...
# 20| 0: [VarAccess] this.<dispatchReceiver>
# 20| -1: [ThisAccess] this
# 20| 1: [VarAccess] <dispatchReceiver>
# 20| 1: [FieldDeclaration] C <dispatchReceiver>;
# 20| -1: [TypeAccess] C
# 20| -3: [TypeAccess] KMutableProperty0<Integer>
# 20| 0: [ClassInstanceExpr] new C(...)
# 20| -3: [TypeAccess] C
# 22| 14: [LocalVariableDeclStmt] var ...;
# 22| 1: [LocalVariableDeclExpr] prop
# 22| 0: [CastExpr] (...)...

View File

@@ -1,14 +1,22 @@
variableInitializerType
| reflection.kt:5:9:5:54 | KFunction<Double> ref | file://<external>/KFunction.class:0:0:0:0 | KFunction<Double> | reflection.kt:5:49:5:54 | new Function2<Ccc,Integer,Double>(...) { ... } | file://<external>/Function2.class:0:0:0:0 | Function2<Ccc,Integer,Double> | true |
| reflection.kt:5:9:5:54 | KFunction<Double> ref | file://<external>/KFunction.class:0:0:0:0 | KFunction<Double> | reflection.kt:5:49:5:54 | new Function2<Ccc,Integer,Double>(...) { ... } | file://<external>/FunctionReference.class:0:0:0:0 | FunctionReference | true |
| reflection.kt:8:9:8:42 | KProperty1<C,Integer> x0 | file://<external>/KProperty1.class:0:0:0:0 | KProperty1<C,Integer> | reflection.kt:8:38:8:42 | new KProperty1<C,Integer>(...) { ... } | file://<external>/KProperty1.class:0:0:0:0 | KProperty1<C,Integer> | true |
| reflection.kt:8:9:8:42 | KProperty1<C,Integer> x0 | file://<external>/KProperty1.class:0:0:0:0 | KProperty1<C,Integer> | reflection.kt:8:38:8:42 | new KProperty1<C,Integer>(...) { ... } | file://<external>/PropertyReference.class:0:0:0:0 | PropertyReference | true |
| reflection.kt:11:9:11:53 | Getter<C,Integer> x3 | file://<external>/KProperty1$Getter.class:0:0:0:0 | Getter<C,Integer> | file://<external>/KProperty1$Getter.class:0:0:0:0 | Getter<C,Integer> | file://<external>/Function1.class:0:0:0:0 | Function1<C,Integer> | true |
| reflection.kt:11:9:11:53 | Getter<C,Integer> x3 | file://<external>/KProperty1$Getter.class:0:0:0:0 | Getter<C,Integer> | file://<external>/KProperty1$Getter.class:0:0:0:0 | Getter<C,Integer> | file://<external>/KProperty$Getter.class:0:0:0:0 | Getter<Integer> | true |
| reflection.kt:12:9:12:44 | KFunction<Integer> x4 | file://<external>/KFunction.class:0:0:0:0 | KFunction<Integer> | reflection.kt:12:38:12:44 | new Function1<T,V>(...) { ... } | file://<external>/Function1.class:0:0:0:0 | Function1<T,V> | true |
| reflection.kt:12:9:12:44 | KFunction<Integer> x4 | file://<external>/KFunction.class:0:0:0:0 | KFunction<Integer> | reflection.kt:12:38:12:44 | new Function1<T,V>(...) { ... } | file://<external>/FunctionReference.class:0:0:0:0 | FunctionReference | true |
| reflection.kt:13:9:13:41 | KProperty0<Integer> x5 | file://<external>/KProperty0.class:0:0:0:0 | KProperty0<Integer> | reflection.kt:13:35:13:41 | new KProperty0<Integer>(...) { ... } | file://<external>/KProperty0.class:0:0:0:0 | KProperty0<Integer> | true |
| reflection.kt:13:9:13:41 | KProperty0<Integer> x5 | file://<external>/KProperty0.class:0:0:0:0 | KProperty0<Integer> | reflection.kt:13:35:13:41 | new KProperty0<Integer>(...) { ... } | file://<external>/PropertyReference.class:0:0:0:0 | PropertyReference | true |
| reflection.kt:15:9:15:49 | KMutableProperty1<C,Integer> y0 | file://<external>/KMutableProperty1.class:0:0:0:0 | KMutableProperty1<C,Integer> | reflection.kt:15:45:15:49 | new KMutableProperty1<C,Integer>(...) { ... } | file://<external>/KMutableProperty1.class:0:0:0:0 | KMutableProperty1<C,Integer> | true |
| reflection.kt:15:9:15:49 | KMutableProperty1<C,Integer> y0 | file://<external>/KMutableProperty1.class:0:0:0:0 | KMutableProperty1<C,Integer> | reflection.kt:15:45:15:49 | new KMutableProperty1<C,Integer>(...) { ... } | file://<external>/PropertyReference.class:0:0:0:0 | PropertyReference | true |
| reflection.kt:18:9:18:60 | Setter<C,Integer> y3 | file://<external>/KMutableProperty1$Setter.class:0:0:0:0 | Setter<C,Integer> | file://<external>/KMutableProperty1$Setter.class:0:0:0:0 | Setter<C,Integer> | file://<external>/Function2.class:0:0:0:0 | Function2<C,Integer,Unit> | true |
| reflection.kt:18:9:18:60 | Setter<C,Integer> y3 | file://<external>/KMutableProperty1$Setter.class:0:0:0:0 | Setter<C,Integer> | file://<external>/KMutableProperty1$Setter.class:0:0:0:0 | Setter<C,Integer> | file://<external>/KMutableProperty$Setter.class:0:0:0:0 | Setter<Integer> | true |
| reflection.kt:19:9:19:50 | KFunction<Unit> y4 | file://<external>/KFunction.class:0:0:0:0 | KFunction<Unit> | reflection.kt:19:44:19:50 | new Function2<T,V,Unit>(...) { ... } | file://<external>/Function2.class:0:0:0:0 | Function2<T,V,Unit> | true |
| reflection.kt:19:9:19:50 | KFunction<Unit> y4 | file://<external>/KFunction.class:0:0:0:0 | KFunction<Unit> | reflection.kt:19:44:19:50 | new Function2<T,V,Unit>(...) { ... } | file://<external>/FunctionReference.class:0:0:0:0 | FunctionReference | true |
| reflection.kt:20:9:20:48 | KMutableProperty0<Integer> y5 | file://<external>/KMutableProperty0.class:0:0:0:0 | KMutableProperty0<Integer> | reflection.kt:20:42:20:48 | new KMutableProperty0<Integer>(...) { ... } | file://<external>/KMutableProperty0.class:0:0:0:0 | KMutableProperty0<Integer> | true |
| reflection.kt:20:9:20:48 | KMutableProperty0<Integer> y5 | file://<external>/KMutableProperty0.class:0:0:0:0 | KMutableProperty0<Integer> | reflection.kt:20:42:20:48 | new KMutableProperty0<Integer>(...) { ... } | file://<external>/PropertyReference.class:0:0:0:0 | PropertyReference | true |
| reflection.kt:22:9:22:91 | KProperty2<C,Integer,Integer> prop | file://<external>/KProperty2.class:0:0:0:0 | KProperty2<C,Integer,Integer> | file://<external>/KProperty2.class:0:0:0:0 | KProperty2<C,Integer,Integer> | file://<external>/Function2.class:0:0:0:0 | Function2<C,Integer,Integer> | true |
| reflection.kt:22:9:22:91 | KProperty2<C,Integer,Integer> prop | file://<external>/KProperty2.class:0:0:0:0 | KProperty2<C,Integer,Integer> | file://<external>/KProperty2.class:0:0:0:0 | KProperty2<C,Integer,Integer> | file://<external>/KProperty.class:0:0:0:0 | KProperty<Integer> | true |
invocation