[FIR] Move type parameter scope above member and static scopes in tower

This fixes a false positive TYPE_PARAMETER_IS_NOT_AN_EXPRESSION when
a type parameter and some member, static or companion declaration have
the same name and referred to inside a class.

#KT-58028 Fixed
This commit is contained in:
Kirill Rakhman
2023-04-27 12:55:58 +02:00
committed by Space Team
parent 7958a9debd
commit bd9f36ad01
9 changed files with 140 additions and 25 deletions
@@ -26478,6 +26478,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
runTest("compiler/testData/diagnostics/tests/resolve/capturedTypesInLambdaParameter.kt"); runTest("compiler/testData/diagnostics/tests/resolve/capturedTypesInLambdaParameter.kt");
} }
@Test
@TestMetadata("companionPropertyAndTypeParameter.kt")
public void testCompanionPropertyAndTypeParameter() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/companionPropertyAndTypeParameter.kt");
}
@Test @Test
@TestMetadata("constructorVsCompanion.kt") @TestMetadata("constructorVsCompanion.kt")
public void testConstructorVsCompanion() throws Exception { public void testConstructorVsCompanion() throws Exception {
@@ -26478,6 +26478,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
runTest("compiler/testData/diagnostics/tests/resolve/capturedTypesInLambdaParameter.kt"); runTest("compiler/testData/diagnostics/tests/resolve/capturedTypesInLambdaParameter.kt");
} }
@Test
@TestMetadata("companionPropertyAndTypeParameter.kt")
public void testCompanionPropertyAndTypeParameter() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/companionPropertyAndTypeParameter.kt");
}
@Test @Test
@TestMetadata("constructorVsCompanion.kt") @TestMetadata("constructorVsCompanion.kt")
public void testConstructorVsCompanion() throws Exception { public void testConstructorVsCompanion() throws Exception {
@@ -26478,6 +26478,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
runTest("compiler/testData/diagnostics/tests/resolve/capturedTypesInLambdaParameter.kt"); runTest("compiler/testData/diagnostics/tests/resolve/capturedTypesInLambdaParameter.kt");
} }
@Test
@TestMetadata("companionPropertyAndTypeParameter.kt")
public void testCompanionPropertyAndTypeParameter() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/companionPropertyAndTypeParameter.kt");
}
@Test @Test
@TestMetadata("constructorVsCompanion.kt") @TestMetadata("constructorVsCompanion.kt")
public void testConstructorVsCompanion() throws Exception { public void testConstructorVsCompanion() throws Exception {
@@ -26490,6 +26490,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
runTest("compiler/testData/diagnostics/tests/resolve/capturedTypesInLambdaParameter.kt"); runTest("compiler/testData/diagnostics/tests/resolve/capturedTypesInLambdaParameter.kt");
} }
@Test
@TestMetadata("companionPropertyAndTypeParameter.kt")
public void testCompanionPropertyAndTypeParameter() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/companionPropertyAndTypeParameter.kt");
}
@Test @Test
@TestMetadata("constructorVsCompanion.kt") @TestMetadata("constructorVsCompanion.kt")
public void testConstructorVsCompanion() throws Exception { public void testConstructorVsCompanion() throws Exception {
@@ -424,36 +424,45 @@ class BodyResolveContext(
val towerElementsForClass = holder.collectTowerDataElementsForClass(owner, type) val towerElementsForClass = holder.collectTowerDataElementsForClass(owner, type)
val base = towerDataContext.addNonLocalTowerDataElements(towerElementsForClass.superClassesStaticsAndCompanionReceivers) val base = towerDataContext.addNonLocalTowerDataElements(towerElementsForClass.superClassesStaticsAndCompanionReceivers)
val statics = base
.addNonLocalScopeIfNotNull(towerElementsForClass.companionStaticScope)
.addNonLocalScopeIfNotNull(towerElementsForClass.staticScope)
val companionReceiver = towerElementsForClass.companionReceiver val statics = base
val staticsAndCompanion = if (companionReceiver == null) statics else base .addNonLocalScopesIfNotNull(towerElementsForClass.companionStaticScope, towerElementsForClass.staticScope)
.addReceiver(null, companionReceiver)
.addNonLocalScopeIfNotNull(towerElementsForClass.companionStaticScope) val staticsAndCompanion = when (val companionReceiver = towerElementsForClass.companionReceiver) {
.addNonLocalScopeIfNotNull(towerElementsForClass.staticScope) null -> statics
else -> base
.addReceiver(null, companionReceiver)
.addNonLocalScopesIfNotNull(towerElementsForClass.companionStaticScope, towerElementsForClass.staticScope)
}
val typeParameterScope = (owner as? FirRegularClass)?.typeParameterScope() val typeParameterScope = (owner as? FirRegularClass)?.typeParameterScope()
val forMembersResolution = // Type parameters must be inserted before all of staticsAndCompanion.
// Optimization: Only rebuild all of staticsAndCompanion that's below type parameters if there are any type parameters.
// Otherwise, reuse staticsAndCompanion.
val forConstructorHeader = if (typeParameterScope != null) {
towerDataContext
.addNonLocalScope(typeParameterScope)
.addNonLocalTowerDataElements(towerElementsForClass.superClassesStaticsAndCompanionReceivers)
.run { towerElementsForClass.companionReceiver?.let { addReceiver(null, it) } ?: this }
.addNonLocalScopesIfNotNull(towerElementsForClass.companionStaticScope, towerElementsForClass.staticScope)
} else {
staticsAndCompanion staticsAndCompanion
.addReceiver(labelName, towerElementsForClass.thisReceiver) }
.addContextReceiverGroup(towerElementsForClass.contextReceivers)
.addNonLocalScopeIfNotNull(typeParameterScope)
val scopeForConstructorHeader = val forMembersResolution = forConstructorHeader
staticsAndCompanion.addNonLocalScopeIfNotNull(typeParameterScope) .addReceiver(labelName, towerElementsForClass.thisReceiver)
.addContextReceiverGroup(towerElementsForClass.contextReceivers)
/* /*
* Scope for enum entries is equal to initial scope for constructor header * Scope for enum entries is equal to initial scope for constructor header
* *
* The only difference that we add value parameters to local scope for constructors * The only difference is that we add value parameters to local scope for constructors
* and should not do this for enum entries * and should not do this for enum entries
*/ */
@Suppress("UnnecessaryVariable") @Suppress("UnnecessaryVariable")
val scopeForEnumEntries = scopeForConstructorHeader val scopeForEnumEntries = forConstructorHeader
val newTowerDataContextForStaticNestedClasses = val newTowerDataContextForStaticNestedClasses =
if ((owner as? FirRegularClass)?.classKind?.isSingleton == true) if ((owner as? FirRegularClass)?.classKind?.isSingleton == true)
@@ -470,14 +479,14 @@ class BodyResolveContext(
} }
val newContexts = FirRegularTowerDataContexts( val newContexts = FirRegularTowerDataContexts(
forMembersResolution, regular = forMembersResolution,
forClassHeaderAnnotations = base, forClassHeaderAnnotations = base,
newTowerDataContextForStaticNestedClasses, forNestedClasses = newTowerDataContextForStaticNestedClasses,
statics, forCompanionObject = statics,
scopeForConstructorHeader, forConstructorHeaders = forConstructorHeader,
scopeForEnumEntries, forEnumEntries = scopeForEnumEntries,
primaryConstructorPureParametersScope, primaryConstructorPureParametersScope = primaryConstructorPureParametersScope,
primaryConstructorAllParametersScope primaryConstructorAllParametersScope = primaryConstructorAllParametersScope
) )
return withTowerDataContexts(newContexts) { return withTowerDataContexts(newContexts) {
@@ -202,6 +202,21 @@ class FirTowerDataContext private constructor(
return addNonLocalScope(scope) return addNonLocalScope(scope)
} }
// Optimized version for two parameters
fun addNonLocalScopesIfNotNull(scope1: FirScope?, scope2: FirScope?): FirTowerDataContext {
return if (scope1 != null) {
if (scope2 != null) {
addNonLocalScopeElements(listOf(scope1.asTowerDataElement(isLocal = false), scope2.asTowerDataElement(isLocal = false)))
} else {
addNonLocalScope(scope1)
}
} else if (scope2 != null) {
addNonLocalScope(scope2)
} else {
this
}
}
fun addNonLocalScope(scope: FirScope): FirTowerDataContext { fun addNonLocalScope(scope: FirScope): FirTowerDataContext {
val element = scope.asTowerDataElement(isLocal = false) val element = scope.asTowerDataElement(isLocal = false)
return FirTowerDataContext( return FirTowerDataContext(
@@ -212,6 +227,15 @@ class FirTowerDataContext private constructor(
) )
} }
private fun addNonLocalScopeElements(elements: List<FirTowerDataElement>): FirTowerDataContext {
return FirTowerDataContext(
towerDataElements.addAll(elements),
implicitReceiverStack,
localScopes,
nonLocalTowerDataElements.addAll(elements)
)
}
fun createSnapshot(): FirTowerDataContext { fun createSnapshot(): FirTowerDataContext {
return FirTowerDataContext( return FirTowerDataContext(
towerDataElements.map(FirTowerDataElement::createSnapshot).toPersistentList(), towerDataElements.map(FirTowerDataElement::createSnapshot).toPersistentList(),
@@ -0,0 +1,54 @@
// FIR_IDENTICAL
// DIAGNOSTICS: -UNUSED_VARIABLE
open class Base(any: Any) {
companion object {
val test = 42L
}
}
class C1<test> : Base(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int")!>test<!>) {
companion object {
val test = 12
val some: Int = test
}
val test = ""
val some: String = test
fun f() {
val test = 1.0
val some: Double = test
}
}
class C2<test> : Base(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int")!>test<!>) {
companion object {
val test = 12
val some: Int = test
}
val some: Int = test
fun f() {
val test = 1.0
val some: Double = test
}
}
class C3<test> : Base(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Long")!>test<!>) {
val some: Long = test
fun f() {
val test = 1.0
val some: Double = test
}
}
class C4<test> {
val some = <!TYPE_PARAMETER_IS_NOT_AN_EXPRESSION!>test<!>
fun f() {
val some = <!TYPE_PARAMETER_IS_NOT_AN_EXPRESSION!>test<!>
}
}
@@ -1,6 +1,4 @@
//ALLOW_AST_ACCESS //ALLOW_AST_ACCESS
// IGNORE_FIR_METADATA_LOADING_K2
// Ignore reason: KT-58028
package test package test
class ConstructorTypeParamClassObjectTypeConflict<test> { class ConstructorTypeParamClassObjectTypeConflict<test> {
@@ -27262,6 +27262,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/resolve/capturedTypesInLambdaParameter.kt"); runTest("compiler/testData/diagnostics/tests/resolve/capturedTypesInLambdaParameter.kt");
} }
@Test
@TestMetadata("companionPropertyAndTypeParameter.kt")
public void testCompanionPropertyAndTypeParameter() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/companionPropertyAndTypeParameter.kt");
}
@Test @Test
@TestMetadata("constructorVsCompanion.kt") @TestMetadata("constructorVsCompanion.kt")
public void testConstructorVsCompanion() throws Exception { public void testConstructorVsCompanion() throws Exception {