[FIR] Fix false positive errors on Throws::class, Throws()

^KT-63794 Fixed
This commit is contained in:
Ivan Kochurkin
2023-12-05 15:23:41 +01:00
committed by Space Team
parent 8dcd4efbc1
commit 3d77d09260
3 changed files with 61 additions and 7 deletions
@@ -11,11 +11,8 @@ import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.isInner
import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.scopes.CallableCopyTypeCalculator
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.*
import org.jetbrains.kotlin.fir.scopes.impl.TypeAliasConstructorsSubstitutingScope
import org.jetbrains.kotlin.fir.scopes.processClassifiersByName
import org.jetbrains.kotlin.fir.scopes.scopeForClass
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
@@ -86,7 +83,12 @@ fun FirScope.getSingleVisibleClassifier(
if (result == null) {
result = classifierSymbol
} else {
isAmbiguousResult = true
val checkResult = checkUnambiguousClassifiers(result!!, classifierSymbol, session)
if (checkResult.shouldReplaceResult) {
result = classifierSymbol
} else {
isAmbiguousResult = checkResult.isAmbiguousResult
}
}
}
}
@@ -137,8 +139,12 @@ private fun FirScope.getFirstClassifierOrNull(
}
result != null -> {
if (isSuccessResult == isSuccessCandidate) {
// results are similar => ambiguity
isAmbiguousResult = true
val checkResult = checkUnambiguousClassifiers(result!!.symbol, symbol, session)
if (checkResult.shouldReplaceResult) {
result = SymbolWithSubstitutor(symbol, substitutor)
} else {
isAmbiguousResult = checkResult.isAmbiguousResult
}
} else {
// ignore unsuccessful result if we have successful one
}
@@ -154,6 +160,41 @@ private fun FirScope.getFirstClassifierOrNull(
return result.takeUnless { isAmbiguousResult }
}
private data class CheckUnambiguousClassifiersResult(val shouldReplaceResult: Boolean, val isAmbiguousResult: Boolean)
/**
* Handle special cases when classifiers don't cause ambiguity (`Throws`)
*
* The following output options are possible:
* * `shouldReplaceResult = true, isAmbiguousResult = false` means successful disambiguation
* but the previous result should be replaced with the new one (typically class symbol wins typealias)
* * `shouldReplaceResult = false, isAmbiguousResult = false` means successful disambiguation
* but the new result should be discarded
* * `shouldReplaceResult = false, isAmbiguousResult = true` means unsuccessful disambiguation
* and both results become irrelevant
*/
private fun checkUnambiguousClassifiers(
foundClassifierSymbol: FirClassifierSymbol<*>,
newClassifierSymbol: FirClassifierSymbol<*>,
session: FirSession,
): CheckUnambiguousClassifiersResult {
val classTypealiasesThatDontCauseAmbiguity = session.platformClassMapper.classTypealiasesThatDontCauseAmbiguity
if (foundClassifierSymbol is FirTypeAliasSymbol && newClassifierSymbol is FirRegularClassSymbol &&
classTypealiasesThatDontCauseAmbiguity[newClassifierSymbol.classId] == foundClassifierSymbol.classId
) {
return CheckUnambiguousClassifiersResult(shouldReplaceResult = true, isAmbiguousResult = false)
}
if (newClassifierSymbol is FirTypeAliasSymbol && foundClassifierSymbol is FirRegularClassSymbol &&
classTypealiasesThatDontCauseAmbiguity[foundClassifierSymbol.classId] == newClassifierSymbol.classId
) {
return CheckUnambiguousClassifiersResult(shouldReplaceResult = false, isAmbiguousResult = false)
}
return CheckUnambiguousClassifiersResult(shouldReplaceResult = false, isAmbiguousResult = true)
}
private fun processSyntheticConstructors(
matchedSymbol: FirClassLikeSymbol<*>,
processor: (FirFunctionSymbol<*>) -> Unit,
@@ -1,4 +1,5 @@
// FIR_IDENTICAL
// ISSUE: KT-63794
// !DIAGNOSTICS: -UNUSED_PARAMETER
// FILE: main1.kt
package abc1
@@ -163,3 +164,10 @@ fun foo3() {}
fun foo5(x: Throws) {}
fun foo6(x: kotlin.Throws) {}
fun foo7(x: kotlin.jvm.Throws) {}
// FILE: main10.kt
val x: Throws? = null
val y = Throws()
val z = Throws::exceptionClasses
val w = Throws::class
@@ -1,5 +1,10 @@
package
public val w: kotlin.reflect.KClass<kotlin.Throws /* = kotlin.jvm.Throws */>
public val x: kotlin.Throws? /* = kotlin.jvm.Throws? */ = null
public val y: kotlin.Throws /* = kotlin.jvm.Throws */
public val z: kotlin.reflect.KProperty1<kotlin.Throws /* = kotlin.jvm.Throws */, kotlin.Array<out kotlin.reflect.KClass<out kotlin.Throwable>>>
package abc1 {
@kotlin.Throws /* = kotlin.jvm.Throws */(exceptionClasses = {java.lang.Exception::class}) public fun foo1(): kotlin.Unit
@kotlin.Throws /* = kotlin.jvm.Throws */(exceptionClasses = {java.lang.Exception::class}) public fun foo2(): kotlin.Unit