K2: Unwrap fake overrides before using them as DFA identifiers

It's necessary because even for stable a.b.c.d we can't guarantee that
this reference will always point to the same symbol because
different capture type instantiations generate different scopes
with different resulting symbol instances.
This commit is contained in:
Denis.Zharkov
2022-12-07 15:43:48 +01:00
committed by Space Team
parent 9af3e5704d
commit a4c5e1bc87
3 changed files with 19 additions and 5 deletions
@@ -12,9 +12,13 @@ import org.jetbrains.kotlin.fir.references.FirNamedReferenceWithCandidateBase
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.references.FirThisReference
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirSyntheticPropertySymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.ConeTypeContext
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.unwrapFakeOverrides
fun TypeStatement?.smartCastedType(context: ConeTypeContext, originalType: ConeKotlinType): ConeKotlinType =
if (this != null && exactType.isNotEmpty()) {
@@ -39,9 +43,9 @@ val FirExpression.coneType: ConeKotlinType
@DfaInternals
val FirElement.symbol: FirBasedSymbol<*>?
get() = when (this) {
is FirResolvable -> symbol
is FirResolvable -> symbol.unwrapFakeOverridesIfNecessary()
is FirVariableAssignment -> unwrapLValue()?.symbol
is FirDeclaration -> symbol
is FirDeclaration -> symbol.unwrapFakeOverridesIfNecessary()
is FirWhenSubjectExpression -> whenRef.value.subject?.symbol
is FirSafeCallExpression -> selector.symbol
is FirSmartCastExpression -> originalExpression.symbol
@@ -52,6 +56,16 @@ val FirElement.symbol: FirBasedSymbol<*>?
(it !is FirFunctionSymbol<*> && it !is FirSyntheticPropertySymbol)
}
private fun FirBasedSymbol<*>?.unwrapFakeOverridesIfNecessary(): FirBasedSymbol<*>? {
if (this !is FirCallableSymbol) return this
// This is necessary only for sake of optimizations necessary because this is a really hot place.
// Not having `dispatchReceiverType` means that this is a local/top-level property that can't be a fake override.
// And at the same time, checking a field is much faster than a couple of attributes (0.3 secs at MT Full Kotlin)
if (this.dispatchReceiverType == null) return this
return this.unwrapFakeOverrides()
}
@DfaInternals
internal val FirResolvable.symbol: FirBasedSymbol<*>?
get() = when (val reference = calleeReference) {
@@ -4,7 +4,7 @@ class Data<T>(val s: T)
fun test(d: Data<out Any>) {
if (d.s is String) {
d.s.<!UNRESOLVED_REFERENCE!>length<!>
d.s.length
}
}
@@ -43,6 +43,6 @@ fun test5(x: Inv<out Any?>) {
fun test6(x: Inv<out String?>) {
when (val y = x.data) {
is String -> x.data<!UNSAFE_CALL!>.<!>length // should be ok
is String -> x.data.length // should be ok
}
}