FIR2IR: support static fake overrides (functions) #KT-53441 Fixed
This commit is contained in:
committed by
Space Team
parent
ec77e1896c
commit
3a81174a4c
@@ -179,7 +179,7 @@ fun FirReference.toSymbolForCall(
|
||||
dispatchReceiver: FirExpression,
|
||||
conversionScope: Fir2IrConversionScope,
|
||||
preferGetter: Boolean = true,
|
||||
explicitReceiver: FirExpression? = null, // Actual only for callable references
|
||||
explicitReceiver: FirExpression? = null,
|
||||
isDelegate: Boolean = false,
|
||||
isReference: Boolean = false
|
||||
): IrSymbol? {
|
||||
@@ -227,23 +227,27 @@ private fun FirCallableSymbol<*>.toSymbolForCall(
|
||||
isDelegate: Boolean = false,
|
||||
isReference: Boolean = false
|
||||
): IrSymbol? {
|
||||
val dispatchReceiverLookupTag = when {
|
||||
dispatchReceiver is FirNoReceiverExpression -> {
|
||||
val dispatchReceiverType = when (dispatchReceiver) {
|
||||
is FirNoReceiverExpression -> {
|
||||
val containingClass = containingClassLookupTag()
|
||||
if (containingClass != null && containingClass.classId != StandardClassIds.Any) {
|
||||
// Make sure that symbol is not extension and is not from inline class
|
||||
val coneType = ((explicitReceiver as? FirResolvedQualifier)?.symbol as? FirClassSymbol)?.defaultType()
|
||||
coneType?.findClassRepresentation(coneType, declarationStorage.session)
|
||||
((explicitReceiver as? FirResolvedQualifier)?.symbol as? FirClassSymbol)?.defaultType()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
is FirResolvedQualifier -> {
|
||||
if (isStatic) (dispatchReceiver.symbol as? FirClassSymbol)?.defaultType() else dispatchReceiver.typeRef.coneType
|
||||
}
|
||||
|
||||
else -> {
|
||||
val coneType = dispatchReceiver.typeRef.coneType
|
||||
dispatchReceiver.typeRef.coneType.findClassRepresentation(coneType, declarationStorage.session)
|
||||
dispatchReceiver.typeRef.coneType
|
||||
}
|
||||
}
|
||||
val dispatchReceiverLookupTag = dispatchReceiverType?.findClassRepresentation(dispatchReceiverType, declarationStorage.session)
|
||||
|
||||
return when (this) {
|
||||
is FirSimpleSyntheticPropertySymbol -> {
|
||||
if (isDelegate) {
|
||||
|
||||
+2
-1
@@ -399,7 +399,8 @@ class CallAndReferenceGenerator(
|
||||
|
||||
val symbol = calleeReference.toSymbolForCall(
|
||||
dispatchReceiver,
|
||||
conversionScope
|
||||
conversionScope,
|
||||
explicitReceiver = qualifiedAccess.explicitReceiver
|
||||
)
|
||||
|
||||
// We might have had a dynamic receiver, but resolved
|
||||
|
||||
+29
-18
@@ -11,22 +11,17 @@ import org.jetbrains.kotlin.fir.backend.Fir2IrConversionScope
|
||||
import org.jetbrains.kotlin.fir.backend.Fir2IrDeclarationStorage
|
||||
import org.jetbrains.kotlin.fir.backend.unwrapSubstitutionAndIntersectionOverrides
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.allowsToHaveFakeOverride
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
|
||||
import org.jetbrains.kotlin.fir.scopes.getDirectOverriddenFunctions
|
||||
import org.jetbrains.kotlin.fir.scopes.getDirectOverriddenProperties
|
||||
import org.jetbrains.kotlin.fir.scopes.*
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirFakeOverrideGenerator
|
||||
import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope
|
||||
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.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.isStatic
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
@@ -98,18 +93,27 @@ class FakeOverrideGenerator(
|
||||
// This parameter is only needed for data-class methods that is irrelevant for lazy library classes
|
||||
realDeclarationSymbols = emptySet()
|
||||
)
|
||||
if (firClass.isEnumClass) return@buildList // F/O for values/valueOf/entries aren't needed, for other members aren't possible
|
||||
val staticScope = firClass.scopeProvider.getStaticMemberScopeForCallables(firClass, session, scopeSession)
|
||||
if (staticScope != null) {
|
||||
generateFakeOverridesForName(
|
||||
irClass, staticScope, name, firClass, this,
|
||||
// This parameter is only needed for data-class methods that is irrelevant for lazy library classes
|
||||
realDeclarationSymbols = emptySet()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun generateFakeOverridesForName(
|
||||
irClass: IrClass,
|
||||
useSiteMemberScope: FirTypeScope,
|
||||
useSiteOrStaticScope: FirScope,
|
||||
name: Name,
|
||||
firClass: FirClass,
|
||||
result: MutableList<IrDeclaration>,
|
||||
realDeclarationSymbols: Set<FirBasedSymbol<*>>
|
||||
) {
|
||||
val isLocal = firClass !is FirRegularClass || firClass.isLocal
|
||||
useSiteMemberScope.processFunctionsByName(name) { functionSymbol ->
|
||||
useSiteOrStaticScope.processFunctionsByName(name) { functionSymbol ->
|
||||
createFakeOverriddenIfNeeded(
|
||||
firClass, irClass, isLocal, functionSymbol,
|
||||
declarationStorage::getCachedIrFunction,
|
||||
@@ -129,11 +133,11 @@ class FakeOverrideGenerator(
|
||||
},
|
||||
realDeclarationSymbols,
|
||||
FirTypeScope::getDirectOverriddenFunctions,
|
||||
useSiteMemberScope,
|
||||
useSiteOrStaticScope,
|
||||
)
|
||||
}
|
||||
|
||||
useSiteMemberScope.processPropertiesByName(name) { propertySymbol ->
|
||||
useSiteOrStaticScope.processPropertiesByName(name) { propertySymbol ->
|
||||
createFakeOverriddenIfNeeded(
|
||||
firClass, irClass, isLocal, propertySymbol,
|
||||
declarationStorage::getCachedIrProperty,
|
||||
@@ -154,7 +158,7 @@ class FakeOverrideGenerator(
|
||||
},
|
||||
realDeclarationSymbols,
|
||||
FirTypeScope::getDirectOverriddenProperties,
|
||||
useSiteMemberScope,
|
||||
useSiteOrStaticScope,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -191,13 +195,13 @@ class FakeOverrideGenerator(
|
||||
containsErrorTypes: (I) -> Boolean,
|
||||
realDeclarationSymbols: Set<FirBasedSymbol<*>>,
|
||||
computeDirectOverridden: FirTypeScope.(S) -> List<S>,
|
||||
scope: FirTypeScope,
|
||||
scope: FirScope,
|
||||
) {
|
||||
if (originalSymbol !is S) return
|
||||
val classLookupTag = klass.symbol.toLookupTag()
|
||||
val originalDeclaration = originalSymbol.fir
|
||||
|
||||
if (originalSymbol.dispatchReceiverClassLookupTagOrNull() == classLookupTag && !originalDeclaration.origin.fromSupertypes) return
|
||||
if (originalSymbol.containingClassLookupTag() == classLookupTag && !originalDeclaration.origin.fromSupertypes) return
|
||||
// Data classes' methods from Any (toString/equals/hashCode) are not handled by the line above because they have Any-typed dispatch receiver
|
||||
// (there are no special FIR method for them, it's just fake overrides)
|
||||
// But they are treated differently in IR (real declarations have already been declared before) and such methods are present among realDeclarationSymbols
|
||||
@@ -321,13 +325,17 @@ class FakeOverrideGenerator(
|
||||
private inline fun <reified S : FirCallableSymbol<*>> computeBaseSymbols(
|
||||
symbol: S,
|
||||
directOverridden: FirTypeScope.(S) -> List<S>,
|
||||
scope: FirTypeScope,
|
||||
scope: FirScope,
|
||||
containingClass: ConeClassLikeLookupTag,
|
||||
): List<S> {
|
||||
if (symbol.fir.origin == FirDeclarationOrigin.SubstitutionOverride) {
|
||||
return listOf(symbol.originalForSubstitutionOverride!!)
|
||||
}
|
||||
|
||||
if (scope !is FirTypeScope) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
return scope.directOverridden(symbol).map {
|
||||
// Unwrapping should happen only for fake overrides members from the same class, not from supertypes
|
||||
if (it.fir.isSubstitutionOverride && it.dispatchReceiverClassLookupTagOrNull() == containingClass)
|
||||
@@ -390,8 +398,11 @@ class FakeOverrideGenerator(
|
||||
?: return emptyList()
|
||||
|
||||
return superClasses.mapNotNull { superClass ->
|
||||
if (superClass == overriddenContainingIrClass) {
|
||||
// `overridden` was a FIR declaration in some of the supertypes
|
||||
if (superClass == overriddenContainingIrClass ||
|
||||
// Note: Kotlin static scopes cannot find base symbol in this case, so we have to fallback to the very base declaration
|
||||
overridden.isStatic && superClass.origin != IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB
|
||||
) {
|
||||
// `overridden` was a FIR declaration in some supertypes
|
||||
irProducer(overridden)
|
||||
} else {
|
||||
// There were no FIR declaration in supertypes, but we know that we have fake overrides in some of them
|
||||
|
||||
+12
@@ -18031,6 +18031,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/fir"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("assertEqualsFakeOverride.kt")
|
||||
public void testAssertEqualsFakeOverride() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/fir/assertEqualsFakeOverride.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("callableReferenceToJavaField.kt")
|
||||
public void testCallableReferenceToJavaField() throws Exception {
|
||||
@@ -28740,6 +28746,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("inheritedPackageStaticFunction.kt")
|
||||
public void testInheritedPackageStaticFunction() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/javaVisibility/package/inheritedPackageStaticFunction.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt2781.kt")
|
||||
public void testKt2781() throws Exception {
|
||||
|
||||
+7
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.declarations.builder.*
|
||||
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty
|
||||
import org.jetbrains.kotlin.fir.declarations.synthetic.buildSyntheticProperty
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ChainedSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
|
||||
@@ -89,6 +90,9 @@ object FirFakeOverrideGenerator {
|
||||
fakeOverrideSubstitution = fakeOverrideSubstitution
|
||||
).apply {
|
||||
originalForSubstitutionOverrideAttr = baseFunction
|
||||
if (isStatic) {
|
||||
containingClassForStaticMemberAttr = (newDispatchReceiverType as? ConeClassLikeType)?.lookupTag
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -298,6 +302,9 @@ object FirFakeOverrideGenerator {
|
||||
fakeOverrideSubstitution = fakeOverrideSubstitution
|
||||
).apply {
|
||||
originalForSubstitutionOverrideAttr = baseProperty
|
||||
if (isStatic) {
|
||||
containingClassForStaticMemberAttr = (newDispatchReceiverType as? ConeClassLikeType)?.lookupTag
|
||||
}
|
||||
}
|
||||
return symbolForSubstitutionOverride
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// FILE: AbstractBlackBoxCodegenTest.java
|
||||
|
||||
public abstract class AbstractBlackBoxCodegenTest extends CodegenTestCase {}
|
||||
|
||||
// FILE: CodegenTestCase.java
|
||||
|
||||
public abstract class CodegenTestCase extends KotlinBaseTest<CharSequence> {}
|
||||
|
||||
// FILE: KotlinBaseTest.kt
|
||||
|
||||
abstract class KotlinBaseTest<F : CharSequence> : KtUsefulTestCase() {}
|
||||
|
||||
// FILE: KtUsefulTestCase.java
|
||||
|
||||
public abstract class KtUsefulTestCase extends TestCase {}
|
||||
|
||||
// FILE: TestCase.java
|
||||
|
||||
public abstract class TestCase {
|
||||
public static void assertEquals(int expected, int actual) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: test.kt
|
||||
|
||||
fun box(): String {
|
||||
AbstractBlackBoxCodegenTest.assertEquals(42, 42)
|
||||
return "OK"
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// ISSUE: KT-53441
|
||||
// MODULE: lib
|
||||
// FILE: test/J.java
|
||||
package test;
|
||||
|
||||
class I {
|
||||
public static String foo() { return "O"; }
|
||||
|
||||
public static String bar() { return "K"; }
|
||||
}
|
||||
|
||||
public class J extends I {}
|
||||
|
||||
// MODULE: main(lib)
|
||||
// FILE: k.kt
|
||||
import test.J
|
||||
import test.J.bar
|
||||
|
||||
fun box() = J.foo() + bar()
|
||||
+12
@@ -18031,6 +18031,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/fir"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("assertEqualsFakeOverride.kt")
|
||||
public void testAssertEqualsFakeOverride() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/fir/assertEqualsFakeOverride.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("callableReferenceToJavaField.kt")
|
||||
public void testCallableReferenceToJavaField() throws Exception {
|
||||
@@ -28740,6 +28746,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("inheritedPackageStaticFunction.kt")
|
||||
public void testInheritedPackageStaticFunction() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/javaVisibility/package/inheritedPackageStaticFunction.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt2781.kt")
|
||||
public void testKt2781() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user