FIR2IR: support static fake overrides for fields (related to KT-53441)
#KT-54921 Fixed
This commit is contained in:
committed by
Space Team
parent
6979271998
commit
c698d060c6
@@ -181,8 +181,8 @@ context(Fir2IrComponents)
|
||||
fun FirReference.toSymbolForCall(
|
||||
dispatchReceiver: FirExpression,
|
||||
conversionScope: Fir2IrConversionScope,
|
||||
explicitReceiver: FirExpression?,
|
||||
preferGetter: Boolean = true,
|
||||
explicitReceiver: FirExpression? = null,
|
||||
isDelegate: Boolean = false,
|
||||
isReference: Boolean = false
|
||||
): IrSymbol? {
|
||||
@@ -278,7 +278,7 @@ private fun FirCallableSymbol<*>.toSymbolForCall(
|
||||
|
||||
is FirFunctionSymbol<*> -> declarationStorage.getIrFunctionSymbol(this, fakeOverrideOwnerLookupTag)
|
||||
is FirPropertySymbol -> declarationStorage.getIrPropertySymbol(this, fakeOverrideOwnerLookupTag)
|
||||
is FirFieldSymbol -> declarationStorage.getIrFieldSymbol(this)
|
||||
is FirFieldSymbol -> declarationStorage.getIrFieldSymbol(this, fakeOverrideOwnerLookupTag)
|
||||
is FirBackingFieldSymbol -> declarationStorage.getIrBackingFieldSymbol(this)
|
||||
is FirDelegateFieldSymbol -> declarationStorage.getIrDelegateFieldSymbol(this)
|
||||
is FirVariableSymbol<*> -> declarationStorage.getIrValueSymbol(this)
|
||||
|
||||
+57
-14
@@ -51,6 +51,7 @@ import org.jetbrains.kotlin.ir.types.IrErrorType
|
||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.SpecialNames
|
||||
@@ -108,6 +109,8 @@ class Fir2IrDeclarationStorage(
|
||||
|
||||
private val fieldCache = ConcurrentHashMap<FirField, IrField>()
|
||||
|
||||
private val fieldStaticOverrideCache = ConcurrentHashMap<Pair<Name, ClassId>, IrField>()
|
||||
|
||||
private val localStorage by threadLocal { Fir2IrLocalStorage() }
|
||||
|
||||
private fun areCompatible(firFunction: FirFunction, irFunction: IrFunction): Boolean {
|
||||
@@ -1014,7 +1017,22 @@ class Fir2IrDeclarationStorage(
|
||||
return fakeOverridesInClass[irClass]?.get(callableDeclaration)
|
||||
}
|
||||
|
||||
fun getCachedIrField(field: FirField): IrField? = fieldCache[field]
|
||||
fun getCachedIrDelegateOrBackingField(field: FirField): IrField? = fieldCache[field]
|
||||
|
||||
fun getCachedIrField(
|
||||
field: FirField,
|
||||
// Always should be null for non-static
|
||||
// For static null means "take containing class instead"
|
||||
staticFakeOverrideOwnerLookupTag: ConeClassLikeLookupTag?,
|
||||
): IrField? {
|
||||
val classId = (staticFakeOverrideOwnerLookupTag ?: field.containingClassLookupTag())?.classId
|
||||
if (classId == null || !field.isStatic ||
|
||||
!field.isSubstitutionOrIntersectionOverride && staticFakeOverrideOwnerLookupTag == field.containingClassLookupTag()
|
||||
) {
|
||||
return fieldCache[field]
|
||||
}
|
||||
return fieldStaticOverrideCache[field.name to classId]
|
||||
}
|
||||
|
||||
fun createIrFieldAndDelegatedMembers(field: FirField, owner: FirClass, irClass: IrClass): IrField? {
|
||||
// Either take a corresponding constructor property backing field,
|
||||
@@ -1045,22 +1063,24 @@ class Fir2IrDeclarationStorage(
|
||||
}
|
||||
}
|
||||
}
|
||||
val irField = createIrField(
|
||||
return createIrField(
|
||||
field,
|
||||
irParent = irClass,
|
||||
typeRef = initializer?.typeRef ?: field.returnTypeRef,
|
||||
origin = IrDeclarationOrigin.DELEGATE
|
||||
)
|
||||
irField.setAndModifyParent(irClass)
|
||||
return irField
|
||||
}
|
||||
|
||||
private fun createIrField(
|
||||
internal fun createIrField(
|
||||
field: FirField,
|
||||
irParent: IrDeclarationParent?,
|
||||
typeRef: FirTypeRef = field.returnTypeRef,
|
||||
origin: IrDeclarationOrigin = IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB
|
||||
): IrField = convertCatching(field) {
|
||||
val type = typeRef.toIrType()
|
||||
val signature = signatureComposer.composeSignature(field)
|
||||
val classId = (irParent as? IrClass)?.classId
|
||||
val containingClass = classId?.let { ConeClassLikeLookupTagImpl(it) }
|
||||
val signature = signatureComposer.composeSignature(field, containingClass)
|
||||
return field.convertWithOffsets { startOffset, endOffset ->
|
||||
if (signature != null) {
|
||||
symbolTable.declareField(
|
||||
@@ -1083,11 +1103,18 @@ class Fir2IrDeclarationStorage(
|
||||
isStatic = field.isStatic
|
||||
)
|
||||
}.apply {
|
||||
fieldCache[field] = this
|
||||
if (classId == null || !field.isStatic ||
|
||||
!field.isSubstitutionOrIntersectionOverride && classId == field.containingClassLookupTag()?.classId
|
||||
) {
|
||||
fieldCache[field] = this
|
||||
} else {
|
||||
fieldStaticOverrideCache[field.name to classId] = this
|
||||
}
|
||||
val initializer = field.initializer
|
||||
if (initializer is FirConstExpression<*>) {
|
||||
this.initializer = factory.createExpressionBody(initializer.toIrConst(type))
|
||||
}
|
||||
setAndModifyParent(irParent)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1513,16 +1540,32 @@ class Fir2IrDeclarationStorage(
|
||||
else -> parentOrigin
|
||||
}
|
||||
|
||||
fun getIrFieldSymbol(firFieldSymbol: FirFieldSymbol): IrFieldSymbol {
|
||||
fun getIrFieldSymbol(
|
||||
firFieldSymbol: FirFieldSymbol,
|
||||
fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null
|
||||
): IrFieldSymbol {
|
||||
val fir = firFieldSymbol.fir
|
||||
val irField = fieldCache[fir] ?: run {
|
||||
// In case of type parameters from the parent as the field's return type, find the parent ahead to cache type parameters.
|
||||
val irParent = findIrParent(fir)
|
||||
createIrField(fir).apply {
|
||||
setAndModifyParent(irParent)
|
||||
val unmatchedOwner = fakeOverrideOwnerLookupTag != null && fakeOverrideOwnerLookupTag != firFieldSymbol.containingClassLookupTag()
|
||||
if (!fir.isStatic || !unmatchedOwner) {
|
||||
fieldCache[fir]?.let { return it.symbol }
|
||||
}
|
||||
|
||||
if (fir.isStatic) {
|
||||
generateLazyFakeOverrides(fir.name, fakeOverrideOwnerLookupTag)
|
||||
if (fakeOverrideOwnerLookupTag != null && fakeOverrideOwnerLookupTag !is ConeClassLookupTagWithFixedSymbol) {
|
||||
getCachedIrField(fir, fakeOverrideOwnerLookupTag)?.let {
|
||||
return it.symbol
|
||||
}
|
||||
}
|
||||
}
|
||||
return irField.symbol
|
||||
// In case of type parameters from the parent as the field's return type, find the parent ahead to cache type parameters.
|
||||
val irParent = findIrParent(fir)
|
||||
|
||||
val unwrapped = fir.unwrapFakeOverrides()
|
||||
if (unwrapped !== fir) {
|
||||
return getIrFieldSymbol(unwrapped.symbol)
|
||||
}
|
||||
return createIrField(fir, irParent).symbol
|
||||
}
|
||||
|
||||
fun getIrBackingFieldSymbol(firBackingFieldSymbol: FirBackingFieldSymbol): IrSymbol {
|
||||
|
||||
@@ -79,7 +79,7 @@ class Fir2IrVisitor(
|
||||
|
||||
override fun visitField(field: FirField, data: Any?): IrField {
|
||||
if (field.isSynthetic) {
|
||||
return declarationStorage.getCachedIrField(field)!!.apply {
|
||||
return declarationStorage.getCachedIrDelegateOrBackingField(field)!!.apply {
|
||||
// If this is a property backing field, then it has no separate initializer,
|
||||
// so we shouldn't convert it
|
||||
if (correspondingPropertySymbol == null) {
|
||||
|
||||
+4
-1
@@ -557,7 +557,10 @@ class CallAndReferenceGenerator(
|
||||
}
|
||||
|
||||
val symbol = calleeReference.toSymbolForCall(
|
||||
variableAssignment.dispatchReceiver, conversionScope, preferGetter = false
|
||||
variableAssignment.dispatchReceiver,
|
||||
conversionScope,
|
||||
explicitReceiver = variableAssignment.explicitReceiver,
|
||||
preferGetter = false,
|
||||
)
|
||||
val origin = variableAssignment.getIrAssignmentOrigin()
|
||||
|
||||
|
||||
+57
-22
@@ -19,9 +19,11 @@ import org.jetbrains.kotlin.fir.scopes.impl.FirFakeOverrideGenerator
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFieldSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.isStatic
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
@@ -39,6 +41,7 @@ class FakeOverrideGenerator(
|
||||
|
||||
private val baseFunctionSymbols = mutableMapOf<IrFunction, List<FirNamedFunctionSymbol>>()
|
||||
private val basePropertySymbols = mutableMapOf<IrProperty, List<FirPropertySymbol>>()
|
||||
private val baseStaticFieldSymbols = mutableMapOf<IrField, List<FirFieldSymbol>>()
|
||||
|
||||
private fun IrSimpleFunction.withFunction(f: IrSimpleFunction.() -> Unit): IrSimpleFunction {
|
||||
return conversionScope.withFunction(this, f)
|
||||
@@ -130,29 +133,61 @@ class FakeOverrideGenerator(
|
||||
)
|
||||
}
|
||||
|
||||
useSiteOrStaticScope.processPropertiesByName(name) { propertySymbol ->
|
||||
createFakeOverriddenIfNeeded(
|
||||
firClass, irClass, isLocal, propertySymbol,
|
||||
declarationStorage::getCachedIrProperty,
|
||||
declarationStorage::createIrProperty,
|
||||
createFakeOverrideSymbol = { firProperty, callableSymbol ->
|
||||
val symbolForOverride = FirFakeOverrideGenerator.createSymbolForSubstitutionOverride(callableSymbol, firClass.symbol.classId)
|
||||
FirFakeOverrideGenerator.createSubstitutionOverrideProperty(
|
||||
session, symbolForOverride, firProperty,
|
||||
newDispatchReceiverType = firClass.defaultType(),
|
||||
isExpect = (firClass as? FirRegularClass)?.isExpect == true
|
||||
useSiteOrStaticScope.processPropertiesByName(name) { propertyOrFieldSymbol ->
|
||||
when (propertyOrFieldSymbol) {
|
||||
is FirPropertySymbol -> {
|
||||
createFakeOverriddenIfNeeded(
|
||||
firClass, irClass, isLocal, propertyOrFieldSymbol,
|
||||
declarationStorage::getCachedIrProperty,
|
||||
declarationStorage::createIrProperty,
|
||||
createFakeOverrideSymbol = { firProperty, callableSymbol ->
|
||||
val symbolForOverride =
|
||||
FirFakeOverrideGenerator.createSymbolForSubstitutionOverride(callableSymbol, firClass.symbol.classId)
|
||||
FirFakeOverrideGenerator.createSubstitutionOverrideProperty(
|
||||
session, symbolForOverride, firProperty,
|
||||
newDispatchReceiverType = firClass.defaultType(),
|
||||
isExpect = (firClass as? FirRegularClass)?.isExpect == true
|
||||
)
|
||||
},
|
||||
basePropertySymbols,
|
||||
result,
|
||||
containsErrorTypes = { irProperty ->
|
||||
irProperty.backingField?.type?.containsErrorType() == true ||
|
||||
irProperty.getter?.returnType?.containsErrorType() == true
|
||||
},
|
||||
realDeclarationSymbols,
|
||||
FirTypeScope::getDirectOverriddenProperties,
|
||||
useSiteOrStaticScope,
|
||||
)
|
||||
},
|
||||
basePropertySymbols,
|
||||
result,
|
||||
containsErrorTypes = { irProperty ->
|
||||
irProperty.backingField?.type?.containsErrorType() == true ||
|
||||
irProperty.getter?.returnType?.containsErrorType() == true
|
||||
},
|
||||
realDeclarationSymbols,
|
||||
FirTypeScope::getDirectOverriddenProperties,
|
||||
useSiteOrStaticScope,
|
||||
)
|
||||
}
|
||||
|
||||
is FirFieldSymbol -> {
|
||||
if (!propertyOrFieldSymbol.isStatic) return@processPropertiesByName
|
||||
createFakeOverriddenIfNeeded(
|
||||
firClass, irClass, isLocal, propertyOrFieldSymbol,
|
||||
{ field, _, _ -> declarationStorage.getCachedIrField(field, staticFakeOverrideOwnerLookupTag = null) },
|
||||
{ field, irParent, _, _, _ ->
|
||||
declarationStorage.createIrField(field, irParent)
|
||||
},
|
||||
createFakeOverrideSymbol = { firField, callableSymbol ->
|
||||
FirFakeOverrideGenerator.createSubstitutionOverrideField(
|
||||
session, firField, callableSymbol,
|
||||
newReturnType = firField.returnTypeRef.coneType,
|
||||
firClass.symbol.classId, withInitializer = true
|
||||
)
|
||||
},
|
||||
baseStaticFieldSymbols,
|
||||
result,
|
||||
containsErrorTypes = { irField -> irField.type.containsErrorType() },
|
||||
realDeclarationSymbols,
|
||||
computeDirectOverridden = { emptyList() },
|
||||
useSiteOrStaticScope,
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+6
@@ -28782,6 +28782,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/javaVisibility/package"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inheritedPackageStaticField.kt")
|
||||
public void testInheritedPackageStaticField() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/javaVisibility/package/inheritedPackageStaticField.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inheritedPackageStaticFunction.kt")
|
||||
public void testInheritedPackageStaticFunction() throws Exception {
|
||||
|
||||
+3
-1
@@ -310,7 +310,9 @@ class FirClassSubstitutionScope(
|
||||
// TODO: do we have fields with implicit type?
|
||||
val newReturnType = returnType?.substitute() ?: return original
|
||||
|
||||
return FirFakeOverrideGenerator.createSubstitutionOverrideField(session, member, original, newReturnType, newOwnerClassId)
|
||||
return FirFakeOverrideGenerator.createSubstitutionOverrideField(
|
||||
session, member, original, newReturnType, newOwnerClassId, withInitializer = false
|
||||
)
|
||||
}
|
||||
|
||||
fun createSubstitutionOverrideSyntheticProperty(original: FirSyntheticPropertySymbol): FirSyntheticPropertySymbol {
|
||||
|
||||
+8
-1
@@ -487,7 +487,8 @@ object FirFakeOverrideGenerator {
|
||||
baseField: FirField,
|
||||
baseSymbol: FirFieldSymbol,
|
||||
newReturnType: ConeKotlinType?,
|
||||
derivedClassId: ClassId?
|
||||
derivedClassId: ClassId?,
|
||||
withInitializer: Boolean
|
||||
): FirFieldSymbol {
|
||||
val symbol = FirFieldSymbol(
|
||||
CallableId(derivedClassId ?: baseSymbol.callableId.classId!!, baseField.name)
|
||||
@@ -507,8 +508,14 @@ object FirFakeOverrideGenerator {
|
||||
annotations += baseField.annotations
|
||||
attributes = baseField.attributes.copy()
|
||||
dispatchReceiverType = baseField.dispatchReceiverType
|
||||
if (withInitializer) {
|
||||
initializer = baseField.initializer
|
||||
}
|
||||
}.apply {
|
||||
originalForSubstitutionOverrideAttr = baseField
|
||||
if (isStatic && derivedClassId != null) {
|
||||
containingClassForStaticMemberAttr = ConeClassLikeLookupTagImpl(derivedClassId)
|
||||
}
|
||||
}
|
||||
return symbol
|
||||
}
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// ISSUE: KT-53441
|
||||
// MODULE: lib
|
||||
// FILE: test/J.java
|
||||
package test;
|
||||
|
||||
interface I {
|
||||
// Not a String to avoid constant inlining
|
||||
public static String[] OK = new String[]{"OK"};
|
||||
}
|
||||
|
||||
public class J implements I {}
|
||||
|
||||
// MODULE: main(lib)
|
||||
// FILE: k.kt
|
||||
import test.J
|
||||
|
||||
fun box() = J.OK[0] // accessible by JVM rules as J.OK, but not I.OK
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_K2: JVM_IR
|
||||
// FILE: Child.java
|
||||
|
||||
class Child extends Parent {
|
||||
|
||||
+6
@@ -28782,6 +28782,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/javaVisibility/package"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inheritedPackageStaticField.kt")
|
||||
public void testInheritedPackageStaticField() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/javaVisibility/package/inheritedPackageStaticField.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inheritedPackageStaticFunction.kt")
|
||||
public void testInheritedPackageStaticFunction() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user