From f719436d1f0ba933c70e19c42893dae373c07382 Mon Sep 17 00:00:00 2001 From: Nikolay Lunyak Date: Tue, 5 Sep 2023 15:10:17 +0300 Subject: [PATCH] [FIR] Report top-level conflicts between TA constructors and funs ^KT-59880 --- .../analysis/checkers/FirConflictsHelpers.kt | 80 +++++++++++++++---- .../checkers/FirRedeclarationPresenter.kt | 6 +- .../FirConflictsDeclarationChecker.kt | 4 +- .../redeclarations/TypeAliasCtorVsFun.fir.kt | 4 +- 4 files changed, 73 insertions(+), 21 deletions(-) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirConflictsHelpers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirConflictsHelpers.kt index 58f19f6fa57..ef73ca264a0 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirConflictsHelpers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirConflictsHelpers.kt @@ -15,14 +15,19 @@ import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirNameConflictsTracker import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.declarations.* -import org.jetbrains.kotlin.fir.declarations.FirOuterClassTypeParameterRef import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl.Companion.DEFAULT_STATUS_FOR_STATUSLESS_DECLARATIONS import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl.Companion.DEFAULT_STATUS_FOR_SUSPEND_MAIN_FUNCTION import org.jetbrains.kotlin.fir.declarations.impl.modifiersRepresentation +import org.jetbrains.kotlin.fir.declarations.utils.expandedConeType import org.jetbrains.kotlin.fir.expressions.FirBlock import org.jetbrains.kotlin.fir.resolve.fullyExpandedType +import org.jetbrains.kotlin.fir.resolve.outerType import org.jetbrains.kotlin.fir.resolve.providers.firProvider +import org.jetbrains.kotlin.fir.resolve.scope +import org.jetbrains.kotlin.fir.scopes.FakeOverrideTypeCalculator +import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.impl.FirPackageMemberScope +import org.jetbrains.kotlin.fir.scopes.impl.TypeAliasConstructorsSubstitutingScope import org.jetbrains.kotlin.fir.scopes.impl.toConeType import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.SymbolInternals @@ -90,7 +95,7 @@ private class DeclarationBuckets { val extensionProperties = mutableListOf>() } -private fun groupTopLevelByName(declarations: List): Map { +private fun groupTopLevelByName(declarations: List, context: CheckerContext): Map { val groups = mutableMapOf() for (declaration in declarations) { if (!declaration.isCollectable()) continue @@ -114,12 +119,20 @@ private fun groupTopLevelByName(declarations: List): Map() - .mapTo(group.constructors) { it to FirRedeclarationPresenter.represent(it, declaration) } + .mapTo(group.constructors) { it to FirRedeclarationPresenter.represent(it, declaration.symbol) } + } + } + is FirTypeAlias -> { + val group = groups.getOrPut(declaration.name, ::DeclarationBuckets) + group.classLikes += declaration to FirRedeclarationPresenter.represent(declaration) + + @OptIn(SymbolInternals::class) + declaration.expandedClassWithConstructorsScope(context)?.let { (_, scopeWithConstructors) -> + scopeWithConstructors.processDeclaredConstructors { + group.constructors += it.fir to FirRedeclarationPresenter.represent(it.fir, declaration.symbol) + } } } - is FirTypeAlias -> - groups.getOrPut(declaration.name, ::DeclarationBuckets).classLikes += - declaration to FirRedeclarationPresenter.represent(declaration) else -> {} } } @@ -173,8 +186,16 @@ fun collectConflictingLocalFunctionsFrom(block: FirBlock, context: CheckerContex is FirRegularClass -> // TODO, KT-61243: Use declaredMemberScope collectable.declarations.filterIsInstance().forEach { - inspector.collect(it, FirRedeclarationPresenter.represent(it, collectable), functionDeclarations) + inspector.collect(it, FirRedeclarationPresenter.represent(it, collectable.symbol), functionDeclarations) } + is FirTypeAlias -> { + collectable.expandedClassWithConstructorsScope(context)?.let { (_, scopeWithConstructors) -> + scopeWithConstructors.processDeclaredConstructors { + @OptIn(SymbolInternals::class) + inspector.collect(it.fir, FirRedeclarationPresenter.represent(it.fir, collectable.symbol), functionDeclarations) + } + } + } else -> {} } } @@ -224,7 +245,7 @@ private fun FirDeclarationCollector.collect( @Suppress("GrazieInspection") fun FirDeclarationCollector.collectTopLevel(file: FirFile, packageMemberScope: FirPackageMemberScope) { - for ((declarationName, group) in groupTopLevelByName(file.declarations)) { + for ((declarationName, group) in groupTopLevelByName(file.declarations, context)) { val groupHasClassLikesOrProperties = group.classLikes.isNotEmpty() || group.properties.isNotEmpty() val groupHasSimpleFunctions = group.simpleFunctions.isNotEmpty() @@ -257,15 +278,21 @@ fun FirDeclarationCollector.collectTopLevel(file: FirFile, packa collect(group.properties, conflictingSymbol, conflictingPresentation, conflictingFile) if (groupHasSimpleFunctions) { - if (conflictingSymbol !is FirRegularClassSymbol) return - if (conflictingSymbol.classKind == ClassKind.OBJECT || conflictingSymbol.classKind == ClassKind.ENUM_ENTRY) return + val declaration = conflictingSymbol.fir - conflictingSymbol.lazyResolveToPhase(FirResolvePhase.STATUS) + if (declaration !is FirClassLikeDeclaration) { + return + } - val classWithSameName = conflictingSymbol.fir - classWithSameName.unsubstitutedScope(context).processDeclaredConstructors { constructor -> - val ctorRepresentation = FirRedeclarationPresenter.represent(constructor.fir, classWithSameName) - collect(group.simpleFunctions, conflictingSymbol = constructor, conflictingPresentation = ctorRepresentation) + declaration.expandedClassWithConstructorsScope(context)?.let { (expandedClass, scopeWithConstructors) -> + if (expandedClass.classKind == ClassKind.OBJECT || expandedClass.classKind == ClassKind.ENUM_ENTRY) { + return + } + + scopeWithConstructors.processDeclaredConstructors { constructor -> + val ctorRepresentation = FirRedeclarationPresenter.represent(constructor.fir, declaration.symbol) + collect(group.simpleFunctions, conflictingSymbol = constructor, conflictingPresentation = ctorRepresentation) + } } } } @@ -311,6 +338,29 @@ fun FirDeclarationCollector.collectTopLevel(file: FirFile, packa } } +private fun FirClassLikeDeclaration.expandedClassWithConstructorsScope(context: CheckerContext): Pair? { + return when (this) { + is FirRegularClass -> symbol to unsubstitutedScope(context) + is FirTypeAlias -> { + val expandedType = expandedConeType + val expandedClass = expandedType?.toRegularClassSymbol(context.session) + val expandedTypeScope = expandedType?.scope( + context.session, context.scopeSession, + FakeOverrideTypeCalculator.DoNothing, + requiredMembersPhase = FirResolvePhase.STATUS, + ) + + if (expandedType != null && expandedClass != null && expandedTypeScope != null) { + val outerType = outerType(expandedType, context.session) { it.outerClassSymbol(context) } + expandedClass to TypeAliasConstructorsSubstitutingScope(symbol, expandedTypeScope, outerType) + } else { + null + } + } + else -> null + } +} + private fun FirDeclarationCollector.collectTopLevelConflict( declaration: FirDeclaration, declarationPresentation: String, diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirRedeclarationPresenter.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirRedeclarationPresenter.kt index 73cd42026c1..1d37b6213d5 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirRedeclarationPresenter.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirRedeclarationPresenter.kt @@ -7,7 +7,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.utils.isOperator -import org.jetbrains.kotlin.fir.types.* +import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.ClassId @@ -99,7 +99,7 @@ internal object FirRedeclarationPresenter { appendRepresentation(it.symbol.classId) } - fun represent(it: FirConstructor, owner: FirRegularClass) = buildString { + fun represent(it: FirConstructor, owner: FirClassLikeSymbol<*>) = buildString { repeat(it.contextReceivers.size) { append(',') } @@ -110,7 +110,7 @@ internal object FirRedeclarationPresenter { append('>') append('[') append(']') - appendRepresentation(owner.symbol.classId) + appendRepresentation(owner.classId) append('(') it.valueParameters.forEach { appendRepresentation(it) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConflictsDeclarationChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConflictsDeclarationChecker.kt index 354c630d9f3..1e36b19d53f 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConflictsDeclarationChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConflictsDeclarationChecker.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.fir.packageFqName import org.jetbrains.kotlin.fir.resolve.getContainingDeclaration import org.jetbrains.kotlin.fir.scopes.impl.FirPackageMemberScope import org.jetbrains.kotlin.fir.scopes.impl.PACKAGE_MEMBER +import org.jetbrains.kotlin.fir.scopes.impl.typeAliasForConstructor import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol import org.jetbrains.kotlin.name.ClassId @@ -58,7 +59,8 @@ object FirConflictsDeclarationChecker : FirBasicDeclarationChecker() { declarationConflictingSymbols: Map>>, ) { declarationConflictingSymbols.forEach { (conflictingDeclaration, symbols) -> - val source = conflictingDeclaration.source + val typeAliasForConstructorSource = (conflictingDeclaration as? FirConstructor)?.typeAliasForConstructor?.source + val source = typeAliasForConstructorSource ?: conflictingDeclaration.source if (symbols.isEmpty()) return@forEach val factory = diff --git a/compiler/testData/diagnostics/tests/redeclarations/TypeAliasCtorVsFun.fir.kt b/compiler/testData/diagnostics/tests/redeclarations/TypeAliasCtorVsFun.fir.kt index 7ef178e52bc..70a4910d45b 100644 --- a/compiler/testData/diagnostics/tests/redeclarations/TypeAliasCtorVsFun.fir.kt +++ b/compiler/testData/diagnostics/tests/redeclarations/TypeAliasCtorVsFun.fir.kt @@ -1,9 +1,9 @@ // !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER -TOPLEVEL_TYPEALIASES_ONLY class C(val x: Int) -typealias CC = C +typealias CC = C -fun CC(x: Int) = x +fun CC(x: Int) = x class Outer { class C(val x: Int)