FIR2IR: support static fake overrides for fields (related to KT-53441)

#KT-54921 Fixed
This commit is contained in:
Mikhail Glukhikh
2022-11-08 13:26:16 +01:00
committed by Space Team
parent 6979271998
commit c698d060c6
11 changed files with 162 additions and 43 deletions
@@ -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)
@@ -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) {
@@ -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()
@@ -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 -> {
}
}
}
}
@@ -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 {
@@ -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 {
@@ -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
}
@@ -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
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_K2: JVM_IR
// FILE: Child.java
class Child extends Parent {
@@ -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 {