From 376eef05f57442ccaba82629284af3649ec23922 Mon Sep 17 00:00:00 2001 From: Georgy Bronnikov Date: Mon, 17 Sep 2018 14:35:25 +0300 Subject: [PATCH] JVM_IR. Accessor lowering --- .../kotlin/backend/common/ir/IrUtils.kt | 121 ++- .../jvm/lower/SyntheticAccessorLowering.kt | 772 +++++++++++------- .../org/jetbrains/kotlin/ir/util/IrUtils.kt | 20 + .../localClasses/closureOfInnerLocalClass.kt | 3 +- .../closureWithSelfInstantiation.kt | 1 - .../localClasses/innerClassInLocalClass.kt | 1 - .../ownClosureOfInnerLocalClass.kt | 3 +- .../optimized/valWithAccessor.kt | 1 - ...tAccessedFromMethodInlinedInNestedClass.kt | 1 - .../codegen/box/syntheticAccessors/inline.kt | 16 + .../box/syntheticAccessors/jvmField.kt | 22 + .../codegen/BlackBoxCodegenTestGenerated.java | 10 + .../LightAnalysisModeTestGenerated.java | 10 + .../ir/IrBlackBoxCodegenTestGenerated.java | 10 + .../IrJsCodegenBoxTestGenerated.java | 5 + .../semantics/JsCodegenBoxTestGenerated.java | 5 + 16 files changed, 691 insertions(+), 310 deletions(-) create mode 100644 compiler/testData/codegen/box/syntheticAccessors/inline.kt create mode 100644 compiler/testData/codegen/box/syntheticAccessors/jvmField.kt diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt index 64dbdc83c59..9c01cc22044 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl import org.jetbrains.kotlin.ir.declarations.impl.IrTypeParameterImpl @@ -36,8 +37,15 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl +import org.jetbrains.kotlin.ir.types.IrSimpleType +import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.ir.types.IrTypeProjection +import org.jetbrains.kotlin.ir.types.defaultType +import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl +import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection import org.jetbrains.kotlin.ir.util.DumpIrTreeVisitor import org.jetbrains.kotlin.ir.util.defaultType +import org.jetbrains.kotlin.name.Name import java.io.StringWriter @@ -145,7 +153,16 @@ val IrCall.isSuspend get() = (symbol.owner as? IrSimpleFunction)?.isSuspend == t val IrFunctionReference.isSuspend get() = (symbol.owner as? IrSimpleFunction)?.isSuspend == true -fun IrValueParameter.copyTo(irFunction: IrFunction, shift: Int = 0): IrValueParameter { +fun IrValueParameter.copyTo( + irFunction: IrFunction, + shift: Int = 0, + startOffset: Int = this.startOffset, + endOffset: Int = this.endOffset, + origin: IrDeclarationOrigin = this.origin, + name: Name = this.name, + type: IrType = this.type.maybeReplace(this.parent as IrTypeParametersContainer, irFunction), + varargElementType: IrType? = this.varargElementType +): IrValueParameter { val descriptor = WrappedValueParameterDescriptor(symbol.descriptor.annotations, symbol.descriptor.source) val symbol = IrValueParameterSymbolImpl(descriptor) return IrValueParameterImpl( @@ -183,3 +200,105 @@ fun IrFunction.copyParameterDeclarationsFrom(from: IrFunction) { assert(typeParameters.isEmpty()) from.typeParameters.mapTo(typeParameters) { it.copyTo(this) } } + +fun IrTypeParametersContainer.copyTypeParametersFrom( + source: IrTypeParametersContainer, + origin: IrDeclarationOrigin +) { + val target = this + assert(target.typeParameters.isEmpty()) + source.typeParameters.forEachIndexed { i, sourceParameter -> + assert(sourceParameter.index == i) + val tpDescriptor = WrappedTypeParameterDescriptor() + target.typeParameters.add( + IrTypeParameterImpl( + UNDEFINED_OFFSET, + UNDEFINED_OFFSET, + origin, + IrTypeParameterSymbolImpl(tpDescriptor), + sourceParameter.name, + sourceParameter.index, + sourceParameter.isReified, + sourceParameter.variance + ).apply { + tpDescriptor.bind(this) + parent = target + sourceParameter.superTypes.forEach { + // Using the already copied portion of target.typeParameters. + superTypes.add(it.maybeReplace(source, target)) + } + } + ) + } +} + +fun IrFunction.copyValueParametersToStatic( + source: IrFunction, + origin: IrDeclarationOrigin +) { + val target = this + assert(target.valueParameters.isEmpty()) + + var shift = 0 + source.dispatchReceiverParameter?.apply { + target.valueParameters.add( + copyTo( + target, + origin = origin, + shift = shift++, + name = Name.identifier("\$this") + ) + ) + } + source.extensionReceiverParameter?.apply { + target.valueParameters.add( + copyTo( + target, + origin = origin, + shift = shift++, + name = Name.identifier("\$receiver") + ) + ) + } + source.valueParameters.forEachIndexed { i, oldValueParameter -> + target.valueParameters.add( + oldValueParameter.copyTo( + target, + origin = origin, + shift = shift + ) + ) + } +} + +/* + Type parameters should correspond to the function where they are defined. + `source` is where the type is originally taken from. + */ +fun IrType.maybeReplace(source: IrTypeParametersContainer, target: IrTypeParametersContainer): IrType = + when (this) { + is IrSimpleType -> { + val classifier = classifier.owner + when { + classifier is IrTypeParameter && classifier.parent == source -> + target.typeParameters[classifier.index].defaultType + classifier is IrClass -> + IrSimpleTypeImpl( + classifier.symbol, + hasQuestionMark, + arguments.map { + when (it) { + is IrTypeProjection -> makeTypeProjection( + it.type.maybeReplace(source, target), + it.variance + ) + else -> it + } + }, + annotations + ) + else -> this + } + } + else -> this + } 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 23730d0dbc9..3501d9347b6 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 @@ -6,341 +6,511 @@ package org.jetbrains.kotlin.backend.jvm.lower import org.jetbrains.kotlin.backend.common.FileLoweringPass +import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext +import org.jetbrains.kotlin.backend.common.IrElementVisitorVoidWithContext +import org.jetbrains.kotlin.backend.common.ScopeWithIr +import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassConstructorDescriptor +import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor +import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor +import org.jetbrains.kotlin.backend.common.ir.* import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.intrinsics.receiverAndArgs -import org.jetbrains.kotlin.codegen.* -import org.jetbrains.kotlin.codegen.context.ClassContext -import org.jetbrains.kotlin.codegen.context.CodegenContext -import org.jetbrains.kotlin.codegen.descriptors.FileClassDescriptor -import org.jetbrains.kotlin.codegen.state.GenerationState -import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper +import org.jetbrains.kotlin.codegen.OwnerKind import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.descriptors.annotations.Annotations -import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl -import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl import org.jetbrains.kotlin.ir.IrElement -import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET -import org.jetbrains.kotlin.ir.declarations.IrClass -import org.jetbrains.kotlin.ir.declarations.IrFile -import org.jetbrains.kotlin.ir.declarations.IrFunction +import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl -import org.jetbrains.kotlin.ir.expressions.IrCall -import org.jetbrains.kotlin.ir.expressions.IrDelegatingConstructorCall -import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression +import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl +import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.* -import org.jetbrains.kotlin.ir.expressions.typeParametersCount -import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol -import org.jetbrains.kotlin.ir.symbols.impl.createFunctionSymbol -import org.jetbrains.kotlin.ir.types.toIrType -import org.jetbrains.kotlin.ir.util.createParameterDeclarations -import org.jetbrains.kotlin.ir.util.defaultType -import org.jetbrains.kotlin.ir.util.usesDefaultArguments -import org.jetbrains.kotlin.ir.visitors.IrElementTransformer +import org.jetbrains.kotlin.ir.symbols.* +import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl +import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl +import org.jetbrains.kotlin.ir.util.* +import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid +import org.jetbrains.kotlin.ir.visitors.acceptVoid +import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid +import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.resolve.DescriptorUtils -interface StubContext { - val irClassContext: IrClassContext -} - -class StubCodegenContext( - contextDescriptor: ClassDescriptor, - parentContext: CodegenContext<*>?, - override val irClassContext: IrClassContext -) : StubContext, CodegenContext( - if (contextDescriptor is FileClassDescriptor) contextDescriptor.containingDeclaration else contextDescriptor, - OwnerKind.IMPLEMENTATION, parentContext, null, - if (contextDescriptor is FileClassDescriptor) null else contextDescriptor, - null -) - -class ClassStubContext( - contextDescriptor: ClassDescriptor, - parentContext: CodegenContext<*>?, - override val irClassContext: IrClassContext, - typeMapper: KotlinTypeMapper -) : StubContext, ClassContext(typeMapper, contextDescriptor, OwnerKind.IMPLEMENTATION, parentContext, null) - -class ContextAnnotator(val state: GenerationState) : ClassLowerWithContext() { - - val context2Codegen = hashMapOf>() - val class2Codegen = hashMapOf>() - - private val IrClassContext.codegenContext: CodegenContext<*> - get() = context2Codegen[this]!! - - - override fun lowerBefore(irClass: IrClass, data: IrClassContext) { - val descriptor = irClass.descriptor - val newContext: CodegenContext<*> = if (descriptor is FileClassDescriptor) { - StubCodegenContext(descriptor, data.parent?.codegenContext, data) - } else { - ClassStubContext(descriptor, data.parent?.codegenContext, data, state.typeMapper) - } - newContext.apply { - context2Codegen.put(data, this) - class2Codegen.put(descriptor, this) - } - } - - override fun lower(irCLass: IrClass, data: IrClassContext) { - - } -} - -class SyntheticAccessorLowering(val context: JvmBackendContext) : FileLoweringPass, IrElementTransformer { - - private val state = context.state - - var pendingTransformations = mutableListOf>() - - private val IrClassContext.codegenContext: CodegenContext<*> - get() = contextAnnotator.context2Codegen[this]!! - - private lateinit var contextAnnotator: ContextAnnotator - - private val ClassDescriptor.codegenContext: CodegenContext<*> - get() = contextAnnotator.class2Codegen[this]!! +class SyntheticAccessorLowering(val context: JvmBackendContext) : IrElementTransformerVoidWithContext(), FileLoweringPass { + private val pendingTransformations = mutableListOf>() + private val inlinedLambdasCollector = InlinedLambdasCollector() override fun lower(irFile: IrFile) { - contextAnnotator = ContextAnnotator(state) - contextAnnotator.lower(irFile) - irFile.transform(this, null) - + irFile.acceptVoid(inlinedLambdasCollector) + irFile.transformChildrenVoid(this) pendingTransformations.forEach { it() } } - override fun visitClass(declaration: IrClass, data: IrClassContext?): IrStatement { - val classContext = (declaration.descriptor.codegenContext as StubContext).irClassContext - return super.visitClass(declaration, classContext).apply { - pendingTransformations.add { lower(classContext) } + private val functionMap = mutableMapOf() + private val getterMap = mutableMapOf() + private val setterMap = mutableMapOf() + + override fun visitFunctionAccess(expression: IrFunctionAccessExpression): IrExpression { + if (expression.usesDefaultArguments()) { + return super.visitFunctionAccess(expression) + } + return super.visitExpression( + handleAccess(expression, expression.symbol, functionMap, ::makeFunctionAccessorSymbol, ::modifyFunctionAccessExpression) + ) + } + + override fun visitGetField(expression: IrGetField) = super.visitExpression( + handleAccess(expression, expression.symbol, getterMap, ::makeGetterAccessorSymbol, ::modifyGetterExpression) + ) + + override fun visitSetField(expression: IrSetField) = super.visitExpression( + handleAccess(expression, expression.symbol, setterMap, ::makeSetterAccessorSymbol, ::modifySetterExpression) + ) + + private inline fun handleAccess( + expression: ExprT, + symbol: FromSyT, + accumMap: MutableMap, + symbolConverter: (FromSyT) -> ToSyT, + exprConverter: (ExprT, ToSyT) -> IrDeclarationReference + ): IrExpression { + if (!symbol.isAccessible()) { + val accessorSymbol = accumMap.getOrPut(symbol, { symbolConverter(symbol) }) + return exprConverter(expression, accessorSymbol) + } else { + return expression } } - fun lower(data: IrClassContext) { - val codegenContext = data.codegenContext - val accessors = codegenContext.accessors - val allAccessors = - ( - accessors.filterIsInstance() + - accessors.filterIsInstance().flatMap { - listOfNotNull( - if (it.isWithSyntheticGetterAccessor) it.getter else null, - if (it.isWithSyntheticSetterAccessor) it.setter else null - ) - } - ).filterIsInstance>() - - val irClassToAddAccessor = data.irClass - allAccessors.forEach { accessor -> - addAccessorToClass(accessor, irClassToAddAccessor, context) - } + private fun makeFunctionAccessorSymbol(functionSymbol: IrFunctionSymbol): IrFunctionSymbol = when (functionSymbol) { + is IrConstructorSymbol -> functionSymbol.owner.makeConstructorAccessor().symbol + is IrSimpleFunctionSymbol -> functionSymbol.owner.makeSimpleFunctionAccessor().symbol + else -> error("Unknown subclass of IrFunctionSymbol") } + private fun IrConstructor.makeConstructorAccessor(): IrConstructor { + val source = this + val accessorDescriptor = WrappedClassConstructorDescriptor() + return IrConstructorImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, + JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR, + IrConstructorSymbolImpl(accessorDescriptor), + name, + Visibilities.PUBLIC, + isInline = false, + isExternal = false, + isPrimary = false + ).also { accessor -> + accessorDescriptor.bind(accessor) + accessor.parent = source.parent + pendingTransformations.add { (accessor.parent as IrDeclarationContainer).declarations.add(accessor) } - override fun visitMemberAccess(expression: IrMemberAccessExpression, data: IrClassContext?): IrElement { - val superResult = super.visitMemberAccess(expression, data) - return createSyntheticAccessorCallForFunction(superResult, expression, data?.codegenContext, context) - } + accessor.copyTypeParametersFrom(source, JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR) + accessor.copyValueParametersToStatic(source, JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR) + accessor.returnType = source.returnType.maybeReplace(source, accessor) - companion object { - fun createSyntheticAccessorCallForFunction( - superResult: IrElement, - expression: IrMemberAccessExpression, - codegenContext: CodegenContext<*>?, - context: JvmBackendContext - ): IrElement { - - val descriptor = expression.descriptor - if (descriptor is FunctionDescriptor && !expression.usesDefaultArguments()) { - val directAccessor = codegenContext!!.accessibleDescriptor( - JvmCodegenUtil.getDirectMember(descriptor), - (expression as? IrCall)?.superQualifier - ) - val accessor = actualAccessor(descriptor, directAccessor) - - if (accessor is AccessorForCallableDescriptor<*> && descriptor !is AccessorForCallableDescriptor<*>) { - val isConstructor = descriptor is ConstructorDescriptor - val accessorOwner = accessor.containingDeclaration as ClassOrPackageFragmentDescriptor - val accessorForIr = - accessorToIrAccessorDescriptor(isConstructor, accessor, context, descriptor, accessorOwner) //TODO change call - - val call = - if (isConstructor && expression is IrDelegatingConstructorCall) - IrDelegatingConstructorCallImpl( - expression.startOffset, - expression.endOffset, - context.irBuiltIns.unitType, - accessorForIr as ClassConstructorDescriptor, - 0 - ) - else IrCallImpl( - expression.startOffset, - expression.endOffset, - expression.type, - accessorForIr, - 0, - expression.origin/*TODO super*/ - ) - //copyAllArgsToValueParams(call, expression) - val receiverAndArgs = expression.receiverAndArgs() - receiverAndArgs.forEachIndexed { i, irExpression -> - call.putValueArgument(i, irExpression) - } - if (isConstructor) { - call.putValueArgument( - receiverAndArgs.size, - IrConstImpl.constNull( - UNDEFINED_OFFSET, - UNDEFINED_OFFSET, - context.ir.symbols.defaultConstructorMarker.owner.defaultType - ) - ) - } - return call - } + val markerParameterDescriptor = WrappedValueParameterDescriptor() + val markerParameter = IrValueParameterImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, + JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR, + IrValueParameterSymbolImpl(markerParameterDescriptor), + Name.identifier("marker"), + index = accessor.valueParameters.size, + type = context.ir.symbols.defaultConstructorMarker.owner.defaultType, + varargElementType = null, + isCrossinline = false, + isNoinline = false + ).apply { + markerParameterDescriptor.bind(this) + parent = accessor } - return superResult - } + accessor.valueParameters.add(markerParameter) - private fun accessorToIrAccessorDescriptor( - isConstructor: Boolean, - accessor: CallableMemberDescriptor, - context: JvmBackendContext, - descriptor: FunctionDescriptor, - accessorOwner: ClassOrPackageFragmentDescriptor - ): FunctionDescriptor { - return if (isConstructor) - (accessor as AccessorForConstructorDescriptor).constructorDescriptorWithMarker( - context.ir.symbols.defaultConstructorMarker.descriptor.defaultType - ) - else descriptor.toStatic( - accessorOwner, - Name.identifier(context.state.typeMapper.mapAsmMethod(accessor as FunctionDescriptor).name) + accessor.body = IrExpressionBodyImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, + createConstructorCall(accessor, source.symbol) ) } + } - fun addAccessorToClass(accessor: AccessorForCallableDescriptor<*>, irClassToAddAccessor: IrClass, context: JvmBackendContext) { - if (accessor is PropertySetterDescriptor && !accessor.correspondingProperty.isVar) return - val accessorOwner = (accessor as FunctionDescriptor).containingDeclaration as ClassOrPackageFragmentDescriptor - val body = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET) - val isConstructor = accessor.calleeDescriptor is ConstructorDescriptor - val accessorForIr = accessorToIrAccessorDescriptor( - isConstructor, accessor, context, - accessor.calleeDescriptor as? FunctionDescriptor ?: return, - accessorOwner - ) - val syntheticFunction = if (isConstructor) IrConstructorImpl( - UNDEFINED_OFFSET, UNDEFINED_OFFSET, JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR, - accessorForIr as ClassConstructorDescriptor, body - ) else IrFunctionImpl( - UNDEFINED_OFFSET, UNDEFINED_OFFSET, JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR, - accessorForIr, body - ) - syntheticFunction.returnType = accessor.calleeDescriptor.returnType!!.toIrType()!! - syntheticFunction.createParameterDeclarations() + private fun createConstructorCall(accessor: IrConstructor, targetSymbol: IrConstructorSymbol) = + IrDelegatingConstructorCallImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, + context.irBuiltIns.unitType, + targetSymbol, targetSymbol.descriptor, targetSymbol.owner.typeParameters.size + ).also { + copyAllParamsToArgs(it, accessor) + } - val calleeDescriptor = accessor.calleeDescriptor as FunctionDescriptor - val delegationCall = - if (!isConstructor) - IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, calleeDescriptor.returnType!!.toIrType()!!, calleeDescriptor, calleeDescriptor.typeParametersCount) - else { - val delegationConstructor = createFunctionSymbol(accessor.calleeDescriptor) - IrDelegatingConstructorCallImpl( + private fun IrSimpleFunction.makeSimpleFunctionAccessor(): IrSimpleFunction { + val source = this + val accessorDescriptor = WrappedSimpleFunctionDescriptor() + return IrFunctionImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, + JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR, + IrSimpleFunctionSymbolImpl(accessorDescriptor), + source.descriptor.accessorName(), + Visibilities.PUBLIC, + Modality.FINAL, + isInline = false, + isExternal = false, + isTailrec = false, + isSuspend = source.isSuspend + ).also { accessor -> + accessorDescriptor.bind(accessor) + accessor.parent = source.parent + pendingTransformations.add { (accessor.parent as IrDeclarationContainer).declarations.add(accessor) } + + accessor.copyTypeParametersFrom(source, JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR) + accessor.copyValueParametersToStatic(source, JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR) + accessor.returnType = source.returnType.maybeReplace(source, accessor) + + accessor.body = IrExpressionBodyImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, + createSimpleFunctionCall(accessor, source.symbol) + ) + } + } + + private fun createSimpleFunctionCall(accessor: IrFunction, targetSymbol: IrFunctionSymbol) = + IrCallImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, + accessor.returnType, + targetSymbol, targetSymbol.descriptor, + targetSymbol.owner.typeParameters.size + ).also { + copyAllParamsToArgs(it, accessor) + } + + private fun makeGetterAccessorSymbol(fieldSymbol: IrFieldSymbol): IrSimpleFunctionSymbol { + val accessorDescriptor = WrappedSimpleFunctionDescriptor() + return IrFunctionImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, + JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR, + IrSimpleFunctionSymbolImpl(accessorDescriptor), + fieldSymbol.descriptor.accessorNameForGetter(), + Visibilities.PUBLIC, + Modality.FINAL, + isInline = false, + isExternal = false, + isTailrec = false, + isSuspend = false + ).also { accessor -> + accessorDescriptor.bind(accessor) + accessor.parent = fieldSymbol.owner.parent + pendingTransformations.add { (accessor.parent as IrDeclarationContainer).declarations.add(accessor) } + + if (!fieldSymbol.owner.isStatic) { + val receiverDescriptor = WrappedValueParameterDescriptor() + accessor.valueParameters.add( + IrValueParameterImpl( UNDEFINED_OFFSET, UNDEFINED_OFFSET, - context.irBuiltIns.unitType, - delegationConstructor as IrConstructorSymbol, - accessor.calleeDescriptor as ClassConstructorDescriptor - ) - } - copyAllArgsToValueParams(delegationCall, syntheticFunction) + JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR, + IrValueParameterSymbolImpl(receiverDescriptor), + Name.identifier("\$this"), + index = 0, + type = (fieldSymbol.owner.parent as IrClass).defaultType, + varargElementType = null, + isCrossinline = false, + isNoinline = false + ).apply { + receiverDescriptor.bind(this) + parent = accessor + } + ) + } - body.statements.add( - if (isConstructor) delegationCall else IrReturnImpl( + accessor.returnType = fieldSymbol.owner.type + accessor.body = createAccessorBodyForGetter(fieldSymbol.owner, accessor) + }.symbol + } + + private fun createAccessorBodyForGetter(targetField: IrField, accessor: IrSimpleFunction): IrBody { + val resolvedTargetField = targetField.resolveFakeOverride()!! + val maybeDispatchReceiver = + if (resolvedTargetField.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, + maybeDispatchReceiver + ) + ) + } + + private fun makeSetterAccessorSymbol(fieldSymbol: IrFieldSymbol): IrSimpleFunctionSymbol { + val accessorDescriptor = WrappedSimpleFunctionDescriptor() + return IrFunctionImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, + JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR, + IrSimpleFunctionSymbolImpl(accessorDescriptor), + fieldSymbol.descriptor.accessorNameForSetter(), + Visibilities.PUBLIC, + Modality.FINAL, + isInline = false, + isExternal = false, + isTailrec = false, + isSuspend = false + ).also { accessor -> + accessorDescriptor.bind(accessor) + accessor.parent = fieldSymbol.owner.parent + pendingTransformations.add { (accessor.parent as IrDeclarationContainer).declarations.add(accessor) } + + if (!fieldSymbol.owner.isStatic) { + val receiverDescriptor = WrappedValueParameterDescriptor() + accessor.valueParameters.add( + IrValueParameterImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, + JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR, + IrValueParameterSymbolImpl(receiverDescriptor), + Name.identifier("\$this"), + index = 0, + type = (fieldSymbol.owner.parent as IrClass).defaultType, + varargElementType = null, + isCrossinline = false, + isNoinline = false + ).apply { + receiverDescriptor.bind(this) + parent = accessor + } + ) + } + val valueDescriptor = WrappedValueParameterDescriptor() + accessor.valueParameters.add( + IrValueParameterImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, + JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR, + IrValueParameterSymbolImpl(valueDescriptor), + Name.identifier("value"), + index = if (fieldSymbol.owner.isStatic) 0 else 1, + type = fieldSymbol.owner.type, + varargElementType = null, + isCrossinline = false, + isNoinline = false + ).apply { + valueDescriptor.bind(this) + parent = accessor + } + ) + + accessor.returnType = context.irBuiltIns.unitType + accessor.body = createAccessorBodyForSetter(fieldSymbol.owner, accessor) + }.symbol + } + + private fun createAccessorBodyForSetter(targetField: IrField, accessor: IrSimpleFunction): IrBody { + val resolvedTargetField = targetField.resolveFakeOverride()!! + val maybeDispatchReceiver = + if (resolvedTargetField.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 + ) + return IrExpressionBodyImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, + IrSetFieldImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, + resolvedTargetField.symbol, + maybeDispatchReceiver, + value, + resolvedTargetField.type + ) + ) + } + + private fun modifyFunctionAccessExpression( + oldExpression: IrFunctionAccessExpression, + accessorSymbol: IrFunctionSymbol + ): IrFunctionAccessExpression { + val newExpression = when (oldExpression) { + is IrCall -> IrCallImpl( + oldExpression.startOffset, oldExpression.endOffset, + oldExpression.type, + accessorSymbol, accessorSymbol.descriptor, + oldExpression.typeArgumentsCount, + oldExpression.origin, + oldExpression.superQualifierSymbol + ) + is IrDelegatingConstructorCall -> IrDelegatingConstructorCallImpl( + oldExpression.startOffset, oldExpression.endOffset, + context.irBuiltIns.unitType, + accessorSymbol as IrConstructorSymbol, accessorSymbol.descriptor, + oldExpression.typeArgumentsCount + ) + else -> error("Need IrCall or IrDelegatingConstructor call, got $oldExpression") + } + newExpression.copyTypeArgumentsFrom(oldExpression) + val receiverAndArgs = oldExpression.receiverAndArgs() + receiverAndArgs.forEachIndexed { i, irExpression -> + newExpression.putValueArgument(i, irExpression) + } + if (accessorSymbol is IrConstructorSymbol) { + newExpression.putValueArgument( + receiverAndArgs.size, + IrConstImpl.constNull( UNDEFINED_OFFSET, UNDEFINED_OFFSET, - syntheticFunction.returnType, - syntheticFunction.symbol, - delegationCall + context.ir.symbols.defaultConstructorMarker.owner.defaultType ) ) - irClassToAddAccessor.declarations.add(syntheticFunction) } - - private fun actualAccessor(descriptor: FunctionDescriptor, calculatedAccessor: CallableMemberDescriptor): CallableMemberDescriptor { - if (calculatedAccessor is AccessorForPropertyDescriptor) { - val isGetter = descriptor is PropertyGetterDescriptor - val propertyAccessor = if (isGetter) calculatedAccessor.getter!! else calculatedAccessor.setter!! - if (isGetter && calculatedAccessor.isWithSyntheticGetterAccessor || !isGetter && calculatedAccessor.isWithSyntheticSetterAccessor) { - return propertyAccessor - } - return descriptor - - } - return calculatedAccessor - } - - private fun copyAllArgsToValueParams( - call: IrMemberAccessExpression, - syntheticFunction: IrFunction - ) { - var offset = 0 - val delegateTo = call.descriptor - delegateTo.dispatchReceiverParameter?.let { - call.dispatchReceiver = - IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, syntheticFunction.valueParameters[offset++].symbol) - } - - delegateTo.extensionReceiverParameter?.let { - call.extensionReceiver = - IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, syntheticFunction.valueParameters[offset++].symbol) - } - - call.descriptor.valueParameters.forEachIndexed { i, _ -> - call.putValueArgument( - i, - IrGetValueImpl( - UNDEFINED_OFFSET, - UNDEFINED_OFFSET, - syntheticFunction.valueParameters[i + offset].symbol - ) - ) - } - } - - private fun AccessorForConstructorDescriptor.constructorDescriptorWithMarker(marker: KotlinType) = - ClassConstructorDescriptorImpl.createSynthesized(containingDeclaration, annotations, false, source).also { - it.initialize( - extensionReceiverParameter?.copy(this), - dispatchReceiverParameter, - emptyList()/*TODO*/, - calleeDescriptor.valueParameters.map { - it.copy( - this, - it.name, - it.index - ) - } + ValueParameterDescriptorImpl.createWithDestructuringDeclarations( - it, - null, - calleeDescriptor.valueParameters.size, - Annotations.EMPTY, - Name.identifier("marker"), - marker, - false, - false, - false, - null, - SourceElement.NO_SOURCE, - null - ), - calleeDescriptor.returnType, - Modality.FINAL, - Visibilities.LOCAL - ) - } + return newExpression } -} \ No newline at end of file + + private fun modifyGetterExpression( + oldExpression: IrGetField, + accessorSymbol: IrFunctionSymbol + ): IrCall { + val call = IrCallImpl( + oldExpression.startOffset, oldExpression.endOffset, + oldExpression.type, + accessorSymbol, accessorSymbol.descriptor, + 0, + oldExpression.origin + ) + oldExpression.receiver?.let { + call.putValueArgument(0, oldExpression.receiver) + } + return call + } + + private fun modifySetterExpression( + oldExpression: IrSetField, + accessorSymbol: IrFunctionSymbol + ): IrCall { + val call = IrCallImpl( + oldExpression.startOffset, oldExpression.endOffset, + oldExpression.type, + accessorSymbol, accessorSymbol.descriptor, + 0, + oldExpression.origin + ) + oldExpression.receiver?.let { + call.putValueArgument(0, oldExpression.receiver) + } + call.putValueArgument(call.valueArgumentsCount - 1, oldExpression.value) + return call + } + + private fun copyAllParamsToArgs( + call: IrFunctionAccessExpression, + syntheticFunction: IrFunction + ) { + var offset = 0 + val delegateTo = call.symbol.owner + syntheticFunction.typeParameters.forEachIndexed { i, typeParam -> + call.putTypeArgument(i, IrSimpleTypeImpl(typeParam.symbol, false, emptyList(), emptyList())) + } + delegateTo.dispatchReceiverParameter?.let { + call.dispatchReceiver = + IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, syntheticFunction.valueParameters[offset++].symbol) + } + + delegateTo.extensionReceiverParameter?.let { + call.extensionReceiver = + IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, syntheticFunction.valueParameters[offset++].symbol) + } + + delegateTo.valueParameters.forEachIndexed { i, _ -> + call.putValueArgument( + i, + IrGetValueImpl( + UNDEFINED_OFFSET, + UNDEFINED_OFFSET, + syntheticFunction.valueParameters[i + offset].symbol + ) + ) + } + } + + // !!!!!! Should I use syntheticAccesssorUtils here ??? + private fun FunctionDescriptor.accessorName(): Name { + val jvmName = DescriptorUtils.getJvmName(this) ?: context.state.typeMapper.mapFunctionName( + this, + OwnerKind.getMemberOwnerKind(containingDeclaration) + ) + return Name.identifier("access\$$jvmName") + } + + private fun PropertyDescriptor.accessorNameForGetter(): Name { + val getterName = JvmAbi.getterName(name.asString()) + return Name.identifier("access\$prop\$$getterName") + } + + private fun PropertyDescriptor.accessorNameForSetter(): Name { + val setterName = JvmAbi.setterName(name.asString()) + return Name.identifier("access\$prop\$$setterName") + } + + private fun IrSymbol.isAccessible(): Boolean { + /// We assume that IR code that reaches us has been checked for correctness at the frontend. + /// This function needs to single out those cases where Java accessibility rules differ from Kotlin's. + + val declarationRaw = owner as IrDeclarationWithVisibility + val declaration = + (declarationRaw as? IrSimpleFunction)?.resolveFakeOverride() + ?: (declarationRaw as? IrField)?.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 + + // The only two visibilities where Kotlin rules differ from JVM rules. + if (!Visibilities.isPrivate(declaration.visibility) && declaration.visibility != Visibilities.PROTECTED) return true + + val symbolDeclarationContainer = (declaration.parent as? IrDeclarationContainer) as? IrElement + // If local variables are accessible by Kotlin rules, they also are by Java rules. + if (symbolDeclarationContainer == null) return true + + // Within inline functions, we have to assume the worst. + if (inlinedLambdasCollector.isInlineNonpublicContext(allScopes)) + return false + + val contextDeclarationContainer = allScopes.lastOrNull { it.irElement is IrDeclarationContainer }?.irElement + + val samePackage = declaration.getPackageFragment()?.fqName == contextDeclarationContainer?.getPackageFragment()?.fqName + return when { + Visibilities.isPrivate(declaration.visibility) && symbolDeclarationContainer != contextDeclarationContainer -> false + (declaration.visibility == Visibilities.PROTECTED && !samePackage && + !(symbolDeclarationContainer is IrClass && contextDeclarationContainer is IrClass && + contextDeclarationContainer.isSubclassOf(symbolDeclarationContainer))) -> false + else -> true + } + } +} + +private class InlinedLambdasCollector : IrElementVisitorVoidWithContext() { + private val inlinedLambdasInNonPublicContexts = mutableSetOf() + + fun isInlineNonpublicContext(scopeStack: List): Boolean { + val currentFunction = scopeStack.map { it.irElement }. lastOrNull { it is IrFunction } as? IrFunction ?: return false + return (currentFunction.isInline == true && currentFunction.visibility in setOf(Visibilities.PRIVATE, Visibilities.PROTECTED)) + || currentFunction in inlinedLambdasInNonPublicContexts + } + + override fun visitElement(element: IrElement) { + element.acceptChildrenVoid(this) + } + + override fun visitFunctionAccess(expression: IrFunctionAccessExpression) { + val callTarget = expression.symbol.owner + if (callTarget.isInline && isInlineNonpublicContext(allScopes)) { + for (i in 0 until expression.valueArgumentsCount) { + val argument = expression.getValueArgument(i)?.removeBlocks() + if (argument is IrFunctionReference && + argument.symbol.owner.origin == IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA && + !callTarget.valueParameters[i].isNoinline) { + inlinedLambdasInNonPublicContexts.add(argument.symbol.owner) + } + } + } + super.visitFunctionAccess(expression) + } +} + 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 212925d3739..b225f3c9f87 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 @@ -16,7 +16,11 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrTypeParameterImpl import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.symbols.* +import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl import org.jetbrains.kotlin.ir.types.* +import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl +import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.psiUtil.endOffset @@ -322,6 +326,16 @@ fun IrSimpleFunction.resolveFakeOverride(): IrSimpleFunction? { return realOverrides.singleOrNull { it.modality != Modality.ABSTRACT } } +fun IrField.resolveFakeOverride(): IrField? { + var toVisit = setOf(this) + val nonOverridden = mutableSetOf() + while (toVisit.isNotEmpty()) { + nonOverridden += toVisit.filter { it.overriddenSymbols.isEmpty() } + toVisit = toVisit.flatMap { it.overriddenSymbols }.map { it.owner }.toSet() + } + return nonOverridden.singleOrNull() +} + val IrClass.isAnnotationClass get() = kind == ClassKind.ANNOTATION_CLASS val IrClass.isEnumClass get() = kind == ClassKind.ENUM_CLASS val IrClass.isEnumEntry get() = kind == ClassKind.ENUM_ENTRY @@ -442,6 +456,12 @@ fun IrFunction.createDispatchReceiverParameter() { ).also { it.parent = this } } +// In presence of `IrBlock`s, return the expression that actually serves as the value (the last one). +tailrec fun IrExpression.removeBlocks(): IrExpression? = when (this) { + is IrBlock -> (statements.last() as? IrExpression)?.removeBlocks() + else -> this +} + fun ReferenceSymbolTable.referenceClassifier(classifier: ClassifierDescriptor): IrClassifierSymbol = when (classifier) { is TypeParameterDescriptor -> diff --git a/compiler/testData/codegen/box/localClasses/closureOfInnerLocalClass.kt b/compiler/testData/codegen/box/localClasses/closureOfInnerLocalClass.kt index 87afaf89ed0..2e1c3cf367b 100644 --- a/compiler/testData/codegen/box/localClasses/closureOfInnerLocalClass.kt +++ b/compiler/testData/codegen/box/localClasses/closureOfInnerLocalClass.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // Enable for JVM backend when KT-8120 gets fixed // IGNORE_BACKEND: JVM @@ -26,4 +25,4 @@ fun box(): String { if (log != "111") return "fail: ${log}" return "OK" -} \ No newline at end of file +} diff --git a/compiler/testData/codegen/box/localClasses/closureWithSelfInstantiation.kt b/compiler/testData/codegen/box/localClasses/closureWithSelfInstantiation.kt index 4be3a3c8e4b..20727829c28 100644 --- a/compiler/testData/codegen/box/localClasses/closureWithSelfInstantiation.kt +++ b/compiler/testData/codegen/box/localClasses/closureWithSelfInstantiation.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // Enable for JVM backend when KT-8120 gets fixed // IGNORE_BACKEND: JVM diff --git a/compiler/testData/codegen/box/localClasses/innerClassInLocalClass.kt b/compiler/testData/codegen/box/localClasses/innerClassInLocalClass.kt index d54fb5ac8f8..72d84e5ddac 100644 --- a/compiler/testData/codegen/box/localClasses/innerClassInLocalClass.kt +++ b/compiler/testData/codegen/box/localClasses/innerClassInLocalClass.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR class A { val a = 1 fun calc () : Int { diff --git a/compiler/testData/codegen/box/localClasses/ownClosureOfInnerLocalClass.kt b/compiler/testData/codegen/box/localClasses/ownClosureOfInnerLocalClass.kt index 57c51e32a67..a9bbbcf9bad 100644 --- a/compiler/testData/codegen/box/localClasses/ownClosureOfInnerLocalClass.kt +++ b/compiler/testData/codegen/box/localClasses/ownClosureOfInnerLocalClass.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR fun box(): String { var log = "" @@ -22,4 +21,4 @@ fun box(): String { if (log != "(1;1)(1;1)(1;1)") return "fail: ${log}" return "OK" -} \ No newline at end of file +} diff --git a/compiler/testData/codegen/box/multifileClasses/optimized/valWithAccessor.kt b/compiler/testData/codegen/box/multifileClasses/optimized/valWithAccessor.kt index c6870f76dbf..e47c2a619c8 100644 --- a/compiler/testData/codegen/box/multifileClasses/optimized/valWithAccessor.kt +++ b/compiler/testData/codegen/box/multifileClasses/optimized/valWithAccessor.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // IGNORE_LIGHT_ANALYSIS // WITH_RUNTIME diff --git a/compiler/testData/codegen/box/objects/companionObjectAccess/privateCompanionObjectAccessedFromMethodInlinedInNestedClass.kt b/compiler/testData/codegen/box/objects/companionObjectAccess/privateCompanionObjectAccessedFromMethodInlinedInNestedClass.kt index ae710b13fb5..aaa63fc49f1 100644 --- a/compiler/testData/codegen/box/objects/companionObjectAccess/privateCompanionObjectAccessedFromMethodInlinedInNestedClass.kt +++ b/compiler/testData/codegen/box/objects/companionObjectAccess/privateCompanionObjectAccessedFromMethodInlinedInNestedClass.kt @@ -1,5 +1,4 @@ // !LANGUAGE: +ProperVisibilityForCompanionObjectInstanceField -// IGNORE_BACKEND: JVM_IR class Outer { private companion object { diff --git a/compiler/testData/codegen/box/syntheticAccessors/inline.kt b/compiler/testData/codegen/box/syntheticAccessors/inline.kt new file mode 100644 index 00000000000..32a562d29e7 --- /dev/null +++ b/compiler/testData/codegen/box/syntheticAccessors/inline.kt @@ -0,0 +1,16 @@ +class A { + fun foo() = o_plus_f_plus_k {""} + + companion object { + private val o = "O" + private val k = "K" + + private inline fun o_plus_f1_plus_f2(f1: () -> String, f2: () -> String) = o + f1() + f2() + private inline fun o_plus_f_plus_k(f: () -> String) = o_plus_f1_plus_f2(f) { k } + + } +} + +fun box(): String { + return A().foo() +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/syntheticAccessors/jvmField.kt b/compiler/testData/codegen/box/syntheticAccessors/jvmField.kt new file mode 100644 index 00000000000..02880f60e6e --- /dev/null +++ b/compiler/testData/codegen/box/syntheticAccessors/jvmField.kt @@ -0,0 +1,22 @@ +// TARGET_BACKEND: JVM + +// FILE: A.kt +package a +import b.* + +class A { + fun foo() = ok + + companion object : B() +} + +fun box(): String { + return A().foo() +} + +// FILE: B.kt +package b + +open class B { + @JvmField protected val ok = "OK" +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index cf3b73e80e8..0a344876fc0 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -22319,6 +22319,16 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/syntheticAccessors"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); } + @TestMetadata("inline.kt") + public void testInline() throws Exception { + runTest("compiler/testData/codegen/box/syntheticAccessors/inline.kt"); + } + + @TestMetadata("jvmField.kt") + public void testJvmField() throws Exception { + runTest("compiler/testData/codegen/box/syntheticAccessors/jvmField.kt"); + } + @TestMetadata("jvmNameForAccessors.kt") public void testJvmNameForAccessors() throws Exception { runTest("compiler/testData/codegen/box/syntheticAccessors/jvmNameForAccessors.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index a33fa685f5e..8aee2cfbe96 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -22319,6 +22319,16 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/syntheticAccessors"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); } + @TestMetadata("inline.kt") + public void testInline() throws Exception { + runTest("compiler/testData/codegen/box/syntheticAccessors/inline.kt"); + } + + @TestMetadata("jvmField.kt") + public void testJvmField() throws Exception { + runTest("compiler/testData/codegen/box/syntheticAccessors/jvmField.kt"); + } + @TestMetadata("jvmNameForAccessors.kt") public void testJvmNameForAccessors() throws Exception { runTest("compiler/testData/codegen/box/syntheticAccessors/jvmNameForAccessors.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index e0c7c04257e..5b7e9f931e0 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -22324,6 +22324,16 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/syntheticAccessors"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true); } + @TestMetadata("inline.kt") + public void testInline() throws Exception { + runTest("compiler/testData/codegen/box/syntheticAccessors/inline.kt"); + } + + @TestMetadata("jvmField.kt") + public void testJvmField() throws Exception { + runTest("compiler/testData/codegen/box/syntheticAccessors/jvmField.kt"); + } + @TestMetadata("jvmNameForAccessors.kt") public void testJvmNameForAccessors() throws Exception { runTest("compiler/testData/codegen/box/syntheticAccessors/jvmNameForAccessors.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java index 7a9841afb01..a19a09a9f4c 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java @@ -20139,6 +20139,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/syntheticAccessors"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS_IR, true); } + @TestMetadata("inline.kt") + public void testInline() throws Exception { + runTest("compiler/testData/codegen/box/syntheticAccessors/inline.kt"); + } + @TestMetadata("jvmNameForAccessors.kt") public void testJvmNameForAccessors() throws Exception { runTest("compiler/testData/codegen/box/syntheticAccessors/jvmNameForAccessors.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index cacac5d8391..a37025a9dca 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -21184,6 +21184,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/syntheticAccessors"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true); } + @TestMetadata("inline.kt") + public void testInline() throws Exception { + runTest("compiler/testData/codegen/box/syntheticAccessors/inline.kt"); + } + @TestMetadata("jvmNameForAccessors.kt") public void testJvmNameForAccessors() throws Exception { runTest("compiler/testData/codegen/box/syntheticAccessors/jvmNameForAccessors.kt");