FIR: look for conflicting declarations more precisely

This commit is contained in:
Mikhail Glukhikh
2022-07-01 15:09:19 +02:00
committed by teamcity
parent 3092a84b6b
commit 4737bb07df
9 changed files with 29 additions and 56 deletions
@@ -61,9 +61,9 @@ class L {
fun B.foo() {} fun B.foo() {}
} }
fun mest() {} <!CONFLICTING_OVERLOADS!>fun mest()<!> {}
class mest class <!CONFLICTING_OVERLOADS!>mest<!>
<!FUNCTION_DECLARATION_WITH_NO_NAME!>fun()<!> {} <!FUNCTION_DECLARATION_WITH_NO_NAME!>fun()<!> {}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.KtFakeSourceElementKind import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.analysis.checkers.FirDeclarationInspector import org.jetbrains.kotlin.fir.analysis.checkers.FirDeclarationInspector
import org.jetbrains.kotlin.fir.analysis.checkers.FirDeclarationPresenter import org.jetbrains.kotlin.fir.analysis.checkers.FirDeclarationPresenter
@@ -95,13 +96,18 @@ object FirConflictsChecker : FirBasicDeclarationChecker() {
is FirCallableSymbol<*> -> session.firProvider.getFirCallableContainerFile(conflictingSymbol) is FirCallableSymbol<*> -> session.firProvider.getFirCallableContainerFile(conflictingSymbol)
else -> null else -> null
} }
if (containingFile == actualConflictingFile) return // TODO: rewrite local decls checker to the same logic and then remove the check if (containingFile == actualConflictingFile && conflicting.origin == FirDeclarationOrigin.Precompiled) {
return // TODO: rewrite local decls checker to the same logic and then remove the check
}
if (areCompatibleMainFunctions(declaration, containingFile, conflicting, actualConflictingFile)) return if (areCompatibleMainFunctions(declaration, containingFile, conflicting, actualConflictingFile)) return
if (isExpectAndActual(declaration, conflicting)) return if (isExpectAndActual(declaration, conflicting)) return
if ( if (
conflicting is FirMemberDeclaration && conflicting is FirMemberDeclaration &&
!session.visibilityChecker.isVisible(conflicting, session, containingFile, emptyList(), null) !session.visibilityChecker.isVisible(conflicting, session, containingFile, emptyList(), null)
) return ) return
val declarationIsLowPriority = hasLowPriorityAnnotation(declaration.annotations)
val conflictingIsLowPriority = hasLowPriorityAnnotation(conflicting.annotations)
if (declarationIsLowPriority != conflictingIsLowPriority) return
declarationConflictingSymbols.getOrPut(declaration) { SmartSet.create() }.add(conflictingSymbol) declarationConflictingSymbols.getOrPut(declaration) { SmartSet.create() }.add(conflictingSymbol)
} }
@@ -355,7 +361,7 @@ class FirNameConflictsTracker : FirNameConflictsTrackerComponent() {
} }
} }
private fun FirDeclaration.onConstructors(action: (ctor: FirConstructor) -> Unit) { private fun FirRegularClass.onConstructors(action: (ctor: FirConstructor) -> Unit) {
class ClassConstructorVisitor : FirVisitorVoid() { class ClassConstructorVisitor : FirVisitorVoid() {
override fun visitElement(element: FirElement) {} override fun visitElement(element: FirElement) {}
@@ -370,7 +376,9 @@ private fun FirDeclaration.onConstructors(action: (ctor: FirConstructor) -> Unit
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction) {} override fun visitSimpleFunction(simpleFunction: FirSimpleFunction) {}
} }
acceptChildren(ClassConstructorVisitor()) if (classKind != ClassKind.OBJECT && classKind != ClassKind.ENUM_ENTRY) {
acceptChildren(ClassConstructorVisitor())
}
} }
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.coneType import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.coneTypeSafe import org.jetbrains.kotlin.fir.types.coneTypeSafe
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.StandardClassIds import org.jetbrains.kotlin.name.StandardClassIds
@@ -186,3 +187,11 @@ val FirAnnotation.resolved: Boolean
if (this !is FirAnnotationCall) return true if (this !is FirAnnotationCall) return true
return calleeReference is FirResolvedNamedReference || calleeReference is FirErrorNamedReference return calleeReference is FirResolvedNamedReference || calleeReference is FirErrorNamedReference
} }
private val LOW_PRIORITY_IN_OVERLOAD_RESOLUTION_CLASS_ID: ClassId =
ClassId(FqName("kotlin.internal"), Name.identifier("LowPriorityInOverloadResolution"))
fun hasLowPriorityAnnotation(annotations: List<FirAnnotation>) = annotations.any {
val lookupTag = it.annotationTypeRef.coneTypeSafe<ConeClassLikeType>()?.lookupTag ?: return@any false
lookupTag.classId == LOW_PRIORITY_IN_OVERLOAD_RESOLUTION_CLASS_ID
}
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.fir.resolve.calls
import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.FirVisibilityChecker
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.isInfix import org.jetbrains.kotlin.fir.declarations.utils.isInfix
import org.jetbrains.kotlin.fir.declarations.utils.isOperator import org.jetbrains.kotlin.fir.declarations.utils.isOperator
@@ -33,8 +32,6 @@ import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.visibilityChecker import org.jetbrains.kotlin.fir.visibilityChecker
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.calls.inference.isSubtypeConstraintCompatible import org.jetbrains.kotlin.resolve.calls.inference.isSubtypeConstraintCompatible
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.* import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.*
@@ -542,9 +539,6 @@ internal object CheckVisibility : CheckerStage() {
} }
internal object CheckLowPriorityInOverloadResolution : CheckerStage() { internal object CheckLowPriorityInOverloadResolution : CheckerStage() {
private val LOW_PRIORITY_IN_OVERLOAD_RESOLUTION_CLASS_ID: ClassId =
ClassId(FqName("kotlin.internal"), Name.identifier("LowPriorityInOverloadResolution"))
override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) { override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) {
val annotations = when (val fir = candidate.symbol.fir) { val annotations = when (val fir = candidate.symbol.fir) {
is FirSimpleFunction -> fir.annotations is FirSimpleFunction -> fir.annotations
@@ -553,12 +547,7 @@ internal object CheckLowPriorityInOverloadResolution : CheckerStage() {
else -> return else -> return
} }
val hasLowPriorityAnnotation = annotations.any { if (hasLowPriorityAnnotation(annotations)) {
val lookupTag = it.annotationTypeRef.coneTypeSafe<ConeClassLikeType>()?.lookupTag ?: return@any false
lookupTag.classId == LOW_PRIORITY_IN_OVERLOAD_RESOLUTION_CLASS_ID
}
if (hasLowPriorityAnnotation) {
sink.reportDiagnostic(ResolvedWithLowPriority) sink.reportDiagnostic(ResolvedWithLowPriority)
} }
} }
@@ -2,9 +2,9 @@
package constructorVsFun package constructorVsFun
class a() { } class a<!CONFLICTING_OVERLOADS!>()<!> { }
fun a() = 1 <!CONFLICTING_OVERLOADS!>fun a()<!> = 1
class Tram { class Tram {
fun f() { } fun f() { }
@@ -10,7 +10,7 @@ object Foo {
fun En() = 239 fun En() = 239
enum class En { enum class <!CONFLICTING_OVERLOADS!>En<!> {
ENTRY, ENTRY,
SUBCLASS { }; SUBCLASS { };
@@ -1,34 +0,0 @@
//If this test hangs, it means something is broken.
package c
fun z(view: () -> Unit) {}
<!CONFLICTING_OVERLOADS!>fun x()<!> = z { z { z { z { z { z { z { z { } } } } } } } }
<!CONFLICTING_OVERLOADS!>fun x()<!> = z { z { z { z { z { z { z { z { } } } } } } } }
<!CONFLICTING_OVERLOADS!>fun x()<!> = z { z { z { z { z { z { z { z { } } } } } } } }
<!CONFLICTING_OVERLOADS!>fun x()<!> = z { z { z { z { z { z { z { z { } } } } } } } }
<!CONFLICTING_OVERLOADS!>fun x()<!> = z { z { z { z { z { z { z { z { } } } } } } } }
<!CONFLICTING_OVERLOADS!>fun x()<!> = z { z { z { z { z { z { z { z { } } } } } } } }
<!CONFLICTING_OVERLOADS!>fun x()<!> = z { z { z { z { z { z { z { z { } } } } } } } }
<!CONFLICTING_OVERLOADS!>fun x()<!> = z { z { z { z { z { z { z { z { } } } } } } } }
<!CONFLICTING_OVERLOADS!>fun x()<!> = z { z { z { z { z { z { z { z { } } } } } } } }
<!CONFLICTING_OVERLOADS!>fun x()<!> = z { z { z { z { z { z { z { z { } } } } } } } }
<!CONFLICTING_OVERLOADS!>fun x()<!> = z { z { z { z { z { z { z { z { } } } } } } } }
<!CONFLICTING_OVERLOADS!>fun x()<!> = z { z { z { z { z { z { z { z { } } } } } } } }
<!CONFLICTING_OVERLOADS!>fun x()<!> = z { z { z { z { z { z { z { z { } } } } } } } }
<!CONFLICTING_OVERLOADS!>fun x()<!> = z { z { z { z { z { z { z { z { } } } } } } } }
<!CONFLICTING_OVERLOADS!>fun x()<!> = z { z { z { z { z { z { z { z { } } } } } } } }
<!CONFLICTING_OVERLOADS!>fun x()<!> = z { z { z { z { z { z { z { z { } } } } } } } }
<!CONFLICTING_OVERLOADS!>fun x()<!> = z { z { z { z { z { z { z { z { } } } } } } } }
<!CONFLICTING_OVERLOADS!>fun x()<!> = z { z { z { z { z { z { z { z { } } } } } } } }
<!CONFLICTING_OVERLOADS!>fun x()<!> = z { z { z { z { z { z { z { z { } } } } } } } }
<!CONFLICTING_OVERLOADS!>fun x()<!> = z { z { z { z { z { z { z { z { } } } } } } } }
<!CONFLICTING_OVERLOADS!>fun x()<!> = z { z { z { z { z { z { z { z { } } } } } } } }
<!CONFLICTING_OVERLOADS!>fun x()<!> = z { z { z { z { z { z { z { z { } } } } } } } }
<!CONFLICTING_OVERLOADS!>fun x()<!> = z { z { z { z { z { z { z { z { } } } } } } } }
<!CONFLICTING_OVERLOADS!>fun x()<!> = z { z { z { z { z { z { z { z { } } } } } } } }
<!CONFLICTING_OVERLOADS!>fun x()<!> = z { z { z { z { z { z { z { z { } } } } } } } }
<!CONFLICTING_OVERLOADS!>fun x()<!> = z { z { z { z { z { z { z { z { } } } } } } } }
<!CONFLICTING_OVERLOADS!>fun x()<!> = z { z { z { z { z { z { z { z { } } } } } } } }
class x() {}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
//If this test hangs, it means something is broken. //If this test hangs, it means something is broken.
package c package c
@@ -7,10 +7,10 @@ class A(x: String = "", y: String = "") {
} }
class B { class B {
constructor(x: Int) <!CONFLICTING_OVERLOADS!>constructor(x: Int)<!>
} }
fun B(x: Int) {} <!CONFLICTING_OVERLOADS!>fun B(x: Int)<!> {}
class Outer { class Outer {
class A(x: String = "", y: String = "") { class A(x: String = "", y: String = "") {