[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.checkers.declaration.FirNameConflictsTracker
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.* 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_STATUSLESS_DECLARATIONS
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl.Companion.DEFAULT_STATUS_FOR_SUSPEND_MAIN_FUNCTION 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.impl.modifiersRepresentation
import org.jetbrains.kotlin.fir.declarations.utils.expandedConeType
import org.jetbrains.kotlin.fir.expressions.FirBlock import org.jetbrains.kotlin.fir.expressions.FirBlock
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType 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.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.FirPackageMemberScope
import org.jetbrains.kotlin.fir.scopes.impl.TypeAliasConstructorsSubstitutingScope
import org.jetbrains.kotlin.fir.scopes.impl.toConeType import org.jetbrains.kotlin.fir.scopes.impl.toConeType
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.SymbolInternals import org.jetbrains.kotlin.fir.symbols.SymbolInternals
@@ -90,7 +95,7 @@ private class DeclarationBuckets {
val extensionProperties = mutableListOf<Pair<FirProperty, String>>() 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>() val groups = mutableMapOf<Name, DeclarationBuckets>()
for (declaration in declarations) { for (declaration in declarations) {
if (!declaration.isCollectable()) continue if (!declaration.isCollectable()) continue
@@ -114,12 +119,20 @@ private fun groupTopLevelByName(declarations: List<FirDeclaration>): Map<Name, D
if (declaration.classKind != ClassKind.OBJECT) { if (declaration.classKind != ClassKind.OBJECT) {
declaration.declarations declaration.declarations
.filterIsInstance<FirConstructor>() .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 -> {} else -> {}
} }
} }
@@ -173,8 +186,16 @@ fun collectConflictingLocalFunctionsFrom(block: FirBlock, context: CheckerContex
is FirRegularClass -> is FirRegularClass ->
// TODO, KT-61243: Use declaredMemberScope // TODO, KT-61243: Use declaredMemberScope
collectable.declarations.filterIsInstance<FirConstructor>().forEach { 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 -> {} else -> {}
} }
} }
@@ -224,7 +245,7 @@ private fun <D : FirDeclaration> FirDeclarationCollector<D>.collect(
@Suppress("GrazieInspection") @Suppress("GrazieInspection")
fun FirDeclarationCollector<FirDeclaration>.collectTopLevel(file: FirFile, packageMemberScope: FirPackageMemberScope) { 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 groupHasClassLikesOrProperties = group.classLikes.isNotEmpty() || group.properties.isNotEmpty()
val groupHasSimpleFunctions = group.simpleFunctions.isNotEmpty() val groupHasSimpleFunctions = group.simpleFunctions.isNotEmpty()
@@ -257,15 +278,21 @@ fun FirDeclarationCollector<FirDeclaration>.collectTopLevel(file: FirFile, packa
collect(group.properties, conflictingSymbol, conflictingPresentation, conflictingFile) collect(group.properties, conflictingSymbol, conflictingPresentation, conflictingFile)
if (groupHasSimpleFunctions) { if (groupHasSimpleFunctions) {
if (conflictingSymbol !is FirRegularClassSymbol) return val declaration = conflictingSymbol.fir
if (conflictingSymbol.classKind == ClassKind.OBJECT || conflictingSymbol.classKind == ClassKind.ENUM_ENTRY) return
conflictingSymbol.lazyResolveToPhase(FirResolvePhase.STATUS) if (declaration !is FirClassLikeDeclaration) {
return
}
val classWithSameName = conflictingSymbol.fir declaration.expandedClassWithConstructorsScope(context)?.let { (expandedClass, scopeWithConstructors) ->
classWithSameName.unsubstitutedScope(context).processDeclaredConstructors { constructor -> if (expandedClass.classKind == ClassKind.OBJECT || expandedClass.classKind == ClassKind.ENUM_ENTRY) {
val ctorRepresentation = FirRedeclarationPresenter.represent(constructor.fir, classWithSameName) return
collect(group.simpleFunctions, conflictingSymbol = constructor, conflictingPresentation = ctorRepresentation) }
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( private fun FirDeclarationCollector<FirDeclaration>.collectTopLevelConflict(
declaration: FirDeclaration, declaration: FirDeclaration,
declarationPresentation: String, 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.*
import org.jetbrains.kotlin.fir.declarations.utils.isOperator 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.CallableId
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
@@ -99,7 +99,7 @@ internal object FirRedeclarationPresenter {
appendRepresentation(it.symbol.classId) appendRepresentation(it.symbol.classId)
} }
fun represent(it: FirConstructor, owner: FirRegularClass) = buildString { fun represent(it: FirConstructor, owner: FirClassLikeSymbol<*>) = buildString {
repeat(it.contextReceivers.size) { repeat(it.contextReceivers.size) {
append(',') append(',')
} }
@@ -110,7 +110,7 @@ internal object FirRedeclarationPresenter {
append('>') append('>')
append('[') append('[')
append(']') append(']')
appendRepresentation(owner.symbol.classId) appendRepresentation(owner.classId)
append('(') append('(')
it.valueParameters.forEach { it.valueParameters.forEach {
appendRepresentation(it) appendRepresentation(it)
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.fir.packageFqName
import org.jetbrains.kotlin.fir.resolve.getContainingDeclaration import org.jetbrains.kotlin.fir.resolve.getContainingDeclaration
import org.jetbrains.kotlin.fir.scopes.impl.FirPackageMemberScope import org.jetbrains.kotlin.fir.scopes.impl.FirPackageMemberScope
import org.jetbrains.kotlin.fir.scopes.impl.PACKAGE_MEMBER 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.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
@@ -58,7 +59,8 @@ object FirConflictsDeclarationChecker : FirBasicDeclarationChecker() {
declarationConflictingSymbols: Map<FirDeclaration, SmartSet<FirBasedSymbol<*>>>, declarationConflictingSymbols: Map<FirDeclaration, SmartSet<FirBasedSymbol<*>>>,
) { ) {
declarationConflictingSymbols.forEach { (conflictingDeclaration, symbols) -> 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 if (symbols.isEmpty()) return@forEach
val factory = val factory =
@@ -1,9 +1,9 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER -TOPLEVEL_TYPEALIASES_ONLY // !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER -TOPLEVEL_TYPEALIASES_ONLY
class C(val x: Int) 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 Outer {
class C(val x: Int) class C(val x: Int)