[AA] Resolve isSubClassOf from the context of a use-site session again

`isSubClassOf` was changed in an earlier commit to use the session of
`subClass` instead, but that approach comes with multiple problems:

- We need to resolve classes from the use-site to take actualization of
  `expect` types into account.
- If `superClass` is a builtin and we resolve supertypes from
  `subClass`'s session, we may get multiple instances of symbols for the
  same builtin from different sessions (i.e. one from a stdlib session
  via the use-site session and another from the fallback builtins
  provider for binary libraries if `subClass` is from a binary library).

^KT-66013
This commit is contained in:
Marco Pennekamp
2024-03-13 20:34:51 +01:00
committed by Space Team
parent 53f2dfec41
commit 9d2298b326
3 changed files with 7 additions and 6 deletions
@@ -182,6 +182,7 @@ internal class KtFirSymbolDeclarationOverridesProvider(
return isSubClassOf(
subClass = subClass.firSymbol.fir as FirClass,
superClass = superClass.firSymbol.fir as FirClass,
rootModuleSession,
allowIndirectSubtyping,
)
}
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.analysis.api.fir.utils
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes
@@ -14,16 +15,15 @@ import org.jetbrains.kotlin.fir.types.toRegularClassSymbol
/**
* Returns whether [subClass] is a strict subtype of [superClass]. Resolves [subClass] to [FirResolvePhase.SUPER_TYPES].
*/
fun isSubClassOf(subClass: FirClass, superClass: FirClass, allowIndirectSubtyping: Boolean = true): Boolean {
fun isSubClassOf(subClass: FirClass, superClass: FirClass, useSiteSession: FirSession, allowIndirectSubtyping: Boolean = true): Boolean {
subClass.lazyResolveToPhase(FirResolvePhase.SUPER_TYPES)
val session = subClass.moduleData.session
if (subClass.superConeTypes.any { it.toRegularClassSymbol(session) == superClass.symbol }) return true
if (subClass.superConeTypes.any { it.toRegularClassSymbol(useSiteSession) == superClass.symbol }) return true
if (!allowIndirectSubtyping) return false
subClass.superConeTypes.forEach { superType ->
val superOfSub = superType.toRegularClassSymbol(session) ?: return@forEach
if (isSubClassOf(superOfSub.fir, superClass, allowIndirectSubtyping = true)) return true
val superOfSub = superType.toRegularClassSymbol(useSiteSession) ?: return@forEach
if (isSubClassOf(superOfSub.fir, superClass, useSiteSession, allowIndirectSubtyping = true)) return true
}
return false
}
@@ -101,7 +101,7 @@ class KotlinStandaloneDirectInheritorsProvider(private val project: Project) : K
// `KotlinDirectInheritorsProvider`'s interface guarantees that `getDirectKotlinInheritors` is only called from lazy resolution to
// `SEALED_CLASS_INHERITORS` or later, so `isSubClassOf` resolving to `SUPER_TYPES` is legal.
return isSubClassOf(candidateFirClass, baseFirClass, allowIndirectSubtyping = false)
return isSubClassOf(candidateFirClass, baseFirClass, candidateFirClass.moduleData.session, allowIndirectSubtyping = false)
}
private fun KtClassOrObject.toFirSymbol(classId: ClassId, ktModule: KtModule): FirClassLikeSymbol<*>? {