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(VariableRemapper(oldConstructorParameterToNew))
|
||||||
|
|
||||||
irClass.transformChildrenVoid(object : IrElementTransformerVoid() {
|
irClass.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||||
|
private var enclosingConstructor: IrConstructor? = null
|
||||||
|
|
||||||
// TODO: maybe add another transformer that skips specified elements
|
// TODO: maybe add another transformer that skips specified elements
|
||||||
override fun visitClass(declaration: IrClass): IrStatement =
|
override fun visitClass(declaration: IrClass): IrStatement =
|
||||||
declaration
|
declaration
|
||||||
|
|
||||||
|
override fun visitConstructor(declaration: IrConstructor): IrStatement =
|
||||||
|
try {
|
||||||
|
enclosingConstructor = declaration
|
||||||
|
super.visitConstructor(declaration)
|
||||||
|
} finally {
|
||||||
|
enclosingConstructor = null
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||||
expression.transformChildrenVoid(this)
|
expression.transformChildrenVoid(this)
|
||||||
|
|
||||||
@@ -100,8 +110,14 @@ class InnerClassesLowering(val context: BackendContext) : ClassLoweringPass {
|
|||||||
return expression
|
return expression
|
||||||
}
|
}
|
||||||
|
|
||||||
val outerThisField = context.declarationFactory.getOuterThisField(innerClass)
|
irThis = if (enclosingConstructor != null && irClass == innerClass) {
|
||||||
irThis = IrGetFieldImpl(startOffset, endOffset, outerThisField.symbol, outerThisField.type, irThis, origin)
|
// 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
|
innerClass = innerClass.parentAsClass
|
||||||
}
|
}
|
||||||
return irThis
|
return irThis
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
class Outer() {
|
class Outer() {
|
||||||
open inner class InnerBase() {
|
open inner class InnerBase() {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
open class A() {
|
open class A() {
|
||||||
open inner class InnerA
|
open inner class InnerA
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
class Outer() {
|
class Outer() {
|
||||||
val s = "xyzzy"
|
val s = "xyzzy"
|
||||||
|
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
open class Base(val fn: () -> String)
|
open class Base(val fn: () -> String)
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
open class Base(val fn: () -> String)
|
open class Base(val fn: () -> String)
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
open class Foo(val x: () -> String)
|
open class Foo(val x: () -> String)
|
||||||
|
|
||||||
class Outer {
|
class Outer {
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
interface Test {
|
interface Test {
|
||||||
fun test(): String
|
fun test(): String
|
||||||
}
|
}
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
open class Base(val fn: () -> String)
|
open class Base(val fn: () -> String)
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
open class Base(val callback: () -> String)
|
open class Base(val callback: () -> String)
|
||||||
|
|
||||||
class Outer {
|
class Outer {
|
||||||
|
|||||||
Vendored
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
open class Base(val callback: () -> String)
|
open class Base(val callback: () -> String)
|
||||||
|
|
||||||
class Outer {
|
class Outer {
|
||||||
|
|||||||
Vendored
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
open class Base(val callback: () -> String)
|
open class Base(val callback: () -> String)
|
||||||
|
|
||||||
class Outer {
|
class Outer {
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
open class Base(val callback: () -> String)
|
open class Base(val callback: () -> String)
|
||||||
|
|
||||||
class Outer {
|
class Outer {
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
open class Foo(val x: () -> String)
|
open class Foo(val x: () -> String)
|
||||||
open class Foo2(val foo: Foo)
|
open class Foo2(val foo: Foo)
|
||||||
|
|
||||||
|
|||||||
Vendored
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
open class Base(val callback: () -> String)
|
open class Base(val callback: () -> String)
|
||||||
|
|
||||||
class Outer {
|
class Outer {
|
||||||
|
|||||||
Vendored
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
interface Callback {
|
interface Callback {
|
||||||
fun invoke(): String
|
fun invoke(): String
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
interface Callback {
|
interface Callback {
|
||||||
fun invoke(): String
|
fun invoke(): String
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
interface Callback {
|
interface Callback {
|
||||||
fun invoke(): String
|
fun invoke(): String
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
// FILE: JavaClass.java
|
// FILE: JavaClass.java
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
open class A1(y: String) {
|
open class A1(y: String) {
|
||||||
val x = "A1.x,$y"
|
val x = "A1.x,$y"
|
||||||
}
|
}
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
open class A(val s: String) {
|
open class A(val s: String) {
|
||||||
open inner class B(s: String): A(s)
|
open inner class B(s: String): A(s)
|
||||||
|
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
open class Father(val param: String) {
|
open class Father(val param: String) {
|
||||||
abstract inner class InClass {
|
abstract inner class InClass {
|
||||||
fun work(): String {
|
fun work(): String {
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
open class Father(val param: String) {
|
open class Father(val param: String) {
|
||||||
abstract inner class InClass {
|
abstract inner class InClass {
|
||||||
fun work(): String {
|
fun work(): String {
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
fun String.bar(): String {
|
fun String.bar(): String {
|
||||||
open class Local {
|
open class Local {
|
||||||
fun result() = this@bar
|
fun result() = this@bar
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
class Outer {
|
class Outer {
|
||||||
val outerProp: String
|
val outerProp: String
|
||||||
constructor(x: String) {
|
constructor(x: String) {
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
class Outer {
|
class Outer {
|
||||||
val outerProp: String
|
val outerProp: String
|
||||||
constructor(x: String) {
|
constructor(x: String) {
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
class Outer(val x: String) {
|
class Outer(val x: String) {
|
||||||
abstract inner class InnerBase
|
abstract inner class InnerBase
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user