```.createMemberFunction( owner = nestedItem, ...
# compiler
m
Copy code
.createMemberFunction(
    owner = nestedItem,
    name = COMPANION_METHOD_TO_GENERATE,
    returnType = outerClass.constructType(),
    key = KEY,
) {
    val functionBuilder = this
    functionBuilder.status {
        val statusBuilder = this
        statusBuilder.isOperator = true
    }
    ctor.valueParameters.forEach { parameter ->
        functionBuilder.valueParameter(
            name = parameter.name,
            type = parameter.returnTypeRef.coneType,
        )
    }
}
How do I also copy over all existing default values of constructor parameters?
this: FirDeclarationGenerationExtension
and
ctor
is
Copy code
outerClass.fir
    .declarations
    .filterIsInstance<FirConstructor>()
    .firstOrNull(FirConstructor::isPrimary)
    .let { nullable -> nullable ?: break }
y
From its docs:
If you set [hasDefaultValue] to true then you need to generate actual default value in [IrGenerationExtension]
In general, it's not recommended to generate bodies in FIR, and instead you're supposed to do it in IR (where it's easier anyway). So simply set
hasDefaultValue = true
, then copy it in IR. If you really really want, I think you can
.createMemberFunction(...).apply { }
and edit the value parameters inside
p
Also, I'd like to note, that you can't do it in general case, as default value, can • be not availiable, if it's already compiled class (not the case, if you are generating something in the file where original function comes from) • be not availiable, if the value of default comes from overridden or expect function • reference something, that is not availiable in new context (such as, other value or type parameter of function, or a something from private context).
m
@Youssef Shoaib [MOD] I’ll try to do exactly this. Thank you for the pointer!
@Pavel Kunyavskiy [JB] Could you please provide examples? I need it to just have the effect of cutting and pasting the default values into my generated function
p
Third one is about something like
Copy code
private fun toY(x: T): T
fun <T> foo(x: T, y: T = toY(x))
You need to make sure, that • toY is accessible from generated function • x in default value references x from new function, not from old one • type of this expression references T from new function not from old one. The first case is about something like
Copy code
//Other module
interface I {
   fun foo(x: Int = 10)
}
// Your module 
claas C : I {
   fun foo(x: Int)
}
In that case C.foo is callable with default, but compiler doesn't know the value of default at all.
The expect case is irrelevant, if you are working with ir, expect don't exist anymore on this stage.
y
I think in this particular case you might be fine cuz you're copying a constructor (so no inheritance involved) into a companion object (so visibility should be about the same). Only concern I'd have is something like:
Copy code
class Foo(val x: Int, val y: Int = x)
you'll need to map the default value so any references to other parameters refer to the new declaration you're making
p
With constructors should be simpler, yes. As I remember there still were some obscure cases with local classes, that are not possible, but probably just asking your users not to do too stupid things should be enough