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
This commit is contained in:
+18
@@ -41764,6 +41764,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
|||||||
runTest("compiler/testData/codegen/box/syntheticAccessors/kt21258_simple.kt");
|
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
|
@Test
|
||||||
@TestMetadata("kt9717.kt")
|
@TestMetadata("kt9717.kt")
|
||||||
public void testKt9717() throws Exception {
|
public void testKt9717() throws Exception {
|
||||||
@@ -41788,12 +41794,24 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
|||||||
runTest("compiler/testData/codegen/box/syntheticAccessors/kt9958Interface.kt");
|
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
|
@Test
|
||||||
@TestMetadata("protectedFromLambda.kt")
|
@TestMetadata("protectedFromLambda.kt")
|
||||||
public void testProtectedFromLambda() throws Exception {
|
public void testProtectedFromLambda() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/syntheticAccessors/protectedFromLambda.kt");
|
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
|
@Test
|
||||||
@TestMetadata("protectedSuperclassCompanionObjectMember.kt")
|
@TestMetadata("protectedSuperclassCompanionObjectMember.kt")
|
||||||
public void testProtectedSuperclassCompanionObjectMember() throws Exception {
|
public void testProtectedSuperclassCompanionObjectMember() throws Exception {
|
||||||
|
|||||||
@@ -271,6 +271,9 @@ class JvmCachedDeclarations(
|
|||||||
parent = irClass
|
parent = irClass
|
||||||
overriddenSymbols = fakeOverride.overriddenSymbols
|
overriddenSymbols = fakeOverride.overriddenSymbols
|
||||||
copyParameterDeclarationsFrom(fakeOverride)
|
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
|
annotations = fakeOverride.annotations
|
||||||
copyCorrespondingPropertyFrom(fakeOverride)
|
copyCorrespondingPropertyFrom(fakeOverride)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-1
@@ -381,7 +381,10 @@ class MethodSignatureMapper(private val context: JvmBackendContext) {
|
|||||||
internal fun mapToCallableMethod(expression: IrCall, caller: IrFunction?): IrCallableMethod {
|
internal fun mapToCallableMethod(expression: IrCall, caller: IrFunction?): IrCallableMethod {
|
||||||
val callee = expression.symbol.owner
|
val callee = expression.symbol.owner
|
||||||
val calleeParent = expression.superQualifierSymbol?.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
|
?: callee.parentAsClass // Static call or type parameter
|
||||||
val owner = typeMapper.mapOwner(calleeParent)
|
val owner = typeMapper.mapOwner(calleeParent)
|
||||||
|
|
||||||
|
|||||||
+4
-1
@@ -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) =
|
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) }
|
||||||
|
|||||||
+1
-15
@@ -30,8 +30,6 @@ import org.jetbrains.kotlin.ir.builders.irReturn
|
|||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
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.util.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.*
|
import org.jetbrains.kotlin.ir.visitors.*
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
@@ -239,19 +237,7 @@ private class InterfaceObjectCallsLowering(val context: JvmBackendContext) : IrE
|
|||||||
if (resolved?.isMethodOfAny() != true)
|
if (resolved?.isMethodOfAny() != true)
|
||||||
return super.visitCall(expression)
|
return super.visitCall(expression)
|
||||||
val newSuperQualifierSymbol = context.irBuiltIns.anyClass.takeIf { expression.superQualifierSymbol != null }
|
val newSuperQualifierSymbol = context.irBuiltIns.anyClass.takeIf { expression.superQualifierSymbol != null }
|
||||||
return super.visitCall(irCall(expression, resolved, newSuperQualifierSymbol = newSuperQualifierSymbol).apply {
|
return super.visitCall(irCall(expression, resolved, newSuperQualifierSymbol = newSuperQualifierSymbol))
|
||||||
dispatchReceiver?.let { receiver ->
|
|
||||||
val receiverType = resolved.parentAsClass.defaultType
|
|
||||||
dispatchReceiver = IrTypeOperatorCallImpl(
|
|
||||||
receiver.startOffset,
|
|
||||||
receiver.endOffset,
|
|
||||||
receiverType,
|
|
||||||
IrTypeOperator.IMPLICIT_CAST,
|
|
||||||
receiverType,
|
|
||||||
receiver
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+90
-75
@@ -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.intrinsics.receiverAndArgs
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.IrInlineReferenceLocator
|
import org.jetbrains.kotlin.backend.jvm.ir.IrInlineReferenceLocator
|
||||||
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.hasMangledParameters
|
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.DescriptorVisibilities
|
||||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
|
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
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.load.java.JvmAbi
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||||
|
|
||||||
internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrElementTransformerVoidWithContext(), FileLoweringPass {
|
internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrElementTransformerVoidWithContext(), FileLoweringPass {
|
||||||
data class LambdaCallSite(val scope: IrDeclaration, val crossinline: Boolean)
|
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.
|
// We have a protected member.
|
||||||
// It is accessible from a synthetic proxy class (created by LambdaMetafactory)
|
// It is accessible from a synthetic proxy class (created by LambdaMetafactory)
|
||||||
// if it belongs to the current class.
|
// if it belongs to the current class.
|
||||||
val outerClassInfo = getOuterClassInfo() ?: return false
|
return getScopeClassOrPackage() == owner.parentAsClass
|
||||||
return outerClassInfo.outerClass == owner.parentAsClass
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitGetField(expression: IrGetField): IrExpression {
|
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 {
|
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.
|
/// 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.
|
/// This function needs to single out those cases where Java accessibility rules differ from Kotlin's.
|
||||||
|
val declarationRaw = owner as IrDeclarationWithVisibility
|
||||||
val symbolOwner = owner
|
|
||||||
val declarationRaw = symbolOwner as IrDeclarationWithVisibility
|
|
||||||
|
|
||||||
// There is never a problem with visibility of inline functions, as those don't end up as Java entities
|
// 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
|
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
|
// 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
|
if (declarationRaw is IrConstructor && declarationRaw.constructedClass.isEnumEntry) return true
|
||||||
|
|
||||||
// `internal` maps to public and requires no accessor.
|
// Public declarations are already accessible. However, `super` calls are subclass-only.
|
||||||
if (!withSuper && !declarationRaw.visibility.isPrivate && !declarationRaw.visibility.isProtected) return true
|
val jvmVisibility = AsmUtil.getVisibilityAccessFlag(declarationRaw.visibility.delegate)
|
||||||
|
if (jvmVisibility == Opcodes.ACC_PUBLIC && !withSuper) return true
|
||||||
|
|
||||||
// `toArray` is always accessible cause mapped to public functions
|
// `toArray` is always accessible cause mapped to public functions
|
||||||
if (symbolOwner is IrSimpleFunction && (symbolOwner.isNonGenericToArray() || symbolOwner.isGenericToArray(context))) {
|
if (declarationRaw is IrSimpleFunction && (declarationRaw.isNonGenericToArray() || declarationRaw.isGenericToArray(context)) &&
|
||||||
if (symbolOwner.parentAsClass.isCollectionSubClass) {
|
declarationRaw.parentAsClass.isCollectionSubClass
|
||||||
return true
|
) return true
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// EnumEntry constructors are always accessible (they are only called from the enclosing Enum class)
|
// `$assertionsDisabled` is accessed only from the same class, even in an inline function
|
||||||
if (symbolOwner is IrConstructor && symbolOwner.parentClassOrNull?.isEnumEntry == true)
|
// (the inliner will generate it at the call site if necessary).
|
||||||
return true
|
if (declarationRaw is IrField && declarationRaw.isAssertionsDisabledField(context)) return true
|
||||||
|
|
||||||
val declaration = when (declarationRaw) {
|
val declaration = when (declarationRaw) {
|
||||||
is IrSimpleFunction ->
|
is IrSimpleFunction -> declarationRaw.resolveFakeOverride(allowAbstract = true)!!
|
||||||
declarationRaw.resolveFakeOverride(allowAbstract = true)
|
is IrField -> declarationRaw.resolveFakeOverride()
|
||||||
?: declarationRaw
|
else -> 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If local variables are accessible by Kotlin rules, they also are by Java rules.
|
val ownerClass = declaration.parent as? IrClass ?: return true // locals are always accessible
|
||||||
val ownerClass = declaration.parent as? IrClass ?: return true
|
val scopeClassOrPackage = getScopeClassOrPackage() ?: return false
|
||||||
|
val samePackage = ownerClass.getPackageFragment()?.fqName == scopeClassOrPackage.getPackageFragment()?.fqName
|
||||||
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))
|
|
||||||
return when {
|
return when {
|
||||||
declaration.visibility.isPrivate && (throughCrossinlineLambda || ownerClass != outerClass) -> false
|
jvmVisibility == 0 /* package only */ -> samePackage
|
||||||
declaration.visibility.isProtected && !samePackage && !fromSubclassOfReceiversClass -> false
|
jvmVisibility == Opcodes.ACC_PRIVATE -> ownerClass == scopeClassOrPackage
|
||||||
withSuper && !fromSubclassOfReceiversClass -> false
|
// JVM `protected`, unlike Kotlin `protected`, permits accesses from the same package.
|
||||||
else -> true
|
!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)
|
// 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
|
||||||
private fun getOuterClassInfo(): OuterClassInfo? {
|
// into some other class; in that case, get at least the package.
|
||||||
var context = currentScope!!.irElement as IrDeclaration
|
private fun getScopeClassOrPackage(): IrDeclarationContainer? {
|
||||||
|
var context = currentScope?.irElement
|
||||||
var throughCrossinlineLambda = false
|
var throughCrossinlineLambda = false
|
||||||
while (context !is IrClass) {
|
while (context is IrDeclaration) {
|
||||||
val callSite = inlineLambdaToCallSite[context]
|
val callSite = inlineLambdaToCallSite[context]
|
||||||
if (callSite != null) {
|
when {
|
||||||
// For inline lambdas, we can navigate to the only call site directly. Crossinline lambdas might be inlined
|
// Crossinline lambdas can be inlined into some other class in the same package. However,
|
||||||
// into other classes in the same package, so private/super require accessors anyway.
|
// classes within crossinline lambdas should not be regenerated, so if we've already found
|
||||||
throughCrossinlineLambda = throughCrossinlineLambda || callSite.crossinline
|
// a class *before* reaching this lambda, it's valid:
|
||||||
context = callSite.scope
|
// class C {
|
||||||
} else if (context is IrFunction && context.isInline) {
|
// fun f() {}
|
||||||
// Accesses from inline functions can actually be anywhere; even private inline functions can be
|
// fun g() = inlineFunctionWithCrossinlineArgument {
|
||||||
// inlined into a different class, e.g. a callable reference. For protected inline functions
|
// f() // this call is done in some unknown class within C's package
|
||||||
// calling methods on `super` we also need an accessor to satisfy INVOKESPECIAL constraints.
|
// object { val x = f() } // this call is done in C$g$1$1
|
||||||
// TODO scan nested classes for calls to private inline functions?
|
// }
|
||||||
return null
|
// }
|
||||||
} else {
|
callSite != null -> throughCrossinlineLambda = throughCrossinlineLambda || callSite.crossinline
|
||||||
context = context.parent as? IrDeclaration
|
// Inline functions can be inlined into anywhere. Not even private inline functions are safe:
|
||||||
?: return null
|
// 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).
|
// 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
|
// 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()
|
name.asString().hashCode().toString()
|
||||||
|
|
||||||
val DescriptorVisibility.isPrivate
|
private fun IrField.resolveFakeOverride(): IrField {
|
||||||
get() = DescriptorVisibilities.isPrivate(this)
|
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
|
private val DescriptorVisibility.isProtected
|
||||||
get() = this == DescriptorVisibilities.PROTECTED ||
|
get() = AsmUtil.getVisibilityAccessFlag(delegate) == Opcodes.ACC_PROTECTED
|
||||||
this == JavaDescriptorVisibilities.PROTECTED_AND_PACKAGE ||
|
|
||||||
this == JavaDescriptorVisibilities.PROTECTED_STATIC_VISIBILITY
|
|
||||||
|
|||||||
+2
-2
@@ -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.getSingleAbstractMethod
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.isCompiledToJvmDefault
|
import org.jetbrains.kotlin.backend.jvm.ir.isCompiledToJvmDefault
|
||||||
import org.jetbrains.kotlin.backend.jvm.lower.findInterfaceImplementation
|
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.builtins.functions.BuiltInFunctionArity
|
||||||
|
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.buildClass
|
import org.jetbrains.kotlin.ir.builders.declarations.buildClass
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.buildValueParameter
|
import org.jetbrains.kotlin.ir.builders.declarations.buildValueParameter
|
||||||
@@ -91,7 +91,7 @@ internal class LambdaMetafactoryArgumentsBuilder(
|
|||||||
if (implFun.isInline)
|
if (implFun.isInline)
|
||||||
return null
|
return null
|
||||||
|
|
||||||
if (implFun is IrConstructor && implFun.visibility.isPrivate) {
|
if (implFun is IrConstructor && DescriptorVisibilities.isPrivate(implFun.visibility)) {
|
||||||
// Kotlin generates constructor accessors differently from Java.
|
// Kotlin generates constructor accessors differently from Java.
|
||||||
// TODO more precise accessibility check (see SyntheticAccessorLowering::isAccessible)
|
// TODO more precise accessibility check (see SyntheticAccessorLowering::isAccessible)
|
||||||
return null
|
return null
|
||||||
|
|||||||
-4
@@ -30,10 +30,6 @@ inline fun inlineMe(crossinline c: suspend () -> Unit) = object : SuspendRunnabl
|
|||||||
StateMachineChecker.suspendHere()
|
StateMachineChecker.suspendHere()
|
||||||
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() }
|
inline fun inlineMe2(crossinline c: suspend () -> Unit) = inlineMe { c(); c() }
|
||||||
|
|||||||
@@ -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()
|
||||||
@@ -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()
|
||||||
@@ -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()()
|
||||||
@@ -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
|
// FILE: 1.kt
|
||||||
package test
|
package test
|
||||||
|
|
||||||
@@ -6,10 +9,9 @@ interface I {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline fun test(crossinline h: () -> String) = object : I {
|
inline fun test(crossinline h: () -> String) = object : I {
|
||||||
// TODO: actually call g() in f() -- currently, the inliner fails to detect
|
// TODO: this does not work because the inliner is not correctly remapping the capture.
|
||||||
// an inlined read of h's field because it uses a copy of `this`
|
override fun f(): String = g()
|
||||||
// as a receiver
|
// TODO: and this does not work in JVM_IR because there is a redundant accessor.
|
||||||
override fun f(): String = h()
|
|
||||||
inline fun g(): String = h()
|
inline fun g(): String = h()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+18
@@ -41614,6 +41614,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
runTest("compiler/testData/codegen/box/syntheticAccessors/kt21258_simple.kt");
|
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
|
@Test
|
||||||
@TestMetadata("kt9717.kt")
|
@TestMetadata("kt9717.kt")
|
||||||
public void testKt9717() throws Exception {
|
public void testKt9717() throws Exception {
|
||||||
@@ -41638,12 +41644,24 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
runTest("compiler/testData/codegen/box/syntheticAccessors/kt9958Interface.kt");
|
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
|
@Test
|
||||||
@TestMetadata("protectedFromLambda.kt")
|
@TestMetadata("protectedFromLambda.kt")
|
||||||
public void testProtectedFromLambda() throws Exception {
|
public void testProtectedFromLambda() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/syntheticAccessors/protectedFromLambda.kt");
|
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
|
@Test
|
||||||
@TestMetadata("protectedSuperclassCompanionObjectMember.kt")
|
@TestMetadata("protectedSuperclassCompanionObjectMember.kt")
|
||||||
public void testProtectedSuperclassCompanionObjectMember() throws Exception {
|
public void testProtectedSuperclassCompanionObjectMember() throws Exception {
|
||||||
|
|||||||
+18
@@ -41764,6 +41764,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
runTest("compiler/testData/codegen/box/syntheticAccessors/kt21258_simple.kt");
|
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
|
@Test
|
||||||
@TestMetadata("kt9717.kt")
|
@TestMetadata("kt9717.kt")
|
||||||
public void testKt9717() throws Exception {
|
public void testKt9717() throws Exception {
|
||||||
@@ -41788,12 +41794,24 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
runTest("compiler/testData/codegen/box/syntheticAccessors/kt9958Interface.kt");
|
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
|
@Test
|
||||||
@TestMetadata("protectedFromLambda.kt")
|
@TestMetadata("protectedFromLambda.kt")
|
||||||
public void testProtectedFromLambda() throws Exception {
|
public void testProtectedFromLambda() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/syntheticAccessors/protectedFromLambda.kt");
|
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
|
@Test
|
||||||
@TestMetadata("protectedSuperclassCompanionObjectMember.kt")
|
@TestMetadata("protectedSuperclassCompanionObjectMember.kt")
|
||||||
public void testProtectedSuperclassCompanionObjectMember() throws Exception {
|
public void testProtectedSuperclassCompanionObjectMember() throws Exception {
|
||||||
|
|||||||
+15
@@ -33390,6 +33390,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
public static class SyntheticAccessors extends AbstractLightAnalysisModeTest {
|
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")
|
@TestMetadata("protectedSuperclassCompanionObjectMember.kt")
|
||||||
public void ignoreProtectedSuperclassCompanionObjectMember() throws Exception {
|
public void ignoreProtectedSuperclassCompanionObjectMember() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/syntheticAccessors/protectedSuperclassCompanionObjectMember.kt");
|
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");
|
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")
|
@TestMetadata("kt9717.kt")
|
||||||
public void testKt9717() throws Exception {
|
public void testKt9717() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/syntheticAccessors/kt9717.kt");
|
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");
|
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")
|
@TestMetadata("superCallFromMultipleSubclasses.kt")
|
||||||
public void testSuperCallFromMultipleSubclasses() throws Exception {
|
public void testSuperCallFromMultipleSubclasses() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/syntheticAccessors/superCallFromMultipleSubclasses.kt");
|
runTest("compiler/testData/codegen/box/syntheticAccessors/superCallFromMultipleSubclasses.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user