Javier
07/19/2023, 3:51 AMIrReturn
which uses a IrCall
as a value. I am creating this IrCall
from a function.
Caused by: java.lang.AssertionError: SyntheticAccessorLowering should not attempt to modify other files!
While lowering this file: FILE fqName:com.javiersc.playground fileName:__GENERATED DECLARATIONS__.kt
Trying to add this accessor: FUN SYNTHETIC_ACCESSOR name:access$resolve visibility:public modality:FINAL <> ($context_receiver_0:kotlin.String) returnType:kotlin.String
Any clue about what I am doing wrong?Tóth István Zoltán
07/19/2023, 5:18 AMJavier
07/19/2023, 9:43 AMpublic fun IrSimpleFunction.toIrCall(
startOffset: Int = UNDEFINED_OFFSET,
endOffset: Int = UNDEFINED_OFFSET,
symbol: IrSimpleFunctionSymbol = this.symbol,
type: IrType = returnType,
typeArgumentsCount: Int = typeParameters.size,
valueArgumentsCount: Int = valueParameters.size,
origin: IrStatementOrigin? = null,
superQualifierSymbol: IrClassSymbol? = null,
block: IrCall.() -> Unit = {},
): IrCall =
IrCallImpl(
startOffset = startOffset,
endOffset = endOffset,
type = type,
symbol = symbol,
typeArgumentsCount = typeArgumentsCount,
valueArgumentsCount = valueArgumentsCount,
origin = origin,
superQualifierSymbol = superQualifierSymbol,
)
.apply {
val functionValueParameters: List<IrValueParameter> = this@toIrCall.valueParameters
for ((index: Int, param: IrValueParameter) in functionValueParameters.withIndex()) {
putValueArgument(index, param.toIrGetValue())
}
block()
}
Javier
07/19/2023, 9:44 AMTóth István Zoltán
07/19/2023, 10:00 AMTóth István Zoltán
07/19/2023, 10:03 AMfun irCall(
symbol: IrFunctionSymbol,
origin: IrStatementOrigin? = null,
dispatchReceiver: IrExpression? = null,
extensionReceiver: IrExpression? = null,
vararg args: IrExpression
): IrCallImpl {
return IrCallImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
symbol.owner.returnType,
symbol as IrSimpleFunctionSymbol,
symbol.owner.typeParameters.size,
symbol.owner.valueParameters.size,
origin
).also {
if (dispatchReceiver != null) it.dispatchReceiver = dispatchReceiver
if (extensionReceiver != null) it.extensionReceiver = extensionReceiver
args.forEachIndexed { index, arg ->
it.putValueArgument(index, arg)
}
}
}
Tóth István Zoltán
07/19/2023, 10:04 AMJavier
07/19/2023, 10:08 AMdispatchReceiver
, I will add those two, but probably they are null, let me checkJavier
07/19/2023, 10:09 AMJavier
07/19/2023, 10:09 AMCALL 'private final fun resolve ($context_receiver_0: kotlin.String): kotlin.String declared in com.javiersc.playground' type=kotlin.String origin=null
$context_receiver_0: GET_VAR '$this$with: kotlin.String declared in com.javiersc.playground.resolve.<anonymous>' type=kotlin.String origin=null
Manually written:
CALL 'private final fun resolve2 ($context_receiver_0: kotlin.String): kotlin.String declared in com.javiersc.playground' type=kotlin.String origin=null
$context_receiver_0: GET_VAR '$this$with: kotlin.String declared in com.javiersc.playground.resolve2.<anonymous>' type=kotlin.String origin=null
Tóth István Zoltán
07/19/2023, 10:11 AMTóth István Zoltán
07/19/2023, 10:12 AMCALL 'public final fun provideDelegate (...), <http://kotlin.Int|kotlin.Int>> origin=null
$this: CALL 'public final fun int (default: <http://kotlin.Int|kotlin.Int>, min: <http://kotlin.Int|kotlin.Int>?, max: <http://kotlin.Int?|kotlin.Int?>):
Javier
07/19/2023, 10:12 AMJavier
07/19/2023, 10:12 AMFUN name:resolve visibility:private modality:FINAL <> ($context_receiver_0:kotlin.String) returnType:kotlin.String
annotations:
ContextResolution
contextReceiverParametersCount: 1
VALUE_PARAMETER name:$context_receiver_0 index:0 type:kotlin.String
BLOCK_BODY
RETURN type=kotlin.Nothing from='private final fun resolve ($context_receiver_0: kotlin.String): kotlin.String declared in com.javiersc.playground'
GET_VAR '$context_receiver_0: kotlin.String declared in com.javiersc.playground.resolve' type=kotlin.String origin=null
And the written manually
FUN name:resolve2 visibility:private modality:FINAL <> ($context_receiver_0:kotlin.String) returnType:kotlin.String
contextReceiverParametersCount: 1
VALUE_PARAMETER name:$context_receiver_0 index:0 type:kotlin.String
BLOCK_BODY
RETURN type=kotlin.Nothing from='private final fun resolve2 ($context_receiver_0: kotlin.String): kotlin.String declared in com.javiersc.playground'
GET_VAR '$context_receiver_0: kotlin.String declared in com.javiersc.playground.resolve2' type=kotlin.String origin=null
Javier
07/19/2023, 10:15 AM$this$with
part was tricky, but even hardcoding a "foo".toIrConst(...)
is giving me the same failTóth István Zoltán
07/19/2023, 10:17 AMJavier
07/19/2023, 10:18 AMTóth István Zoltán
07/19/2023, 10:27 AMcontext(String)
?Javier
07/19/2023, 10:29 AMresolve
)
context(String)
@ContextResolution private fun resolve(): String {
return this@String
}
context(String)
private fun resolve2(): String {
return this@String
}
Javier
07/19/2023, 10:31 AMcontext(String)
fun resolve(): String {
return this@String
}
// I am trying to generate this
fun resolve(foo: ContextualProvider<String> = Foo_Factory): String {
with(foo.get()) {
return resolve()
}
}
Tóth István Zoltán
07/19/2023, 10:34 AM$context_receiver_0: GET_VAR '$this$with: kotlin.String declared in com.javiersc.playground.resolve.<anonymous>'
My guess is that in the line above the .resolve
is not the right one. Try renaming one of the functions.Tóth István Zoltán
07/19/2023, 10:35 AMTóth István Zoltán
07/19/2023, 10:37 AMJavier
07/19/2023, 10:37 AMJavier
07/19/2023, 10:38 AMresolve
should be the only one, I am going to checkTóth István Zoltán
07/19/2023, 10:39 AMfoo
and one without.Javier
07/19/2023, 10:41 AMthis.extensionReceiverParameter = getValueIrValueParameter
val originalContextResolutionCall: IrCall =
originalContextResolutionFunction.toIrCall {
val getValueArgument: IrGetValue = getValueArgument(0).asIr()!!
val updatedGetValueArgument: IrGetValue =
getValueArgument.symbol.owner
.deepCopyWithSymbols(this@createLambdaIrSimpleFunction)
.apply { this.name = "\$this\$with".toName() }
.asIr<IrValueParameter>()!!
.toIrGetValue()
putValueArgument(0, updatedGetValueArgument)
}
val originalContextResolutionIrReturn: IrReturn =
createIrReturn(
type = irBuiltIns.nothingType,
returnTargetSymbol = originalContextResolutionFunction.symbol,
value = originalContextResolutionCall
)
this.body = createIrBlockBody {
this.statements.add(originalContextResolutionIrReturn)
}
Tóth István Zoltán
07/19/2023, 10:42 AMJavier
07/19/2023, 10:42 AMJavier
07/19/2023, 10:43 AMresolve2
equivalent 🤔Javier
07/19/2023, 10:45 AMwith
lambda?Tóth István Zoltán
07/19/2023, 10:49 AMcontext(String) resolve()
with a call to resolve(foo...)
?Javier
07/19/2023, 10:51 AMcontext(String)
fun resolve(): String {
return this@String
}
// generated with no body
fun resolve(foo: ContextualProvider<String> = Foo_Factory): String
// add body
fun resolve(foo: ContextualProvider<String> = Foo_Factory): String {
with(foo.get()) {
return resolve() // call to `resolve()` with context receiver
}
}
Javier
07/19/2023, 10:53 AMTóth István Zoltán
07/19/2023, 10:56 AMJavier
07/19/2023, 11:09 AMNon-mapped local declaration: VALUE_PARAMETER name:$this$with index:0 type:kotlin.String
Javier
07/19/2023, 11:09 AM$this
?Javier
07/19/2023, 11:11 AMval updatedGetValueArgument: IrGetValue =
getValueArgument.symbol.owner
.deepCopyWithSymbols(this@createLambdaIrSimpleFunction)
.apply { this.name = "\$this\$with".toName() }
.asIr<IrValueParameter>()!!
.toIrGetValue()
Tóth István Zoltán
07/19/2023, 11:13 AMwith(foo.get())
I think, you could just set it's value to the context receiver parameter.Tóth István Zoltán
07/19/2023, 11:15 AMJavier
07/19/2023, 11:16 AMval getValueIrValueParameter: IrValueParameter =
parameter.deepCopyWithSymbols(this@createLambdaIrSimpleFunction).apply {
this.name = "\$this\$with".toName()
this.type = getFunction.returnType
this.index = -1
this.defaultValue = null
}
this.extensionReceiverParameter = getValueIrValueParameter
val originalContextResolutionCall: IrCall =
originalContextResolutionFunction.toIrCall {
putValueArgument(0, getValueIrValueParameter.toIrGetValue())
}
But I am not sure if I should put the extensionReceiverParameter
so or I should do it in a different wayJavier
07/19/2023, 11:17 AMJavier
07/19/2023, 11:48 AMbox()
works, calling box2()
failsJavier
07/19/2023, 11:49 AMException in thread "main" java.lang.ClassCastException: class java.lang.String cannot be cast to class java.lang.Number (java.lang.String and java.lang.Number are in module java.base of loader 'bootstrap')
at com.javiersc.kotlin.inject.playground.__GENERATED_DECLARATIONS__Kt.resolve2(__GENERATED DECLARATIONS__.kt)
at com.javiersc.kotlin.inject.playground.__GENERATED_DECLARATIONS__Kt.resolve2$default(__GENERATED DECLARATIONS__.kt)
at com.javiersc.kotlin.inject.playground.MainKt.box2(Main.kt:16)
at com.javiersc.kotlin.inject.playground.MainKt.main(Main.kt:7)
Tóth István Zoltán
07/19/2023, 12:00 PMJavier
07/19/2023, 12:03 PMJavier
07/19/2023, 12:09 PMJavier
07/19/2023, 12:23 PMJavier
07/19/2023, 12:23 PMJavier
07/19/2023, 12:25 PMTóth István Zoltán
07/19/2023, 12:30 PMJavier
07/19/2023, 12:33 PMJavier
07/23/2023, 2:02 PM$this$with
.
class Bur_Factory(
private val contextualProviderString: ContextualProvider<String>,
) : ContextualFactory<Int> {
override fun get(): Int {
with(contextualProviderString.get()) {
return bar()
}
}
}
As you recommended me to avoid deep copy with deepCopyWithSymbols
how would you add the receiver to the with
lambda?
contextualProviderString.get()
type is String
, and with the copy approach I am getting Non-mapped local declaration: VALUE_PARAMETER name:$this$with type:kotlin.String
But I can't set the call
to get
as receiver in the lambda, that is the reason I am building a $this$with
value parameter manuallyTóth István Zoltán
07/28/2023, 2:20 PMcontextualProviderString.get()
to bar
directly. The with
is just syntactical sugar so the programmer can tell the compiler which receivers to use.
If I'm guessing right, the context receivers are just the first N parameters of the function and there is nothing really special about them. This is from IrCallImpl
code:
valueArgumentsCount: Int = symbol.descriptor.valueParameters.size + symbol.descriptor.contextReceiverParameters.size,
So, I guess they are just go in as normal value arguments.Javier
07/28/2023, 2:23 PMJavier
07/29/2023, 1:18 AMVALUE_PARAMETER name:<this> type:com.javiersc.kotlin.inject.ContextualProvider<T of com.javiersc.kotlin.inject.ContextualProvider>
but I am getting
VALUE_PARAMETER name:string index:0 type:com.javiersc.kotlin.inject.ContextualProvider<kotlin.String>
I am picking the valueParameters from the primary constructor and converting them to IrGetValue
I could deep copy it and start to fix it in a manual way, but I am not sure what I am missing to avoid doing that
Note: I have renamedtocontextualProviderString
string
Javier
07/29/2023, 1:28 AMthis.dispatchReceiver = providerClass.getGetterIrCall(parameter)
fun IrClass.getGetterIrCall(valueParameter: IrValueParameter): IrCall =
declarationPropertyGetter(valueParameter).getter!!.toIrCall(
type = valueParameter.type,
origin = IrStatementOrigin.GET_PROPERTY
) {
this.dispatchReceiver = getFunctionGetValue
this.extensionReceiver = null
}
Tóth István Zoltán
07/29/2023, 7:31 AMJavier
07/29/2023, 8:25 AM