FIR DFA: isolate effects between blocks in try expression
This commit is contained in:
committed by
Dmitriy Novozhilov
parent
1f1e1828a7
commit
bd173ebebc
+12
-7
@@ -637,7 +637,9 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
|||||||
fun enterTryExpression(tryExpression: FirTryExpression) {
|
fun enterTryExpression(tryExpression: FirTryExpression) {
|
||||||
val (tryExpressionEnterNode, tryMainBlockEnterNode) = graphBuilder.enterTryExpression(tryExpression)
|
val (tryExpressionEnterNode, tryMainBlockEnterNode) = graphBuilder.enterTryExpression(tryExpression)
|
||||||
tryExpressionEnterNode.mergeIncomingFlow()
|
tryExpressionEnterNode.mergeIncomingFlow()
|
||||||
tryMainBlockEnterNode.mergeIncomingFlow()
|
// NB: fork to isolate effects inside the try main block
|
||||||
|
// Otherwise, changes in the try main block could affect the try expression enter node as well as its previous nodes.
|
||||||
|
tryMainBlockEnterNode.mergeIncomingFlow(shouldForkFlow = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun exitTryMainBlock(tryExpression: FirTryExpression) {
|
fun exitTryMainBlock(tryExpression: FirTryExpression) {
|
||||||
@@ -645,7 +647,9 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun enterCatchClause(catch: FirCatch) {
|
fun enterCatchClause(catch: FirCatch) {
|
||||||
graphBuilder.enterCatchClause(catch).mergeIncomingFlow(updateReceivers = true)
|
// NB: fork to isolate effects inside the catch clause
|
||||||
|
// Otherwise, changes in the catch clause could affect the previous node: try main block.
|
||||||
|
graphBuilder.enterCatchClause(catch).mergeIncomingFlow(updateReceivers = true, shouldForkFlow = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun exitCatchClause(catch: FirCatch) {
|
fun exitCatchClause(catch: FirCatch) {
|
||||||
@@ -653,19 +657,20 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun enterFinallyBlock() {
|
fun enterFinallyBlock() {
|
||||||
// TODO
|
// NB: fork to isolate effects inside the finally block
|
||||||
graphBuilder.enterFinallyBlock().mergeIncomingFlow()
|
// Otherwise, changes in the finally block could affect the previous nodes: try main block and catch clauses.
|
||||||
|
graphBuilder.enterFinallyBlock().mergeIncomingFlow(shouldForkFlow = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun exitFinallyBlock(tryExpression: FirTryExpression) {
|
fun exitFinallyBlock(tryExpression: FirTryExpression) {
|
||||||
// TODO
|
|
||||||
graphBuilder.exitFinallyBlock(tryExpression).mergeIncomingFlow()
|
graphBuilder.exitFinallyBlock(tryExpression).mergeIncomingFlow()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun exitTryExpression(callCompleted: Boolean) {
|
fun exitTryExpression(callCompleted: Boolean) {
|
||||||
// TODO
|
|
||||||
val (tryExpressionExitNode, unionNode) = graphBuilder.exitTryExpression(callCompleted)
|
val (tryExpressionExitNode, unionNode) = graphBuilder.exitTryExpression(callCompleted)
|
||||||
tryExpressionExitNode.mergeIncomingFlow()
|
// NB: fork to prevent effects after the try expression from being flown into the try expression
|
||||||
|
// Otherwise, changes in any following nodes could affect the previous nodes, including try main block and finally block if any.
|
||||||
|
tryExpressionExitNode.mergeIncomingFlow(shouldForkFlow = true)
|
||||||
unionNode?.let { unionFlowFromArguments(it) }
|
unionNode?.let { unionFlowFromArguments(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
|
||||||
|
|
||||||
sealed class Result {
|
sealed class Result {
|
||||||
class Failure(val exception: Exception) : Result()
|
class Failure(val exception: Exception) : Result()
|
||||||
class Success(val message: String) : Result()
|
class Success(val message: String) : Result()
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@ fun tryCatchFinally(x: Int?) {
|
|||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
x!!
|
x!!
|
||||||
} finally {
|
} finally {
|
||||||
checkSubtype<Int>(x)
|
<!INAPPLICABLE_CANDIDATE!>checkSubtype<!><Int>(x)
|
||||||
x!!
|
x!!
|
||||||
}
|
}
|
||||||
checkSubtype<Int>(x)
|
checkSubtype<Int>(x)
|
||||||
|
|||||||
+5
-5
@@ -2,11 +2,11 @@ fun castInTry(s: Any) {
|
|||||||
try {
|
try {
|
||||||
s as String // Potential cast exception
|
s as String // Potential cast exception
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
s.length // shouldn't be resolved
|
s.<!UNRESOLVED_REFERENCE!>length<!> // shouldn't be resolved
|
||||||
} finally {
|
} finally {
|
||||||
s.length // shouldn't be resolved
|
s.<!UNRESOLVED_REFERENCE!>length<!> // shouldn't be resolved
|
||||||
}
|
}
|
||||||
s.length // shouldn't be resolved
|
s.<!UNRESOLVED_REFERENCE!>length<!> // shouldn't be resolved
|
||||||
}
|
}
|
||||||
|
|
||||||
fun castInTryAndCatch(s: Any) {
|
fun castInTryAndCatch(s: Any) {
|
||||||
@@ -15,9 +15,9 @@ fun castInTryAndCatch(s: Any) {
|
|||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
s as String // Potential cast exception
|
s as String // Potential cast exception
|
||||||
} finally {
|
} finally {
|
||||||
s.length // shouldn't be resolved
|
s.<!UNRESOLVED_REFERENCE!>length<!> // shouldn't be resolved
|
||||||
}
|
}
|
||||||
s.length // should be smartcast
|
s.<!UNRESOLVED_REFERENCE!>length<!> // should be smartcast
|
||||||
}
|
}
|
||||||
|
|
||||||
fun castAtAll(s: Any) {
|
fun castAtAll(s: Any) {
|
||||||
|
|||||||
+2
-2
@@ -2,9 +2,9 @@ fun castInTry(s: Any) {
|
|||||||
try {
|
try {
|
||||||
s as String // Potential cast exception
|
s as String // Potential cast exception
|
||||||
} finally {
|
} finally {
|
||||||
s.length // Shouldn't be resolved
|
s.<!UNRESOLVED_REFERENCE!>length<!> // Shouldn't be resolved
|
||||||
}
|
}
|
||||||
s.length // Shouldn't be resolved
|
s.<!UNRESOLVED_REFERENCE!>length<!> // Shouldn't be resolved
|
||||||
}
|
}
|
||||||
|
|
||||||
fun castInTryAndFinally(s: Any) {
|
fun castInTryAndFinally(s: Any) {
|
||||||
|
|||||||
+1
-1
@@ -37,7 +37,7 @@ fun test3() {
|
|||||||
catch (e: B) {
|
catch (e: B) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
a.hashCode() // a is nullable here
|
a.<!INAPPLICABLE_CANDIDATE!>hashCode<!>() // a is nullable here
|
||||||
}
|
}
|
||||||
fun test4() {
|
fun test4() {
|
||||||
var a: Int? = null
|
var a: Int? = null
|
||||||
|
|||||||
+1
-1
@@ -10,5 +10,5 @@ fun foo() {
|
|||||||
} catch (ex: Exception) {}
|
} catch (ex: Exception) {}
|
||||||
bar(s)
|
bar(s)
|
||||||
if (s != null) { }
|
if (s != null) { }
|
||||||
s.hashCode()
|
s.<!INAPPLICABLE_CANDIDATE!>hashCode<!>()
|
||||||
}
|
}
|
||||||
Vendored
+1
-1
@@ -17,5 +17,5 @@ fun testWithCatch(x: Any?) {
|
|||||||
x.length
|
x.length
|
||||||
} catch (e: java.lang.IllegalArgumentException) { }
|
} catch (e: java.lang.IllegalArgumentException) { }
|
||||||
|
|
||||||
x.length
|
x.<!UNRESOLVED_REFERENCE!>length<!>
|
||||||
}
|
}
|
||||||
+1
-1
@@ -45,7 +45,7 @@ fun testTryCatch(x: Any?) {
|
|||||||
} catch (e: kotlin.IllegalArgumentException) {
|
} catch (e: kotlin.IllegalArgumentException) {
|
||||||
|
|
||||||
}
|
}
|
||||||
x.length
|
x.<!UNRESOLVED_REFERENCE!>length<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testUncertainFlow(x: Any?) {
|
fun testUncertainFlow(x: Any?) {
|
||||||
|
|||||||
Reference in New Issue
Block a user