What is the intended way to access properties in a...
# compiler
j
What is the intended way to access properties in a parentClass when trying to create the body for a function in ir? I have added a member function in fir and when filling out it's body all of the property access calls are generating java byte code using
getstatic
which results in this exception at runtime
Expected static field foo.SampleClass.param0
.
Fir implementation:
Copy code
override fun getCallableNamesForClass(
    classSymbol: FirClassSymbol<*>,
    context: MemberGenerationContext
  ): Set<Name> {
    return setOf(Name.identifier("sample"))
  }

  override fun generateFunctions(
    callableId: CallableId,
    context: MemberGenerationContext?
  ): List<FirNamedFunctionSymbol> {
    return createMemberFunction(
      owner = context!!.owner,
      key = Key,
      name = callableId.callableName,
      returnType = context.owner.constructType()
    ).symbol.let(::listOf)
  }
Ir implementation:
Copy code
override fun visitSimpleFunction(declaration: IrSimpleFunction) {
  val parentClass = declaration.parentAsClass
  val builder = IrBlockBodyBuilder(
    context = context,
    scope = Scope(declaration.symbol),
    startOffset = -1,
    endOffset = -1,
  )
  builder.run {
    declaration.body = context.irFactory.createBlockBody(-1, -1) {
      statements += irReturn(
        irCallConstructor(
          callee = parentClass.primaryConstructor!!.symbol,
          typeArguments = emptyList(),
        ).apply {
          parentClass.properties.forEachIndexed { index, property ->
            putValueArgument(index, irCall(property.getter!!))
          }
        },
      )
    }
  }
}
Class bytecode:
Copy code
Compiled from "Source0.kt"
public final class foo.SampleClass {
  public foo.SampleClass(java.lang.String);
    Code:
       0: aload_1
       1: ldc           #10                 // String param0
       3: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: invokespecial #19                 // Method java/lang/Object."<init>":()V
      10: aload_0
      11: aload_1
      12: putfield      #22                 // Field param0:Ljava/lang/String;
      15: return

  public final foo.SampleClass sample();
    Code:
       0: new           #2                  // class foo/SampleClass
       3: dup
       4: getstatic     #22                 // Field param0:Ljava/lang/String;
       7: invokespecial #28                 // Method "<init>":(Ljava/lang/String;)V
      10: areturn
}
b
You need to add a dispatch receiver to your
irCall
, otherwise it won't be treated as member access.
Copy code
override fun visitSimpleFunction(declaration: IrSimpleFunction) {
    val receiver = declaration.dispatchReceiverParameter ?: return
    val parentClass = declaration.parentAsClass
    val builder = DeclarationIrBuilder(context, declaration.symbol)
    declaration.body = builder.irBlockBody {
      +irReturn(
        irCallConstructor(
          callee = parentClass.primaryConstructor!!.symbol,
          typeArguments = emptyList(),
        ).apply {
          parentClass.properties.forEachIndexed { index, property ->
            putValueArgument(index, irCall(property.getter!!).apply {
              dispatchReceiver = irGet(receiver)
            })
          }
        },
      )
    }
  }
1
j
WOW Thank you that is working!!!!
Copy code
parentClass.properties.forEachIndexed { index, property ->
  putValueArgument(index, irCallOp(
    callee = property.getter!!.symbol,
    type = property.getter!!.returnType,
    dispatchReceiver = irGet(declaration.dispatchReceiverParameter!!),
  ))
}
I spent so many hours attempting to use
parentClass.thisReceiver
and
irGetField
etc