Use nearest Java super qualifier for fields in IR converter

Related to KT-49507
This commit is contained in:
Mikhail Glukhikh
2022-06-15 14:45:59 +02:00
committed by Space
parent 8ae47d4c4d
commit fa914f20a4
7 changed files with 34 additions and 20 deletions
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.fir.backend.generators package org.jetbrains.kotlin.fir.backend.generators
import org.jetbrains.kotlin.KtFakeSourceElementKind import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.backend.* import org.jetbrains.kotlin.fir.backend.*
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
@@ -265,14 +266,15 @@ class CallAndReferenceGenerator(
val ownContainingClass = typeRef.toIrType().classifierOrNull?.owner as? IrClass ?: return null val ownContainingClass = typeRef.toIrType().classifierOrNull?.owner as? IrClass ?: return null
// For static field, we shouldn't unwrap fake override in any case // For static field, we shouldn't unwrap fake override in any case
if (fieldSymbol.owner.isStatic) return ownContainingClass.symbol if (fieldSymbol.owner.isStatic) return ownContainingClass.symbol
// This means own containing class exposes original containing class, which is possible only in Java (Kotlin forbids it) // Find first Java super class to avoid possible visibility exposure & separate compilation problems
// In this case we take own containing class as qualifier symbol to avoid visibility problems (see testKt48954 as an example) var superQualifierClass = ownContainingClass
// Otherwise we should take original containing class to avoid possible clash with Kotlin backing field while (!superQualifierClass.isFromJava() && superQualifierClass !== originalContainingClass) {
if (ownContainingClass.visibility.compareTo( superQualifierClass = superQualifierClass.superTypes.find {
originalContainingClass.visibility val kind = it.getClass()?.kind
).let { it == null || it > 0 } kind == ClassKind.CLASS || kind == ClassKind.ENUM_CLASS
) return ownContainingClass.symbol }?.getClass() ?: break
return originalContainingClass.symbol }
return superQualifierClass.symbol
} }
private fun FirExpression.superQualifierSymbol(): IrClassSymbol? { private fun FirExpression.superQualifierSymbol(): IrClassSymbol? {
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.psi2ir.generators
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB
import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
@@ -36,6 +37,7 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
import org.jetbrains.kotlin.resolve.descriptorUtil.classValueType import org.jetbrains.kotlin.resolve.descriptorUtil.classValueType
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
class CallGenerator(statementGenerator: StatementGenerator) : StatementGeneratorExtension(statementGenerator) { class CallGenerator(statementGenerator: StatementGenerator) : StatementGeneratorExtension(statementGenerator) {
@@ -198,14 +200,14 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator
// For static field, we shouldn't unwrap fake override in any case // For static field, we shouldn't unwrap fake override in any case
if (dispatchReceiverParameter == null) return ownContainingClass if (dispatchReceiverParameter == null) return ownContainingClass
val originalContainingClass = resolveFakeOverride().containingDeclaration as? ClassDescriptor ?: return ownContainingClass val originalContainingClass = resolveFakeOverride().containingDeclaration as? ClassDescriptor ?: return ownContainingClass
// This means own containing class exposes original containing class, which is possible only in Java (Kotlin forbids it) // Find first Java super class to avoid possible visibility exposure & separate compilation problems
// In this case we take own containing class as qualifier symbol to avoid visibility problems (see testKt48954 as an example) var containingClassForField = ownContainingClass
// Otherwise we should take original containing class to avoid possible clash with Kotlin backing field while (context.extensions.computeExternalDeclarationOrigin(containingClassForField) != IR_EXTERNAL_JAVA_DECLARATION_STUB &&
if (ownContainingClass.visibility.compareTo( containingClassForField !== originalContainingClass
originalContainingClass.visibility ) {
).let { it == null || it > 0 } containingClassForField = containingClassForField.getSuperClassNotAny() ?: break
) return ownContainingClass }
return originalContainingClass return containingClassForField
} }
private fun generatePropertyGetterCall( private fun generatePropertyGetterCall(
+10
View File
@@ -16,8 +16,18 @@ open class Kotlin2 : Java2() {
fun test1(j: Kotlin2) = j.f fun test1(j: Kotlin2) = j.f
// JVM_IR_TEMPLATES
// @Kotlin2.class:
// 2 GETFIELD Java2.f : I
// JVM_IR_TEMPLATES
// @TestKt.class:
// 2 GETFIELD Java2.f : I
// JVM_TEMPLATES
// @Kotlin2.class: // @Kotlin2.class:
// 1 GETFIELD Java2.f : I // 1 GETFIELD Java2.f : I
// JVM_TEMPLATES
// @TestKt.class: // @TestKt.class:
// 1 GETFIELD Java2.f : I // 1 GETFIELD Java2.f : I
@@ -13,7 +13,7 @@ class C : B {
fun f(): @FlexibleNullability String? { fun f(): @FlexibleNullability String? {
return eval<@FlexibleNullability String?>(f = local fun <anonymous>(): @FlexibleNullability String? { return eval<@FlexibleNullability String?>(f = local fun <anonymous>(): @FlexibleNullability String? {
return <this>(super<A>).#x return <this>(super<B>).#x
} }
) )
} }
@@ -13,7 +13,7 @@ class C : B {
fun f(): @FlexibleNullability String? { fun f(): @FlexibleNullability String? {
return eval<@FlexibleNullability String?>(f = local fun <anonymous>(): @FlexibleNullability String? { return eval<@FlexibleNullability String?>(f = local fun <anonymous>(): @FlexibleNullability String? {
return <this>(super<A>).#x return <this>(super<B>).#x
} }
) )
} }
@@ -1,6 +1,6 @@
fun foo(movedPaths: MutableList<Couple<FilePath>>) { fun foo(movedPaths: MutableList<Couple<FilePath>>) {
movedPaths.forEach<Couple<FilePath>>(action = local fun <anonymous>(it: Couple<FilePath>) { movedPaths.forEach<Couple<FilePath>>(action = local fun <anonymous>(it: Couple<FilePath>) {
it(super<Pair>).#second.getName() /*~> Unit */ it(super<Couple>).#second.getName() /*~> Unit */
} }
) )
} }
@@ -1,6 +1,6 @@
fun foo(movedPaths: MutableList<Couple<FilePath>>) { fun foo(movedPaths: MutableList<Couple<FilePath>>) {
movedPaths.forEach<Couple<FilePath>>(action = local fun <anonymous>(it: Couple<FilePath>) { movedPaths.forEach<Couple<FilePath>>(action = local fun <anonymous>(it: Couple<FilePath>) {
it(super<Pair>).#second /*!! FilePath */.getName() /*~> Unit */ it(super<Couple>).#second /*!! FilePath */.getName() /*~> Unit */
} }
) )
} }