K2 JVM IR: fix access to Java field shadowed by Kotlin property
#KT-56386 Fixed Co-authored-by: Mikhail Glukhikh <Mikhail.Glukhikh@jetbrains.com>
This commit is contained in:
+12
-6
@@ -28737,6 +28737,18 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/javaFieldAndKotlinProperty/javaInvisibleFieldAndKotlinPropertyReference.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("javaPackagePrivateClassAndPublicField.kt")
|
||||
public void testJavaPackagePrivateClassAndPublicField() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/javaFieldAndKotlinProperty/javaPackagePrivateClassAndPublicField.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("javaPackagePrivateClassExposedViaProtectedStatic.kt")
|
||||
public void testJavaPackagePrivateClassExposedViaProtectedStatic() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/javaFieldAndKotlinProperty/javaPackagePrivateClassExposedViaProtectedStatic.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("javaProtectedFieldAndKotlinInvisibleProperty.kt")
|
||||
public void testJavaProtectedFieldAndKotlinInvisibleProperty() throws Exception {
|
||||
@@ -28749,12 +28761,6 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/javaFieldAndKotlinProperty/javaProtectedFieldAndKotlinInvisiblePropertyReference.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("javaProtectedFieldAndKotlinInvisiblePropertyWrite.kt")
|
||||
public void testJavaProtectedFieldAndKotlinInvisiblePropertyWrite() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/javaFieldAndKotlinProperty/javaProtectedFieldAndKotlinInvisiblePropertyWrite.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("javaProtectedFieldAndKotlinPropertyReference.kt")
|
||||
public void testJavaProtectedFieldAndKotlinPropertyReference() throws Exception {
|
||||
|
||||
+12
@@ -253,6 +253,18 @@ public class FirBytecodeTextTestGenerated extends AbstractFirBytecodeTextTest {
|
||||
runTest("compiler/testData/codegen/bytecodeText/javaFieldsWithIntersectionTypes.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("javaFieldsWithIntersectionTypes_k1.kt")
|
||||
public void testJavaFieldsWithIntersectionTypes_k1() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/javaFieldsWithIntersectionTypes_k1.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("javaFields_k1.kt")
|
||||
public void testJavaFields_k1() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/javaFields_k1.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("javaStatics.kt")
|
||||
public void testJavaStatics() throws Exception {
|
||||
|
||||
+12
-6
@@ -28737,6 +28737,18 @@ public class FirPsiBlackBoxCodegenTestGenerated extends AbstractFirPsiBlackBoxCo
|
||||
runTest("compiler/testData/codegen/box/javaFieldAndKotlinProperty/javaInvisibleFieldAndKotlinPropertyReference.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("javaPackagePrivateClassAndPublicField.kt")
|
||||
public void testJavaPackagePrivateClassAndPublicField() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/javaFieldAndKotlinProperty/javaPackagePrivateClassAndPublicField.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("javaPackagePrivateClassExposedViaProtectedStatic.kt")
|
||||
public void testJavaPackagePrivateClassExposedViaProtectedStatic() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/javaFieldAndKotlinProperty/javaPackagePrivateClassExposedViaProtectedStatic.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("javaProtectedFieldAndKotlinInvisibleProperty.kt")
|
||||
public void testJavaProtectedFieldAndKotlinInvisibleProperty() throws Exception {
|
||||
@@ -28749,12 +28761,6 @@ public class FirPsiBlackBoxCodegenTestGenerated extends AbstractFirPsiBlackBoxCo
|
||||
runTest("compiler/testData/codegen/box/javaFieldAndKotlinProperty/javaProtectedFieldAndKotlinInvisiblePropertyReference.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("javaProtectedFieldAndKotlinInvisiblePropertyWrite.kt")
|
||||
public void testJavaProtectedFieldAndKotlinInvisiblePropertyWrite() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/javaFieldAndKotlinProperty/javaProtectedFieldAndKotlinInvisiblePropertyWrite.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("javaProtectedFieldAndKotlinPropertyReference.kt")
|
||||
public void testJavaProtectedFieldAndKotlinPropertyReference() throws Exception {
|
||||
|
||||
+12
@@ -253,6 +253,18 @@ public class FirPsiBytecodeTextTestGenerated extends AbstractFirPsiBytecodeTextT
|
||||
runTest("compiler/testData/codegen/bytecodeText/javaFieldsWithIntersectionTypes.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("javaFieldsWithIntersectionTypes_k1.kt")
|
||||
public void testJavaFieldsWithIntersectionTypes_k1() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/javaFieldsWithIntersectionTypes_k1.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("javaFields_k1.kt")
|
||||
public void testJavaFields_k1() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/javaFields_k1.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("javaStatics.kt")
|
||||
public void testJavaStatics() throws Exception {
|
||||
|
||||
@@ -376,6 +376,7 @@ private val jvmFilePhases = listOf(
|
||||
replaceKFunctionInvokeWithFunctionInvokePhase,
|
||||
kotlinNothingValueExceptionPhase,
|
||||
makePropertyDelegateMethodsStaticPhase,
|
||||
addSuperQualifierToJavaFieldAccessPhase,
|
||||
|
||||
renameFieldsPhase,
|
||||
fakeInliningLocalVariablesLowering,
|
||||
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.jvm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFieldAccessExpression
|
||||
import org.jetbrains.kotlin.ir.types.getClass
|
||||
import org.jetbrains.kotlin.ir.util.isClass
|
||||
import org.jetbrains.kotlin.ir.util.isEnumClass
|
||||
import org.jetbrains.kotlin.ir.util.isFromJava
|
||||
import org.jetbrains.kotlin.ir.util.parentClassOrNull
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
|
||||
internal val addSuperQualifierToJavaFieldAccessPhase = makeIrFilePhase(
|
||||
{ context ->
|
||||
if (context.state.configuration.getBoolean(CommonConfigurationKeys.USE_FIR)) {
|
||||
AddSuperQualifierToJavaFieldAccessLowering
|
||||
} else {
|
||||
FileLoweringPass.Empty
|
||||
}
|
||||
},
|
||||
name = "AddSuperQualifierToJavaFieldAccess",
|
||||
description = "Make `\$delegate` methods for optimized delegated properties static",
|
||||
// Property references need to be lowered to classes with field access inside. We can't perform this phase on unlowered property
|
||||
// references as IrPropertyReference doesn't have superQualifierSymbol.
|
||||
prerequisite = setOf(propertyReferencePhase),
|
||||
)
|
||||
|
||||
// This lowering changes field accesses so that codegen will correctly generate access to a public field in a Java superclass of a Kotlin
|
||||
// class, even if that field is "shadowed" by a property in the Kotlin class, with a _private_ field with the same name.
|
||||
// See KT-49507 and KT-48954 as good examples for cases we try to handle here.
|
||||
private object AddSuperQualifierToJavaFieldAccessLowering : IrElementVisitorVoid, FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.accept(this, null)
|
||||
}
|
||||
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildren(this, null)
|
||||
}
|
||||
|
||||
override fun visitFieldAccess(expression: IrFieldAccessExpression) {
|
||||
val dispatchReceiver = expression.receiver
|
||||
if (dispatchReceiver != null) {
|
||||
expression.superQualifierSymbol = superQualifierSymbolForField(dispatchReceiver, expression.symbol.owner)?.symbol
|
||||
}
|
||||
super.visitFieldAccess(expression)
|
||||
}
|
||||
|
||||
// Note that we're abusing superQualifierSymbol to make codegen generate the correct field owner in the bytecode.
|
||||
// However, currently there seems to be no better way to support it.
|
||||
private fun superQualifierSymbolForField(dispatchReceiver: IrExpression, field: IrField): IrClass? {
|
||||
if (field.correspondingPropertySymbol != null) return null
|
||||
val originalContainingClass = field.parentClassOrNull ?: return null
|
||||
val dispatchReceiverRepresentativeClass = dispatchReceiver.type.erasedUpperBound
|
||||
// Find first Java super class to avoid possible visibility exposure & separate compilation problems
|
||||
return getJavaFieldContainingClassSymbol(dispatchReceiverRepresentativeClass, originalContainingClass)
|
||||
}
|
||||
|
||||
// Note: dispatchReceiverRepresentativeClassifierSymbol here is the use-site receiver class,
|
||||
// and originalContainingClass is the class which contains Java field we are trying to access
|
||||
// ! Interfaces are out of our interests here !
|
||||
// This function returns a class symbol which:
|
||||
// - is the most derived Java class in hierarchy which has no Kotlin base classes (including transitive ones)
|
||||
// E.g. K2 <: J3 <: K1 <: J2 <: J1 ==> J2 is chosen
|
||||
// We shouldn't allow base Kotlin classes to avoid possible clashes with invisible properties inside
|
||||
private fun getJavaFieldContainingClassSymbol(dispatchReceiverRepresentativeClass: IrClass, originalContainingClass: IrClass): IrClass =
|
||||
findMostSpecificJavaClassWithoutKotlinSuperclasses(
|
||||
dispatchReceiverRepresentativeClass, originalContainingClass
|
||||
)?.resultingClass ?: originalContainingClass
|
||||
|
||||
private fun findMostSpecificJavaClassWithoutKotlinSuperclasses(current: IrClass, top: IrClass): SearchResult? {
|
||||
if (current == top) return SearchResult(top, false)
|
||||
|
||||
val superClass = current.superTypes.firstNotNullOfOrNull { supertype ->
|
||||
supertype.getClass()?.takeIf { it.isClass || it.isEnumClass }
|
||||
} ?: return null
|
||||
|
||||
val result = findMostSpecificJavaClassWithoutKotlinSuperclasses(superClass, top) ?: return null
|
||||
return if (current.isFromJava()) {
|
||||
if (result.hasKotlinSuperclasses) result else SearchResult(current, false)
|
||||
} else {
|
||||
SearchResult(result.resultingClass, true)
|
||||
}
|
||||
}
|
||||
|
||||
private class SearchResult(val resultingClass: IrClass, val hasKotlinSuperclasses: Boolean)
|
||||
}
|
||||
+4
@@ -1013,6 +1013,10 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
||||
// in the anonymous class for this callable reference. Technically it's incorrect because this field is not declared here. It would
|
||||
// be more correct to create a fake override but that seems like more work for no clear benefit. Codegen will generate the correct
|
||||
// field access anyway, even if the field is not present in this parent.
|
||||
// Note that it is necessary to generate an access to the field whose parent is this anonymous class, and NOT some supertype like
|
||||
// k.j.i.CallableReference, or k.j.i.FunctionReferenceImpl, because then AddSuperQualifierToJavaFieldAccess lowering would add
|
||||
// superQualifierSymbol, which would break inlining of bound function references, since inliner will not understand how to transform
|
||||
// this getfield instruction in the bytecode.
|
||||
internal fun IrClass.getReceiverField(context: JvmBackendContext): IrField =
|
||||
context.irFactory.buildField {
|
||||
name = Name.identifier("receiver")
|
||||
|
||||
+1
-3
@@ -1,7 +1,5 @@
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// FIR_STATUS: accesses companion property backing field statically and fails (does not work in K1/JVM too)
|
||||
// IGNORE_BACKEND_K1: JVM_IR
|
||||
|
||||
// FILE: Base.java
|
||||
public class Base {
|
||||
|
||||
Vendored
-2
@@ -1,7 +1,5 @@
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND_K1: JVM_IR
|
||||
// IGNORE_BACKEND_K2: JVM_IR
|
||||
// tried to access field Derived.a from class DerivedKt
|
||||
|
||||
// FILE: BaseJava.java
|
||||
public class BaseJava {
|
||||
|
||||
-2
@@ -1,7 +1,5 @@
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND_K1: JVM_IR
|
||||
// IGNORE_BACKEND_K2: JVM_IR
|
||||
// tried to access field Derived.a from class DerivedKt
|
||||
|
||||
// FILE: BaseJava.java
|
||||
public class BaseJava {
|
||||
|
||||
Vendored
-2
@@ -1,7 +1,5 @@
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND_K1: JVM_IR
|
||||
// IGNORE_BACKEND_K2: JVM_IR
|
||||
// FIR status: fails because of incorrect receiver in bytecode
|
||||
// Field VS property: case "reference"
|
||||
|
||||
// FILE: BaseJava.java
|
||||
|
||||
Vendored
-2
@@ -1,7 +1,5 @@
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND_K1: JVM_IR
|
||||
// IGNORE_BACKEND_K2: JVM_IR
|
||||
// tried to access field My.b from class Some
|
||||
|
||||
// FILE: Jaba.java
|
||||
|
||||
|
||||
-2
@@ -1,7 +1,5 @@
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND_K1: JVM_IR
|
||||
// IGNORE_BACKEND_K2: JVM_IR
|
||||
// tried to access field My.a from class TestKt
|
||||
|
||||
// FILE: Jaba.java
|
||||
|
||||
|
||||
Vendored
-2
@@ -1,7 +1,5 @@
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND_K1: JVM_IR
|
||||
// IGNORE_BACKEND_K2: JVM_IR
|
||||
// tried to access field My.b from class TestKt
|
||||
|
||||
// FILE: Jaba.java
|
||||
|
||||
|
||||
Vendored
+3
-2
@@ -1,7 +1,6 @@
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND_K1: JVM_IR
|
||||
// IGNORE_BACKEND_K2: JVM_IR
|
||||
// tried to access field B.f from class TestKt
|
||||
// CHECK_BYTECODE_TEXT
|
||||
|
||||
// FILE: A.java
|
||||
|
||||
@@ -24,3 +23,5 @@ public class C extends B {}
|
||||
fun box(): String {
|
||||
return C().f
|
||||
}
|
||||
|
||||
// 1 GETFIELD A.f
|
||||
|
||||
+3
-2
@@ -1,7 +1,6 @@
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND_K1: JVM_IR
|
||||
// IGNORE_BACKEND_K2: JVM_IR
|
||||
// tried to access field base.B.f from class TestKt
|
||||
// CHECK_BYTECODE_TEXT
|
||||
|
||||
// FILE: Y.java
|
||||
|
||||
@@ -36,3 +35,5 @@ public class C extends B {}
|
||||
fun box(): String {
|
||||
return C().f
|
||||
}
|
||||
|
||||
// 1 GETFIELD base/A.f
|
||||
|
||||
Vendored
+37
@@ -0,0 +1,37 @@
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND_K1: JVM_IR
|
||||
// CHECK_BYTECODE_TEXT
|
||||
// FILE: a/VeryBase.java
|
||||
|
||||
package a;
|
||||
|
||||
class VeryBase {
|
||||
public String foo = "OK";
|
||||
}
|
||||
|
||||
// FILE: a/Base.java
|
||||
|
||||
package a;
|
||||
|
||||
public class Base extends VeryBase {
|
||||
}
|
||||
|
||||
// FILE: b/Intermediate.java
|
||||
|
||||
package b;
|
||||
|
||||
class Intermediate extends a.Base {
|
||||
}
|
||||
|
||||
// FILE: box.kt
|
||||
|
||||
package b
|
||||
|
||||
private class Final : Intermediate() {
|
||||
private val foo = "FAIL"
|
||||
}
|
||||
|
||||
fun box(): String =
|
||||
Final().foo
|
||||
|
||||
// 1 GETFIELD b/Intermediate.foo
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND_K1: JVM_IR
|
||||
// CHECK_BYTECODE_TEXT
|
||||
// FILE: p/PackagePrivateJavaClass.java
|
||||
|
||||
package p;
|
||||
|
||||
class PackagePrivateJavaClass {
|
||||
public String foo = "OK";
|
||||
}
|
||||
|
||||
// FILE: p/JavaWrapper.java
|
||||
|
||||
package p;
|
||||
|
||||
public class JavaWrapper {
|
||||
protected static class JavaDerived extends PackagePrivateJavaClass {}
|
||||
}
|
||||
|
||||
// FILE: test.kt
|
||||
|
||||
import p.JavaWrapper
|
||||
|
||||
class KotlinWrapper : JavaWrapper() {
|
||||
protected class KotlinDerived : JavaDerived() {
|
||||
private val foo = "FAIL"
|
||||
}
|
||||
|
||||
fun bar() = KotlinDerived().foo
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
return KotlinWrapper().bar()
|
||||
}
|
||||
|
||||
// 1 GETFIELD p/JavaWrapper\$JavaDerived.foo
|
||||
+6
-3
@@ -1,7 +1,5 @@
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND_K1: JVM_IR
|
||||
// IGNORE_BACKEND_K2: JVM_IR
|
||||
// tried to access field derived.Intermediate.a from class derived.Derived
|
||||
// Field VS property: case "reference", protected field, invisible property
|
||||
|
||||
// FILE: BaseJava.java
|
||||
@@ -9,7 +7,7 @@
|
||||
package base;
|
||||
|
||||
public class BaseJava {
|
||||
protected String a = "OK";
|
||||
protected String a = "";
|
||||
}
|
||||
|
||||
// FILE: Derived.kt
|
||||
@@ -24,9 +22,14 @@ open class Intermediate : BaseJava() {
|
||||
|
||||
class Derived : Intermediate() {
|
||||
fun foo() = a
|
||||
|
||||
fun bar() {
|
||||
a = "OK"
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val d = Derived()
|
||||
d.bar()
|
||||
return d.foo()
|
||||
}
|
||||
|
||||
+11
-5
@@ -1,7 +1,5 @@
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND_K1: JVM_IR
|
||||
// IGNORE_BACKEND_K2: JVM_IR
|
||||
// tried to access field base.Intermediate.a from class base.Derived$foo$1
|
||||
// Field VS property: case "reference", protected field in the same package, invisible property
|
||||
|
||||
// FILE: BaseJava.java
|
||||
@@ -9,23 +7,31 @@
|
||||
package base;
|
||||
|
||||
public class BaseJava {
|
||||
protected String a = "OK";
|
||||
protected String a = "";
|
||||
}
|
||||
|
||||
// FILE: Derived.kt
|
||||
|
||||
package base
|
||||
// Note: this test should report an error when we are in different package
|
||||
package derived
|
||||
|
||||
import base.BaseJava
|
||||
|
||||
open class Intermediate : BaseJava() {
|
||||
private val a = "FAIL"
|
||||
}
|
||||
|
||||
// TODO: remove suppress after dropping the relevant diagnostic
|
||||
@Suppress("JAVA_SHADOWED_PROTECTED_FIELD_REFERENCE")
|
||||
class Derived : Intermediate() {
|
||||
fun foo() = this::a.get()
|
||||
|
||||
fun bar() {
|
||||
Derived::a.set(this, "OK")
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val d = Derived()
|
||||
d.bar()
|
||||
return d.foo()
|
||||
}
|
||||
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND_K1: JVM_IR
|
||||
// IGNORE_BACKEND_K2: JVM_IR
|
||||
// tried to access field derived.Intermediate.a from class derived.Derived
|
||||
// Field VS property: case "reference", protected field, invisible property
|
||||
|
||||
// FILE: BaseJava.java
|
||||
|
||||
package base;
|
||||
|
||||
public class BaseJava {
|
||||
protected String a = "";
|
||||
}
|
||||
|
||||
// FILE: Derived.kt
|
||||
|
||||
package derived
|
||||
|
||||
import base.BaseJava
|
||||
|
||||
open class Intermediate : BaseJava() {
|
||||
private val a = "FAIL"
|
||||
}
|
||||
|
||||
class Derived : Intermediate() {
|
||||
fun foo() = a
|
||||
|
||||
fun bar() {
|
||||
a = "OK"
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val d = Derived()
|
||||
d.bar()
|
||||
return d.foo()
|
||||
}
|
||||
+9
-4
@@ -1,3 +1,7 @@
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND_K1: JVM_IR
|
||||
// ^ See javaFields_k1.kt for a copy of this test for K1.
|
||||
|
||||
// FILE: Java1.java
|
||||
public class Java1 {
|
||||
public int f;
|
||||
@@ -16,8 +20,9 @@ open class Kotlin2 : Java2() {
|
||||
|
||||
fun test1(j: Kotlin2) = j.f
|
||||
|
||||
// @Kotlin2.class:
|
||||
// 1 GETFIELD Java2.f : I
|
||||
// K2 generates access to Java1.f in both cases. The main motivation for this is to fix cases like KT-49507.
|
||||
// Java1 in this case is the most specific Java superclass of Kotlin2 which has no Kotlin superclasses in its hierarchy.
|
||||
|
||||
// @TestKt.class:
|
||||
// 1 GETFIELD Kotlin2.f : I
|
||||
// 2 GETFIELD Java1.f : I
|
||||
// 0 GETFIELD Java2.f : I
|
||||
// 0 GETFIELD Kotlin2.f : I
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND_K1: JVM_IR
|
||||
// ^ See javaFieldsWithIntersectionTypes_k1.kt for a copy of this test for K1.
|
||||
|
||||
// FILE: JFieldOwner.java
|
||||
|
||||
public class JFieldOwner {
|
||||
@@ -30,8 +34,9 @@ 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
|
||||
// K2 generates access to Java1.f in both cases. The main motivation for this is to fix cases like KT-49507.
|
||||
|
||||
// 2 GETFIELD JFieldOwner.f : I
|
||||
// 2 PUTFIELD JFieldOwner.f : I
|
||||
// 0 GETFIELD Mid.f : I
|
||||
// 0 PUTFIELD Mid.f : I
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
// IGNORE_BACKEND_K2: JVM_IR
|
||||
// ^ See javaFieldsWithIntersectionTypes.kt for a copy of this test for K2.
|
||||
|
||||
// FILE: JFieldOwner.java
|
||||
|
||||
public class JFieldOwner {
|
||||
public int f;
|
||||
}
|
||||
|
||||
// FILE: test.kt
|
||||
|
||||
interface IFoo
|
||||
|
||||
class Derived1 : JFieldOwner(), IFoo
|
||||
class Derived2 : JFieldOwner(), IFoo
|
||||
|
||||
open class Mid : JFieldOwner()
|
||||
class DerivedThroughMid1 : Mid(), IFoo
|
||||
class DerivedThroughMid2 : Mid(), IFoo
|
||||
|
||||
fun test(b : Boolean) {
|
||||
val d1 = Derived1()
|
||||
val d2 = Derived2()
|
||||
val k = if (b) d1 else d2
|
||||
k.f = 42
|
||||
k.f
|
||||
|
||||
val md1 = DerivedThroughMid1()
|
||||
val md2 = DerivedThroughMid2()
|
||||
val mk = if (b) md1 else md2
|
||||
mk.f = 44
|
||||
mk.f
|
||||
|
||||
}
|
||||
|
||||
// @TestKt.class:
|
||||
// 1 GETFIELD JFieldOwner.f : I
|
||||
// 1 PUTFIELD JFieldOwner.f : I
|
||||
// 1 GETFIELD Mid.f : I
|
||||
// 1 PUTFIELD Mid.f : I
|
||||
@@ -0,0 +1,26 @@
|
||||
// IGNORE_BACKEND_K2: JVM_IR
|
||||
// ^ See javaFields.kt for a copy of this test for K2.
|
||||
|
||||
// FILE: Java1.java
|
||||
public class Java1 {
|
||||
public int f;
|
||||
}
|
||||
|
||||
// FILE: Java2.java
|
||||
public class Java2 extends Kotlin1 {
|
||||
}
|
||||
|
||||
// FILE: test.kt
|
||||
open class Kotlin1 : Java1()
|
||||
|
||||
open class Kotlin2 : Java2() {
|
||||
fun getF() = super.f
|
||||
}
|
||||
|
||||
fun test1(j: Kotlin2) = j.f
|
||||
|
||||
// @Kotlin2.class:
|
||||
// 1 GETFIELD Java2.f : I
|
||||
|
||||
// @TestKt.class:
|
||||
// 1 GETFIELD Kotlin2.f : I
|
||||
+6
-6
@@ -230,15 +230,15 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("javaFields.kt")
|
||||
public void testJavaFields() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/javaFields.kt");
|
||||
@TestMetadata("javaFieldsWithIntersectionTypes_k1.kt")
|
||||
public void testJavaFieldsWithIntersectionTypes_k1() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/javaFieldsWithIntersectionTypes_k1.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("javaFieldsWithIntersectionTypes.kt")
|
||||
public void testJavaFieldsWithIntersectionTypes() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/javaFieldsWithIntersectionTypes.kt");
|
||||
@TestMetadata("javaFields_k1.kt")
|
||||
public void testJavaFields_k1() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/javaFields_k1.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+12
-6
@@ -28737,6 +28737,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/javaFieldAndKotlinProperty/javaInvisibleFieldAndKotlinPropertyReference.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("javaPackagePrivateClassAndPublicField.kt")
|
||||
public void testJavaPackagePrivateClassAndPublicField() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/javaFieldAndKotlinProperty/javaPackagePrivateClassAndPublicField.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("javaPackagePrivateClassExposedViaProtectedStatic.kt")
|
||||
public void testJavaPackagePrivateClassExposedViaProtectedStatic() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/javaFieldAndKotlinProperty/javaPackagePrivateClassExposedViaProtectedStatic.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("javaProtectedFieldAndKotlinInvisibleProperty.kt")
|
||||
public void testJavaProtectedFieldAndKotlinInvisibleProperty() throws Exception {
|
||||
@@ -28749,12 +28761,6 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/javaFieldAndKotlinProperty/javaProtectedFieldAndKotlinInvisiblePropertyReference.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("javaProtectedFieldAndKotlinInvisiblePropertyWrite.kt")
|
||||
public void testJavaProtectedFieldAndKotlinInvisiblePropertyWrite() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/javaFieldAndKotlinProperty/javaProtectedFieldAndKotlinInvisiblePropertyWrite.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("javaProtectedFieldAndKotlinPropertyReference.kt")
|
||||
public void testJavaProtectedFieldAndKotlinPropertyReference() throws Exception {
|
||||
|
||||
+12
@@ -253,6 +253,18 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
|
||||
runTest("compiler/testData/codegen/bytecodeText/javaFieldsWithIntersectionTypes.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("javaFieldsWithIntersectionTypes_k1.kt")
|
||||
public void testJavaFieldsWithIntersectionTypes_k1() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/javaFieldsWithIntersectionTypes_k1.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("javaFields_k1.kt")
|
||||
public void testJavaFields_k1() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/javaFields_k1.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("javaStatics.kt")
|
||||
public void testJavaStatics() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user