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");