FIR: Rework FirRegularTowerDataContexts

- Get rid of SPECIAL mode (just left REGULAR and class-related instead)
- Clear naming
- Restore contexts after lambda/callable reference are processed

The test has been failing before this change because after
callable reference is resolved, its tower data context has been left
erroneously in the SPECIAL-related entry
This commit is contained in:
Denis.Zharkov
2022-06-02 18:27:29 +03:00
committed by teamcity
parent 521d6c307c
commit eae673233b
8 changed files with 104 additions and 44 deletions
@@ -7164,6 +7164,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
runTest("compiler/testData/diagnostics/tests/dataFlow/IsExpression.kt"); runTest("compiler/testData/diagnostics/tests/dataFlow/IsExpression.kt");
} }
@Test
@TestMetadata("smartCastWithLambdaAndCallableReference.kt")
public void testSmartCastWithLambdaAndCallableReference() throws Exception {
runTest("compiler/testData/diagnostics/tests/dataFlow/smartCastWithLambdaAndCallableReference.kt");
}
@Test @Test
@TestMetadata("WhenSubject.kt") @TestMetadata("WhenSubject.kt")
public void testWhenSubject() throws Exception { public void testWhenSubject() throws Exception {
@@ -7164,6 +7164,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/dataFlow/IsExpression.kt"); runTest("compiler/testData/diagnostics/tests/dataFlow/IsExpression.kt");
} }
@Test
@TestMetadata("smartCastWithLambdaAndCallableReference.kt")
public void testSmartCastWithLambdaAndCallableReference() throws Exception {
runTest("compiler/testData/diagnostics/tests/dataFlow/smartCastWithLambdaAndCallableReference.kt");
}
@Test @Test
@TestMetadata("WhenSubject.kt") @TestMetadata("WhenSubject.kt")
public void testWhenSubject() throws Exception { public void testWhenSubject() throws Exception {
@@ -7164,6 +7164,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/dataFlow/IsExpression.kt"); runTest("compiler/testData/diagnostics/tests/dataFlow/IsExpression.kt");
} }
@Test
@TestMetadata("smartCastWithLambdaAndCallableReference.kt")
public void testSmartCastWithLambdaAndCallableReference() throws Exception {
runTest("compiler/testData/diagnostics/tests/dataFlow/smartCastWithLambdaAndCallableReference.kt");
}
@Test @Test
@TestMetadata("WhenSubject.kt") @TestMetadata("WhenSubject.kt")
public void testWhenSubject() throws Exception { public void testWhenSubject() throws Exception {
@@ -10,7 +10,7 @@ import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope
import java.util.* import java.util.*
enum class FirTowerDataMode { enum class FirTowerDataMode {
MEMBER_DECLARATION, REGULAR,
NESTED_CLASS, NESTED_CLASS,
COMPANION_OBJECT, COMPANION_OBJECT,
CONSTRUCTOR_HEADER, CONSTRUCTOR_HEADER,
@@ -22,64 +22,63 @@ class FirRegularTowerDataContexts private constructor(
private val modeMap: EnumMap<FirTowerDataMode, FirTowerDataContext>, private val modeMap: EnumMap<FirTowerDataMode, FirTowerDataContext>,
val primaryConstructorPureParametersScope: FirLocalScope?, val primaryConstructorPureParametersScope: FirLocalScope?,
val primaryConstructorAllParametersScope: FirLocalScope?, val primaryConstructorAllParametersScope: FirLocalScope?,
val mode: FirTowerDataMode, val activeMode: FirTowerDataMode,
) { ) {
constructor( constructor(
forMemberDeclarations: FirTowerDataContext, regular: FirTowerDataContext,
forNestedClasses: FirTowerDataContext? = null, forNestedClasses: FirTowerDataContext? = null,
forCompanionObject: FirTowerDataContext? = null, forCompanionObject: FirTowerDataContext? = null,
forConstructorHeaders: FirTowerDataContext? = null, forConstructorHeaders: FirTowerDataContext? = null,
forEnumEntries: FirTowerDataContext? = null, forEnumEntries: FirTowerDataContext? = null,
forSpecial: FirTowerDataContext? = null,
primaryConstructorPureParametersScope: FirLocalScope? = null, primaryConstructorPureParametersScope: FirLocalScope? = null,
primaryConstructorAllParametersScope: FirLocalScope? = null, primaryConstructorAllParametersScope: FirLocalScope? = null,
) : this( ) : this(
enumMap(forMemberDeclarations, forNestedClasses, forCompanionObject, forConstructorHeaders, forEnumEntries, forSpecial), enumMap(regular, forNestedClasses, forCompanionObject, forConstructorHeaders, forEnumEntries),
primaryConstructorPureParametersScope, primaryConstructorPureParametersScope,
primaryConstructorAllParametersScope, primaryConstructorAllParametersScope,
FirTowerDataMode.MEMBER_DECLARATION FirTowerDataMode.REGULAR
) )
val currentContext: FirTowerDataContext? val currentContext: FirTowerDataContext?
get() = modeMap[mode] get() = modeMap[activeMode]
fun copy(newContext: FirTowerDataContext): FirRegularTowerDataContexts { fun replaceCurrentlyActiveContext(newContext: FirTowerDataContext): FirRegularTowerDataContexts {
val modeMap = EnumMap<FirTowerDataMode, FirTowerDataContext>(FirTowerDataMode::class.java) val modeMap = EnumMap<FirTowerDataMode, FirTowerDataContext>(FirTowerDataMode::class.java)
modeMap.putAll(this.modeMap) modeMap.putAll(this.modeMap)
modeMap[mode] = newContext modeMap[activeMode] = newContext
return FirRegularTowerDataContexts(modeMap, primaryConstructorPureParametersScope, primaryConstructorAllParametersScope, mode) return FirRegularTowerDataContexts(modeMap, primaryConstructorPureParametersScope, primaryConstructorAllParametersScope, activeMode)
} }
fun copy(newMode: FirTowerDataMode): FirRegularTowerDataContexts { fun replaceTowerDataMode(newMode: FirTowerDataMode): FirRegularTowerDataContexts {
if (newMode == mode) return this if (newMode == activeMode) return this
return FirRegularTowerDataContexts(modeMap, primaryConstructorPureParametersScope, primaryConstructorAllParametersScope, newMode) return FirRegularTowerDataContexts(modeMap, primaryConstructorPureParametersScope, primaryConstructorAllParametersScope, newMode)
} }
fun copyWithSpecial(newContext: FirTowerDataContext): FirRegularTowerDataContexts { // Effectively equal to replaceTowerDataMode(REGULAR) + replaceCurrentlyActiveContext(newContext)
// But left just for sake of optimization
fun replaceAndSetActiveRegularContext(newContext: FirTowerDataContext): FirRegularTowerDataContexts {
val modeMap = EnumMap<FirTowerDataMode, FirTowerDataContext>(FirTowerDataMode::class.java) val modeMap = EnumMap<FirTowerDataMode, FirTowerDataContext>(FirTowerDataMode::class.java)
modeMap.putAll(this.modeMap) modeMap.putAll(this.modeMap)
modeMap[FirTowerDataMode.SPECIAL] = newContext modeMap[FirTowerDataMode.REGULAR] = newContext
return FirRegularTowerDataContexts( return FirRegularTowerDataContexts(
modeMap, primaryConstructorPureParametersScope, primaryConstructorAllParametersScope, FirTowerDataMode.SPECIAL modeMap, primaryConstructorPureParametersScope, primaryConstructorAllParametersScope, FirTowerDataMode.REGULAR
) )
} }
companion object { companion object {
private fun enumMap( private fun enumMap(
forMemberDeclarations: FirTowerDataContext, regular: FirTowerDataContext,
forNestedClasses: FirTowerDataContext?, forNestedClasses: FirTowerDataContext?,
forCompanionObject: FirTowerDataContext?, forCompanionObject: FirTowerDataContext?,
forConstructorHeaders: FirTowerDataContext?, forConstructorHeaders: FirTowerDataContext?,
forEnumEntries: FirTowerDataContext?, forEnumEntries: FirTowerDataContext?,
forSpecial: FirTowerDataContext?,
): EnumMap<FirTowerDataMode, FirTowerDataContext> { ): EnumMap<FirTowerDataMode, FirTowerDataContext> {
val modeMap = EnumMap<FirTowerDataMode, FirTowerDataContext>(FirTowerDataMode::class.java) val modeMap = EnumMap<FirTowerDataMode, FirTowerDataContext>(FirTowerDataMode::class.java)
modeMap[FirTowerDataMode.MEMBER_DECLARATION] = forMemberDeclarations modeMap[FirTowerDataMode.REGULAR] = regular
modeMap[FirTowerDataMode.NESTED_CLASS] = forNestedClasses modeMap[FirTowerDataMode.NESTED_CLASS] = forNestedClasses
modeMap[FirTowerDataMode.COMPANION_OBJECT] = forCompanionObject modeMap[FirTowerDataMode.COMPANION_OBJECT] = forCompanionObject
modeMap[FirTowerDataMode.CONSTRUCTOR_HEADER] = forConstructorHeaders modeMap[FirTowerDataMode.CONSTRUCTOR_HEADER] = forConstructorHeaders
modeMap[FirTowerDataMode.ENUM_ENTRY] = forEnumEntries modeMap[FirTowerDataMode.ENUM_ENTRY] = forEnumEntries
modeMap[FirTowerDataMode.SPECIAL] = forSpecial
return modeMap return modeMap
} }
} }
@@ -52,7 +52,7 @@ class BodyResolveContext(
lateinit var file: FirFile lateinit var file: FirFile
@PrivateForInline @PrivateForInline
var regularTowerDataContexts = FirRegularTowerDataContexts(forMemberDeclarations = FirTowerDataContext()) var regularTowerDataContexts = FirRegularTowerDataContexts(regular = FirTowerDataContext())
@PrivateForInline @PrivateForInline
val specialTowerDataContexts = FirSpecialTowerDataContexts() val specialTowerDataContexts = FirSpecialTowerDataContexts()
@@ -64,9 +64,9 @@ class BodyResolveContext(
@OptIn(PrivateForInline::class) @OptIn(PrivateForInline::class)
var towerDataMode: FirTowerDataMode var towerDataMode: FirTowerDataMode
get() = regularTowerDataContexts.mode get() = regularTowerDataContexts.activeMode
set(value) { set(value) {
regularTowerDataContexts = regularTowerDataContexts.copy(newMode = value) regularTowerDataContexts = regularTowerDataContexts.replaceTowerDataMode(newMode = value)
} }
val implicitReceiverStack: ImplicitReceiverStack val implicitReceiverStack: ImplicitReceiverStack
@@ -95,7 +95,7 @@ class BodyResolveContext(
get() = containingClassDeclarations.lastOrNull() get() = containingClassDeclarations.lastOrNull()
@OptIn(PrivateForInline::class) @OptIn(PrivateForInline::class)
inline fun <T> withNewTowerDataForClass(newContexts: FirRegularTowerDataContexts, f: () -> T): T { inline fun <T> withTowerDataContexts(newContexts: FirRegularTowerDataContexts, f: () -> T): T {
val old = regularTowerDataContexts val old = regularTowerDataContexts
regularTowerDataContexts = newContexts regularTowerDataContexts = newContexts
return try { return try {
@@ -158,14 +158,14 @@ class BodyResolveContext(
@PrivateForInline @PrivateForInline
inline fun <T> withTowerDataMode(mode: FirTowerDataMode, f: () -> T): T { inline fun <T> withTowerDataMode(mode: FirTowerDataMode, f: () -> T): T {
return withTowerModeCleanup { return withTowerDataModeCleanup {
towerDataMode = mode towerDataMode = mode
f() f()
} }
} }
@PrivateForInline @PrivateForInline
inline fun <R> withTowerModeCleanup(l: () -> R): R { inline fun <R> withTowerDataModeCleanup(l: () -> R): R {
val initialMode = towerDataMode val initialMode = towerDataMode
return try { return try {
l() l()
@@ -176,7 +176,7 @@ class BodyResolveContext(
@PrivateForInline @PrivateForInline
fun replaceTowerDataContext(newContext: FirTowerDataContext) { fun replaceTowerDataContext(newContext: FirTowerDataContext) {
regularTowerDataContexts = regularTowerDataContexts.copy(newContext) regularTowerDataContexts = regularTowerDataContexts.replaceCurrentlyActiveContext(newContext)
} }
@PrivateForInline @PrivateForInline
@@ -315,23 +315,19 @@ class BodyResolveContext(
@OptIn(PrivateForInline::class) @OptIn(PrivateForInline::class)
inline fun <T> withAnonymousFunctionTowerDataContext(symbol: FirAnonymousFunctionSymbol, f: () -> T): T { inline fun <T> withAnonymousFunctionTowerDataContext(symbol: FirAnonymousFunctionSymbol, f: () -> T): T {
return withTowerModeCleanup { return withTemporaryRegularContext(specialTowerDataContexts.getAnonymousFunctionContext(symbol), f)
val newContext = specialTowerDataContexts.getAnonymousFunctionContext(symbol)
if (newContext != null) {
regularTowerDataContexts = regularTowerDataContexts.copyWithSpecial(newContext)
}
f()
}
} }
@OptIn(PrivateForInline::class) @OptIn(PrivateForInline::class)
inline fun <T> withCallableReferenceTowerDataContext(access: FirCallableReferenceAccess, f: () -> T): T { inline fun <T> withCallableReferenceTowerDataContext(access: FirCallableReferenceAccess, f: () -> T): T {
return withTowerModeCleanup { return withTemporaryRegularContext(specialTowerDataContexts.getCallableReferenceContext(access), f)
val newContext = specialTowerDataContexts.getCallableReferenceContext(access) }
if (newContext != null) {
regularTowerDataContexts = regularTowerDataContexts.copyWithSpecial(newContext) @PrivateForInline
} inline fun <T> withTemporaryRegularContext(newContext: FirTowerDataContext?, f: () -> T): T {
f() if (newContext == null) return f()
return withTowerDataModeCleanup {
withTowerDataContexts(regularTowerDataContexts.replaceAndSetActiveRegularContext(newContext), f)
} }
} }
@@ -396,7 +392,7 @@ class BodyResolveContext(
withContainerClass(regularClass, f) withContainerClass(regularClass, f)
} }
} }
return withTowerModeCleanup { return withTowerDataModeCleanup {
if (!regularClass.isInner && containerIfAny is FirRegularClass) { if (!regularClass.isInner && containerIfAny is FirRegularClass) {
towerDataMode = if (regularClass.isCompanion) { towerDataMode = if (regularClass.isCompanion) {
FirTowerDataMode.COMPANION_OBJECT FirTowerDataMode.COMPANION_OBJECT
@@ -486,12 +482,11 @@ class BodyResolveContext(
statics, statics,
scopeForConstructorHeader, scopeForConstructorHeader,
scopeForEnumEntries, scopeForEnumEntries,
forSpecial = null,
primaryConstructorPureParametersScope, primaryConstructorPureParametersScope,
primaryConstructorAllParametersScope primaryConstructorAllParametersScope
) )
return withNewTowerDataForClass(newContexts) { return withTowerDataContexts(newContexts) {
f() f()
} }
} }
@@ -521,7 +516,7 @@ class BodyResolveContext(
val whenSubjectImportingScope = whenSubjectImportingScopes.lastOrNull() ?: return f() val whenSubjectImportingScope = whenSubjectImportingScopes.lastOrNull() ?: return f()
val newTowerDataContext = towerDataContext.addNonLocalScope(whenSubjectImportingScope) val newTowerDataContext = towerDataContext.addNonLocalScope(whenSubjectImportingScope)
val newContexts = FirRegularTowerDataContexts(newTowerDataContext) val newContexts = FirRegularTowerDataContexts(newTowerDataContext)
return withNewTowerDataForClass(newContexts) { return withTowerDataContexts(newContexts) {
f() f()
} }
} }
@@ -0,0 +1,21 @@
// SKIP_TXT
fun <T> T.myApply(block: T.() -> Unit): T = this
fun bar(): Int = 1
interface A : C
interface B : C
interface C {
fun baz()
}
fun Any.foo() = myApply {
when (this) {
is A -> ::bar
is B -> ::bar
else -> throw RuntimeException()
}
baz() // Smart cast should work
}
@@ -0,0 +1,21 @@
// SKIP_TXT
fun <T> T.myApply(block: T.() -> Unit): T = this
fun bar(): Int = 1
interface A : C
interface B : C
interface C {
fun baz()
}
fun Any.foo() = myApply {
when (this) {
is A -> ::bar
is B -> ::bar
else -> throw RuntimeException()
}
<!UNRESOLVED_REFERENCE!>baz<!>() // Smart cast should work
}
@@ -7170,6 +7170,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/dataFlow/IsExpression.kt"); runTest("compiler/testData/diagnostics/tests/dataFlow/IsExpression.kt");
} }
@Test
@TestMetadata("smartCastWithLambdaAndCallableReference.kt")
public void testSmartCastWithLambdaAndCallableReference() throws Exception {
runTest("compiler/testData/diagnostics/tests/dataFlow/smartCastWithLambdaAndCallableReference.kt");
}
@Test @Test
@TestMetadata("WhenSubject.kt") @TestMetadata("WhenSubject.kt")
public void testWhenSubject() throws Exception { public void testWhenSubject() throws Exception {