Fix this remapping in inner class constructors
Inner class constructors should use the argument instead of reading outer `this` from a field because if such an access happens before a delegating constructor call, e.g. when evaluating an argument, a JVM bytecode validation error will be thrown. (The only operation on `this` allowed before a delegating constructor call is SETFIELD, and only if the field in question is declared in the same class.)
This commit is contained in:
+18
-2
@@ -77,10 +77,20 @@ class InnerClassesLowering(val context: BackendContext) : ClassLoweringPass {
|
||||
irClass.transformChildrenVoid(VariableRemapper(oldConstructorParameterToNew))
|
||||
|
||||
irClass.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
private var enclosingConstructor: IrConstructor? = null
|
||||
|
||||
// TODO: maybe add another transformer that skips specified elements
|
||||
override fun visitClass(declaration: IrClass): IrStatement =
|
||||
declaration
|
||||
|
||||
override fun visitConstructor(declaration: IrConstructor): IrStatement =
|
||||
try {
|
||||
enclosingConstructor = declaration
|
||||
super.visitConstructor(declaration)
|
||||
} finally {
|
||||
enclosingConstructor = null
|
||||
}
|
||||
|
||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||
expression.transformChildrenVoid(this)
|
||||
|
||||
@@ -100,8 +110,14 @@ class InnerClassesLowering(val context: BackendContext) : ClassLoweringPass {
|
||||
return expression
|
||||
}
|
||||
|
||||
val outerThisField = context.declarationFactory.getOuterThisField(innerClass)
|
||||
irThis = IrGetFieldImpl(startOffset, endOffset, outerThisField.symbol, outerThisField.type, irThis, origin)
|
||||
irThis = if (enclosingConstructor != null && irClass == innerClass) {
|
||||
// Might be before a super() call (e.g. an argument to one), in which case the JVM bytecode verifier will reject
|
||||
// an attempt to access the field. Good thing we have a local variable as well.
|
||||
IrGetValueImpl(startOffset, endOffset, enclosingConstructor!!.valueParameters[0].symbol, origin)
|
||||
} else {
|
||||
val outerThisField = context.declarationFactory.getOuterThisField(innerClass)
|
||||
IrGetFieldImpl(startOffset, endOffset, outerThisField.symbol, outerThisField.type, irThis, origin)
|
||||
}
|
||||
innerClass = innerClass.parentAsClass
|
||||
}
|
||||
return irThis
|
||||
|
||||
Reference in New Issue
Block a user