Handle Java base class field read properly in IR converters

For FE 1.0, we just change super qualifier symbol to
base class, if it's possible.
For FIR, we introduce using of super qualifier symbols for
field accesses and repeat FE 1.0 behavior here.

#KT-49507 Fixed
This commit is contained in:
Mikhail Glukhikh
2022-06-08 14:45:52 +02:00
committed by Space
parent c2ae74c7cd
commit b0a6508d4b
23 changed files with 370 additions and 18 deletions
@@ -0,0 +1,36 @@
FILE fqName:<root> fileName:/Derived.kt
CLASS CLASS name:Derived modality:FINAL visibility:public superTypes:[<root>.BaseJava]
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.Derived
CONSTRUCTOR visibility:public <> () returnType:<root>.Derived [primary]
BLOCK_BODY
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.BaseJava'
INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:Derived modality:FINAL visibility:public superTypes:[<root>.BaseJava]'
PROPERTY name:a visibility:public modality:FINAL [val]
FIELD PROPERTY_BACKING_FIELD name:a type:kotlin.String visibility:private [final]
EXPRESSION_BODY
CONST String type=kotlin.String value="FAIL"
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-a> visibility:public modality:FINAL <> ($this:<root>.Derived) returnType:kotlin.String
correspondingProperty: PROPERTY name:a visibility:public modality:FINAL [val]
$this: VALUE_PARAMETER name:<this> type:<root>.Derived
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun <get-a> (): kotlin.String declared in <root>.Derived'
GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:a type:kotlin.String visibility:private [final]' type=kotlin.String origin=null
receiver: GET_VAR '<this>: <root>.Derived declared in <root>.Derived.<get-a>' type=<root>.Derived origin=null
FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator]
overridden:
public open fun equals (other: kotlin.Any?): kotlin.Boolean [fake_override,operator] declared in <root>.BaseJava
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
VALUE_PARAMETER name:other index:0 type:kotlin.Any?
FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override]
overridden:
public open fun hashCode (): kotlin.Int [fake_override] declared in <root>.BaseJava
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override]
overridden:
public open fun toString (): kotlin.String [fake_override] declared in <root>.BaseJava
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
FUN name:box visibility:public modality:FINAL <> () returnType:@[FlexibleNullability] kotlin.String?
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun box (): @[FlexibleNullability] kotlin.String? declared in <root>'
GET_FIELD 'FIELD IR_EXTERNAL_JAVA_DECLARATION_STUB name:a type:@[FlexibleNullability] kotlin.String? visibility:public' type=@[FlexibleNullability] kotlin.String? origin=GET_PROPERTY
receiver: CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.Derived' type=<root>.Derived origin=null
@@ -0,0 +1,39 @@
FILE fqName:<root> fileName:/Derived.kt
CLASS CLASS name:Derived modality:FINAL visibility:public superTypes:[<root>.BaseJava]
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.Derived
CONSTRUCTOR visibility:public <> () returnType:<root>.Derived [primary]
BLOCK_BODY
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.BaseJava'
INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:Derived modality:FINAL visibility:public superTypes:[<root>.BaseJava]'
PROPERTY name:a visibility:public modality:FINAL [val]
FIELD PROPERTY_BACKING_FIELD name:a type:kotlin.String visibility:private [final]
EXPRESSION_BODY
CONST String type=kotlin.String value="FAIL"
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-a> visibility:public modality:FINAL <> ($this:<root>.Derived) returnType:kotlin.String
correspondingProperty: PROPERTY name:a visibility:public modality:FINAL [val]
$this: VALUE_PARAMETER name:<this> type:<root>.Derived
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun <get-a> (): kotlin.String declared in <root>.Derived'
GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:a type:kotlin.String visibility:private [final]' type=kotlin.String origin=null
receiver: GET_VAR '<this>: <root>.Derived declared in <root>.Derived.<get-a>' type=<root>.Derived origin=null
PROPERTY FAKE_OVERRIDE name:a visibility:public modality:FINAL [fake_override,var]
overridden:
public final a: @[FlexibleNullability] kotlin.String? [var]
FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator]
overridden:
public open fun equals (other: kotlin.Any?): kotlin.Boolean [fake_override,operator] declared in <root>.BaseJava
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
VALUE_PARAMETER name:other index:0 type:kotlin.Any?
FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override]
overridden:
public open fun hashCode (): kotlin.Int [fake_override] declared in <root>.BaseJava
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override]
overridden:
public open fun toString (): kotlin.String [fake_override] declared in <root>.BaseJava
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
FUN name:box visibility:public modality:FINAL <> () returnType:@[FlexibleNullability] kotlin.String?
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun box (): @[FlexibleNullability] kotlin.String? declared in <root>'
GET_FIELD 'FIELD IR_EXTERNAL_JAVA_DECLARATION_STUB name:a type:@[FlexibleNullability] kotlin.String? visibility:public' type=@[FlexibleNullability] kotlin.String? origin=GET_PROPERTY
receiver: CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.Derived' type=<root>.Derived origin=null
@@ -0,0 +1,14 @@
// TARGET_BACKEND: JVM_IR
// DUMP_IR
// FILE: BaseJava.java
public class BaseJava {
public String a = "OK";
}
// FILE: Derived.kt
class Derived : BaseJava() {
val a = "FAIL"
}
fun box() = Derived().a
+1 -1
View File
@@ -20,4 +20,4 @@ fun test1(j: Kotlin2) = j.f
// 1 GETFIELD Java2.f : I
// @TestKt.class:
// 1 GETFIELD Kotlin2.f : I
// 1 GETFIELD Java2.f : I
@@ -31,7 +31,13 @@ fun test(b : Boolean) {
}
// @TestKt.class:
// 1 GETFIELD JFieldOwner.f : I
// 1 PUTFIELD JFieldOwner.f : I
// 1 GETFIELD Mid.f : I
// 1 PUTFIELD Mid.f : I
// JVM_IR_TEMPLATES
// 2 GETFIELD JFieldOwner.f : I
// 0 GETFIELD Mid.f : I
// JVM_TEMPLATES
// 1 GETFIELD JFieldOwner.f : I
// 1 GETFIELD Mid.f : I
@@ -0,0 +1,51 @@
FILE fqName:test fileName:/test.kt
FUN name:eval visibility:public modality:FINAL <T> (f:kotlin.Function0<T of test.eval>) returnType:T of test.eval
TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?] reified:false
VALUE_PARAMETER name:f index:0 type:kotlin.Function0<T of test.eval>
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun eval <T> (f: kotlin.Function0<T of test.eval>): T of test.eval declared in test'
CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=T of test.eval origin=INVOKE
$this: GET_VAR 'f: kotlin.Function0<T of test.eval> declared in test.eval' type=kotlin.Function0<T of test.eval> origin=VARIABLE_AS_FUNCTION
CLASS CLASS name:C modality:FINAL visibility:public superTypes:[<root>.A.B]
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:test.C
CONSTRUCTOR visibility:public <> () returnType:test.C [primary]
BLOCK_BODY
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.A.B'
INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:C modality:FINAL visibility:public superTypes:[<root>.A.B]'
FUN name:f visibility:public modality:FINAL <> ($this:test.C) returnType:@[FlexibleNullability] kotlin.String?
$this: VALUE_PARAMETER name:<this> type:test.C
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun f (): @[FlexibleNullability] kotlin.String? declared in test.C'
CALL 'public final fun eval <T> (f: kotlin.Function0<T of test.eval>): T of test.eval declared in test' type=@[FlexibleNullability] kotlin.String? origin=null
<T>: @[FlexibleNullability] kotlin.String?
f: FUN_EXPR type=kotlin.Function0<@[FlexibleNullability] kotlin.String?> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:@[FlexibleNullability] kotlin.String?
BLOCK_BODY
RETURN type=kotlin.Nothing from='local final fun <anonymous> (): @[FlexibleNullability] kotlin.String? declared in test.C.f'
GET_FIELD 'FIELD IR_EXTERNAL_JAVA_DECLARATION_STUB name:x type:@[FlexibleNullability] kotlin.String? visibility:protected/*protected and package*/' type=@[FlexibleNullability] kotlin.String? origin=GET_PROPERTY
receiver: GET_VAR '<this>: test.C declared in test.C.f' type=test.C origin=null
FUN name:g visibility:public modality:FINAL <> ($this:test.C) returnType:@[FlexibleNullability] kotlin.String?
$this: VALUE_PARAMETER name:<this> type:test.C
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun g (): @[FlexibleNullability] kotlin.String? declared in test.C'
CALL 'public final fun eval <T> (f: kotlin.Function0<T of test.eval>): T of test.eval declared in test' type=@[FlexibleNullability] kotlin.String? origin=null
<T>: @[FlexibleNullability] kotlin.String?
f: FUN_EXPR type=kotlin.Function0<@[FlexibleNullability] kotlin.String?> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:@[FlexibleNullability] kotlin.String?
BLOCK_BODY
RETURN type=kotlin.Nothing from='local final fun <anonymous> (): @[FlexibleNullability] kotlin.String? declared in test.C.g'
GET_FIELD 'FIELD IR_EXTERNAL_JAVA_DECLARATION_STUB name:y type:@[FlexibleNullability] kotlin.String? visibility:protected/*protected and package*/' type=@[FlexibleNullability] kotlin.String? origin=GET_PROPERTY
receiver: GET_VAR '<this>: test.C declared in test.C.g' type=test.C origin=null
FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator]
overridden:
public open fun equals (other: kotlin.Any?): kotlin.Boolean [fake_override,operator] declared in <root>.A.B
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
VALUE_PARAMETER name:other index:0 type:kotlin.Any?
FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override]
overridden:
public open fun hashCode (): kotlin.Int [fake_override] declared in <root>.A.B
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override]
overridden:
public open fun toString (): kotlin.String [fake_override] declared in <root>.A.B
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
@@ -0,0 +1,28 @@
package test
fun <T : Any?> eval(f: Function0<T>): T {
return f.invoke()
}
class C : B {
constructor() /* primary */ {
super/*B*/()
/* <init>() */
}
fun f(): @FlexibleNullability String? {
return eval<@FlexibleNullability String?>(f = local fun <anonymous>(): @FlexibleNullability String? {
return <this>super.#x
}
)
}
fun g(): @FlexibleNullability String? {
return eval<@FlexibleNullability String?>(f = local fun <anonymous>(): @FlexibleNullability String? {
return <this>super.#y
}
)
}
}
@@ -0,0 +1,57 @@
FILE fqName:test fileName:/test.kt
FUN name:eval visibility:public modality:FINAL <T> (f:kotlin.Function0<T of test.eval>) returnType:T of test.eval
TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?] reified:false
VALUE_PARAMETER name:f index:0 type:kotlin.Function0<T of test.eval>
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun eval <T> (f: kotlin.Function0<T of test.eval>): T of test.eval declared in test'
CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=T of test.eval origin=INVOKE
$this: GET_VAR 'f: kotlin.Function0<T of test.eval> declared in test.eval' type=kotlin.Function0<T of test.eval> origin=VARIABLE_AS_FUNCTION
CLASS CLASS name:C modality:FINAL visibility:public superTypes:[<root>.A.B]
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:test.C
CONSTRUCTOR visibility:public <> () returnType:test.C [primary]
BLOCK_BODY
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.A.B'
INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:C modality:FINAL visibility:public superTypes:[<root>.A.B]'
FUN name:f visibility:public modality:FINAL <> ($this:test.C) returnType:@[FlexibleNullability] kotlin.String?
$this: VALUE_PARAMETER name:<this> type:test.C
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun f (): @[FlexibleNullability] kotlin.String? declared in test.C'
CALL 'public final fun eval <T> (f: kotlin.Function0<T of test.eval>): T of test.eval declared in test' type=@[FlexibleNullability] kotlin.String? origin=null
<T>: @[FlexibleNullability] kotlin.String?
f: FUN_EXPR type=kotlin.Function0<@[FlexibleNullability] kotlin.String?> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:@[FlexibleNullability] kotlin.String?
BLOCK_BODY
RETURN type=kotlin.Nothing from='local final fun <anonymous> (): @[FlexibleNullability] kotlin.String? declared in test.C.f'
GET_FIELD 'FIELD IR_EXTERNAL_JAVA_DECLARATION_STUB name:x type:@[FlexibleNullability] kotlin.String? visibility:protected/*protected and package*/' type=@[FlexibleNullability] kotlin.String? origin=GET_PROPERTY
receiver: GET_VAR '<this>: test.C declared in test.C.f' type=test.C origin=null
FUN name:g visibility:public modality:FINAL <> ($this:test.C) returnType:@[FlexibleNullability] kotlin.String?
$this: VALUE_PARAMETER name:<this> type:test.C
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun g (): @[FlexibleNullability] kotlin.String? declared in test.C'
CALL 'public final fun eval <T> (f: kotlin.Function0<T of test.eval>): T of test.eval declared in test' type=@[FlexibleNullability] kotlin.String? origin=null
<T>: @[FlexibleNullability] kotlin.String?
f: FUN_EXPR type=kotlin.Function0<@[FlexibleNullability] kotlin.String?> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:@[FlexibleNullability] kotlin.String?
BLOCK_BODY
RETURN type=kotlin.Nothing from='local final fun <anonymous> (): @[FlexibleNullability] kotlin.String? declared in test.C.g'
GET_FIELD 'FIELD IR_EXTERNAL_JAVA_DECLARATION_STUB name:y type:@[FlexibleNullability] kotlin.String? visibility:protected/*protected and package*/' type=@[FlexibleNullability] kotlin.String? origin=GET_PROPERTY
receiver: GET_VAR '<this>: test.C declared in test.C.g' type=test.C origin=null
FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator]
overridden:
public open fun equals (other: kotlin.Any?): kotlin.Boolean [fake_override,operator] declared in <root>.A.B
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
VALUE_PARAMETER name:other index:0 type:kotlin.Any?
FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override]
overridden:
public open fun hashCode (): kotlin.Int [fake_override] declared in <root>.A.B
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override]
overridden:
public open fun toString (): kotlin.String [fake_override] declared in <root>.A.B
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
PROPERTY FAKE_OVERRIDE name:y visibility:protected/*protected and package*/ modality:FINAL [fake_override,var]
overridden:
protected/*protected and package*/ final y: @[FlexibleNullability] kotlin.String? [var]
PROPERTY FAKE_OVERRIDE name:x visibility:protected/*protected and package*/ modality:FINAL [fake_override,var]
overridden:
protected/*protected and package*/ final x: @[FlexibleNullability] kotlin.String? [fake_override,var]
@@ -0,0 +1,23 @@
// SKIP_KLIB_TEST
// Related to KT-49507
// FILE: A.java
public class A {
protected String x = "1";
protected String y = "2";
public static class B extends A {
protected String y = "3";
}
}
// FILE: test.kt
package test
fun <T> eval(f: () -> T) = f()
class C : A.B() {
// Both x & y here should in fact be taken from B class: this.(super<B>.x), this.(super<B>.y)
fun f() = eval { x }
fun g() = eval { y }
}
@@ -0,0 +1,28 @@
package test
fun <T : Any?> eval(f: Function0<T>): T {
return f.invoke()
}
class C : B {
constructor() /* primary */ {
super/*B*/()
/* <init>() */
}
fun f(): @FlexibleNullability String? {
return eval<@FlexibleNullability String?>(f = local fun <anonymous>(): @FlexibleNullability String? {
return <this>super.#x
}
)
}
fun g(): @FlexibleNullability String? {
return eval<@FlexibleNullability String?>(f = local fun <anonymous>(): @FlexibleNullability String? {
return <this>super.#y
}
)
}
}
@@ -55,7 +55,7 @@ fun test(b: Boolean) {
else -> d2
}
k.#f = 42
k.#f /*~> Unit */
ksuper.#f /*~> Unit */
val md1: DerivedThroughMid1 = DerivedThroughMid1()
val md2: DerivedThroughMid2 = DerivedThroughMid2()
val mk: Mid = when {
@@ -63,5 +63,5 @@ fun test(b: Boolean) {
else -> md2
}
mk.#f = 44
mk.#f /*~> Unit */
mksuper.#f /*~> Unit */
}
@@ -10,7 +10,7 @@ class Derived : Base {
}
fun getValue(): Int {
return <this>.#value
return <this>super.#value
}
fun setValue(value: Int) {
+1 -1
View File
@@ -13,7 +13,7 @@ class Owner<out T : JCTree> {
get(): String {
var tree: JCTree = <this>.<get-tree>()
when {
tree is JCTypeApply -> return tree /*as JCTypeApply */.#clazz /*!! String */
tree is JCTypeApply -> return tree /*as JCTypeApply */super.#clazz /*!! String */
}
return ""
}
@@ -1,6 +1,6 @@
fun foo(movedPaths: MutableList<Couple<FilePath>>) {
movedPaths.forEach<Couple<FilePath>>(action = local fun <anonymous>(it: Couple<FilePath>) {
it.#second.getName() /*~> Unit */
itsuper.#second.getName() /*~> Unit */
}
)
}
@@ -6,6 +6,6 @@ fun testSetField(a: Any, b: Any) {
fun testGetField(a: Any): String {
a as JCell<String> /*~> Unit */
return a /*as JCell<String> */.#value /*!! String */
return a /*as JCell<String> */super.#value /*!! String */
}