diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt index 35f89bbba54..3f69c102b3a 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt @@ -535,7 +535,7 @@ class ExpressionCodegen( assert(callee.constantValue() == null) { "access of const val: ${expression.dump()}" } } - val realField = callee.resolveFakeOverride()!! + val realField = callee val fieldType = typeMapper.mapType(realField.type) val fieldName = realField.name.asString() val isStatic = expression.receiver == null diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt index a97d9364649..dbe295cc4a7 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt @@ -339,7 +339,7 @@ fun IrProperty.needsAccessor(accessor: IrSimpleFunction): Boolean = when { // Properties in annotation classes become abstract methods named after the property. (parent as? IrClass)?.kind == ClassKind.ANNOTATION_CLASS -> true // @JvmField properties have no getters/setters - backingField?.hasAnnotation(JvmAbi.JVM_FIELD_ANNOTATION_FQ_NAME) == true -> false + resolveFakeOverride()?.backingField?.hasAnnotation(JvmAbi.JVM_FIELD_ANNOTATION_FQ_NAME) == true -> false // We do not produce default accessors for private fields else -> accessor.origin != IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR || !Visibilities.isPrivate(accessor.visibility) } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmPropertiesLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmPropertiesLowering.kt index e801910db91..0477a0f7097 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmPropertiesLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmPropertiesLowering.kt @@ -29,10 +29,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl import org.jetbrains.kotlin.ir.types.classifierOrFail import org.jetbrains.kotlin.ir.types.makeNotNull import org.jetbrains.kotlin.ir.types.typeWith -import org.jetbrains.kotlin.ir.util.coerceToUnit -import org.jetbrains.kotlin.ir.util.hasAnnotation -import org.jetbrains.kotlin.ir.util.render -import org.jetbrains.kotlin.ir.util.transformDeclarationsFlat +import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.name.Name @@ -69,10 +66,10 @@ class JvmPropertiesLowering(private val backendContext: JvmBackendContext) : IrE } private fun IrBuilderWithScope.substituteSetter(irProperty: IrProperty, expression: IrCall): IrExpression = - patchReceiver(irSetField(expression.dispatchReceiver, irProperty.backingField!!, expression.getValueArgument(0)!!)) + patchReceiver(irSetField(expression.dispatchReceiver, irProperty.resolveFakeOverride()!!.backingField!!, expression.getValueArgument(0)!!)) private fun IrBuilderWithScope.substituteGetter(irProperty: IrProperty, expression: IrCall): IrExpression { - val backingField = irProperty.backingField!! + val backingField = irProperty.resolveFakeOverride()!!.backingField!! val value = irGetField(expression.dispatchReceiver, backingField) return if (irProperty.isLateinit) { irBlock { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SyntheticAccessorLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SyntheticAccessorLowering.kt index 2924fb3ef9e..94d86eb722e 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SyntheticAccessorLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SyntheticAccessorLowering.kt @@ -326,7 +326,7 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle copyAllParamsToArgs(it, accessor) } - private fun makeGetterAccessorSymbol(fieldSymbol: IrFieldSymbol, parent: IrDeclarationParent): IrSimpleFunctionSymbol = + private fun makeGetterAccessorSymbol(fieldSymbol: IrFieldSymbol, parent: IrClass): IrSimpleFunctionSymbol = buildFun { origin = JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR name = fieldSymbol.owner.accessorNameForGetter() @@ -338,8 +338,9 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle pendingAccessorsToAdd.add(accessor) if (!fieldSymbol.owner.isStatic) { + // Accessors are always to one's own fields. accessor.addValueParameter( - "\$this", fieldSymbol.owner.parentAsClass.defaultType, JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR + "\$this", parent.defaultType, JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR ) } @@ -347,22 +348,21 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle }.symbol private fun createAccessorBodyForGetter(targetField: IrField, accessor: IrSimpleFunction): IrBody { - val resolvedTargetField = targetField.resolveFakeOverride()!! val maybeDispatchReceiver = - if (resolvedTargetField.isStatic) null + if (targetField.isStatic) null else IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, accessor.valueParameters[0].symbol) return IrExpressionBodyImpl( UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrGetFieldImpl( UNDEFINED_OFFSET, UNDEFINED_OFFSET, - resolvedTargetField.symbol, - resolvedTargetField.type, + targetField.symbol, + targetField.type, maybeDispatchReceiver ) ) } - private fun makeSetterAccessorSymbol(fieldSymbol: IrFieldSymbol, parent: IrDeclarationParent): IrSimpleFunctionSymbol = + private fun makeSetterAccessorSymbol(fieldSymbol: IrFieldSymbol, parent: IrClass): IrSimpleFunctionSymbol = buildFun { origin = JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR name = fieldSymbol.owner.accessorNameForSetter() @@ -374,8 +374,9 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle pendingAccessorsToAdd.add(accessor) if (!fieldSymbol.owner.isStatic) { + // Accessors are always to one's own fields. accessor.addValueParameter( - "\$this", fieldSymbol.owner.parentAsClass.defaultType, JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR + "\$this", parent.defaultType, JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR ) } @@ -385,19 +386,18 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle }.symbol private fun createAccessorBodyForSetter(targetField: IrField, accessor: IrSimpleFunction): IrBody { - val resolvedTargetField = targetField.resolveFakeOverride()!! val maybeDispatchReceiver = - if (resolvedTargetField.isStatic) null + if (targetField.isStatic) null else IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, accessor.valueParameters[0].symbol) val value = IrGetValueImpl( UNDEFINED_OFFSET, UNDEFINED_OFFSET, - accessor.valueParameters[if (resolvedTargetField.isStatic) 0 else 1].symbol + accessor.valueParameters[if (targetField.isStatic) 0 else 1].symbol ) return IrExpressionBodyImpl( UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrSetFieldImpl( UNDEFINED_OFFSET, UNDEFINED_OFFSET, - resolvedTargetField.symbol, + targetField.symbol, maybeDispatchReceiver, value, context.irBuiltIns.unitType @@ -574,8 +574,7 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle val symbolOwner = owner val declarationRaw = symbolOwner as IrDeclarationWithVisibility val declaration = - (declarationRaw as? IrSimpleFunction)?.resolveFakeOverride() - ?: (declarationRaw as? IrField)?.resolveFakeOverride() ?: declarationRaw + (declarationRaw as? IrSimpleFunction)?.resolveFakeOverride() ?: declarationRaw // There is never a problem with visibility of inline functions, as those don't end up as Java entities if (declaration is IrFunction && declaration.isInline) return true 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 7d98feb27ce..964680664ed 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 @@ -179,7 +179,7 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator return if (getMethodDescriptor == null) { call.callReceiver.call { dispatchReceiverValue, _ -> - val fieldSymbol = context.symbolTable.referenceField(descriptor.original) + val fieldSymbol = context.symbolTable.referenceField(descriptor.resolveFakeOverride().original) IrGetFieldImpl( startOffset, endOffset, fieldSymbol, @@ -416,3 +416,14 @@ fun CallGenerator.generateCall(ktElement: KtElement, call: CallBuilder, origin: fun CallGenerator.generateCall(irExpression: IrExpression, call: CallBuilder, origin: IrStatementOrigin? = null) = generateCall(irExpression.startOffset, irExpression.endOffset, call, origin) + +// Only works for descriptors of Java fields. +private fun PropertyDescriptor.resolveFakeOverride(): PropertyDescriptor { + assert(getter == null) + // Fields can only be inherited from objects, so there will be at most one overridden descriptor at each step. + var current = this + while (current.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) { + current = current.overriddenDescriptors.single() + } + return current +} \ No newline at end of file diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/PropertyGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/PropertyGenerator.kt index c756786dd80..07e6096c872 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/PropertyGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/PropertyGenerator.kt @@ -145,17 +145,7 @@ class PropertyGenerator(declarationGenerator: DeclarationGenerator) : Declaratio val startOffset = ktElement.pureStartOffsetOrUndefined val endOffset = ktElement.pureEndOffsetOrUndefined - val backingField = - if (propertyDescriptor.actuallyHasBackingField(context.bindingContext) && propertyDescriptor.fieldVisibility.admitsFakeOverride) - context.symbolTable.declareFieldWithOverrides( - startOffset, endOffset, IrDeclarationOrigin.FAKE_OVERRIDE, - propertyDescriptor, propertyDescriptor.type.toIrType() - ) { it.actuallyHasBackingField(context.bindingContext) } - else - null - return context.symbolTable.declareProperty(startOffset, endOffset, IrDeclarationOrigin.FAKE_OVERRIDE, propertyDescriptor).apply { - this.backingField = backingField this.getter = propertyDescriptor.getter?.let { FunctionGenerator(declarationGenerator).generateFakeOverrideFunction(it, ktElement) } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt index 9edcd79b2d6..0fed840390e 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt @@ -265,6 +265,8 @@ fun IrSimpleFunction.findInterfaceImplementation(): IrSimpleFunction? { return resolveFakeOverride()?.run { if (parentAsClass.isInterface) this else null } } +fun IrProperty.resolveFakeOverride(): IrProperty? = getter?.resolveFakeOverride()?.correspondingPropertySymbol?.owner + val IrClass.isAnnotationClass get() = kind == ClassKind.ANNOTATION_CLASS val IrClass.isEnumClass get() = kind == ClassKind.ENUM_CLASS val IrClass.isEnumEntry get() = kind == ClassKind.ENUM_ENTRY diff --git a/compiler/testData/ir/irText/expressions/jvmInstanceFieldReference.txt b/compiler/testData/ir/irText/expressions/jvmInstanceFieldReference.txt index fdea6c34e11..e06f4d8f042 100644 --- a/compiler/testData/ir/irText/expressions/jvmInstanceFieldReference.txt +++ b/compiler/testData/ir/irText/expressions/jvmInstanceFieldReference.txt @@ -24,9 +24,6 @@ FILE fqName: fileName:/Derived.kt receiver: GET_VAR ': .Derived declared in .Derived.setValue' type=.Derived origin=null value: GET_VAR 'value: kotlin.Int declared in .Derived.setValue' type=kotlin.Int origin=null PROPERTY FAKE_OVERRIDE name:value visibility:public modality:FINAL [fake_override,var] - FIELD FAKE_OVERRIDE name:value type:kotlin.Int visibility:public [fake_override] - overridden: - FIELD IR_EXTERNAL_JAVA_DECLARATION_STUB name:value type:kotlin.Int visibility:public 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 .Base diff --git a/compiler/testData/ir/irText/expressions/kt16904.txt b/compiler/testData/ir/irText/expressions/kt16904.txt index 458403e8051..fddf5a8780d 100644 --- a/compiler/testData/ir/irText/expressions/kt16904.txt +++ b/compiler/testData/ir/irText/expressions/kt16904.txt @@ -136,9 +136,6 @@ FILE fqName: fileName:/kt16904.kt receiver: GET_VAR ': .Test2 declared in .Test2' type=.Test2 origin=null value: CONST Int type=kotlin.Int value=42 PROPERTY FAKE_OVERRIDE name:field visibility:public modality:FINAL [fake_override,var] - FIELD FAKE_OVERRIDE name:field type:kotlin.Int visibility:public [fake_override] - overridden: - FIELD IR_EXTERNAL_JAVA_DECLARATION_STUB name:field type:kotlin.Int visibility:public 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 .J diff --git a/compiler/testData/ir/irText/expressions/setFieldWithImplicitCast.txt b/compiler/testData/ir/irText/expressions/setFieldWithImplicitCast.txt index e4f06abfb4f..4be3fefe608 100644 --- a/compiler/testData/ir/irText/expressions/setFieldWithImplicitCast.txt +++ b/compiler/testData/ir/irText/expressions/setFieldWithImplicitCast.txt @@ -19,9 +19,6 @@ FILE fqName: fileName:/Derived.kt value: TYPE_OP type=kotlin.String origin=IMPLICIT_CAST typeOperand=kotlin.String GET_VAR 'v: kotlin.Any declared in .Derived.setValue' type=kotlin.Any origin=null PROPERTY FAKE_OVERRIDE name:value visibility:public modality:FINAL [fake_override,var] - FIELD FAKE_OVERRIDE name:value type:kotlin.String? visibility:public [fake_override] - overridden: - FIELD IR_EXTERNAL_JAVA_DECLARATION_STUB name:value type:kotlin.String? visibility:public 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 .Base diff --git a/compiler/testData/ir/irText/stubs/javaInnerClass.txt b/compiler/testData/ir/irText/stubs/javaInnerClass.txt index f2248cd7937..52f19c052bf 100644 --- a/compiler/testData/ir/irText/stubs/javaInnerClass.txt +++ b/compiler/testData/ir/irText/stubs/javaInnerClass.txt @@ -18,9 +18,6 @@ FILE fqName: fileName:/javaInnerClass.kt GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:test type:.J.JInner visibility:private [final]' type=.J.JInner origin=null receiver: GET_VAR ': .Test1 declared in .Test1.' type=.Test1 origin=null PROPERTY FAKE_OVERRIDE name:x visibility:public modality:FINAL [fake_override,var] - FIELD FAKE_OVERRIDE name:x type:kotlin.Int visibility:public [fake_override] - overridden: - FIELD IR_EXTERNAL_JAVA_DECLARATION_STUB name:x type:kotlin.Int visibility:public FUN FAKE_OVERRIDE name:bar visibility:public modality:OPEN <> ($this:.J) returnType:kotlin.Unit [fake_override] overridden: public open fun bar (): kotlin.Unit declared in .J