[FIR] Create alternate DFA flows through finally blocks
Entering a `finally` block can happen from many different places:
through an exception, a jump, or normal exit from the `try` block. When
in the `finally` block, all DFA flows must be merged to have correct
smart casting. However, after the `finally` block, if exiting normally
or because of a jump, the combined flow from within the `finally` block
should not be used, but rather an alternate flow which combines the
correct flows from before the `finally` block.
```
try {
str as String // Potential cast exception
} finally {
str.length // Shouldn`t be resolved
}
str.length // Should be resolved
```
When building DFA flows, track the start of possible alternate flows,
and continue building them until they end. Both of these situations are
now marked on CFGNodes via interfaces.
When building the default DFA flow, and the source node is the end node
of alternate flows, attempt to use the alternate flow with the same edge
label instead of the default flow of the source node.
#KT-56888 Fixed
This commit is contained in:
+1
-1
@@ -17,7 +17,7 @@ fun castInTryAndCatch(s: Any) {
|
||||
} finally {
|
||||
s.<!UNRESOLVED_REFERENCE!>length<!> // shouldn't be resolved
|
||||
}
|
||||
s.<!UNRESOLVED_REFERENCE!>length<!> // should be smartcast
|
||||
s.length // should be smartcast
|
||||
}
|
||||
|
||||
fun castAtAll(s: Any) {
|
||||
|
||||
+521
-485
File diff suppressed because it is too large
Load Diff
+10
-10
@@ -26,13 +26,13 @@ fun breakInTry_withNestedFinally() {
|
||||
x.<!UNRESOLVED_REFERENCE!>bbb<!>() // should be error
|
||||
}
|
||||
x.<!UNRESOLVED_REFERENCE!>aaa<!>() // should be error
|
||||
x.<!UNRESOLVED_REFERENCE!>bbb<!>() // should be ok
|
||||
x.bbb() // should be ok
|
||||
}
|
||||
x.<!UNRESOLVED_REFERENCE!>aaa<!>() // should be error
|
||||
x.<!UNRESOLVED_REFERENCE!>bbb<!>() // should be ok
|
||||
x.bbb() // should be ok
|
||||
}
|
||||
x.<!UNRESOLVED_REFERENCE!>aaa<!>() // should be ok
|
||||
x.<!UNRESOLVED_REFERENCE!>bbb<!>() // should be ok
|
||||
x.aaa() // should be ok
|
||||
x.bbb() // should be ok
|
||||
}
|
||||
|
||||
fun returnInCatch() {
|
||||
@@ -46,7 +46,7 @@ fun returnInCatch() {
|
||||
x.<!UNRESOLVED_REFERENCE!>aaa<!>() // should be error
|
||||
x.<!UNRESOLVED_REFERENCE!>bbb<!>() // should be error
|
||||
}
|
||||
x.<!UNRESOLVED_REFERENCE!>aaa<!>() // should be ok
|
||||
x.aaa() // should be ok
|
||||
x.<!UNRESOLVED_REFERENCE!>bbb<!>() // should be error
|
||||
}
|
||||
|
||||
@@ -65,13 +65,13 @@ fun returnInCatch_insideFinally() {
|
||||
x.<!UNRESOLVED_REFERENCE!>bbb<!>() // should be error
|
||||
x.<!UNRESOLVED_REFERENCE!>ccc<!>() // should be error
|
||||
}
|
||||
x.<!UNRESOLVED_REFERENCE!>aaa<!>() // should be ok
|
||||
x.aaa() // should be ok
|
||||
x.<!UNRESOLVED_REFERENCE!>bbb<!>() // should be error
|
||||
x.<!UNRESOLVED_REFERENCE!>ccc<!>() // should be error
|
||||
}
|
||||
x.<!UNRESOLVED_REFERENCE!>aaa<!>() // should be ok
|
||||
x.aaa() // should be ok
|
||||
x.<!UNRESOLVED_REFERENCE!>bbb<!>() // should be error
|
||||
x.<!UNRESOLVED_REFERENCE!>ccc<!>() // should be ok
|
||||
x.ccc() // should be ok
|
||||
}
|
||||
|
||||
fun breakInCatch() {
|
||||
@@ -86,11 +86,11 @@ fun breakInCatch() {
|
||||
x.<!UNRESOLVED_REFERENCE!>aaa<!>() // should be error
|
||||
x.<!UNRESOLVED_REFERENCE!>bbb<!>() // should be error
|
||||
}
|
||||
x.<!UNRESOLVED_REFERENCE!>aaa<!>() // should be ok
|
||||
x.aaa() // should be ok
|
||||
x.<!UNRESOLVED_REFERENCE!>bbb<!>() // should be error
|
||||
}
|
||||
x.<!UNRESOLVED_REFERENCE!>aaa<!>() // should be error
|
||||
x.<!UNRESOLVED_REFERENCE!>bbb<!>() // should be ok
|
||||
x.bbb() // should be ok
|
||||
}
|
||||
|
||||
fun returnInFinally_insideTry_nonLocal() {
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ fun castInTry(s: Any) {
|
||||
} finally {
|
||||
s.<!UNRESOLVED_REFERENCE!>length<!> // Shouldn't be resolved
|
||||
}
|
||||
s.<!UNRESOLVED_REFERENCE!>length<!> // Shouldn't be resolved
|
||||
s.length // Should be smartcast
|
||||
}
|
||||
|
||||
fun castInTryAndFinally(s: Any) {
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ fun castInTry(s: Any) {
|
||||
} finally {
|
||||
s.<!UNRESOLVED_REFERENCE!>length<!> // Shouldn't be resolved
|
||||
}
|
||||
s.<!UNRESOLVED_REFERENCE!>length<!> // Shouldn't be resolved
|
||||
s.<!UNRESOLVED_REFERENCE!>length<!> // Should be smartcast
|
||||
}
|
||||
|
||||
fun castInTryAndFinally(s: Any) {
|
||||
|
||||
@@ -72,7 +72,7 @@ fun conditionalThrowInTry_rethrow_smartcastAfterTryCatchFinally(a: A) {
|
||||
} catch (e: Throwable) {
|
||||
throw e
|
||||
} finally {}
|
||||
takeB(<!ARGUMENT_TYPE_MISMATCH!>a<!>)
|
||||
takeB(a)
|
||||
}
|
||||
|
||||
fun conditionalThrowInTry_rethrow_noSmartcastInFinally(a: A) {
|
||||
|
||||
Reference in New Issue
Block a user