From b0a6508d4bd6e39199e4d2920f709dd8e7189c6f Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Wed, 8 Jun 2022 14:45:52 +0200 Subject: [PATCH] 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 --- .../generators/CallAndReferenceGenerator.kt | 29 ++++++++-- .../FirBlackBoxCodegenTestGenerated.java | 6 ++ .../runners/ir/Fir2IrTextTestGenerated.java | 6 ++ .../ir/LightTreeFir2IrTextTestGenerated.java | 6 ++ .../kotlin/psi2ir/generators/CallGenerator.kt | 24 ++++++-- .../javaFieldAndKotlinProperty.fir.ir.txt | 36 ++++++++++++ .../javaFieldAndKotlinProperty.ir.txt | 39 +++++++++++++ .../fieldRename/javaFieldAndKotlinProperty.kt | 14 +++++ .../codegen/bytecodeText/javaFields.kt | 2 +- .../javaFieldsWithIntersectionTypes.kt | 10 +++- .../ambiguousFieldAccess.fir.ir.txt | 51 +++++++++++++++++ .../ambiguousFieldAccess.fir.kt.txt | 28 +++++++++ .../expressions/ambiguousFieldAccess.ir.txt | 57 +++++++++++++++++++ .../expressions/ambiguousFieldAccess.kt | 23 ++++++++ .../expressions/ambiguousFieldAccess.kt.txt | 28 +++++++++ ...dReferenceWithIntersectionTypes.fir.kt.txt | 4 +- .../jvmInstanceFieldReference.fir.kt.txt | 2 +- .../ir/irText/firProblems/JCTree.fir.kt.txt | 2 +- .../typeParameterFromJavaClass.fir.kt.txt | 2 +- ...astOnFieldReceiverOfGenericType.fir.kt.txt | 2 +- .../IrBlackBoxCodegenTestGenerated.java | 6 ++ .../test/runners/ir/IrTextTestGenerated.java | 6 ++ .../klib/KlibTextTestCaseGenerated.java | 5 ++ 23 files changed, 370 insertions(+), 18 deletions(-) create mode 100644 compiler/testData/codegen/box/fieldRename/javaFieldAndKotlinProperty.fir.ir.txt create mode 100644 compiler/testData/codegen/box/fieldRename/javaFieldAndKotlinProperty.ir.txt create mode 100644 compiler/testData/codegen/box/fieldRename/javaFieldAndKotlinProperty.kt create mode 100644 compiler/testData/ir/irText/expressions/ambiguousFieldAccess.fir.ir.txt create mode 100644 compiler/testData/ir/irText/expressions/ambiguousFieldAccess.fir.kt.txt create mode 100644 compiler/testData/ir/irText/expressions/ambiguousFieldAccess.ir.txt create mode 100644 compiler/testData/ir/irText/expressions/ambiguousFieldAccess.kt create mode 100644 compiler/testData/ir/irText/expressions/ambiguousFieldAccess.kt.txt diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt index 8a0a245c26f..e3945d8b653 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt @@ -40,10 +40,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl import org.jetbrains.kotlin.ir.types.* -import org.jetbrains.kotlin.ir.util.dump -import org.jetbrains.kotlin.ir.util.isFunctionTypeOrSubtype -import org.jetbrains.kotlin.ir.util.isInterface -import org.jetbrains.kotlin.ir.util.isMethodOfAny +import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi2ir.generators.hasNoSideEffects import org.jetbrains.kotlin.psi2ir.generators.isUnchanging @@ -256,6 +253,28 @@ class CallAndReferenceGenerator( return null } + // Note: I don't like using super qualifier symbols to determine field receivers in bytecode properly. + // Would be much better to use super qualifiers only in case when it's used explicitly. + // However, FE 1.0 does it, and currently we have no better way to provide these receivers. + // See KT-49507 and KT-48954 as good examples for cases we try to handle here + private fun FirExpression.superQualifierSymbolForField(fieldSymbol: IrFieldSymbol): IrClassSymbol? { + if (this !is FirQualifiedAccess) return null + if (calleeReference is FirSuperReference) return superQualifierSymbol() + if (fieldSymbol.owner.correspondingPropertySymbol != null) return null + val originalContainingClass = fieldSymbol.owner.parentClassOrNull ?: return null + val ownContainingClass = typeRef.toIrType().classifierOrNull?.owner as? IrClass ?: return null + // For static field, we shouldn't unwrap fake override in any case + if (fieldSymbol.owner.isStatic) return ownContainingClass.symbol + // This means own containing class exposes original containing class, which is possible only in Java (Kotlin forbids it) + // In this case we take own containing class as qualifier symbol to avoid visibility problems (see testKt48954 as an example) + // Otherwise we should take original containing class to avoid possible clash with Kotlin backing field + if (ownContainingClass.visibility.compareTo( + originalContainingClass.visibility + ).let { it == null || it > 0 } + ) return ownContainingClass.symbol + return originalContainingClass.symbol + } + private fun FirExpression.superQualifierSymbol(): IrClassSymbol? { if (this !is FirQualifiedAccess) { return null @@ -462,7 +481,7 @@ class CallAndReferenceGenerator( is IrFieldSymbol -> IrGetFieldImpl( startOffset, endOffset, symbol, type, origin = IrStatementOrigin.GET_PROPERTY.takeIf { calleeReference !is FirDelegateFieldReference }, - superQualifierSymbol = dispatchReceiver.superQualifierSymbol() + superQualifierSymbol = dispatchReceiver.superQualifierSymbolForField(symbol) ) is IrValueSymbol -> { IrGetValueImpl( diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index a25b44f8b4f..ec007e0570a 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -17347,6 +17347,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/fieldRename/genericPropertyWithItself.kt"); } + @Test + @TestMetadata("javaFieldAndKotlinProperty.kt") + public void testJavaFieldAndKotlinProperty() throws Exception { + runTest("compiler/testData/codegen/box/fieldRename/javaFieldAndKotlinProperty.kt"); + } + @Test @TestMetadata("jvmFieldNoClash1.kt") public void testJvmFieldNoClash1() throws Exception { diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/Fir2IrTextTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/Fir2IrTextTestGenerated.java index b8182758e7e..dceb0208ed4 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/Fir2IrTextTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/Fir2IrTextTestGenerated.java @@ -1118,6 +1118,12 @@ public class Fir2IrTextTestGenerated extends AbstractFir2IrTextTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/ir/irText/expressions"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @Test + @TestMetadata("ambiguousFieldAccess.kt") + public void testAmbiguousFieldAccess() throws Exception { + runTest("compiler/testData/ir/irText/expressions/ambiguousFieldAccess.kt"); + } + @Test @TestMetadata("argumentMappedWithError.kt") public void testArgumentMappedWithError() throws Exception { diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/LightTreeFir2IrTextTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/LightTreeFir2IrTextTestGenerated.java index 11d277f8f8e..814135fe792 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/LightTreeFir2IrTextTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/LightTreeFir2IrTextTestGenerated.java @@ -1118,6 +1118,12 @@ public class LightTreeFir2IrTextTestGenerated extends AbstractLightTreeFir2IrTex KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/ir/irText/expressions"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @Test + @TestMetadata("ambiguousFieldAccess.kt") + public void testAmbiguousFieldAccess() throws Exception { + runTest("compiler/testData/ir/irText/expressions/ambiguousFieldAccess.kt"); + } + @Test @TestMetadata("argumentMappedWithError.kt") public void testArgumentMappedWithError() throws Exception { diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt index bb2353dbdbf..1f108722637 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt @@ -193,6 +193,21 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator } } + private fun PropertyDescriptor.containingClassForField(): ClassDescriptor? { + val ownContainingClass = containingDeclaration as? ClassDescriptor ?: return null + // For static field, we shouldn't unwrap fake override in any case + if (dispatchReceiverParameter == null) return ownContainingClass + val originalContainingClass = resolveFakeOverride().containingDeclaration as? ClassDescriptor ?: return ownContainingClass + // This means own containing class exposes original containing class, which is possible only in Java (Kotlin forbids it) + // In this case we take own containing class as qualifier symbol to avoid visibility problems (see testKt48954 as an example) + // Otherwise we should take original containing class to avoid possible clash with Kotlin backing field + if (ownContainingClass.visibility.compareTo( + originalContainingClass.visibility + ).let { it == null || it > 0 } + ) return ownContainingClass + return originalContainingClass + } + private fun generatePropertyGetterCall( descriptor: PropertyDescriptor, startOffset: Int, @@ -203,10 +218,11 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator val irType = descriptor.type.toIrType() return if (getMethodDescriptor == null) { - val superQualifierSymbol = (call.superQualifier ?: descriptor.containingDeclaration as? ClassDescriptor)?.let { - if (it is ScriptDescriptor) null // otherwise it creates a reference to script as class; TODO: check if correct - else context.symbolTable.referenceClass(it) - } + val superQualifierSymbol = + (call.superQualifier ?: descriptor.containingClassForField())?.let { + if (it is ScriptDescriptor) null // otherwise it creates a reference to script as class; TODO: check if correct + else context.symbolTable.referenceClass(it) + } val fieldSymbol = context.symbolTable.referenceField(context.extensions.remapDebuggerFieldPropertyDescriptor(descriptor.resolveFakeOverride().original)) call.callReceiver.call { dispatchReceiverValue, extensionReceiverValue, _ -> diff --git a/compiler/testData/codegen/box/fieldRename/javaFieldAndKotlinProperty.fir.ir.txt b/compiler/testData/codegen/box/fieldRename/javaFieldAndKotlinProperty.fir.ir.txt new file mode 100644 index 00000000000..46767087de5 --- /dev/null +++ b/compiler/testData/codegen/box/fieldRename/javaFieldAndKotlinProperty.fir.ir.txt @@ -0,0 +1,36 @@ +FILE fqName: fileName:/Derived.kt + CLASS CLASS name:Derived modality:FINAL visibility:public superTypes:[.BaseJava] + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.Derived + CONSTRUCTOR visibility:public <> () returnType:.Derived [primary] + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'public constructor () [primary] declared in .BaseJava' + INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:Derived modality:FINAL visibility:public superTypes:[.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: visibility:public modality:FINAL <> ($this:.Derived) returnType:kotlin.String + correspondingProperty: PROPERTY name:a visibility:public modality:FINAL [val] + $this: VALUE_PARAMETER name: type:.Derived + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun (): kotlin.String declared in .Derived' + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:a type:kotlin.String visibility:private [final]' type=kotlin.String origin=null + receiver: GET_VAR ': .Derived declared in .Derived.' type=.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 .BaseJava + $this: VALUE_PARAMETER name: 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 .BaseJava + $this: VALUE_PARAMETER name: 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 .BaseJava + $this: VALUE_PARAMETER name: 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 ' + 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 () [primary] declared in .Derived' type=.Derived origin=null diff --git a/compiler/testData/codegen/box/fieldRename/javaFieldAndKotlinProperty.ir.txt b/compiler/testData/codegen/box/fieldRename/javaFieldAndKotlinProperty.ir.txt new file mode 100644 index 00000000000..bee2c059f2f --- /dev/null +++ b/compiler/testData/codegen/box/fieldRename/javaFieldAndKotlinProperty.ir.txt @@ -0,0 +1,39 @@ +FILE fqName: fileName:/Derived.kt + CLASS CLASS name:Derived modality:FINAL visibility:public superTypes:[.BaseJava] + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.Derived + CONSTRUCTOR visibility:public <> () returnType:.Derived [primary] + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'public constructor () [primary] declared in .BaseJava' + INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:Derived modality:FINAL visibility:public superTypes:[.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: visibility:public modality:FINAL <> ($this:.Derived) returnType:kotlin.String + correspondingProperty: PROPERTY name:a visibility:public modality:FINAL [val] + $this: VALUE_PARAMETER name: type:.Derived + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun (): kotlin.String declared in .Derived' + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:a type:kotlin.String visibility:private [final]' type=kotlin.String origin=null + receiver: GET_VAR ': .Derived declared in .Derived.' type=.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 .BaseJava + $this: VALUE_PARAMETER name: 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 .BaseJava + $this: VALUE_PARAMETER name: 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 .BaseJava + $this: VALUE_PARAMETER name: 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 ' + 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 () [primary] declared in .Derived' type=.Derived origin=null diff --git a/compiler/testData/codegen/box/fieldRename/javaFieldAndKotlinProperty.kt b/compiler/testData/codegen/box/fieldRename/javaFieldAndKotlinProperty.kt new file mode 100644 index 00000000000..6eac6bc4cc4 --- /dev/null +++ b/compiler/testData/codegen/box/fieldRename/javaFieldAndKotlinProperty.kt @@ -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 \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/javaFields.kt b/compiler/testData/codegen/bytecodeText/javaFields.kt index a3afb7bb6ff..dbce0ae3292 100644 --- a/compiler/testData/codegen/bytecodeText/javaFields.kt +++ b/compiler/testData/codegen/bytecodeText/javaFields.kt @@ -20,4 +20,4 @@ fun test1(j: Kotlin2) = j.f // 1 GETFIELD Java2.f : I // @TestKt.class: -// 1 GETFIELD Kotlin2.f : I \ No newline at end of file +// 1 GETFIELD Java2.f : I \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/javaFieldsWithIntersectionTypes.kt b/compiler/testData/codegen/bytecodeText/javaFieldsWithIntersectionTypes.kt index 93bcb38f0f4..ac29c48c02b 100644 --- a/compiler/testData/codegen/bytecodeText/javaFieldsWithIntersectionTypes.kt +++ b/compiler/testData/codegen/bytecodeText/javaFieldsWithIntersectionTypes.kt @@ -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 diff --git a/compiler/testData/ir/irText/expressions/ambiguousFieldAccess.fir.ir.txt b/compiler/testData/ir/irText/expressions/ambiguousFieldAccess.fir.ir.txt new file mode 100644 index 00000000000..23f2e3a5079 --- /dev/null +++ b/compiler/testData/ir/irText/expressions/ambiguousFieldAccess.fir.ir.txt @@ -0,0 +1,51 @@ +FILE fqName:test fileName:/test.kt + FUN name:eval visibility:public modality:FINAL (f:kotlin.Function0) 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 + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun eval (f: kotlin.Function0): 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 declared in test.eval' type=kotlin.Function0 origin=VARIABLE_AS_FUNCTION + CLASS CLASS name:C modality:FINAL visibility:public superTypes:[.A.B] + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:test.C + CONSTRUCTOR visibility:public <> () returnType:test.C [primary] + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'public constructor () [primary] declared in .A.B' + INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:C modality:FINAL visibility:public superTypes:[.A.B]' + FUN name:f visibility:public modality:FINAL <> ($this:test.C) returnType:@[FlexibleNullability] kotlin.String? + $this: VALUE_PARAMETER name: 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 (f: kotlin.Function0): T of test.eval declared in test' type=@[FlexibleNullability] kotlin.String? origin=null + : @[FlexibleNullability] kotlin.String? + f: FUN_EXPR type=kotlin.Function0<@[FlexibleNullability] kotlin.String?> origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:@[FlexibleNullability] kotlin.String? + BLOCK_BODY + RETURN type=kotlin.Nothing from='local final fun (): @[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 ': 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: 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 (f: kotlin.Function0): T of test.eval declared in test' type=@[FlexibleNullability] kotlin.String? origin=null + : @[FlexibleNullability] kotlin.String? + f: FUN_EXPR type=kotlin.Function0<@[FlexibleNullability] kotlin.String?> origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:@[FlexibleNullability] kotlin.String? + BLOCK_BODY + RETURN type=kotlin.Nothing from='local final fun (): @[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 ': 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 .A.B + $this: VALUE_PARAMETER name: 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 .A.B + $this: VALUE_PARAMETER name: 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 .A.B + $this: VALUE_PARAMETER name: type:kotlin.Any diff --git a/compiler/testData/ir/irText/expressions/ambiguousFieldAccess.fir.kt.txt b/compiler/testData/ir/irText/expressions/ambiguousFieldAccess.fir.kt.txt new file mode 100644 index 00000000000..4821fc99a1e --- /dev/null +++ b/compiler/testData/ir/irText/expressions/ambiguousFieldAccess.fir.kt.txt @@ -0,0 +1,28 @@ +package test + +fun eval(f: Function0): T { + return f.invoke() +} + +class C : B { + constructor() /* primary */ { + super/*B*/() + /* () */ + + } + + fun f(): @FlexibleNullability String? { + return eval<@FlexibleNullability String?>(f = local fun (): @FlexibleNullability String? { + return super.#x + } +) + } + + fun g(): @FlexibleNullability String? { + return eval<@FlexibleNullability String?>(f = local fun (): @FlexibleNullability String? { + return super.#y + } +) + } + +} diff --git a/compiler/testData/ir/irText/expressions/ambiguousFieldAccess.ir.txt b/compiler/testData/ir/irText/expressions/ambiguousFieldAccess.ir.txt new file mode 100644 index 00000000000..caff651dcab --- /dev/null +++ b/compiler/testData/ir/irText/expressions/ambiguousFieldAccess.ir.txt @@ -0,0 +1,57 @@ +FILE fqName:test fileName:/test.kt + FUN name:eval visibility:public modality:FINAL (f:kotlin.Function0) 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 + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun eval (f: kotlin.Function0): 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 declared in test.eval' type=kotlin.Function0 origin=VARIABLE_AS_FUNCTION + CLASS CLASS name:C modality:FINAL visibility:public superTypes:[.A.B] + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:test.C + CONSTRUCTOR visibility:public <> () returnType:test.C [primary] + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'public constructor () [primary] declared in .A.B' + INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:C modality:FINAL visibility:public superTypes:[.A.B]' + FUN name:f visibility:public modality:FINAL <> ($this:test.C) returnType:@[FlexibleNullability] kotlin.String? + $this: VALUE_PARAMETER name: 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 (f: kotlin.Function0): T of test.eval declared in test' type=@[FlexibleNullability] kotlin.String? origin=null + : @[FlexibleNullability] kotlin.String? + f: FUN_EXPR type=kotlin.Function0<@[FlexibleNullability] kotlin.String?> origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:@[FlexibleNullability] kotlin.String? + BLOCK_BODY + RETURN type=kotlin.Nothing from='local final fun (): @[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 ': 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: 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 (f: kotlin.Function0): T of test.eval declared in test' type=@[FlexibleNullability] kotlin.String? origin=null + : @[FlexibleNullability] kotlin.String? + f: FUN_EXPR type=kotlin.Function0<@[FlexibleNullability] kotlin.String?> origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:@[FlexibleNullability] kotlin.String? + BLOCK_BODY + RETURN type=kotlin.Nothing from='local final fun (): @[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 ': 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 .A.B + $this: VALUE_PARAMETER name: 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 .A.B + $this: VALUE_PARAMETER name: 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 .A.B + $this: VALUE_PARAMETER name: 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] diff --git a/compiler/testData/ir/irText/expressions/ambiguousFieldAccess.kt b/compiler/testData/ir/irText/expressions/ambiguousFieldAccess.kt new file mode 100644 index 00000000000..82445744ee4 --- /dev/null +++ b/compiler/testData/ir/irText/expressions/ambiguousFieldAccess.kt @@ -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 eval(f: () -> T) = f() + +class C : A.B() { + // Both x & y here should in fact be taken from B class: this.(super.x), this.(super.y) + fun f() = eval { x } + fun g() = eval { y } +} + diff --git a/compiler/testData/ir/irText/expressions/ambiguousFieldAccess.kt.txt b/compiler/testData/ir/irText/expressions/ambiguousFieldAccess.kt.txt new file mode 100644 index 00000000000..4821fc99a1e --- /dev/null +++ b/compiler/testData/ir/irText/expressions/ambiguousFieldAccess.kt.txt @@ -0,0 +1,28 @@ +package test + +fun eval(f: Function0): T { + return f.invoke() +} + +class C : B { + constructor() /* primary */ { + super/*B*/() + /* () */ + + } + + fun f(): @FlexibleNullability String? { + return eval<@FlexibleNullability String?>(f = local fun (): @FlexibleNullability String? { + return super.#x + } +) + } + + fun g(): @FlexibleNullability String? { + return eval<@FlexibleNullability String?>(f = local fun (): @FlexibleNullability String? { + return super.#y + } +) + } + +} diff --git a/compiler/testData/ir/irText/expressions/jvmFieldReferenceWithIntersectionTypes.fir.kt.txt b/compiler/testData/ir/irText/expressions/jvmFieldReferenceWithIntersectionTypes.fir.kt.txt index 19a6f58cbab..fe955b62632 100644 --- a/compiler/testData/ir/irText/expressions/jvmFieldReferenceWithIntersectionTypes.fir.kt.txt +++ b/compiler/testData/ir/irText/expressions/jvmFieldReferenceWithIntersectionTypes.fir.kt.txt @@ -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 */ } diff --git a/compiler/testData/ir/irText/expressions/jvmInstanceFieldReference.fir.kt.txt b/compiler/testData/ir/irText/expressions/jvmInstanceFieldReference.fir.kt.txt index 242c7bc48aa..a2e7586c85d 100644 --- a/compiler/testData/ir/irText/expressions/jvmInstanceFieldReference.fir.kt.txt +++ b/compiler/testData/ir/irText/expressions/jvmInstanceFieldReference.fir.kt.txt @@ -10,7 +10,7 @@ class Derived : Base { } fun getValue(): Int { - return .#value + return super.#value } fun setValue(value: Int) { diff --git a/compiler/testData/ir/irText/firProblems/JCTree.fir.kt.txt b/compiler/testData/ir/irText/firProblems/JCTree.fir.kt.txt index d7e07480e29..c932dd08d23 100644 --- a/compiler/testData/ir/irText/firProblems/JCTree.fir.kt.txt +++ b/compiler/testData/ir/irText/firProblems/JCTree.fir.kt.txt @@ -13,7 +13,7 @@ class Owner { get(): String { var tree: JCTree = .() when { - tree is JCTypeApply -> return tree /*as JCTypeApply */.#clazz /*!! String */ + tree is JCTypeApply -> return tree /*as JCTypeApply */super.#clazz /*!! String */ } return "" } diff --git a/compiler/testData/ir/irText/firProblems/typeParameterFromJavaClass.fir.kt.txt b/compiler/testData/ir/irText/firProblems/typeParameterFromJavaClass.fir.kt.txt index 2e0d59300f3..094680b0542 100644 --- a/compiler/testData/ir/irText/firProblems/typeParameterFromJavaClass.fir.kt.txt +++ b/compiler/testData/ir/irText/firProblems/typeParameterFromJavaClass.fir.kt.txt @@ -1,6 +1,6 @@ fun foo(movedPaths: MutableList>) { movedPaths.forEach>(action = local fun (it: Couple) { - it.#second.getName() /*~> Unit */ + itsuper.#second.getName() /*~> Unit */ } ) } diff --git a/compiler/testData/ir/irText/types/smartCastOnFieldReceiverOfGenericType.fir.kt.txt b/compiler/testData/ir/irText/types/smartCastOnFieldReceiverOfGenericType.fir.kt.txt index 5cff33b63be..04a59707c0d 100644 --- a/compiler/testData/ir/irText/types/smartCastOnFieldReceiverOfGenericType.fir.kt.txt +++ b/compiler/testData/ir/irText/types/smartCastOnFieldReceiverOfGenericType.fir.kt.txt @@ -6,6 +6,6 @@ fun testSetField(a: Any, b: Any) { fun testGetField(a: Any): String { a as JCell /*~> Unit */ - return a /*as JCell */.#value /*!! String */ + return a /*as JCell */super.#value /*!! String */ } diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index 053110711a4..fe3995a7c1b 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -17347,6 +17347,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/fieldRename/genericPropertyWithItself.kt"); } + @Test + @TestMetadata("javaFieldAndKotlinProperty.kt") + public void testJavaFieldAndKotlinProperty() throws Exception { + runTest("compiler/testData/codegen/box/fieldRename/javaFieldAndKotlinProperty.kt"); + } + @Test @TestMetadata("jvmFieldNoClash1.kt") public void testJvmFieldNoClash1() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ir/IrTextTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ir/IrTextTestGenerated.java index d2c6a4bb80d..bdda88e567f 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ir/IrTextTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ir/IrTextTestGenerated.java @@ -1118,6 +1118,12 @@ public class IrTextTestGenerated extends AbstractIrTextTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/ir/irText/expressions"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @Test + @TestMetadata("ambiguousFieldAccess.kt") + public void testAmbiguousFieldAccess() throws Exception { + runTest("compiler/testData/ir/irText/expressions/ambiguousFieldAccess.kt"); + } + @Test @TestMetadata("argumentMappedWithError.kt") public void testArgumentMappedWithError() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/klib/KlibTextTestCaseGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/klib/KlibTextTestCaseGenerated.java index fe3cb3c8b8d..b1cfe5f5c5f 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/klib/KlibTextTestCaseGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/klib/KlibTextTestCaseGenerated.java @@ -862,6 +862,11 @@ public class KlibTextTestCaseGenerated extends AbstractKlibTextTestCase { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/ir/irText/expressions"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true); } + @TestMetadata("ambiguousFieldAccess.kt") + public void testAmbiguousFieldAccess() throws Exception { + runTest("compiler/testData/ir/irText/expressions/ambiguousFieldAccess.kt"); + } + @TestMetadata("argumentMappedWithError.kt") public void testArgumentMappedWithError() throws Exception { runTest("compiler/testData/ir/irText/expressions/argumentMappedWithError.kt");