[FIR] Don't save DFA implications for unstable local vars

^KT-57502 Fixed
This commit is contained in:
Dmitriy Novozhilov
2023-05-09 14:22:33 +03:00
committed by Space Team
parent 31424e38ac
commit 40b8b682f9
16 changed files with 289 additions and 12 deletions
@@ -31287,6 +31287,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
runTest("compiler/testData/diagnostics/tests/smartCasts/variables/lambdaBetweenArguments.kt");
}
@Test
@TestMetadata("localDelegatedProperty.kt")
public void testLocalDelegatedProperty() throws Exception {
runTest("compiler/testData/diagnostics/tests/smartCasts/variables/localDelegatedProperty.kt");
}
@Test
@TestMetadata("objectMembers.kt")
public void testObjectMembers() throws Exception {
@@ -4771,6 +4771,12 @@ public class DiagnosticCompilerTestFirTestdataTestGenerated extends AbstractDiag
public void testSmartcastAfterReassignment() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/variables/smartcastAfterReassignment.kt");
}
@Test
@TestMetadata("smartcastStoredInLocalVar.kt")
public void testSmartcastStoredInLocalVar() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/variables/smartcastStoredInLocalVar.kt");
}
}
}
@@ -31287,6 +31287,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
runTest("compiler/testData/diagnostics/tests/smartCasts/variables/lambdaBetweenArguments.kt");
}
@Test
@TestMetadata("localDelegatedProperty.kt")
public void testLocalDelegatedProperty() throws Exception {
runTest("compiler/testData/diagnostics/tests/smartCasts/variables/localDelegatedProperty.kt");
}
@Test
@TestMetadata("objectMembers.kt")
public void testObjectMembers() throws Exception {
@@ -4771,6 +4771,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFirTestDataTestGenerated
public void testSmartcastAfterReassignment() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/variables/smartcastAfterReassignment.kt");
}
@Test
@TestMetadata("smartcastStoredInLocalVar.kt")
public void testSmartcastStoredInLocalVar() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/variables/smartcastStoredInLocalVar.kt");
}
}
}
@@ -4230,6 +4230,11 @@ public class LazyBodyIsNotTouchedTestGenerated extends AbstractLazyBodyIsNotTouc
public void testSmartcastAfterReassignment() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/variables/smartcastAfterReassignment.kt");
}
@TestMetadata("smartcastStoredInLocalVar.kt")
public void testSmartcastStoredInLocalVar() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/variables/smartcastStoredInLocalVar.kt");
}
}
}
@@ -0,0 +1,122 @@
FILE: smartcastStoredInLocalVar.kt
public final fun nonInPlaceRun(block: R|() -> kotlin/Unit|): R|kotlin/Unit| {
}
public final fun test_0(a: R|kotlin/Any|): R|kotlin/Unit| {
lvar b: R|kotlin/Boolean| = (R|<local>/a| is R|kotlin/String|)
when () {
R|<local>/b| -> {
R|<local>/a|.<Unresolved name: length>#
}
}
R|/nonInPlaceRun|(<L> = nonInPlaceRun@fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
when () {
R|<local>/b| -> {
R|<local>/a|.<Unresolved name: length>#
}
}
}
)
when () {
R|<local>/b| -> {
R|<local>/a|.<Unresolved name: length>#
}
}
}
public final fun test_1(a: R|kotlin/Any|): R|kotlin/Unit| {
lvar b: R|kotlin/Boolean| = (R|<local>/a| is R|kotlin/String|)
when () {
R|<local>/b| -> {
R|<local>/a|.<Unresolved name: length>#
}
}
R|/nonInPlaceRun|(<L> = nonInPlaceRun@fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
when () {
R|<local>/b| -> {
R|<local>/a|.<Unresolved name: length>#
}
}
}
)
R|<local>/b| = Boolean(true)
}
public final fun test_2(a: R|kotlin/Any|): R|kotlin/Unit| {
lvar b: R|kotlin/Boolean| = (R|<local>/a| is R|kotlin/String|)
when () {
R|<local>/b| -> {
R|<local>/a|.<Unresolved name: length>#
}
}
R|/nonInPlaceRun|(<L> = nonInPlaceRun@fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
R|<local>/b| = Boolean(true)
}
)
when () {
R|<local>/b| -> {
R|<local>/a|.<Unresolved name: length>#
}
}
}
public final fun test_3(a: R|kotlin/Any|): R|kotlin/Unit| {
lvar b: R|kotlin/Boolean| = (R|<local>/a| is R|kotlin/String|)
when () {
R|<local>/b| -> {
R|<local>/a|.<Unresolved name: length>#
}
}
R|kotlin/run|<R|kotlin/Unit|>(<L> = run@fun <anonymous>(): R|kotlin/Unit| <inline=Inline, kind=EXACTLY_ONCE> {
when () {
R|<local>/b| -> {
R|<local>/a|.<Unresolved name: length>#
}
}
}
)
R|<local>/b| = Boolean(true)
}
public final fun test_4(a: R|kotlin/Any|): R|kotlin/Unit| {
lvar b: R|kotlin/Boolean| = (R|<local>/a| is R|kotlin/String|)
when () {
R|<local>/b| -> {
R|<local>/a|.<Unresolved name: length>#
}
}
R|kotlin/run|<R|kotlin/Unit|>(<L> = run@fun <anonymous>(): R|kotlin/Unit| <inline=Inline, kind=EXACTLY_ONCE> {
R|<local>/b| = Boolean(true)
}
)
when () {
R|<local>/b| -> {
R|<local>/a|.<Unresolved name: length>#
}
}
}
public final fun test_5(a: R|kotlin/Any|): R|kotlin/Unit| {
lvar b: R|kotlin/Boolean| = (R|<local>/a| is R|kotlin/String|)
while(R|<local>/b|) {
when () {
R|<local>/b| -> {
R|<local>/a|.<Unresolved name: length>#
}
}
R|<local>/b| = (R|<local>/a| is R|kotlin/String|)
}
when () {
R|<local>/b| -> {
R|<local>/a|.<Unresolved name: length>#
}
}
}
@@ -0,0 +1,84 @@
// WITH_STDLIB
// ISSUE: KT-58604
fun nonInPlaceRun(block: () -> Unit) {}
fun test_0(a: Any) {
var b = a is String
if (b) {
a.<!UNRESOLVED_REFERENCE!>length<!> // can be ok
}
nonInPlaceRun {
if (b) {
a.<!UNRESOLVED_REFERENCE!>length<!> // can be ok
}
}
if (b) {
a.<!UNRESOLVED_REFERENCE!>length<!> // can be ok
}
}
fun test_1(a: Any) {
var b = a is String
if (b) {
a.<!UNRESOLVED_REFERENCE!>length<!> // can be ok
}
nonInPlaceRun {
if (b) {
a.<!UNRESOLVED_REFERENCE!>length<!> // not ok
}
}
b = true
}
fun test_2(a: Any) {
var b = a is String
if (b) {
a.<!UNRESOLVED_REFERENCE!>length<!> // can be ok
}
nonInPlaceRun {
b = true
}
if (b) {
a.<!UNRESOLVED_REFERENCE!>length<!> // not ok
}
}
fun test_3(a: Any) {
var b = a is String
if (b) {
a.<!UNRESOLVED_REFERENCE!>length<!> // // can be ok
}
run {
if (b) {
a.<!UNRESOLVED_REFERENCE!>length<!> // // can be ok
}
}
b = true
}
fun test_4(a: Any) {
var b = a is String
if (b) {
a.<!UNRESOLVED_REFERENCE!>length<!> // // can be ok
}
run {
b = true
}
if (b) {
a.<!UNRESOLVED_REFERENCE!>length<!> // not ok
}
}
fun test_5(a: Any) {
var b = a is String
while (b) {
if (b) {
a.<!UNRESOLVED_REFERENCE!>length<!> // not ok
}
b = a is String
}
if (b) {
a.<!UNRESOLVED_REFERENCE!>length<!> // // can be ok
}
}
@@ -4771,6 +4771,12 @@ public class FirLightTreeDiagnosticsTestGenerated extends AbstractFirLightTreeDi
public void testSmartcastAfterReassignment() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/variables/smartcastAfterReassignment.kt");
}
@Test
@TestMetadata("smartcastStoredInLocalVar.kt")
public void testSmartcastStoredInLocalVar() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/variables/smartcastStoredInLocalVar.kt");
}
}
}
@@ -31287,6 +31287,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
runTest("compiler/testData/diagnostics/tests/smartCasts/variables/lambdaBetweenArguments.kt");
}
@Test
@TestMetadata("localDelegatedProperty.kt")
public void testLocalDelegatedProperty() throws Exception {
runTest("compiler/testData/diagnostics/tests/smartCasts/variables/localDelegatedProperty.kt");
}
@Test
@TestMetadata("objectMembers.kt")
public void testObjectMembers() throws Exception {
@@ -4771,6 +4771,12 @@ public class FirPsiDiagnosticTestGenerated extends AbstractFirPsiDiagnosticTest
public void testSmartcastAfterReassignment() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/variables/smartcastAfterReassignment.kt");
}
@Test
@TestMetadata("smartcastStoredInLocalVar.kt")
public void testSmartcastStoredInLocalVar() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/variables/smartcastStoredInLocalVar.kt");
}
}
}
@@ -31383,6 +31383,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
runTest("compiler/testData/diagnostics/tests/smartCasts/variables/lambdaBetweenArguments.kt");
}
@Test
@TestMetadata("localDelegatedProperty.kt")
public void testLocalDelegatedProperty() throws Exception {
runTest("compiler/testData/diagnostics/tests/smartCasts/variables/localDelegatedProperty.kt");
}
@Test
@TestMetadata("objectMembers.kt")
public void testObjectMembers() throws Exception {
@@ -919,11 +919,8 @@ abstract class FirDataFlowAnalyzer(
assignmentLhs: FirExpression?,
hasExplicitType: Boolean,
) {
val propertyVariable = variableStorage.getOrCreateRealVariableWithoutUnwrappingAlias(
flow,
property.symbol,
assignmentLhs ?: property,
if (property.isVal) PropertyStability.STABLE_VALUE else PropertyStability.LOCAL_VAR
val propertyVariable = variableStorage.getOrCreateRealVariableWithoutUnwrappingAliasForPropertyInitialization(
flow, property.symbol, assignmentLhs ?: property
)
val isAssignment = assignmentLhs != null
if (isAssignment) {
@@ -932,8 +929,7 @@ abstract class FirDataFlowAnalyzer(
val initializerVariable = variableStorage.getOrCreateIfReal(flow, initializer)
if (initializerVariable is RealVariable) {
val isInitializerStable =
initializerVariable.isStable || (initializerVariable.hasLocalStability && !isAccessToUnstableLocalVariable(initializer))
val isInitializerStable = initializerVariable.isStableOrLocalStableAccess(initializer)
if (!hasExplicitType && isInitializerStable && (propertyVariable.hasLocalStability || propertyVariable.isStable)) {
// val a = ...
// val b = a
@@ -945,7 +941,7 @@ abstract class FirDataFlowAnalyzer(
// if (b != null) { /* a != null, but a.x could have changed */ }
logicSystem.translateVariableFromConditionInStatements(flow, initializerVariable, propertyVariable)
}
} else if (initializerVariable != null) {
} else if (initializerVariable != null && propertyVariable.isStable) {
// val b = x is String
// if (b) { /* x is String */ }
logicSystem.translateVariableFromConditionInStatements(flow, initializerVariable, propertyVariable)
@@ -961,6 +957,9 @@ abstract class FirDataFlowAnalyzer(
private val RealVariable.isStable get() = stability == PropertyStability.STABLE_VALUE
private val RealVariable.hasLocalStability get() = stability == PropertyStability.LOCAL_VAR
private fun RealVariable.isStableOrLocalStableAccess(access: FirExpression): Boolean {
return isStable || (hasLocalStability && !isAccessToUnstableLocalVariable(access))
}
fun exitThrowExceptionNode(throwExpression: FirThrowExpression) {
graphBuilder.exitThrowExceptionNode(throwExpression).mergeIncomingFlow()
@@ -25,7 +25,6 @@ import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.coneTypeSafe
import org.jetbrains.kotlin.fir.expressions.explicitReceiver
@OptIn(DfaInternals::class)
class VariableStorageImpl(private val session: FirSession) : VariableStorage() {
@@ -38,14 +37,15 @@ class VariableStorageImpl(private val session: FirSession) : VariableStorage() {
fun clear(): VariableStorageImpl = VariableStorageImpl(session)
fun getOrCreateRealVariableWithoutUnwrappingAlias(
fun getOrCreateRealVariableWithoutUnwrappingAliasForPropertyInitialization(
flow: Flow,
symbol: FirBasedSymbol<*>,
fir: FirElement,
stability: PropertyStability
): RealVariable {
val realFir = fir.unwrapElement()
val identifier = getIdentifierBySymbol(flow, symbol, realFir)
val stability = symbol.getStability(fir)
requireNotNull(stability) { "Stability for initialized variable always should be computable" }
return _realVariables[identifier] ?: createReal(flow, identifier, realFir, stability)
}
@@ -0,0 +1,13 @@
// FIR_IDENTICAL
// WITH_STDLIB
// ISSUE: KT-57502
import kotlin.properties.Delegates
fun test(foo: Any) {
var test by Delegates.observable(true) { property, oldValue, newValue -> }
test = foo is String
if (test) {
foo.<!UNRESOLVED_REFERENCE!>length<!> // no smartcast
}
}
@@ -15,6 +15,6 @@ fun foo(arg: Int?) {
var z = arg
z = z?.let { 42 }
if (z != null) {
arg.hashCode()
arg<!UNSAFE_CALL!>.<!>hashCode()
}
}
@@ -32155,6 +32155,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/smartCasts/variables/lambdaBetweenArguments.kt");
}
@Test
@TestMetadata("localDelegatedProperty.kt")
public void testLocalDelegatedProperty() throws Exception {
runTest("compiler/testData/diagnostics/tests/smartCasts/variables/localDelegatedProperty.kt");
}
@Test
@TestMetadata("objectMembers.kt")
public void testObjectMembers() throws Exception {