fix or disallow 'break' and 'continue' in 'finally'
break (and likely continue) in finally can create confusing definite initialization scenarios that aren't properly handled by the type checker.
It may make sense to disallow them (and return too, for good measure?)
Here's an example where break is used to "skip past" a return statement, which confuses the type checker:
shared void run() {
String s;
while (true) {
try {
if (1==2) {
s = "hello";
break; // if the type checker were smarter, we could comment out this line
} else {
return;
}
} finally {
break; // skips over the "return" in "else" above
}
}
print(s); // prints "<null>"! (or on the JVM, a backend error)
}
By the way, I haven't tried it, but I remember someone saying that C# disallows this.
Yeah, I think they made the right decision with C#. These things are too confusing to possibly be useful.
This one (not involving finally) also compiles:
shared void run() {
String s;
while (true) {
try {
throw;
} catch (e) {
break;
}
}
print(s);
}
@jvasileff so I've done two things:
- I've fixed the definite assignment checking for the scenario of
breakinfinally, so at least the two cases you provided are correctly detected as errors by the typechecker. - I've added warnings for any sort of control directive within a
finallyblock. This seems reasonable to me:finallyblocks definitely aren't for doingbreak/return/continue. However, I'm not certain aboutthrow. I've certainly seen peoplethrowfromfinally, and, though I don't like it, perhaps you need to sometimes?
WDYT? Is this a good solution?
I believe throw should always be allowed without warning (and, it’s unrelated to the initialization issue, and exceptions can occur in any code anyway), but otherwise that sounds reasonable to me.