[FIR] Report top-level conflicts between TA constructors and funs

^KT-59880
This commit is contained in:
Nikolay Lunyak
2023-09-05 15:10:17 +03:00
committed by Space Team
parent 01d4f25363
commit f719436d1f
4 changed files with 73 additions and 21 deletions
@@ -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<Pair<FirProperty, String>>()
}
private fun groupTopLevelByName(declarations: List<FirDeclaration>): Map<Name, DeclarationBuckets> {
private fun groupTopLevelByName(declarations: List<FirDeclaration>, context: CheckerContext): Map<Name, DeclarationBuckets> {
val groups = mutableMapOf<Name, DeclarationBuckets>()
for (declaration in declarations) {
if (!declaration.isCollectable()) continue
@@ -114,12 +119,20 @@ private fun groupTopLevelByName(declarations: List<FirDeclaration>): Map<Name, D
if (declaration.classKind != ClassKind.OBJECT) {
declaration.declarations
.filterIsInstance<FirConstructor>()
.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<FirConstructor>().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 <D : FirDeclaration> FirDeclarationCollector<D>.collect(
@Suppress("GrazieInspection")
fun FirDeclarationCollector<FirDeclaration>.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<FirDeclaration>.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<FirDeclaration>.collectTopLevel(file: FirFile, packa
}
}
private fun FirClassLikeDeclaration.expandedClassWithConstructorsScope(context: CheckerContext): Pair<FirRegularClassSymbol, FirScope>? {
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<FirDeclaration>.collectTopLevelConflict(
declaration: FirDeclaration,
declarationPresentation: String,
@@ -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)
@@ -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<FirDeclaration, SmartSet<FirBasedSymbol<*>>>,
) {
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 =
@@ -1,9 +1,9 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER -TOPLEVEL_TYPEALIASES_ONLY
class C(val x: Int)
typealias CC = C
<!CONFLICTING_OVERLOADS!>typealias CC = C<!>
fun CC(x: Int) = x
<!CONFLICTING_OVERLOADS!>fun CC(x: Int)<!> = x
class Outer {
class C(val x: Int)