From 7ce5556de32090ee5b4af2c6f268cec88a41f7d8 Mon Sep 17 00:00:00 2001 From: pyos Date: Mon, 23 Aug 2021 13:48:23 +0200 Subject: [PATCH] JVM_IR: try to fix SyntheticAccessorLowering.isAccessible again The condition on the relationship between the current class and the type of the receiver for protected members was the opposite of what the JVMS says, and yet somehow mostly worked? #KT-48331 Fixed #KT-20542 Fixed --- .../FirBlackBoxCodegenTestGenerated.java | 18 ++ .../backend/jvm/JvmCachedDeclarations.kt | 3 + .../jvm/codegen/MethodSignatureMapper.kt | 5 +- .../backend/jvm/lower/AssertionLowering.kt | 5 +- ...nheritedDefaultMethodsOnClassesLowering.kt | 16 +- .../jvm/lower/SyntheticAccessorLowering.kt | 165 ++++++++++-------- .../lower/indy/LambdaMetafactoryArguments.kt | 4 +- .../javaInterop/objectWithSeveralSuspends.kt | 4 - .../codegen/box/syntheticAccessors/kt48331.kt | 25 +++ .../box/syntheticAccessors/packagePrivate.kt | 16 ++ .../box/syntheticAccessors/protectedSuper.kt | 11 ++ .../anonymousObject/withInlineMethod.kt | 10 +- .../codegen/BlackBoxCodegenTestGenerated.java | 18 ++ .../IrBlackBoxCodegenTestGenerated.java | 18 ++ .../LightAnalysisModeTestGenerated.java | 15 ++ 15 files changed, 231 insertions(+), 102 deletions(-) create mode 100644 compiler/testData/codegen/box/syntheticAccessors/kt48331.kt create mode 100644 compiler/testData/codegen/box/syntheticAccessors/packagePrivate.kt create mode 100644 compiler/testData/codegen/box/syntheticAccessors/protectedSuper.kt 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 e332d7ea65d..31e61380f6b 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 @@ -41764,6 +41764,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/syntheticAccessors/kt21258_simple.kt"); } + @Test + @TestMetadata("kt48331.kt") + public void testKt48331() throws Exception { + runTest("compiler/testData/codegen/box/syntheticAccessors/kt48331.kt"); + } + @Test @TestMetadata("kt9717.kt") public void testKt9717() throws Exception { @@ -41788,12 +41794,24 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/syntheticAccessors/kt9958Interface.kt"); } + @Test + @TestMetadata("packagePrivate.kt") + public void testPackagePrivate() throws Exception { + runTest("compiler/testData/codegen/box/syntheticAccessors/packagePrivate.kt"); + } + @Test @TestMetadata("protectedFromLambda.kt") public void testProtectedFromLambda() throws Exception { runTest("compiler/testData/codegen/box/syntheticAccessors/protectedFromLambda.kt"); } + @Test + @TestMetadata("protectedSuper.kt") + public void testProtectedSuper() throws Exception { + runTest("compiler/testData/codegen/box/syntheticAccessors/protectedSuper.kt"); + } + @Test @TestMetadata("protectedSuperclassCompanionObjectMember.kt") public void testProtectedSuperclassCompanionObjectMember() throws Exception { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmCachedDeclarations.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmCachedDeclarations.kt index 23d717d4679..478bb3f7d6b 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmCachedDeclarations.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmCachedDeclarations.kt @@ -271,6 +271,9 @@ class JvmCachedDeclarations( parent = irClass overriddenSymbols = fakeOverride.overriddenSymbols copyParameterDeclarationsFrom(fakeOverride) + // The fake override's dispatch receiver has the same type as the real declaration's, + // i.e. some superclass of the current class. This is not good for accessibility checks. + dispatchReceiverParameter?.type = irClass.defaultType annotations = fakeOverride.annotations copyCorrespondingPropertyFrom(fakeOverride) } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt index 55ff1ee20c7..e35c7979419 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt @@ -381,7 +381,10 @@ class MethodSignatureMapper(private val context: JvmBackendContext) { internal fun mapToCallableMethod(expression: IrCall, caller: IrFunction?): IrCallableMethod { val callee = expression.symbol.owner val calleeParent = expression.superQualifierSymbol?.owner - ?: expression.dispatchReceiver?.type?.classOrNull?.owner + ?: expression.dispatchReceiver?.type?.classOrNull?.owner?.let { + // Calling Object class methods on interfaces is permitted, but they're not interface methods. + if (it.isJvmInterface && callee.isMethodOfAny()) context.irBuiltIns.anyClass.owner else it + } ?: callee.parentAsClass // Static call or type parameter val owner = typeMapper.mapOwner(calleeParent) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/AssertionLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/AssertionLowering.kt index 757731b8a07..e12016cfa66 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/AssertionLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/AssertionLowering.kt @@ -140,5 +140,8 @@ fun IrClass.buildAssertionsDisabledField(backendContext: JvmBackendContext, topL } } +fun IrField.isAssertionsDisabledField(context: JvmBackendContext) = + name.asString() == ASSERTIONS_DISABLED_FIELD_NAME && type == context.irBuiltIns.booleanType && isStatic + fun IrClass.hasAssertionsDisabledField(context: JvmBackendContext) = - fields.any { it.name.asString() == ASSERTIONS_DISABLED_FIELD_NAME && it.type == context.irBuiltIns.booleanType && it.isStatic } + fields.any { it.isAssertionsDisabledField(context) } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InheritedDefaultMethodsOnClassesLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InheritedDefaultMethodsOnClassesLowering.kt index ea9e12274c1..f7558a7a4a4 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InheritedDefaultMethodsOnClassesLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InheritedDefaultMethodsOnClassesLowering.kt @@ -30,8 +30,6 @@ import org.jetbrains.kotlin.ir.builders.irReturn import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrExpression -import org.jetbrains.kotlin.ir.expressions.IrTypeOperator -import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.* import org.jetbrains.kotlin.utils.addToStdlib.safeAs @@ -239,19 +237,7 @@ private class InterfaceObjectCallsLowering(val context: JvmBackendContext) : IrE if (resolved?.isMethodOfAny() != true) return super.visitCall(expression) val newSuperQualifierSymbol = context.irBuiltIns.anyClass.takeIf { expression.superQualifierSymbol != null } - return super.visitCall(irCall(expression, resolved, newSuperQualifierSymbol = newSuperQualifierSymbol).apply { - dispatchReceiver?.let { receiver -> - val receiverType = resolved.parentAsClass.defaultType - dispatchReceiver = IrTypeOperatorCallImpl( - receiver.startOffset, - receiver.endOffset, - receiverType, - IrTypeOperator.IMPLICIT_CAST, - receiverType, - receiver - ) - } - }) + return super.visitCall(irCall(expression, resolved, newSuperQualifierSymbol = newSuperQualifierSymbol)) } } 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 e0d16a83bb5..5889c85dceb 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 @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface import org.jetbrains.kotlin.backend.jvm.intrinsics.receiverAndArgs import org.jetbrains.kotlin.backend.jvm.ir.IrInlineReferenceLocator import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.hasMangledParameters +import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.descriptors.DescriptorVisibility import org.jetbrains.kotlin.descriptors.Modality @@ -34,6 +35,7 @@ import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name +import org.jetbrains.org.objectweb.asm.Opcodes internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrElementTransformerVoidWithContext(), FileLoweringPass { data class LambdaCallSite(val scope: IrDeclaration, val crossinline: Boolean) @@ -232,8 +234,7 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle // We have a protected member. // It is accessible from a synthetic proxy class (created by LambdaMetafactory) // if it belongs to the current class. - val outerClassInfo = getOuterClassInfo() ?: return false - return outerClassInfo.outerClass == owner.parentAsClass + return getScopeClassOrPackage() == owner.parentAsClass } override fun visitGetField(expression: IrGetField): IrExpression { @@ -707,9 +708,7 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle private fun IrSymbol.isAccessible(withSuper: Boolean, thisObjReference: IrClassSymbol?): 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 symbolOwner = owner - val declarationRaw = symbolOwner as IrDeclarationWithVisibility + val declarationRaw = owner as IrDeclarationWithVisibility // There is never a problem with visibility of inline functions, as those don't end up as Java entities if (declarationRaw is IrFunction && declarationRaw.isInline) return true @@ -717,85 +716,93 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle // Enum entry constructors are generated as package-private and are accessed only from corresponding enum class if (declarationRaw is IrConstructor && declarationRaw.constructedClass.isEnumEntry) return true - // `internal` maps to public and requires no accessor. - if (!withSuper && !declarationRaw.visibility.isPrivate && !declarationRaw.visibility.isProtected) return true + // Public declarations are already accessible. However, `super` calls are subclass-only. + val jvmVisibility = AsmUtil.getVisibilityAccessFlag(declarationRaw.visibility.delegate) + if (jvmVisibility == Opcodes.ACC_PUBLIC && !withSuper) return true // `toArray` is always accessible cause mapped to public functions - if (symbolOwner is IrSimpleFunction && (symbolOwner.isNonGenericToArray() || symbolOwner.isGenericToArray(context))) { - if (symbolOwner.parentAsClass.isCollectionSubClass) { - return true - } - } + if (declarationRaw is IrSimpleFunction && (declarationRaw.isNonGenericToArray() || declarationRaw.isGenericToArray(context)) && + declarationRaw.parentAsClass.isCollectionSubClass + ) return true - // EnumEntry constructors are always accessible (they are only called from the enclosing Enum class) - if (symbolOwner is IrConstructor && symbolOwner.parentClassOrNull?.isEnumEntry == true) - return true + // `$assertionsDisabled` is accessed only from the same class, even in an inline function + // (the inliner will generate it at the call site if necessary). + if (declarationRaw is IrField && declarationRaw.isAssertionsDisabledField(context)) return true val declaration = when (declarationRaw) { - is IrSimpleFunction -> - declarationRaw.resolveFakeOverride(allowAbstract = true) - ?: declarationRaw - is IrField -> { - val correspondingProperty = declarationRaw.correspondingPropertySymbol?.owner - if (correspondingProperty != null && correspondingProperty.isFakeOverride) { - val realProperty = correspondingProperty.resolveFakeOverride() - ?: throw AssertionError("No real override for ${correspondingProperty.render()}") - realProperty.backingField - ?: throw AssertionError( - "Fake override property ${correspondingProperty.render()} with backing field " + - "overrides a real property with no backing field: ${realProperty.render()}" - ) - } else { - declarationRaw - } - } - else -> - declarationRaw + is IrSimpleFunction -> declarationRaw.resolveFakeOverride(allowAbstract = true)!! + is IrField -> declarationRaw.resolveFakeOverride() + else -> declarationRaw } - // If local variables are accessible by Kotlin rules, they also are by Java rules. - val ownerClass = declaration.parent as? IrClass ?: return true - - val outerClassInfo = getOuterClassInfo() ?: return false - val outerClass = outerClassInfo.outerClass - val throughCrossinlineLambda = outerClassInfo.throughCrossinlineLambda - - val samePackage = ownerClass.getPackageFragment()?.fqName == outerClass.getPackageFragment()?.fqName - val fromSubclassOfReceiversClass = !throughCrossinlineLambda && - outerClass.isSubclassOf(ownerClass) && - (thisObjReference == null || outerClass.symbol.isSubtypeOfClass(thisObjReference)) + val ownerClass = declaration.parent as? IrClass ?: return true // locals are always accessible + val scopeClassOrPackage = getScopeClassOrPackage() ?: return false + val samePackage = ownerClass.getPackageFragment()?.fqName == scopeClassOrPackage.getPackageFragment()?.fqName return when { - declaration.visibility.isPrivate && (throughCrossinlineLambda || ownerClass != outerClass) -> false - declaration.visibility.isProtected && !samePackage && !fromSubclassOfReceiversClass -> false - withSuper && !fromSubclassOfReceiversClass -> false - else -> true + jvmVisibility == 0 /* package only */ -> samePackage + jvmVisibility == Opcodes.ACC_PRIVATE -> ownerClass == scopeClassOrPackage + // JVM `protected`, unlike Kotlin `protected`, permits accesses from the same package. + !withSuper && samePackage -> true + // Super calls and cross-package protected accesses are both only possible from a subclass of the declaration + // owner. Also, the target of a non-static call must be assignable to the current class. This is a verification + // constraint: https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.10.1.8 + else -> (scopeClassOrPackage is IrClass && scopeClassOrPackage.isSubclassOf(ownerClass)) && + (thisObjReference == null || thisObjReference.owner.isSubclassOf(scopeClassOrPackage)) } } - private class OuterClassInfo(val outerClass: IrClass, val throughCrossinlineLambda: Boolean) - - private fun getOuterClassInfo(): OuterClassInfo? { - var context = currentScope!!.irElement as IrDeclaration + // Get the class from which all accesses in the current scope will be done after bytecode generation. + // If the current scope is a crossinline lambda, this is not possible, as the lambda maybe inlined + // into some other class; in that case, get at least the package. + private fun getScopeClassOrPackage(): IrDeclarationContainer? { + var context = currentScope?.irElement var throughCrossinlineLambda = false - while (context !is IrClass) { + while (context is IrDeclaration) { val callSite = inlineLambdaToCallSite[context] - if (callSite != null) { - // For inline lambdas, we can navigate to the only call site directly. Crossinline lambdas might be inlined - // into other classes in the same package, so private/super require accessors anyway. - throughCrossinlineLambda = throughCrossinlineLambda || callSite.crossinline - context = callSite.scope - } else if (context is IrFunction && context.isInline) { - // Accesses from inline functions can actually be anywhere; even private inline functions can be - // inlined into a different class, e.g. a callable reference. For protected inline functions - // calling methods on `super` we also need an accessor to satisfy INVOKESPECIAL constraints. - // TODO scan nested classes for calls to private inline functions? - return null - } else { - context = context.parent as? IrDeclaration - ?: return null + when { + // Crossinline lambdas can be inlined into some other class in the same package. However, + // classes within crossinline lambdas should not be regenerated, so if we've already found + // a class *before* reaching this lambda, it's valid: + // class C { + // fun f() {} + // fun g() = inlineFunctionWithCrossinlineArgument { + // f() // this call is done in some unknown class within C's package + // object { val x = f() } // this call is done in C$g$1$1 + // } + // } + callSite != null -> throughCrossinlineLambda = throughCrossinlineLambda || callSite.crossinline + // Inline functions can be inlined into anywhere. Not even private inline functions are safe: + // class C { + // fun f() {} + // private inline fun g1() = f() // `f` is called from C? + // fun g2() = { g1() } // ...or from C$g2$1 in the same package? + // inline fun g3() = g1() // ...or from some other package that calls g3? + // } + // TODO: this has some weird effects for inline functions in local classes, e.g. they + // access the capture fields (package-private) through accessors; this may or may not + // be necessary - local types should in theory not be usable outside the current file. + context is IrFunction && context.isInline -> return null + // TODO: if this class is an object local to an inline function, it could be regenerated, + // so the scope depends on the declaration accessed (see KT-48508): + // class C { + // fun f1() + // inline fun inlineFun() = object { + // fun f2() {} + // fun g1() { + // f1() // this access can be anywhere + // f2() // can pretend this access is from C$foo$1 + // } + // } + // } + // Further complicating things, the accessor for `f1` cannot be in `C$foo$1`, as otherwise + // the accessor itself will be regenerated (and thus not work) at `inlineFun` call sites. + context is IrClass && !throughCrossinlineLambda -> return context } + // Inline lambdas have already been moved out to the containing class, but we still need to check + // the containing function (again, see above), so navigate there instead. + context = callSite?.scope ?: context.parent } - return OuterClassInfo(context, throughCrossinlineLambda) + return context as? IrPackageFragment } // monitorEnter/monitorExit are the only functions which are accessed "illegally" (see kotlin/util/Synchronized.kt). @@ -813,10 +820,18 @@ private fun IrClass.syntheticAccessorToSuperSuffix(): String = // TODO: change this to `fqNameUnsafe.asString().replace(".", "_")` as soon as we're ready to break compatibility with pre-KT-21178 code name.asString().hashCode().toString() -val DescriptorVisibility.isPrivate - get() = DescriptorVisibilities.isPrivate(this) +private fun IrField.resolveFakeOverride(): IrField { + val correspondingProperty = correspondingPropertySymbol?.owner + if (correspondingProperty == null || !correspondingProperty.isFakeOverride) + return this + val realProperty = correspondingProperty.resolveFakeOverride() + ?: throw AssertionError("No real override for ${correspondingProperty.render()}") + return realProperty.backingField + ?: throw AssertionError( + "Fake override property ${correspondingProperty.render()} with backing field " + + "overrides a real property with no backing field: ${realProperty.render()}" + ) +} -val DescriptorVisibility.isProtected - get() = this == DescriptorVisibilities.PROTECTED || - this == JavaDescriptorVisibilities.PROTECTED_AND_PACKAGE || - this == JavaDescriptorVisibilities.PROTECTED_STATIC_VISIBILITY +private val DescriptorVisibility.isProtected + get() = AsmUtil.getVisibilityAccessFlag(delegate) == Opcodes.ACC_PROTECTED diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/indy/LambdaMetafactoryArguments.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/indy/LambdaMetafactoryArguments.kt index 39173ca61da..b395b2f5b35 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/indy/LambdaMetafactoryArguments.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/indy/LambdaMetafactoryArguments.kt @@ -13,8 +13,8 @@ import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound import org.jetbrains.kotlin.backend.jvm.ir.getSingleAbstractMethod import org.jetbrains.kotlin.backend.jvm.ir.isCompiledToJvmDefault import org.jetbrains.kotlin.backend.jvm.lower.findInterfaceImplementation -import org.jetbrains.kotlin.backend.jvm.lower.isPrivate import org.jetbrains.kotlin.builtins.functions.BuiltInFunctionArity +import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.ir.builders.declarations.buildClass import org.jetbrains.kotlin.ir.builders.declarations.buildValueParameter @@ -91,7 +91,7 @@ internal class LambdaMetafactoryArgumentsBuilder( if (implFun.isInline) return null - if (implFun is IrConstructor && implFun.visibility.isPrivate) { + if (implFun is IrConstructor && DescriptorVisibilities.isPrivate(implFun.visibility)) { // Kotlin generates constructor accessors differently from Java. // TODO more precise accessibility check (see SyntheticAccessorLowering::isAccessible) return null diff --git a/compiler/testData/codegen/box/coroutines/javaInterop/objectWithSeveralSuspends.kt b/compiler/testData/codegen/box/coroutines/javaInterop/objectWithSeveralSuspends.kt index e18f4e0f1e9..99b657e016c 100644 --- a/compiler/testData/codegen/box/coroutines/javaInterop/objectWithSeveralSuspends.kt +++ b/compiler/testData/codegen/box/coroutines/javaInterop/objectWithSeveralSuspends.kt @@ -30,10 +30,6 @@ inline fun inlineMe(crossinline c: suspend () -> Unit) = object : SuspendRunnabl StateMachineChecker.suspendHere() StateMachineChecker.suspendHere() } - // TODO: call it from run1 - inline suspend fun inlineMeCapturing() { - c(); c() - } } inline fun inlineMe2(crossinline c: suspend () -> Unit) = inlineMe { c(); c() } diff --git a/compiler/testData/codegen/box/syntheticAccessors/kt48331.kt b/compiler/testData/codegen/box/syntheticAccessors/kt48331.kt new file mode 100644 index 00000000000..d728e3f5123 --- /dev/null +++ b/compiler/testData/codegen/box/syntheticAccessors/kt48331.kt @@ -0,0 +1,25 @@ +// TARGET_BACKEND: JVM +// FILE: foo.kt +package foo + +abstract class Base { + protected abstract fun foo(): String +} + +// FILE: bar.kt +import foo.* + +abstract class C : Base() { + class A : C() { + override fun foo() = "OK" + } + + class B(val x: C) : C() { + // Needs an accessor (`foo` is in another package and `x` is not assignable to `B`) + override fun foo() = x.foo() + + fun bar() = foo() + } +} + +fun box() = C.B(C.A()).bar() diff --git a/compiler/testData/codegen/box/syntheticAccessors/packagePrivate.kt b/compiler/testData/codegen/box/syntheticAccessors/packagePrivate.kt new file mode 100644 index 00000000000..a92fdb5c6fd --- /dev/null +++ b/compiler/testData/codegen/box/syntheticAccessors/packagePrivate.kt @@ -0,0 +1,16 @@ +// TARGET_BACKEND: JVM +// IGNORE_BACKEND: JVM +// FILE: x.kt +package x + +internal class C { + // `foo$default` generated as package-private (not protected): + private fun foo(result: String = "OK") = result + // this needs an accessor: + internal inline fun bar() = foo() +} + +// FILE: y.kt +import x.* + +fun box() = C().bar() diff --git a/compiler/testData/codegen/box/syntheticAccessors/protectedSuper.kt b/compiler/testData/codegen/box/syntheticAccessors/protectedSuper.kt new file mode 100644 index 00000000000..ab6592c6e43 --- /dev/null +++ b/compiler/testData/codegen/box/syntheticAccessors/protectedSuper.kt @@ -0,0 +1,11 @@ +// TARGET_BACKEND: JVM +open class C { + protected open fun foo() = "OK" +} + +class D : C() { + // same package, but `super` needs to be related by class hierarchy: + fun bar() = { super.foo() } +} + +fun box() = D().bar()() diff --git a/compiler/testData/codegen/boxInline/anonymousObject/withInlineMethod.kt b/compiler/testData/codegen/boxInline/anonymousObject/withInlineMethod.kt index 84c5d9d696e..91926ee70ce 100644 --- a/compiler/testData/codegen/boxInline/anonymousObject/withInlineMethod.kt +++ b/compiler/testData/codegen/boxInline/anonymousObject/withInlineMethod.kt @@ -1,3 +1,6 @@ +// IGNORE_BACKEND: JVM, JVM_IR +// IGNORE_BACKEND_FIR: JVM_IR +// IGNORE_BACKEND_MULTI_MODULE: JVM, JVM_IR, JVM_MULTI_MODULE_OLD_AGAINST_IR, JVM_MULTI_MODULE_IR_AGAINST_OLD // FILE: 1.kt package test @@ -6,10 +9,9 @@ interface I { } inline fun test(crossinline h: () -> String) = object : I { - // TODO: actually call g() in f() -- currently, the inliner fails to detect - // an inlined read of h's field because it uses a copy of `this` - // as a receiver - override fun f(): String = h() + // TODO: this does not work because the inliner is not correctly remapping the capture. + override fun f(): String = g() + // TODO: and this does not work in JVM_IR because there is a redundant accessor. inline fun g(): String = h() } diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index 24d4f840d93..87be82f0e90 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -41614,6 +41614,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/syntheticAccessors/kt21258_simple.kt"); } + @Test + @TestMetadata("kt48331.kt") + public void testKt48331() throws Exception { + runTest("compiler/testData/codegen/box/syntheticAccessors/kt48331.kt"); + } + @Test @TestMetadata("kt9717.kt") public void testKt9717() throws Exception { @@ -41638,12 +41644,24 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/syntheticAccessors/kt9958Interface.kt"); } + @Test + @TestMetadata("packagePrivate.kt") + public void testPackagePrivate() throws Exception { + runTest("compiler/testData/codegen/box/syntheticAccessors/packagePrivate.kt"); + } + @Test @TestMetadata("protectedFromLambda.kt") public void testProtectedFromLambda() throws Exception { runTest("compiler/testData/codegen/box/syntheticAccessors/protectedFromLambda.kt"); } + @Test + @TestMetadata("protectedSuper.kt") + public void testProtectedSuper() throws Exception { + runTest("compiler/testData/codegen/box/syntheticAccessors/protectedSuper.kt"); + } + @Test @TestMetadata("protectedSuperclassCompanionObjectMember.kt") public void testProtectedSuperclassCompanionObjectMember() throws Exception { 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 4897e92e245..2c652a8ab88 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 @@ -41764,6 +41764,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/syntheticAccessors/kt21258_simple.kt"); } + @Test + @TestMetadata("kt48331.kt") + public void testKt48331() throws Exception { + runTest("compiler/testData/codegen/box/syntheticAccessors/kt48331.kt"); + } + @Test @TestMetadata("kt9717.kt") public void testKt9717() throws Exception { @@ -41788,12 +41794,24 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/syntheticAccessors/kt9958Interface.kt"); } + @Test + @TestMetadata("packagePrivate.kt") + public void testPackagePrivate() throws Exception { + runTest("compiler/testData/codegen/box/syntheticAccessors/packagePrivate.kt"); + } + @Test @TestMetadata("protectedFromLambda.kt") public void testProtectedFromLambda() throws Exception { runTest("compiler/testData/codegen/box/syntheticAccessors/protectedFromLambda.kt"); } + @Test + @TestMetadata("protectedSuper.kt") + public void testProtectedSuper() throws Exception { + runTest("compiler/testData/codegen/box/syntheticAccessors/protectedSuper.kt"); + } + @Test @TestMetadata("protectedSuperclassCompanionObjectMember.kt") public void testProtectedSuperclassCompanionObjectMember() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 02f0e8fee15..d0d481ef365 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -33390,6 +33390,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) public static class SyntheticAccessors extends AbstractLightAnalysisModeTest { + @TestMetadata("packagePrivate.kt") + public void ignorePackagePrivate() throws Exception { + runTest("compiler/testData/codegen/box/syntheticAccessors/packagePrivate.kt"); + } + @TestMetadata("protectedSuperclassCompanionObjectMember.kt") public void ignoreProtectedSuperclassCompanionObjectMember() throws Exception { runTest("compiler/testData/codegen/box/syntheticAccessors/protectedSuperclassCompanionObjectMember.kt"); @@ -33473,6 +33478,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/syntheticAccessors/kt21258_simple.kt"); } + @TestMetadata("kt48331.kt") + public void testKt48331() throws Exception { + runTest("compiler/testData/codegen/box/syntheticAccessors/kt48331.kt"); + } + @TestMetadata("kt9717.kt") public void testKt9717() throws Exception { runTest("compiler/testData/codegen/box/syntheticAccessors/kt9717.kt"); @@ -33498,6 +33508,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/syntheticAccessors/protectedFromLambda.kt"); } + @TestMetadata("protectedSuper.kt") + public void testProtectedSuper() throws Exception { + runTest("compiler/testData/codegen/box/syntheticAccessors/protectedSuper.kt"); + } + @TestMetadata("superCallFromMultipleSubclasses.kt") public void testSuperCallFromMultipleSubclasses() throws Exception { runTest("compiler/testData/codegen/box/syntheticAccessors/superCallFromMultipleSubclasses.kt");