[FIR] Fix various corner cases in DFA

This commit is contained in:
Mikhail Glukhikh
2020-02-05 20:27:23 +03:00
parent 1344d6407c
commit a8e89a6390
3 changed files with 30 additions and 26 deletions
@@ -184,7 +184,9 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
flow.addTypeStatement(operandVariable typeEq any) flow.addTypeStatement(operandVariable typeEq any)
} }
if (isNotNullCheck) { if (isNotNullCheck) {
flow.addImplication((expressionVariable eq true) implies (operandVariable typeEq any)) } flow.addImplication((expressionVariable eq true) implies (operandVariable typeEq any))
flow.addImplication((expressionVariable eq true) implies (operandVariable notEq null))
}
} else { } else {
if (isNotNullCheck) { if (isNotNullCheck) {
@@ -196,14 +198,13 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
FirOperation.AS -> { FirOperation.AS -> {
if (operandVariable.isReal()) { if (operandVariable.isReal()) {
flow.addTypeStatement(operandVariable typeEq type) flow.addTypeStatement(operandVariable typeEq type)
} else {
logicSystem.approveStatementsInsideFlow(
flow,
operandVariable notEq null,
shouldRemoveSynthetics = true,
shouldForkFlow = false
)
} }
logicSystem.approveStatementsInsideFlow(
flow,
operandVariable notEq null,
shouldRemoveSynthetics = true,
shouldForkFlow = false
)
} }
FirOperation.SAFE_AS -> { FirOperation.SAFE_AS -> {
@@ -329,6 +330,12 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
val argument = checkNotNullCall.argument val argument = checkNotNullCall.argument
val operandVariable = variableStorage.getOrCreateRealVariable(argument.symbol, argument) ?: return val operandVariable = variableStorage.getOrCreateRealVariable(argument.symbol, argument) ?: return
node.flow.addTypeStatement(operandVariable typeEq any) node.flow.addTypeStatement(operandVariable typeEq any)
logicSystem.approveStatementsInsideFlow(
node.flow,
operandVariable notEq null,
shouldRemoveSynthetics = true,
shouldForkFlow = false
)
} }
// ----------------------------------- When ----------------------------------- // ----------------------------------- When -----------------------------------
@@ -511,22 +518,19 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
?.withNullability(ConeNullability.NOT_NULL) ?.withNullability(ConeNullability.NOT_NULL)
?: return@let ?: return@let
when (val variable = variableStorage.getOrCreateVariable(receiver)) { val variable = variableStorage.getOrCreateVariable(receiver)
is RealVariable -> { if (variable is RealVariable) {
if (shouldFork) { if (shouldFork) {
flow = logicSystem.forkFlow(flow) flow = logicSystem.forkFlow(flow)
}
flow.addTypeStatement(variable typeEq type)
}
is SyntheticVariable -> {
flow = logicSystem.approveStatementsInsideFlow(
flow,
variable notEq null,
shouldFork,
shouldRemoveSynthetics = true
)
} }
flow.addTypeStatement(variable typeEq type)
} }
flow = logicSystem.approveStatementsInsideFlow(
flow,
variable notEq null,
shouldFork,
shouldRemoveSynthetics = true
)
} }
node.flow = flow node.flow = flow
@@ -654,9 +658,8 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
variableStorage.getOrCreateRealVariable(initializer.symbol, initializer)?.let { initializerVariable -> variableStorage.getOrCreateRealVariable(initializer.symbol, initializer)?.let { initializerVariable ->
if (initializerVariable.isStable) { if (initializerVariable.isStable) {
variableStorage.attachSymbolToVariable(variable.symbol, initializerVariable) variableStorage.attachSymbolToVariable(variable.symbol, initializerVariable)
} else {
node.flow.addImplication((propertyVariable notEq null) implies (initializerVariable notEq null))
} }
node.flow.addImplication((propertyVariable notEq null) implies (initializerVariable notEq null))
} }
if (!isVariableDeclaration) { if (!isVariableDeclaration) {
@@ -52,7 +52,7 @@ fun kt4565_1(a: SomeClass?) {
a.data.hashCode() a.data.hashCode()
} }
if (a?.data is String) { if (a?.data is String) {
a.<!INAPPLICABLE_CANDIDATE!>data<!>.<!UNRESOLVED_REFERENCE!>length<!> a.data.length
data.length data.length
} }
} }
+2 -1
View File
@@ -58,7 +58,8 @@ FILE fqName:<root> fileName:/kt30020.kt
$receiver: CALL 'public final fun CHECK_NOT_NULL <T0> (arg0: T0 of kotlin.internal.ir.CHECK_NOT_NULL?): T0 of kotlin.internal.ir.CHECK_NOT_NULL declared in kotlin.internal.ir' type=kotlin.collections.MutableList<kotlin.Any> origin=EXCLEXCL $receiver: CALL 'public final fun CHECK_NOT_NULL <T0> (arg0: T0 of kotlin.internal.ir.CHECK_NOT_NULL?): T0 of kotlin.internal.ir.CHECK_NOT_NULL declared in kotlin.internal.ir' type=kotlin.collections.MutableList<kotlin.Any> origin=EXCLEXCL
<T0>: kotlin.collections.MutableList<kotlin.Any> <T0>: kotlin.collections.MutableList<kotlin.Any>
arg0: CALL 'public abstract fun f (): kotlin.collections.MutableList<kotlin.Any> declared in <root>.X' type=kotlin.collections.MutableList<kotlin.Any>? origin=null arg0: CALL 'public abstract fun f (): kotlin.collections.MutableList<kotlin.Any> declared in <root>.X' type=kotlin.collections.MutableList<kotlin.Any>? origin=null
$this: GET_VAR 'nx: <root>.X? declared in <root>.test' type=<root>.X? origin=null $this: TYPE_OP type=<root>.X origin=IMPLICIT_CAST typeOperand=<root>.X
GET_VAR 'nx: <root>.X? declared in <root>.test' type=<root>.X? origin=null
element: CONST Int type=kotlin.Int value=6 element: CONST Int type=kotlin.Int value=6
FUN name:testExtensionReceiver visibility:public modality:FINAL <> ($receiver:kotlin.collections.MutableList<kotlin.Any>) returnType:kotlin.Unit FUN name:testExtensionReceiver visibility:public modality:FINAL <> ($receiver:kotlin.collections.MutableList<kotlin.Any>) returnType:kotlin.Unit
$receiver: VALUE_PARAMETER name:<this> type:kotlin.collections.MutableList<kotlin.Any> $receiver: VALUE_PARAMETER name:<this> type:kotlin.collections.MutableList<kotlin.Any>