[FIR] Stop using .fir when checking conflicts
Use the symbols API in the declarations presenter and conflicts helpers.
This commit is contained in:
committed by
Space Team
parent
942bff8a03
commit
a1cb6258bc
+92
-94
@@ -18,7 +18,6 @@ import org.jetbrains.kotlin.fir.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.modifiersRepresentation
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.expandedConeType
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.nameOrSpecialName
|
||||
import org.jetbrains.kotlin.fir.expressions.FirBlock
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
@@ -32,10 +31,7 @@ import org.jetbrains.kotlin.fir.scopes.impl.TypeAliasConstructorsSubstitutingSco
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.toConeType
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.util.ListMultimap
|
||||
@@ -47,8 +43,8 @@ import org.jetbrains.kotlin.utils.SmartSet
|
||||
|
||||
val DEFAULT_STATUS_FOR_NORMAL_MAIN_FUNCTION = DEFAULT_STATUS_FOR_STATUSLESS_DECLARATIONS
|
||||
|
||||
private val FirSimpleFunction.hasMainFunctionStatus
|
||||
get() = when (status.modifiersRepresentation) {
|
||||
private val FirNamedFunctionSymbol.hasMainFunctionStatus
|
||||
get() = when (resolvedStatus.modifiersRepresentation) {
|
||||
DEFAULT_STATUS_FOR_NORMAL_MAIN_FUNCTION.modifiersRepresentation,
|
||||
DEFAULT_STATUS_FOR_SUSPEND_MAIN_FUNCTION.modifiersRepresentation,
|
||||
-> true
|
||||
@@ -57,76 +53,81 @@ private val FirSimpleFunction.hasMainFunctionStatus
|
||||
|
||||
private val CallableId.isTopLevel get() = className == null
|
||||
|
||||
private fun FirDeclaration.isCollectable(): Boolean {
|
||||
if (this is FirCallableDeclaration) {
|
||||
if (contextReceivers.any { it.typeRef.coneType.hasError() }) return false
|
||||
if (typeParameters.any { it.toConeType().hasError() }) return false
|
||||
private fun FirBasedSymbol<*>.isCollectable(): Boolean {
|
||||
if (this is FirCallableSymbol<*>) {
|
||||
if (resolvedContextReceivers.any { it.typeRef.coneType.hasError() }) return false
|
||||
if (typeParameterSymbols.any { it.toConeType().hasError() }) return false
|
||||
if (receiverParameter?.typeRef?.coneType?.hasError() == true) return false
|
||||
if (this is FirFunction && valueParameters.any { it.returnTypeRef.coneType.hasError() }) return false
|
||||
if (this is FirFunctionSymbol<*> && valueParameterSymbols.any { it.resolvedReturnType.hasError() }) return false
|
||||
}
|
||||
|
||||
return when (this) {
|
||||
// - see tests with `fun () {}`.
|
||||
// you can't redeclare something that has no name.
|
||||
is FirSimpleFunction -> source?.kind !is KtFakeSourceElementKind && name != SpecialNames.NO_NAME_PROVIDED
|
||||
is FirRegularClass -> name != SpecialNames.NO_NAME_PROVIDED
|
||||
is FirNamedFunctionSymbol -> source?.kind !is KtFakeSourceElementKind && name != SpecialNames.NO_NAME_PROVIDED
|
||||
is FirRegularClassSymbol -> name != SpecialNames.NO_NAME_PROVIDED
|
||||
// - see testEnumValuesValueOf.
|
||||
// it generates a static function that has
|
||||
// the same signature as the function defined
|
||||
// explicitly.
|
||||
is FirProperty -> source?.kind !is KtFakeSourceElementKind.EnumGeneratedDeclaration
|
||||
is FirPropertySymbol -> source?.kind !is KtFakeSourceElementKind.EnumGeneratedDeclaration
|
||||
// class delegation field will be renamed after by the IR backend in a case of a name clash
|
||||
is FirField -> source?.kind != KtFakeSourceElementKind.ClassDelegationField
|
||||
is FirFieldSymbol -> source?.kind != KtFakeSourceElementKind.ClassDelegationField
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
|
||||
private fun isExpectAndActual(declaration1: FirDeclaration, declaration2: FirDeclaration): Boolean {
|
||||
if (declaration1 !is FirMemberDeclaration) return false
|
||||
if (declaration2 !is FirMemberDeclaration) return false
|
||||
return (declaration1.status.isExpect && declaration2.status.isActual) ||
|
||||
(declaration1.status.isActual && declaration2.status.isExpect)
|
||||
private val FirBasedSymbol<*>.resolvedStatus
|
||||
get() = when (this) {
|
||||
is FirCallableSymbol<*> -> resolvedStatus
|
||||
is FirClassLikeSymbol<*> -> resolvedStatus
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun isExpectAndActual(declaration1: FirBasedSymbol<*>, declaration2: FirBasedSymbol<*>): Boolean {
|
||||
val status1 = declaration1.resolvedStatus ?: return false
|
||||
val status2 = declaration2.resolvedStatus ?: return false
|
||||
return (status1.isExpect && status2.isActual) || (status1.isActual && status2.isExpect)
|
||||
}
|
||||
|
||||
private class DeclarationBuckets {
|
||||
val simpleFunctions = mutableListOf<Pair<FirSimpleFunction, String>>()
|
||||
val constructors = mutableListOf<Pair<FirConstructor, String>>()
|
||||
val classLikes = mutableListOf<Pair<FirClassLikeDeclaration, String>>()
|
||||
val properties = mutableListOf<Pair<FirProperty, String>>()
|
||||
val extensionProperties = mutableListOf<Pair<FirProperty, String>>()
|
||||
val simpleFunctions = mutableListOf<Pair<FirNamedFunctionSymbol, String>>()
|
||||
val constructors = mutableListOf<Pair<FirConstructorSymbol, String>>()
|
||||
val classLikes = mutableListOf<Pair<FirClassLikeSymbol<*>, String>>()
|
||||
val properties = mutableListOf<Pair<FirPropertySymbol, String>>()
|
||||
val extensionProperties = mutableListOf<Pair<FirPropertySymbol, String>>()
|
||||
}
|
||||
|
||||
private fun groupTopLevelByName(declarations: List<FirDeclaration>, context: CheckerContext): Map<Name, DeclarationBuckets> {
|
||||
val groups = mutableMapOf<Name, DeclarationBuckets>()
|
||||
for (declaration in declarations) {
|
||||
if (!declaration.isCollectable()) continue
|
||||
if (!declaration.symbol.isCollectable()) continue
|
||||
|
||||
when (declaration) {
|
||||
is FirSimpleFunction ->
|
||||
groups.getOrPut(declaration.name, ::DeclarationBuckets).simpleFunctions +=
|
||||
declaration to FirRedeclarationPresenter.represent(declaration)
|
||||
declaration.symbol to FirRedeclarationPresenter.represent(declaration.symbol)
|
||||
is FirProperty -> {
|
||||
val group = groups.getOrPut(declaration.name, ::DeclarationBuckets)
|
||||
val representation = FirRedeclarationPresenter.represent(declaration)
|
||||
val representation = FirRedeclarationPresenter.represent(declaration.symbol)
|
||||
if (declaration.receiverParameter != null) {
|
||||
group.extensionProperties += declaration to representation
|
||||
group.extensionProperties += declaration.symbol to representation
|
||||
} else {
|
||||
group.properties += declaration to representation
|
||||
group.properties += declaration.symbol to representation
|
||||
}
|
||||
}
|
||||
is FirClassLikeDeclaration -> {
|
||||
val representation = FirRedeclarationPresenter.represent(declaration) ?: continue
|
||||
val representation = FirRedeclarationPresenter.represent(declaration.symbol) ?: continue
|
||||
val group = groups.getOrPut(declaration.nameOrSpecialName, ::DeclarationBuckets)
|
||||
group.classLikes += declaration to representation
|
||||
group.classLikes += declaration.symbol to representation
|
||||
|
||||
declaration.expandedClassWithConstructorsScope(context)?.let { (expandedClass, scopeWithConstructors) ->
|
||||
declaration.symbol.expandedClassWithConstructorsScope(context)?.let { (expandedClass, scopeWithConstructors) ->
|
||||
if (expandedClass.classKind == ClassKind.OBJECT) {
|
||||
return@let
|
||||
}
|
||||
|
||||
@OptIn(SymbolInternals::class)
|
||||
scopeWithConstructors.processDeclaredConstructors {
|
||||
group.constructors += it.fir to FirRedeclarationPresenter.represent(it.fir, declaration.symbol)
|
||||
group.constructors += it to FirRedeclarationPresenter.represent(it, declaration.symbol)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -137,9 +138,9 @@ private fun groupTopLevelByName(declarations: List<FirDeclaration>, context: Che
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects FirDeclarations for further analysis.
|
||||
* Collects symbols of FirDeclarations for further analysis.
|
||||
*/
|
||||
class FirDeclarationCollector<D : FirDeclaration>(
|
||||
class FirDeclarationCollector<D : FirBasedSymbol<*>>(
|
||||
internal val context: CheckerContext,
|
||||
) {
|
||||
internal val session: FirSession get() = context.sessionHolder.session
|
||||
@@ -147,44 +148,44 @@ class FirDeclarationCollector<D : FirDeclaration>(
|
||||
val declarationConflictingSymbols: HashMap<D, SmartSet<FirBasedSymbol<*>>> = hashMapOf()
|
||||
}
|
||||
|
||||
fun FirDeclarationCollector<FirDeclaration>.collectClassMembers(klass: FirRegularClass) {
|
||||
val otherDeclarations = mutableMapOf<String, MutableList<FirDeclaration>>()
|
||||
val functionDeclarations = mutableMapOf<String, MutableList<FirDeclaration>>()
|
||||
fun FirDeclarationCollector<FirBasedSymbol<*>>.collectClassMembers(klass: FirRegularClassSymbol) {
|
||||
val otherDeclarations = mutableMapOf<String, MutableList<FirBasedSymbol<*>>>()
|
||||
val functionDeclarations = mutableMapOf<String, MutableList<FirBasedSymbol<*>>>()
|
||||
|
||||
// TODO, KT-61243: Use declaredMemberScope
|
||||
for (it in klass.declarations) {
|
||||
if (!it.isCollectable()) continue
|
||||
@OptIn(SymbolInternals::class)
|
||||
for (it in klass.fir.declarations) {
|
||||
if (!it.symbol.isCollectable()) continue
|
||||
|
||||
when (it) {
|
||||
is FirSimpleFunction -> collect(it, FirRedeclarationPresenter.represent(it), functionDeclarations)
|
||||
is FirRegularClass -> collect(it, FirRedeclarationPresenter.represent(it), otherDeclarations)
|
||||
is FirTypeAlias -> collect(it, FirRedeclarationPresenter.represent(it), otherDeclarations)
|
||||
is FirVariable -> collect(it, FirRedeclarationPresenter.represent(it), otherDeclarations)
|
||||
is FirSimpleFunction -> collect(it.symbol, FirRedeclarationPresenter.represent(it.symbol), functionDeclarations)
|
||||
is FirRegularClass -> collect(it.symbol, FirRedeclarationPresenter.represent(it.symbol), otherDeclarations)
|
||||
is FirTypeAlias -> collect(it.symbol, FirRedeclarationPresenter.represent(it.symbol), otherDeclarations)
|
||||
is FirVariable -> collect(it.symbol, FirRedeclarationPresenter.represent(it.symbol), otherDeclarations)
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun collectConflictingLocalFunctionsFrom(block: FirBlock, context: CheckerContext): Map<FirFunction, Set<FirBasedSymbol<*>>> {
|
||||
fun collectConflictingLocalFunctionsFrom(block: FirBlock, context: CheckerContext): Map<FirFunctionSymbol<*>, Set<FirBasedSymbol<*>>> {
|
||||
val collectables =
|
||||
block.statements.filter {
|
||||
(it is FirSimpleFunction || it is FirRegularClass) && (it as FirDeclaration).isCollectable()
|
||||
(it is FirSimpleFunction || it is FirRegularClass) && (it as FirDeclaration).symbol.isCollectable()
|
||||
}
|
||||
|
||||
if (collectables.isEmpty()) return emptyMap()
|
||||
|
||||
val inspector = FirDeclarationCollector<FirFunction>(context)
|
||||
val functionDeclarations = mutableMapOf<String, MutableList<FirFunction>>()
|
||||
val inspector = FirDeclarationCollector<FirFunctionSymbol<*>>(context)
|
||||
val functionDeclarations = mutableMapOf<String, MutableList<FirFunctionSymbol<*>>>()
|
||||
|
||||
for (collectable in collectables) {
|
||||
when (collectable) {
|
||||
is FirSimpleFunction ->
|
||||
inspector.collect(collectable, FirRedeclarationPresenter.represent(collectable), functionDeclarations)
|
||||
inspector.collect(collectable.symbol, FirRedeclarationPresenter.represent(collectable.symbol), functionDeclarations)
|
||||
is FirClassLikeDeclaration -> {
|
||||
collectable.expandedClassWithConstructorsScope(context)?.let { (_, scopeWithConstructors) ->
|
||||
collectable.symbol.expandedClassWithConstructorsScope(context)?.let { (_, scopeWithConstructors) ->
|
||||
scopeWithConstructors.processDeclaredConstructors {
|
||||
@OptIn(SymbolInternals::class)
|
||||
inspector.collect(it.fir, FirRedeclarationPresenter.represent(it.fir, collectable.symbol), functionDeclarations)
|
||||
inspector.collect(it, FirRedeclarationPresenter.represent(it, collectable.symbol), functionDeclarations)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -195,7 +196,7 @@ fun collectConflictingLocalFunctionsFrom(block: FirBlock, context: CheckerContex
|
||||
return inspector.declarationConflictingSymbols
|
||||
}
|
||||
|
||||
private fun <D : FirDeclaration> FirDeclarationCollector<D>.collect(
|
||||
private fun <D : FirBasedSymbol<*>> FirDeclarationCollector<D>.collect(
|
||||
declaration: D,
|
||||
representation: String,
|
||||
map: MutableMap<String, MutableList<D>>,
|
||||
@@ -206,8 +207,8 @@ private fun <D : FirDeclaration> FirDeclarationCollector<D>.collect(
|
||||
val conflicts = SmartSet.create<FirBasedSymbol<*>>()
|
||||
for (otherDeclaration in it) {
|
||||
if (otherDeclaration != declaration && !isOverloadable(declaration, otherDeclaration, session)) {
|
||||
conflicts.add(otherDeclaration.symbol)
|
||||
declarationConflictingSymbols.getOrPut(otherDeclaration) { SmartSet.create() }.add(declaration.symbol)
|
||||
conflicts.add(otherDeclaration)
|
||||
declarationConflictingSymbols.getOrPut(otherDeclaration) { SmartSet.create() }.add(declaration)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,16 +234,15 @@ private fun <D : FirDeclaration> FirDeclarationCollector<D>.collect(
|
||||
* | constructors of classes | X | | | | |
|
||||
* | properties | | | X | X | X |
|
||||
*/
|
||||
@OptIn(SymbolInternals::class)
|
||||
@Suppress("GrazieInspection")
|
||||
fun FirDeclarationCollector<FirDeclaration>.collectTopLevel(file: FirFile, packageMemberScope: FirPackageMemberScope) {
|
||||
fun FirDeclarationCollector<FirBasedSymbol<*>>.collectTopLevel(file: FirFile, packageMemberScope: FirPackageMemberScope) {
|
||||
|
||||
for ((declarationName, group) in groupTopLevelByName(file.declarations, context)) {
|
||||
val groupHasClassLikesOrProperties = group.classLikes.isNotEmpty() || group.properties.isNotEmpty()
|
||||
val groupHasSimpleFunctions = group.simpleFunctions.isNotEmpty()
|
||||
|
||||
fun collect(
|
||||
declarations: List<Pair<FirDeclaration, String>>,
|
||||
declarations: List<Pair<FirBasedSymbol<*>, String>>,
|
||||
conflictingSymbol: FirBasedSymbol<*>,
|
||||
conflictingPresentation: String? = null,
|
||||
conflictingFile: FirFile? = null,
|
||||
@@ -270,19 +270,17 @@ fun FirDeclarationCollector<FirDeclaration>.collectTopLevel(file: FirFile, packa
|
||||
collect(group.properties, conflictingSymbol, conflictingPresentation, conflictingFile)
|
||||
|
||||
if (groupHasSimpleFunctions) {
|
||||
val declaration = conflictingSymbol.fir
|
||||
|
||||
if (declaration !is FirClassLikeDeclaration) {
|
||||
if (conflictingSymbol !is FirClassLikeSymbol<*>) {
|
||||
return
|
||||
}
|
||||
|
||||
declaration.expandedClassWithConstructorsScope(context)?.let { (expandedClass, scopeWithConstructors) ->
|
||||
conflictingSymbol.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)
|
||||
val ctorRepresentation = FirRedeclarationPresenter.represent(constructor, conflictingSymbol)
|
||||
collect(group.simpleFunctions, conflictingSymbol = constructor, conflictingPresentation = ctorRepresentation)
|
||||
}
|
||||
}
|
||||
@@ -315,7 +313,7 @@ fun FirDeclarationCollector<FirDeclaration>.collectTopLevel(file: FirFile, packa
|
||||
// session.nameConflictsTracker doesn't seem to work for LL API for redeclarations in the same file, for this reason
|
||||
// we explicitly check classLikes in the same file, too.
|
||||
for ((classLike, representation) in group.classLikes) {
|
||||
collectFromClassifierSource(classLike.symbol, conflictingPresentation = representation, conflictingFile = file)
|
||||
collectFromClassifierSource(classLike, conflictingPresentation = representation, conflictingFile = file)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,11 +328,11 @@ fun FirDeclarationCollector<FirDeclaration>.collectTopLevel(file: FirFile, packa
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirClassLikeDeclaration.expandedClassWithConstructorsScope(context: CheckerContext): Pair<FirRegularClassSymbol, FirScope>? {
|
||||
private fun FirClassLikeSymbol<*>.expandedClassWithConstructorsScope(context: CheckerContext): Pair<FirRegularClassSymbol, FirScope>? {
|
||||
return when (this) {
|
||||
is FirRegularClass -> symbol to unsubstitutedScope(context)
|
||||
is FirTypeAlias -> {
|
||||
val expandedType = expandedConeType
|
||||
is FirRegularClassSymbol -> this to unsubstitutedScope(context)
|
||||
is FirTypeAliasSymbol -> {
|
||||
val expandedType = resolvedExpandedTypeRef.coneType as? ConeClassLikeType
|
||||
val expandedClass = expandedType?.toRegularClassSymbol(context.session)
|
||||
val expandedTypeScope = expandedType?.scope(
|
||||
context.session, context.scopeSession,
|
||||
@@ -344,7 +342,7 @@ private fun FirClassLikeDeclaration.expandedClassWithConstructorsScope(context:
|
||||
|
||||
if (expandedType != null && expandedClass != null && expandedTypeScope != null) {
|
||||
val outerType = outerType(expandedType, context.session) { it.outerClassSymbol(context) }
|
||||
expandedClass to TypeAliasConstructorsSubstitutingScope(symbol, expandedTypeScope, outerType)
|
||||
expandedClass to TypeAliasConstructorsSubstitutingScope(this, expandedTypeScope, outerType)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
@@ -353,8 +351,8 @@ private fun FirClassLikeDeclaration.expandedClassWithConstructorsScope(context:
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirDeclarationCollector<FirDeclaration>.collectTopLevelConflict(
|
||||
declaration: FirDeclaration,
|
||||
private fun FirDeclarationCollector<FirBasedSymbol<*>>.collectTopLevelConflict(
|
||||
declaration: FirBasedSymbol<*>,
|
||||
declarationPresentation: String,
|
||||
containingFile: FirFile,
|
||||
conflictingSymbol: FirBasedSymbol<*>,
|
||||
@@ -362,10 +360,8 @@ private fun FirDeclarationCollector<FirDeclaration>.collectTopLevelConflict(
|
||||
conflictingFile: FirFile? = null,
|
||||
) {
|
||||
conflictingSymbol.lazyResolveToPhase(FirResolvePhase.STATUS)
|
||||
@OptIn(SymbolInternals::class)
|
||||
val conflicting = conflictingSymbol.fir
|
||||
if (conflicting == declaration || declaration.moduleData != conflicting.moduleData) return
|
||||
val actualConflictingPresentation = conflictingPresentation ?: FirRedeclarationPresenter.represent(conflicting)
|
||||
if (conflictingSymbol == declaration || declaration.moduleData != conflictingSymbol.moduleData) return
|
||||
val actualConflictingPresentation = conflictingPresentation ?: FirRedeclarationPresenter.represent(conflictingSymbol)
|
||||
if (actualConflictingPresentation != declarationPresentation) return
|
||||
val actualConflictingFile =
|
||||
conflictingFile ?: when (conflictingSymbol) {
|
||||
@@ -373,22 +369,24 @@ private fun FirDeclarationCollector<FirDeclaration>.collectTopLevelConflict(
|
||||
is FirCallableSymbol<*> -> session.firProvider.getFirCallableContainerFile(conflictingSymbol)
|
||||
else -> null
|
||||
}
|
||||
if (!conflicting.isCollectable()) return
|
||||
if (areCompatibleMainFunctions(declaration, containingFile, conflicting, actualConflictingFile, session)) return
|
||||
if (!conflictingSymbol.isCollectable()) return
|
||||
if (areCompatibleMainFunctions(declaration, containingFile, conflictingSymbol, actualConflictingFile, session)) return
|
||||
@OptIn(SymbolInternals::class)
|
||||
val conflicting = conflictingSymbol.fir
|
||||
if (
|
||||
conflicting is FirMemberDeclaration &&
|
||||
!session.visibilityChecker.isVisible(conflicting, session, containingFile, emptyList(), dispatchReceiver = null)
|
||||
) return
|
||||
if (isOverloadable(declaration, conflicting, session)) return
|
||||
if (isOverloadable(declaration, conflictingSymbol, session)) return
|
||||
|
||||
declarationConflictingSymbols.getOrPut(declaration) { SmartSet.create() }.add(conflictingSymbol)
|
||||
}
|
||||
|
||||
private fun FirSimpleFunction.representsMainFunctionAllowingConflictingOverloads(session: FirSession): Boolean {
|
||||
if (name != StandardNames.MAIN || !symbol.callableId.isTopLevel || !hasMainFunctionStatus) return false
|
||||
if (receiverParameter != null || typeParameters.isNotEmpty()) return false
|
||||
if (valueParameters.isEmpty()) return true
|
||||
val paramType = valueParameters.singleOrNull()?.returnTypeRef?.coneType?.fullyExpandedType(session) ?: return false
|
||||
private fun FirNamedFunctionSymbol.representsMainFunctionAllowingConflictingOverloads(session: FirSession): Boolean {
|
||||
if (name != StandardNames.MAIN || !callableId.isTopLevel || !hasMainFunctionStatus) return false
|
||||
if (receiverParameter != null || typeParameterSymbols.isNotEmpty()) return false
|
||||
if (valueParameterSymbols.isEmpty()) return true
|
||||
val paramType = valueParameterSymbols.singleOrNull()?.resolvedReturnTypeRef?.coneType?.fullyExpandedType(session) ?: return false
|
||||
if (!paramType.isNonPrimitiveArray) return false
|
||||
val typeArgument = paramType.typeArguments.singleOrNull() as? ConeKotlinTypeProjection ?: return false
|
||||
// only Array<String> and Array<out String> are accepted
|
||||
@@ -397,18 +395,18 @@ private fun FirSimpleFunction.representsMainFunctionAllowingConflictingOverloads
|
||||
}
|
||||
|
||||
private fun areCompatibleMainFunctions(
|
||||
declaration1: FirDeclaration, file1: FirFile,
|
||||
declaration2: FirDeclaration, file2: FirFile?,
|
||||
declaration1: FirBasedSymbol<*>, file1: FirFile,
|
||||
declaration2: FirBasedSymbol<*>, file2: FirFile?,
|
||||
session: FirSession,
|
||||
) = file1 != file2
|
||||
&& declaration1 is FirSimpleFunction
|
||||
&& declaration2 is FirSimpleFunction
|
||||
&& declaration1 is FirNamedFunctionSymbol
|
||||
&& declaration2 is FirNamedFunctionSymbol
|
||||
&& declaration1.representsMainFunctionAllowingConflictingOverloads(session)
|
||||
&& declaration2.representsMainFunctionAllowingConflictingOverloads(session)
|
||||
|
||||
private fun isOverloadable(
|
||||
declaration: FirDeclaration,
|
||||
conflicting: FirDeclaration,
|
||||
declaration: FirBasedSymbol<*>,
|
||||
conflicting: FirBasedSymbol<*>,
|
||||
session: FirSession,
|
||||
): Boolean {
|
||||
if (isExpectAndActual(declaration, conflicting)) return true
|
||||
@@ -417,8 +415,8 @@ private fun isOverloadable(
|
||||
val conflictingIsLowPriority = hasLowPriorityAnnotation(conflicting.annotations)
|
||||
if (declarationIsLowPriority != conflictingIsLowPriority) return true
|
||||
|
||||
return declaration is FirCallableDeclaration &&
|
||||
conflicting is FirCallableDeclaration &&
|
||||
return declaration is FirCallableSymbol<*> &&
|
||||
conflicting is FirCallableSymbol<*> &&
|
||||
session.declarationOverloadabilityHelper.isOverloadable(declaration, conflicting)
|
||||
}
|
||||
|
||||
|
||||
+25
-25
@@ -5,9 +5,9 @@
|
||||
|
||||
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.symbols.impl.FirClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
|
||||
@@ -34,18 +34,18 @@ internal object FirRedeclarationPresenter {
|
||||
append(it.callableName)
|
||||
}
|
||||
|
||||
private fun StringBuilder.appendRepresentation(it: FirValueParameter) {
|
||||
private fun StringBuilder.appendRepresentation(it: FirValueParameterSymbol) {
|
||||
if (it.isVararg) {
|
||||
append("vararg ")
|
||||
}
|
||||
}
|
||||
|
||||
private fun StringBuilder.appendRepresentationBeforeCallableId(it: FirCallableDeclaration) {
|
||||
repeat(it.contextReceivers.size) {
|
||||
private fun StringBuilder.appendRepresentationBeforeCallableId(it: FirCallableSymbol<*>) {
|
||||
repeat(it.resolvedContextReceivers.size) {
|
||||
append(',')
|
||||
}
|
||||
append('<')
|
||||
repeat(it.typeParameters.size) {
|
||||
repeat(it.typeParameterSymbols.size) {
|
||||
append(',')
|
||||
}
|
||||
append('>')
|
||||
@@ -56,55 +56,55 @@ internal object FirRedeclarationPresenter {
|
||||
append(']')
|
||||
}
|
||||
|
||||
private fun StringBuilder.appendValueParameters(it: FirSimpleFunction) {
|
||||
private fun StringBuilder.appendValueParameters(it: FirNamedFunctionSymbol) {
|
||||
append('(')
|
||||
it.valueParameters.forEach {
|
||||
it.valueParameterSymbols.forEach {
|
||||
appendRepresentation(it)
|
||||
append(',')
|
||||
}
|
||||
append(')')
|
||||
}
|
||||
|
||||
fun represent(declaration: FirDeclaration): String? = when (declaration) {
|
||||
is FirSimpleFunction -> represent(declaration)
|
||||
is FirRegularClass -> represent(declaration)
|
||||
is FirTypeAlias -> represent(declaration)
|
||||
is FirProperty -> represent(declaration)
|
||||
fun represent(declaration: FirBasedSymbol<*>): String? = when (declaration) {
|
||||
is FirNamedFunctionSymbol -> represent(declaration)
|
||||
is FirRegularClassSymbol -> represent(declaration)
|
||||
is FirTypeAliasSymbol -> represent(declaration)
|
||||
is FirPropertySymbol -> represent(declaration)
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun represent(it: FirSimpleFunction) = buildString {
|
||||
fun represent(it: FirNamedFunctionSymbol) = buildString {
|
||||
appendRepresentationBeforeCallableId(it)
|
||||
if (it.isOperator) {
|
||||
append("operator ")
|
||||
}
|
||||
appendRepresentation(it.symbol.callableId)
|
||||
appendRepresentation(it.callableId)
|
||||
appendValueParameters(it)
|
||||
}
|
||||
|
||||
|
||||
fun represent(it: FirVariable) = buildString {
|
||||
fun represent(it: FirVariableSymbol<*>) = buildString {
|
||||
appendRepresentationBeforeCallableId(it)
|
||||
appendRepresentation(it.symbol.callableId)
|
||||
appendRepresentation(it.callableId)
|
||||
}
|
||||
|
||||
fun represent(it: FirTypeAlias) = representClassLike(it)
|
||||
fun represent(it: FirRegularClass) = representClassLike(it)
|
||||
fun represent(it: FirTypeAliasSymbol) = representClassLike(it)
|
||||
fun represent(it: FirRegularClassSymbol) = representClassLike(it)
|
||||
|
||||
private fun representClassLike(it: FirClassLikeDeclaration) = buildString {
|
||||
private fun representClassLike(it: FirClassLikeSymbol<*>) = buildString {
|
||||
append('<')
|
||||
append('>')
|
||||
append('[')
|
||||
append(']')
|
||||
appendRepresentation(it.symbol.classId)
|
||||
appendRepresentation(it.classId)
|
||||
}
|
||||
|
||||
fun represent(it: FirConstructor, owner: FirClassLikeSymbol<*>) = buildString {
|
||||
repeat(it.contextReceivers.size) {
|
||||
fun represent(it: FirConstructorSymbol, owner: FirClassLikeSymbol<*>) = buildString {
|
||||
repeat(it.resolvedContextReceivers.size) {
|
||||
append(',')
|
||||
}
|
||||
append('<')
|
||||
repeat(it.typeParameters.size) {
|
||||
repeat(it.typeParameterSymbols.size) {
|
||||
append(',')
|
||||
}
|
||||
append('>')
|
||||
@@ -112,7 +112,7 @@ internal object FirRedeclarationPresenter {
|
||||
append(']')
|
||||
appendRepresentation(owner.classId)
|
||||
append('(')
|
||||
it.valueParameters.forEach {
|
||||
it.valueParameterSymbols.forEach {
|
||||
appendRepresentation(it)
|
||||
append(',')
|
||||
}
|
||||
|
||||
+12
-14
@@ -9,20 +9,18 @@ import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.FirNameConflictsTrackerComponent
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.FirDeclarationCollector
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.checkForLocalRedeclarations
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.collectClassMembers
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.collectTopLevel
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.*
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
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.fir.symbols.impl.FirConstructorSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.utils.SmartSet
|
||||
|
||||
@@ -30,7 +28,7 @@ object FirConflictsDeclarationChecker : FirBasicDeclarationChecker() {
|
||||
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
when (declaration) {
|
||||
is FirFile -> {
|
||||
val inspector = FirDeclarationCollector<FirDeclaration>(context)
|
||||
val inspector = FirDeclarationCollector<FirBasedSymbol<*>>(context)
|
||||
checkFile(declaration, inspector, context)
|
||||
reportConflicts(reporter, context, inspector.declarationConflictingSymbols)
|
||||
}
|
||||
@@ -38,8 +36,8 @@ object FirConflictsDeclarationChecker : FirBasicDeclarationChecker() {
|
||||
if (declaration.source?.kind !is KtFakeSourceElementKind) {
|
||||
checkForLocalRedeclarations(declaration.typeParameters, context, reporter)
|
||||
}
|
||||
val inspector = FirDeclarationCollector<FirDeclaration>(context)
|
||||
inspector.collectClassMembers(declaration)
|
||||
val inspector = FirDeclarationCollector<FirBasedSymbol<*>>(context)
|
||||
inspector.collectClassMembers(declaration.symbol)
|
||||
reportConflicts(reporter, context, inspector.declarationConflictingSymbols)
|
||||
}
|
||||
else -> {
|
||||
@@ -56,18 +54,18 @@ object FirConflictsDeclarationChecker : FirBasicDeclarationChecker() {
|
||||
private fun reportConflicts(
|
||||
reporter: DiagnosticReporter,
|
||||
context: CheckerContext,
|
||||
declarationConflictingSymbols: Map<FirDeclaration, SmartSet<FirBasedSymbol<*>>>,
|
||||
declarationConflictingSymbols: Map<FirBasedSymbol<*>, SmartSet<FirBasedSymbol<*>>>,
|
||||
) {
|
||||
declarationConflictingSymbols.forEach { (conflictingDeclaration, symbols) ->
|
||||
val typeAliasForConstructorSource = (conflictingDeclaration as? FirConstructor)?.typeAliasForConstructor?.source
|
||||
val typeAliasForConstructorSource = (conflictingDeclaration as? FirConstructorSymbol)?.typeAliasForConstructor?.source
|
||||
val source = typeAliasForConstructorSource ?: conflictingDeclaration.source
|
||||
if (symbols.isEmpty()) return@forEach
|
||||
|
||||
val factory =
|
||||
if (conflictingDeclaration is FirSimpleFunction || conflictingDeclaration is FirConstructor) {
|
||||
if (conflictingDeclaration is FirNamedFunctionSymbol || conflictingDeclaration is FirConstructorSymbol) {
|
||||
FirErrors.CONFLICTING_OVERLOADS
|
||||
} else if (conflictingDeclaration is FirClassLikeDeclaration &&
|
||||
conflictingDeclaration.getContainingDeclaration(context.session) == null &&
|
||||
} else if (conflictingDeclaration is FirClassLikeSymbol<*> &&
|
||||
conflictingDeclaration.getContainingClassSymbol(context.session) == null &&
|
||||
symbols.any { it is FirClassLikeSymbol<*> }
|
||||
) {
|
||||
FirErrors.PACKAGE_OR_CLASSIFIER_REDECLARATION
|
||||
@@ -79,7 +77,7 @@ object FirConflictsDeclarationChecker : FirBasicDeclarationChecker() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkFile(file: FirFile, inspector: FirDeclarationCollector<FirDeclaration>, context: CheckerContext) {
|
||||
private fun checkFile(file: FirFile, inspector: FirDeclarationCollector<FirBasedSymbol<*>>, context: CheckerContext) {
|
||||
val packageMemberScope: FirPackageMemberScope = context.sessionHolder.scopeSession.getOrBuild(file.packageFqName, PACKAGE_MEMBER) {
|
||||
FirPackageMemberScope(file.packageFqName, context.sessionHolder.session)
|
||||
}
|
||||
|
||||
+2
-1
@@ -7,9 +7,10 @@ package org.jetbrains.kotlin.fir.declarations
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.FirSessionComponent
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
|
||||
interface FirDeclarationOverloadabilityHelper : FirSessionComponent {
|
||||
fun isOverloadable(a: FirCallableDeclaration, b: FirCallableDeclaration): Boolean
|
||||
fun isOverloadable(a: FirCallableSymbol<*>, b: FirCallableSymbol<*>): Boolean
|
||||
}
|
||||
|
||||
val FirSession.declarationOverloadabilityHelper: FirDeclarationOverloadabilityHelper by FirSession.sessionComponentAccessor()
|
||||
|
||||
+13
-15
@@ -6,19 +6,17 @@
|
||||
package org.jetbrains.kotlin.fir.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOverloadabilityHelper
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.typeSpecificityComparatorProvider
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isSynthetic
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.inferenceComponents
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.resolve.calls.results.*
|
||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||
|
||||
class FirDeclarationOverloadabilityHelperImpl(val session: FirSession) : FirDeclarationOverloadabilityHelper {
|
||||
override fun isOverloadable(a: FirCallableDeclaration, b: FirCallableDeclaration): Boolean {
|
||||
override fun isOverloadable(a: FirCallableSymbol<*>, b: FirCallableSymbol<*>): Boolean {
|
||||
val sigA = createSignature(a)
|
||||
val sigB = createSignature(b)
|
||||
|
||||
@@ -26,8 +24,8 @@ class FirDeclarationOverloadabilityHelperImpl(val session: FirSession) : FirDecl
|
||||
}
|
||||
|
||||
private fun isNotLessSpecific(
|
||||
sigA: FlatSignature<FirCallableDeclaration>,
|
||||
sigB: FlatSignature<FirCallableDeclaration>,
|
||||
sigA: FlatSignature<FirCallableSymbol<*>>,
|
||||
sigB: FlatSignature<FirCallableSymbol<*>>,
|
||||
): Boolean = createEmptyConstraintSystem().isSignatureNotLessSpecific(
|
||||
sigA,
|
||||
sigB,
|
||||
@@ -35,23 +33,23 @@ class FirDeclarationOverloadabilityHelperImpl(val session: FirSession) : FirDecl
|
||||
session.typeSpecificityComparatorProvider?.typeSpecificityComparator ?: TypeSpecificityComparator.NONE,
|
||||
)
|
||||
|
||||
private fun createSignature(declaration: FirCallableDeclaration): FlatSignature<FirCallableDeclaration> {
|
||||
val valueParameters = (declaration as? FirFunction)?.valueParameters.orEmpty()
|
||||
private fun createSignature(declaration: FirCallableSymbol<*>): FlatSignature<FirCallableSymbol<*>> {
|
||||
val valueParameters = (declaration as? FirFunctionSymbol<*>)?.valueParameterSymbols.orEmpty()
|
||||
|
||||
return FlatSignature(
|
||||
origin = declaration,
|
||||
typeParameters = declaration.typeParameters.map { it.symbol.toLookupTag() },
|
||||
typeParameters = declaration.typeParameterSymbols.map { it.toLookupTag() },
|
||||
valueParameterTypes = buildList<KotlinTypeMarker> {
|
||||
declaration.contextReceivers.mapTo(this) { it.typeRef.coneType }
|
||||
declaration.resolvedContextReceivers.mapTo(this) { it.typeRef.coneType }
|
||||
declaration.receiverParameter?.let { add(it.typeRef.coneType) }
|
||||
valueParameters.mapTo(this) { it.returnTypeRef.coneType }
|
||||
valueParameters.mapTo(this) { it.resolvedReturnType }
|
||||
},
|
||||
hasExtensionReceiver = declaration.receiverParameter != null,
|
||||
contextReceiverCount = declaration.contextReceivers.size,
|
||||
contextReceiverCount = declaration.resolvedContextReceivers.size,
|
||||
hasVarargs = valueParameters.any { it.isVararg },
|
||||
numDefaults = 0,
|
||||
isExpect = declaration.isExpect,
|
||||
isSyntheticMember = declaration.isSynthetic
|
||||
isSyntheticMember = declaration.origin is FirDeclarationOrigin.Synthetic
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user