[FIR] Carefully process constructors of inner and nested classes in the tower

If there is an expression receiver, we should process constructors only
  of inner classes. Constructors of nested classes can be called only
  on classifier

^KT-65333 Fixed
This commit is contained in:
Dmitriy Novozhilov
2024-02-27 12:36:29 +02:00
committed by Space Team
parent 67557ce731
commit 5b01396a11
15 changed files with 182 additions and 25 deletions
@@ -30642,6 +30642,12 @@ public class LLFirBlackBoxCodegenBasedTestGenerated extends AbstractLLFirBlackBo
runTest("compiler/testData/codegen/box/innerNested/importNestedClass.kt"); runTest("compiler/testData/codegen/box/innerNested/importNestedClass.kt");
} }
@Test
@TestMetadata("inheritedInnerAndNested.kt")
public void testInheritedInnerAndNested() {
runTest("compiler/testData/codegen/box/innerNested/inheritedInnerAndNested.kt");
}
@Test @Test
@TestMetadata("innerGeneric.kt") @TestMetadata("innerGeneric.kt")
public void testInnerGeneric() { public void testInnerGeneric() {
@@ -30642,6 +30642,12 @@ public class LLFirReversedBlackBoxCodegenBasedTestGenerated extends AbstractLLFi
runTest("compiler/testData/codegen/box/innerNested/importNestedClass.kt"); runTest("compiler/testData/codegen/box/innerNested/importNestedClass.kt");
} }
@Test
@TestMetadata("inheritedInnerAndNested.kt")
public void testInheritedInnerAndNested() {
runTest("compiler/testData/codegen/box/innerNested/inheritedInnerAndNested.kt");
}
@Test @Test
@TestMetadata("innerGeneric.kt") @TestMetadata("innerGeneric.kt")
public void testInnerGeneric() { public void testInnerGeneric() {
@@ -30559,6 +30559,12 @@ public class FirLightTreeBlackBoxCodegenTestGenerated extends AbstractFirLightTr
runTest("compiler/testData/codegen/box/innerNested/importNestedClass.kt"); runTest("compiler/testData/codegen/box/innerNested/importNestedClass.kt");
} }
@Test
@TestMetadata("inheritedInnerAndNested.kt")
public void testInheritedInnerAndNested() {
runTest("compiler/testData/codegen/box/innerNested/inheritedInnerAndNested.kt");
}
@Test @Test
@TestMetadata("innerGeneric.kt") @TestMetadata("innerGeneric.kt")
public void testInnerGeneric() { public void testInnerGeneric() {
@@ -30559,6 +30559,12 @@ public class FirLightTreeBlackBoxCodegenWithIrFakeOverrideGeneratorTestGenerated
runTest("compiler/testData/codegen/box/innerNested/importNestedClass.kt"); runTest("compiler/testData/codegen/box/innerNested/importNestedClass.kt");
} }
@Test
@TestMetadata("inheritedInnerAndNested.kt")
public void testInheritedInnerAndNested() {
runTest("compiler/testData/codegen/box/innerNested/inheritedInnerAndNested.kt");
}
@Test @Test
@TestMetadata("innerGeneric.kt") @TestMetadata("innerGeneric.kt")
public void testInnerGeneric() { public void testInnerGeneric() {
@@ -30559,6 +30559,12 @@ public class FirPsiBlackBoxCodegenTestGenerated extends AbstractFirPsiBlackBoxCo
runTest("compiler/testData/codegen/box/innerNested/importNestedClass.kt"); runTest("compiler/testData/codegen/box/innerNested/importNestedClass.kt");
} }
@Test
@TestMetadata("inheritedInnerAndNested.kt")
public void testInheritedInnerAndNested() {
runTest("compiler/testData/codegen/box/innerNested/inheritedInnerAndNested.kt");
}
@Test @Test
@TestMetadata("innerGeneric.kt") @TestMetadata("innerGeneric.kt")
public void testInnerGeneric() { public void testInnerGeneric() {
@@ -22,17 +22,23 @@ import org.jetbrains.kotlin.fir.whileAnalysing
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.deprecation.DeprecationLevelValue import org.jetbrains.kotlin.resolve.deprecation.DeprecationLevelValue
private operator fun <T> Pair<T, *>?.component1() = this?.first private operator fun <T> Pair<T, *>?.component1(): T? = this?.first
private operator fun <T> Pair<*, T>?.component2() = this?.second private operator fun <T> Pair<*, T>?.component2(): T? = this?.second
internal fun FirScope.processConstructorsByName( internal enum class ConstructorFilter(val acceptInner: Boolean, val acceptNested: Boolean) {
OnlyInner(acceptInner = true, acceptNested = false),
OnlyNested(acceptInner = false, acceptNested = true),
Both(acceptInner = true, acceptNested = true),
}
private fun FirScope.processConstructorsByName(
callInfo: CallInfo, callInfo: CallInfo,
session: FirSession, session: FirSession,
bodyResolveComponents: BodyResolveComponents, bodyResolveComponents: BodyResolveComponents,
includeInnerConstructors: Boolean, constructorFilter: ConstructorFilter,
processor: (FirCallableSymbol<*>) -> Unit processor: (FirCallableSymbol<*>) -> Unit
) { ) {
val (matchedClassifierSymbol, substitutor) = getFirstClassifierOrNull(callInfo, session, bodyResolveComponents) ?: return val (matchedClassifierSymbol, substitutor) = getFirstClassifierOrNull(callInfo, constructorFilter, session, bodyResolveComponents) ?: return
val matchedClassSymbol = matchedClassifierSymbol as? FirClassLikeSymbol<*> ?: return val matchedClassSymbol = matchedClassifierSymbol as? FirClassLikeSymbol<*> ?: return
processConstructors( processConstructors(
@@ -41,7 +47,7 @@ internal fun FirScope.processConstructorsByName(
processor, processor,
session, session,
bodyResolveComponents, bodyResolveComponents,
includeInnerConstructors constructorFilter
) )
processSyntheticConstructors( processSyntheticConstructors(
@@ -55,12 +61,12 @@ internal fun FirScope.processFunctionsAndConstructorsByName(
callInfo: CallInfo, callInfo: CallInfo,
session: FirSession, session: FirSession,
bodyResolveComponents: BodyResolveComponents, bodyResolveComponents: BodyResolveComponents,
includeInnerConstructors: Boolean, constructorFilter: ConstructorFilter,
processor: (FirCallableSymbol<*>) -> Unit processor: (FirCallableSymbol<*>) -> Unit
) { ) {
processConstructorsByName( processConstructorsByName(
callInfo, session, bodyResolveComponents, callInfo, session, bodyResolveComponents,
includeInnerConstructors = includeInnerConstructors, constructorFilter,
processor processor
) )
@@ -116,6 +122,7 @@ private fun FirDeclaration.isInvisibleOrHidden(session: FirSession, bodyResolveC
private fun FirScope.getFirstClassifierOrNull( private fun FirScope.getFirstClassifierOrNull(
callInfo: CallInfo, callInfo: CallInfo,
constructorFilter: ConstructorFilter,
session: FirSession, session: FirSession,
bodyResolveComponents: BodyResolveComponents bodyResolveComponents: BodyResolveComponents
): SymbolWithSubstitutor? { ): SymbolWithSubstitutor? {
@@ -124,7 +131,14 @@ private fun FirScope.getFirstClassifierOrNull(
var result: SymbolWithSubstitutor? = null var result: SymbolWithSubstitutor? = null
processClassifiersByNameWithSubstitution(callInfo.name) { symbol, substitutor -> processClassifiersByNameWithSubstitution(callInfo.name) { symbol, substitutor ->
val classifierDeclaration = symbol.fir val classifierDeclaration = symbol.fir
val isSuccessCandidate = !classifierDeclaration.isInvisibleOrHidden(session, bodyResolveComponents) var isSuccessCandidate = !classifierDeclaration.isInvisibleOrHidden(session, bodyResolveComponents)
if (classifierDeclaration is FirClassLikeDeclaration) {
val acceptedByFilter = when (classifierDeclaration.isInner) {
true -> constructorFilter.acceptInner
false -> constructorFilter.acceptNested
}
isSuccessCandidate = isSuccessCandidate && acceptedByFilter
}
when { when {
isSuccessCandidate && !isSuccessResult -> { isSuccessCandidate && !isSuccessResult -> {
@@ -212,7 +226,7 @@ private fun processConstructors(
processor: (FirFunctionSymbol<*>) -> Unit, processor: (FirFunctionSymbol<*>) -> Unit,
session: FirSession, session: FirSession,
bodyResolveComponents: BodyResolveComponents, bodyResolveComponents: BodyResolveComponents,
includeInnerConstructors: Boolean constructorFilter: ConstructorFilter
) { ) {
whileAnalysing(session, matchedSymbol.fir) { whileAnalysing(session, matchedSymbol.fir) {
val scope = when (matchedSymbol) { val scope = when (matchedSymbol) {
@@ -254,10 +268,13 @@ private fun processConstructors(
} }
} }
scope?.processDeclaredConstructors { scope?.processDeclaredConstructors {
if (includeInnerConstructors || !it.fir.isInner) { val shouldProcess = when (it.fir.isInner) {
processor(it) true -> constructorFilter.acceptInner
false -> constructorFilter.acceptNested
}
if (shouldProcess) {
processor(it)
} }
} }
} }
@@ -86,24 +86,31 @@ internal abstract class FirBaseTowerResolveTask(
protected fun FirScope.toScopeTowerLevel( protected fun FirScope.toScopeTowerLevel(
extensionReceiver: ReceiverValue? = null, extensionReceiver: ReceiverValue? = null,
withHideMembersOnly: Boolean = false, withHideMembersOnly: Boolean = false,
includeInnerConstructors: Boolean = extensionReceiver != null, constructorFilter: ConstructorFilter = extensionReceiver.toConstructorFilter(),
contextReceiverGroup: ContextReceiverGroup? = null, contextReceiverGroup: ContextReceiverGroup? = null,
dispatchReceiverForStatics: ExpressionReceiverValue? = null dispatchReceiverForStatics: ExpressionReceiverValue? = null
): ScopeTowerLevel { ): ScopeTowerLevel {
return ScopeTowerLevel( return ScopeTowerLevel(
components, this, components, this,
givenExtensionReceiverOptions = createExtensionReceiverOptions(contextReceiverGroup, extensionReceiver), givenExtensionReceiverOptions = createExtensionReceiverOptions(contextReceiverGroup, extensionReceiver),
withHideMembersOnly, includeInnerConstructors, dispatchReceiverForStatics withHideMembersOnly, constructorFilter, dispatchReceiverForStatics
) )
} }
private fun ReceiverValue?.toConstructorFilter(): ConstructorFilter {
return when (this) {
null -> ConstructorFilter.OnlyNested
else -> ConstructorFilter.Both
}
}
protected fun FirScope.toScopeTowerLevelForStaticWithImplicitDispatchReceiver( protected fun FirScope.toScopeTowerLevelForStaticWithImplicitDispatchReceiver(
staticOwnerOwnerSymbol: FirRegularClassSymbol? = null, staticOwnerOwnerSymbol: FirRegularClassSymbol? = null,
source: KtSourceElement? = null source: KtSourceElement? = null
): ScopeTowerLevel = toScopeTowerLevel( ): ScopeTowerLevel = toScopeTowerLevel(
extensionReceiver = null, extensionReceiver = null,
withHideMembersOnly = false, withHideMembersOnly = false,
includeInnerConstructors = false, constructorFilter = ConstructorFilter.OnlyNested,
contextReceiverGroup = null, contextReceiverGroup = null,
staticOwnerOwnerSymbol?.let { staticOwnerOwnerSymbol?.let {
val resolvedQualifier = buildResolvedQualifier { val resolvedQualifier = buildResolvedQualifier {
@@ -256,7 +263,7 @@ internal open class FirTowerResolveTask(
val callableScope = qualifierReceiver.callableScope() ?: return val callableScope = qualifierReceiver.callableScope() ?: return
processLevel( processLevel(
callableScope.toScopeTowerLevel( callableScope.toScopeTowerLevel(
includeInnerConstructors = false, constructorFilter = ConstructorFilter.OnlyNested,
dispatchReceiverForStatics = when (qualifierReceiver) { dispatchReceiverForStatics = when (qualifierReceiver) {
is ClassQualifierReceiver -> ExpressionReceiverValue(qualifierReceiver.explicitReceiver) is ClassQualifierReceiver -> ExpressionReceiverValue(qualifierReceiver.explicitReceiver)
else -> null else -> null
@@ -276,7 +283,7 @@ internal open class FirTowerResolveTask(
) return ) return
val scope = qualifierReceiver.classifierScope() ?: return val scope = qualifierReceiver.classifierScope() ?: return
processLevel( processLevel(
scope.toScopeTowerLevel(includeInnerConstructors = false), info, scope.toScopeTowerLevel(constructorFilter = ConstructorFilter.OnlyNested), info,
TowerGroup.Classifier TowerGroup.Classifier
) )
} }
@@ -280,7 +280,7 @@ class MemberScopeTowerLevel(
withMemberCallLookup(lookupTracker, info) { lookupCtx -> withMemberCallLookup(lookupTracker, info) { lookupCtx ->
this.processFunctionsAndConstructorsByName( this.processFunctionsAndConstructorsByName(
info, session, bodyResolveComponents, info, session, bodyResolveComponents,
includeInnerConstructors = true, ConstructorFilter.OnlyInner,
processor = { processor = {
lookupCtx.recordCallableMemberLookup(it) lookupCtx.recordCallableMemberLookup(it)
// WARNING, DO NOT CAST FUNCTIONAL TYPE ITSELF // WARNING, DO NOT CAST FUNCTIONAL TYPE ITSELF
@@ -370,12 +370,12 @@ class ContextReceiverGroupMemberScopeTowerLevel(
// So: dispatch receiver = strictly none (EXCEPTIONS: importing scopes with import from objects, synthetic field variable) // So: dispatch receiver = strictly none (EXCEPTIONS: importing scopes with import from objects, synthetic field variable)
// So: extension receiver = either none or explicit // So: extension receiver = either none or explicit
// (if explicit receiver exists, it always *should* be an extension receiver) // (if explicit receiver exists, it always *should* be an extension receiver)
class ScopeTowerLevel( internal class ScopeTowerLevel(
private val bodyResolveComponents: BodyResolveComponents, private val bodyResolveComponents: BodyResolveComponents,
val scope: FirScope, val scope: FirScope,
private val givenExtensionReceiverOptions: List<FirExpression>, private val givenExtensionReceiverOptions: List<FirExpression>,
private val withHideMembersOnly: Boolean, private val withHideMembersOnly: Boolean,
private val includeInnerConstructors: Boolean, private val constructorFilter: ConstructorFilter,
private val dispatchReceiverForStatics: ExpressionReceiverValue? private val dispatchReceiverForStatics: ExpressionReceiverValue?
) : TowerScopeLevel() { ) : TowerScopeLevel() {
private val session: FirSession get() = bodyResolveComponents.session private val session: FirSession get() = bodyResolveComponents.session
@@ -486,7 +486,7 @@ class ScopeTowerLevel(
info, info,
session, session,
bodyResolveComponents, bodyResolveComponents,
includeInnerConstructors = includeInnerConstructors constructorFilter
) { candidate -> ) { candidate ->
empty = false empty = false
consumeCallableCandidate(candidate, info, processor) consumeCallableCandidate(candidate, info, processor)
@@ -0,0 +1,74 @@
// TARGET_BACKEND: JVM_IR
// ISSUE: KT-65333
// FILE: BaseClass.java
public class BaseClass {
public class Inner {
public String box() {
return "BaseClass";
}
}
}
// FILE: BaseInterface.java
public interface BaseInterface {
class Inner {
public String box() {
return "BaseInterface";
}
}
}
// FILE: main.kt
class A: BaseClass(), BaseInterface
class B : BaseClass(), BaseInterface {
class Inner {
fun box(): String = "B"
}
}
class C : BaseClass(), BaseInterface {
inner class Inner {
fun box(): String = "C"
}
}
object D : BaseClass(), BaseInterface
object E : BaseClass(), BaseInterface {
class Inner {
fun box(): String = "E"
}
}
object F : BaseClass()
object G : BaseClass() {
class Inner {
fun box(): String = "G"
}
}
object H : BaseInterface
object I : BaseInterface {
class Inner {
fun box(): String = "I"
}
}
fun check(actual: String, expected: String) {
if (expected != actual) {
throw AssertionError("\nExpected: $expected\nActual: $actual\n")
}
}
fun box(): String {
check(A().Inner().box(), "BaseClass")
// check(A.Inner().box(), "BaseInterface")
// check(B().Inner().box(), "BaseInterface")
check(B.Inner().box(), "B")
check(C().Inner().box(), "C")
// check(C.Inner().box(), "BaseInterface")
check(D.Inner().box(), "BaseClass")
check(E.Inner().box(), "E")
check(F.Inner().box(), "BaseClass")
check(G.Inner().box(), "G")
// check(H.Inner().box(), "E")
check(I.Inner().box(), "I")
return "OK"
}
@@ -53,13 +53,13 @@ object I : BaseInterface {
fun test() { fun test() {
A().<!UNRESOLVED_REFERENCE!>Inner<!>().box() A().Inner().box()
A.<!UNRESOLVED_REFERENCE!>Inner<!>().box() // should be an error A.<!UNRESOLVED_REFERENCE!>Inner<!>().box() // should be an error
B().<!UNRESOLVED_REFERENCE!>Inner<!>().box() // should be an error B().<!UNRESOLVED_REFERENCE!>Inner<!>().box() // should be an error
B.Inner().box() B.Inner().box()
C().Inner().box() C().Inner().box()
C.<!INNER_CLASS_CONSTRUCTOR_NO_RECEIVER!>Inner<!>().<!UNRESOLVED_REFERENCE!>box<!>() // should be an error C.<!INNER_CLASS_CONSTRUCTOR_NO_RECEIVER!>Inner<!>().<!UNRESOLVED_REFERENCE!>box<!>() // should be an error
D.<!UNRESOLVED_REFERENCE!>Inner<!>().box() D.Inner().box()
E.Inner().box() E.Inner().box()
F.Inner().box() F.Inner().box()
G.Inner().box() G.Inner().box()
@@ -30559,6 +30559,12 @@ public class JvmAbiConsistencyTestBoxGenerated extends AbstractJvmAbiConsistency
runTest("compiler/testData/codegen/box/innerNested/importNestedClass.kt"); runTest("compiler/testData/codegen/box/innerNested/importNestedClass.kt");
} }
@Test
@TestMetadata("inheritedInnerAndNested.kt")
public void testInheritedInnerAndNested() {
runTest("compiler/testData/codegen/box/innerNested/inheritedInnerAndNested.kt");
}
@Test @Test
@TestMetadata("innerGeneric.kt") @TestMetadata("innerGeneric.kt")
public void testInnerGeneric() { public void testInnerGeneric() {
@@ -30559,6 +30559,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/innerNested/importNestedClass.kt"); runTest("compiler/testData/codegen/box/innerNested/importNestedClass.kt");
} }
@Test
@TestMetadata("inheritedInnerAndNested.kt")
public void testInheritedInnerAndNested() {
runTest("compiler/testData/codegen/box/innerNested/inheritedInnerAndNested.kt");
}
@Test @Test
@TestMetadata("innerGeneric.kt") @TestMetadata("innerGeneric.kt")
public void testInnerGeneric() { public void testInnerGeneric() {
@@ -30559,6 +30559,12 @@ public class IrBlackBoxCodegenWithIrInlinerTestGenerated extends AbstractIrBlack
runTest("compiler/testData/codegen/box/innerNested/importNestedClass.kt"); runTest("compiler/testData/codegen/box/innerNested/importNestedClass.kt");
} }
@Test
@TestMetadata("inheritedInnerAndNested.kt")
public void testInheritedInnerAndNested() {
runTest("compiler/testData/codegen/box/innerNested/inheritedInnerAndNested.kt");
}
@Test @Test
@TestMetadata("innerGeneric.kt") @TestMetadata("innerGeneric.kt")
public void testInnerGeneric() { public void testInnerGeneric() {
@@ -30559,6 +30559,12 @@ public class FirBlackBoxCodegenTestWithInlineScopesGenerated extends AbstractFir
runTest("compiler/testData/codegen/box/innerNested/importNestedClass.kt"); runTest("compiler/testData/codegen/box/innerNested/importNestedClass.kt");
} }
@Test
@TestMetadata("inheritedInnerAndNested.kt")
public void testInheritedInnerAndNested() {
runTest("compiler/testData/codegen/box/innerNested/inheritedInnerAndNested.kt");
}
@Test @Test
@TestMetadata("innerGeneric.kt") @TestMetadata("innerGeneric.kt")
public void testInnerGeneric() { public void testInnerGeneric() {
@@ -25813,6 +25813,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/innerNested/importNestedClass.kt"); runTest("compiler/testData/codegen/box/innerNested/importNestedClass.kt");
} }
@TestMetadata("inheritedInnerAndNested.kt")
public void testInheritedInnerAndNested() {
runTest("compiler/testData/codegen/box/innerNested/inheritedInnerAndNested.kt");
}
@TestMetadata("innerGeneric.kt") @TestMetadata("innerGeneric.kt")
public void testInnerGeneric() { public void testInnerGeneric() {
runTest("compiler/testData/codegen/box/innerNested/innerGeneric.kt"); runTest("compiler/testData/codegen/box/innerNested/innerGeneric.kt");