[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");
}
@Test
@TestMetadata("companionPropertyAndTypeParameter.kt")
public void testCompanionPropertyAndTypeParameter() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/companionPropertyAndTypeParameter.kt");
}
@Test
@TestMetadata("constructorVsCompanion.kt")
public void testConstructorVsCompanion() throws Exception {
@@ -26478,6 +26478,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
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
@TestMetadata("constructorVsCompanion.kt")
public void testConstructorVsCompanion() throws Exception {
@@ -26478,6 +26478,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
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
@TestMetadata("constructorVsCompanion.kt")
public void testConstructorVsCompanion() throws Exception {
@@ -26490,6 +26490,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
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
@TestMetadata("constructorVsCompanion.kt")
public void testConstructorVsCompanion() throws Exception {
@@ -424,36 +424,45 @@ class BodyResolveContext(
val towerElementsForClass = holder.collectTowerDataElementsForClass(owner, type)
val base = towerDataContext.addNonLocalTowerDataElements(towerElementsForClass.superClassesStaticsAndCompanionReceivers)
val statics = base
.addNonLocalScopeIfNotNull(towerElementsForClass.companionStaticScope)
.addNonLocalScopeIfNotNull(towerElementsForClass.staticScope)
val companionReceiver = towerElementsForClass.companionReceiver
val staticsAndCompanion = if (companionReceiver == null) statics else base
.addReceiver(null, companionReceiver)
.addNonLocalScopeIfNotNull(towerElementsForClass.companionStaticScope)
.addNonLocalScopeIfNotNull(towerElementsForClass.staticScope)
val statics = base
.addNonLocalScopesIfNotNull(towerElementsForClass.companionStaticScope, towerElementsForClass.staticScope)
val staticsAndCompanion = when (val companionReceiver = towerElementsForClass.companionReceiver) {
null -> statics
else -> base
.addReceiver(null, companionReceiver)
.addNonLocalScopesIfNotNull(towerElementsForClass.companionStaticScope, towerElementsForClass.staticScope)
}
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
.addReceiver(labelName, towerElementsForClass.thisReceiver)
.addContextReceiverGroup(towerElementsForClass.contextReceivers)
.addNonLocalScopeIfNotNull(typeParameterScope)
}
val scopeForConstructorHeader =
staticsAndCompanion.addNonLocalScopeIfNotNull(typeParameterScope)
val forMembersResolution = forConstructorHeader
.addReceiver(labelName, towerElementsForClass.thisReceiver)
.addContextReceiverGroup(towerElementsForClass.contextReceivers)
/*
* 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
*/
@Suppress("UnnecessaryVariable")
val scopeForEnumEntries = scopeForConstructorHeader
val scopeForEnumEntries = forConstructorHeader
val newTowerDataContextForStaticNestedClasses =
if ((owner as? FirRegularClass)?.classKind?.isSingleton == true)
@@ -470,14 +479,14 @@ class BodyResolveContext(
}
val newContexts = FirRegularTowerDataContexts(
forMembersResolution,
regular = forMembersResolution,
forClassHeaderAnnotations = base,
newTowerDataContextForStaticNestedClasses,
statics,
scopeForConstructorHeader,
scopeForEnumEntries,
primaryConstructorPureParametersScope,
primaryConstructorAllParametersScope
forNestedClasses = newTowerDataContextForStaticNestedClasses,
forCompanionObject = statics,
forConstructorHeaders = forConstructorHeader,
forEnumEntries = scopeForEnumEntries,
primaryConstructorPureParametersScope = primaryConstructorPureParametersScope,
primaryConstructorAllParametersScope = primaryConstructorAllParametersScope
)
return withTowerDataContexts(newContexts) {
@@ -202,6 +202,21 @@ class FirTowerDataContext private constructor(
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 {
val element = scope.asTowerDataElement(isLocal = false)
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 {
return FirTowerDataContext(
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
// IGNORE_FIR_METADATA_LOADING_K2
// Ignore reason: KT-58028
package test
class ConstructorTypeParamClassObjectTypeConflict<test> {
@@ -27262,6 +27262,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
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
@TestMetadata("constructorVsCompanion.kt")
public void testConstructorVsCompanion() throws Exception {