-
Notifications
You must be signed in to change notification settings - Fork 213
Flow analysis of try/catch/finally seems to use a conservative join too broadly #4327
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Unfortunately, it looks like what's documented in the spec for try/catch also fails to match the implementation. Here's what's currently implemented for try/catch.
(The primary difference is the presence of The way the implementation currently handles try/catch/finally is to desugar them into a try/catch nested inside a try/finally. So if we fuse together the adjusted rules for try/catch and try/finally, the effect is:
Contrasting that with your proposal:
Here are the differences I see:
Can you say more about your thoughts here? I'm having trouble coming up with an example where there is an observable difference. But that could just be a failure of imagination on my part!
Depends what you mean by "compatible" I guess. It's different from the existing implementation, that's for sure. But like I said, I'm having trouble coming up with an example where there is an observable difference. Taking a step back, one of the mistakes I feel like I've made in my past efforts to write a formal spec for flow analysis was that I didn't do a great job in separating the tasks of:
And I think the result of my not doing a good job of separating those tasks is that we got into this messy situation we're in today, where the flow analysis spec doesn't match the behavior of any version of Dart we've had in the past, nor does it match the behavior of any version of Dart we expect to have in the future. It's a mishmash of speculations (sometimes correct, sometimes not) about how people thought flow analysis behaved at some point in the past, along with ideas about how flow analysis ought to behave (some of which have been implemented, some of which haven't). Which makes the whole spec really difficult to reason about. For this specific question of how we handle try/catch/finally, I would like to start by updating the spec to match what the implementation currently does. We could do that pretty simply, e.g.:
Once we've updated the spec to match the implementation, I'm open to considering an improvement to try/catch/finally handling, but to be honest, even if we can find some code where there's an observable difference, I suspect it'll probably be tough to convince me that the improvement is worth the implementation effort. The existing desugaring approach has the advantage of being really simple implementation-wise, and I think it does a pretty good job. Footnotes
|
The flow analysis feature specification specifies the treatment of a try/catch statement and the treatment of a try/finally statement, but the try/catch/finally statement hasn't been specified yet (I don't think it will work to read any of the two existing rules as a rule that also covers try/catch/finally).
We have an adjusted rule for the try/finally statement:
The
attachFinally
function is complex, but it basically compares thebefore
andafter
ofB2
(the finally block) and treats that as a flow model increment which is applied to each of the predecessors in the control flow graph, no matter how they're completing.This would need to be generalized somewhat in order to handle the case where we have both
try
,catch
, andfinally
.The try/catch case is handled as follows:
This seems to imply that the conservative join would be used with the
try
block in order to take into account that this part may have many different control flow edges out of the block and into any of thecatch
clauses. However, each catch block is subject to normal flow analysis (there is no need for a conservative join here).We might then be able to use something along these lines:
N
is a try/catch/finally statement of the formtry B1 alternatives finally F
then:before(B1) = before(N)
before(Si) = join(after(B1), conservativeJoin(before(N), assignedIn(B1), capturedIn(B1)))
, whereSi
is the body of the i'th alternativeafter(N) = join(attachFinally(after(B1), before(F), after(F)), M1 .. Mk)
whereMj = attachFinally(after(Sj), before(F), after(F))
@stereotype441, WDYT? It seems likely to me that using
attachFinally
first and thenjoin
would yield a more precise analysis than the opposite ordering. Is this compatible with the existing implementation?The text was updated successfully, but these errors were encountered: