[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");
}
@Test
@TestMetadata("inheritedInnerAndNested.kt")
public void testInheritedInnerAndNested() {
runTest("compiler/testData/codegen/box/innerNested/inheritedInnerAndNested.kt");
}
@Test
@TestMetadata("innerGeneric.kt")
public void testInnerGeneric() {
@@ -30642,6 +30642,12 @@ public class LLFirReversedBlackBoxCodegenBasedTestGenerated extends AbstractLLFi
runTest("compiler/testData/codegen/box/innerNested/importNestedClass.kt");
}
@Test
@TestMetadata("inheritedInnerAndNested.kt")
public void testInheritedInnerAndNested() {
runTest("compiler/testData/codegen/box/innerNested/inheritedInnerAndNested.kt");
}
@Test
@TestMetadata("innerGeneric.kt")
public void testInnerGeneric() {
@@ -30559,6 +30559,12 @@ public class FirLightTreeBlackBoxCodegenTestGenerated extends AbstractFirLightTr
runTest("compiler/testData/codegen/box/innerNested/importNestedClass.kt");
}
@Test
@TestMetadata("inheritedInnerAndNested.kt")
public void testInheritedInnerAndNested() {
runTest("compiler/testData/codegen/box/innerNested/inheritedInnerAndNested.kt");
}
@Test
@TestMetadata("innerGeneric.kt")
public void testInnerGeneric() {
@@ -30559,6 +30559,12 @@ public class FirLightTreeBlackBoxCodegenWithIrFakeOverrideGeneratorTestGenerated
runTest("compiler/testData/codegen/box/innerNested/importNestedClass.kt");
}
@Test
@TestMetadata("inheritedInnerAndNested.kt")
public void testInheritedInnerAndNested() {
runTest("compiler/testData/codegen/box/innerNested/inheritedInnerAndNested.kt");
}
@Test
@TestMetadata("innerGeneric.kt")
public void testInnerGeneric() {
@@ -30559,6 +30559,12 @@ public class FirPsiBlackBoxCodegenTestGenerated extends AbstractFirPsiBlackBoxCo
runTest("compiler/testData/codegen/box/innerNested/importNestedClass.kt");
}
@Test
@TestMetadata("inheritedInnerAndNested.kt")
public void testInheritedInnerAndNested() {
runTest("compiler/testData/codegen/box/innerNested/inheritedInnerAndNested.kt");
}
@Test
@TestMetadata("innerGeneric.kt")
public void testInnerGeneric() {
@@ -22,17 +22,23 @@ import org.jetbrains.kotlin.fir.whileAnalysing
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.deprecation.DeprecationLevelValue
private operator fun <T> Pair<T, *>?.component1() = this?.first
private operator fun <T> Pair<*, T>?.component2() = this?.second
private operator fun <T> Pair<T, *>?.component1(): T? = this?.first
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,
session: FirSession,
bodyResolveComponents: BodyResolveComponents,
includeInnerConstructors: Boolean,
constructorFilter: ConstructorFilter,
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
processConstructors(
@@ -41,7 +47,7 @@ internal fun FirScope.processConstructorsByName(
processor,
session,
bodyResolveComponents,
includeInnerConstructors
constructorFilter
)
processSyntheticConstructors(
@@ -55,12 +61,12 @@ internal fun FirScope.processFunctionsAndConstructorsByName(
callInfo: CallInfo,
session: FirSession,
bodyResolveComponents: BodyResolveComponents,
includeInnerConstructors: Boolean,
constructorFilter: ConstructorFilter,
processor: (FirCallableSymbol<*>) -> Unit
) {
processConstructorsByName(
callInfo, session, bodyResolveComponents,
includeInnerConstructors = includeInnerConstructors,
constructorFilter,
processor
)
@@ -116,6 +122,7 @@ private fun FirDeclaration.isInvisibleOrHidden(session: FirSession, bodyResolveC
private fun FirScope.getFirstClassifierOrNull(
callInfo: CallInfo,
constructorFilter: ConstructorFilter,
session: FirSession,
bodyResolveComponents: BodyResolveComponents
): SymbolWithSubstitutor? {
@@ -124,7 +131,14 @@ private fun FirScope.getFirstClassifierOrNull(
var result: SymbolWithSubstitutor? = null
processClassifiersByNameWithSubstitution(callInfo.name) { symbol, substitutor ->
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 {
isSuccessCandidate && !isSuccessResult -> {
@@ -212,7 +226,7 @@ private fun processConstructors(
processor: (FirFunctionSymbol<*>) -> Unit,
session: FirSession,
bodyResolveComponents: BodyResolveComponents,
includeInnerConstructors: Boolean
constructorFilter: ConstructorFilter
) {
whileAnalysing(session, matchedSymbol.fir) {
val scope = when (matchedSymbol) {
@@ -254,10 +268,13 @@ private fun processConstructors(
}
}
scope?.processDeclaredConstructors {
if (includeInnerConstructors || !it.fir.isInner) {
processor(it)
scope?.processDeclaredConstructors {
val shouldProcess = when (it.fir.isInner) {
true -> constructorFilter.acceptInner
false -> constructorFilter.acceptNested
}
if (shouldProcess) {
processor(it)
}
}
}
@@ -86,24 +86,31 @@ internal abstract class FirBaseTowerResolveTask(
protected fun FirScope.toScopeTowerLevel(
extensionReceiver: ReceiverValue? = null,
withHideMembersOnly: Boolean = false,
includeInnerConstructors: Boolean = extensionReceiver != null,
constructorFilter: ConstructorFilter = extensionReceiver.toConstructorFilter(),
contextReceiverGroup: ContextReceiverGroup? = null,
dispatchReceiverForStatics: ExpressionReceiverValue? = null
): ScopeTowerLevel {
return ScopeTowerLevel(
components, this,
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(
staticOwnerOwnerSymbol: FirRegularClassSymbol? = null,
source: KtSourceElement? = null
): ScopeTowerLevel = toScopeTowerLevel(
extensionReceiver = null,
withHideMembersOnly = false,
includeInnerConstructors = false,
constructorFilter = ConstructorFilter.OnlyNested,
contextReceiverGroup = null,
staticOwnerOwnerSymbol?.let {
val resolvedQualifier = buildResolvedQualifier {
@@ -256,7 +263,7 @@ internal open class FirTowerResolveTask(
val callableScope = qualifierReceiver.callableScope() ?: return
processLevel(
callableScope.toScopeTowerLevel(
includeInnerConstructors = false,
constructorFilter = ConstructorFilter.OnlyNested,
dispatchReceiverForStatics = when (qualifierReceiver) {
is ClassQualifierReceiver -> ExpressionReceiverValue(qualifierReceiver.explicitReceiver)
else -> null
@@ -276,7 +283,7 @@ internal open class FirTowerResolveTask(
) return
val scope = qualifierReceiver.classifierScope() ?: return
processLevel(
scope.toScopeTowerLevel(includeInnerConstructors = false), info,
scope.toScopeTowerLevel(constructorFilter = ConstructorFilter.OnlyNested), info,
TowerGroup.Classifier
)
}
@@ -280,7 +280,7 @@ class MemberScopeTowerLevel(
withMemberCallLookup(lookupTracker, info) { lookupCtx ->
this.processFunctionsAndConstructorsByName(
info, session, bodyResolveComponents,
includeInnerConstructors = true,
ConstructorFilter.OnlyInner,
processor = {
lookupCtx.recordCallableMemberLookup(it)
// 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: extension receiver = either none or explicit
// (if explicit receiver exists, it always *should* be an extension receiver)
class ScopeTowerLevel(
internal class ScopeTowerLevel(
private val bodyResolveComponents: BodyResolveComponents,
val scope: FirScope,
private val givenExtensionReceiverOptions: List<FirExpression>,
private val withHideMembersOnly: Boolean,
private val includeInnerConstructors: Boolean,
private val constructorFilter: ConstructorFilter,
private val dispatchReceiverForStatics: ExpressionReceiverValue?
) : TowerScopeLevel() {
private val session: FirSession get() = bodyResolveComponents.session
@@ -486,7 +486,7 @@ class ScopeTowerLevel(
info,
session,
bodyResolveComponents,
includeInnerConstructors = includeInnerConstructors
constructorFilter
) { candidate ->
empty = false
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() {
A().<!UNRESOLVED_REFERENCE!>Inner<!>().box()
A().Inner().box()
A.<!UNRESOLVED_REFERENCE!>Inner<!>().box() // should be an error
B().<!UNRESOLVED_REFERENCE!>Inner<!>().box() // should be an error
B.Inner().box()
C().Inner().box()
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()
F.Inner().box()
G.Inner().box()
@@ -30559,6 +30559,12 @@ public class JvmAbiConsistencyTestBoxGenerated extends AbstractJvmAbiConsistency
runTest("compiler/testData/codegen/box/innerNested/importNestedClass.kt");
}
@Test
@TestMetadata("inheritedInnerAndNested.kt")
public void testInheritedInnerAndNested() {
runTest("compiler/testData/codegen/box/innerNested/inheritedInnerAndNested.kt");
}
@Test
@TestMetadata("innerGeneric.kt")
public void testInnerGeneric() {
@@ -30559,6 +30559,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/innerNested/importNestedClass.kt");
}
@Test
@TestMetadata("inheritedInnerAndNested.kt")
public void testInheritedInnerAndNested() {
runTest("compiler/testData/codegen/box/innerNested/inheritedInnerAndNested.kt");
}
@Test
@TestMetadata("innerGeneric.kt")
public void testInnerGeneric() {
@@ -30559,6 +30559,12 @@ public class IrBlackBoxCodegenWithIrInlinerTestGenerated extends AbstractIrBlack
runTest("compiler/testData/codegen/box/innerNested/importNestedClass.kt");
}
@Test
@TestMetadata("inheritedInnerAndNested.kt")
public void testInheritedInnerAndNested() {
runTest("compiler/testData/codegen/box/innerNested/inheritedInnerAndNested.kt");
}
@Test
@TestMetadata("innerGeneric.kt")
public void testInnerGeneric() {
@@ -30559,6 +30559,12 @@ public class FirBlackBoxCodegenTestWithInlineScopesGenerated extends AbstractFir
runTest("compiler/testData/codegen/box/innerNested/importNestedClass.kt");
}
@Test
@TestMetadata("inheritedInnerAndNested.kt")
public void testInheritedInnerAndNested() {
runTest("compiler/testData/codegen/box/innerNested/inheritedInnerAndNested.kt");
}
@Test
@TestMetadata("innerGeneric.kt")
public void testInnerGeneric() {
@@ -25813,6 +25813,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
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")
public void testInnerGeneric() {
runTest("compiler/testData/codegen/box/innerNested/innerGeneric.kt");