-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[Sema] SR-2327: Improve error message when using 'break' inside 'guar… #4286
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
Conversation
Very cool! @swift-ci please smoke test OS X platform. |
@@ -767,7 +767,8 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> { | |||
// statement, produce a more specific error. | |||
if (S->getTargetName().empty() && !ActiveLabeledStmts.empty() && | |||
(isa<IfStmt>(ActiveLabeledStmts.back()) || | |||
isa<DoStmt>(ActiveLabeledStmts.back()))) | |||
isa<DoStmt>(ActiveLabeledStmts.back()) || | |||
isa<GuardStmt>(ActiveLabeledStmts.back()))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this work for this?
func fn(a: Int) {
guard a < 1 else {
break
}
}
In this case, IMO, the message should be normal 'break' is only allowed inside a loop, if, do, or switch
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we put if
, do
, in single quotes, just like break
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rintaro I've updated the code to handle the case and added your example into the test cases.
@tkremenek I prefer to submit another pull request to change the format of diagnosis message. I am also in favor of quoting if
and do
, but touching the message in this commit would make some noises on the logic change behind this commit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One suggestion: either in this commit or in the follow-up, probably best to change the 'guard' body may not fall through, consider using 'return' or 'break' ...to... 'guard' body may not fall through, consider using 'return' or labeled 'break' |
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for nit-picking. This doesn't work for
func fn(x: Int) {
if x >= 0 {
guard x < 1 else {
guard x < 2 else {
break
}
return
}
}
}
The rule here is: If ActiveLabeledStmts
contains if
or do
, we can use unlabeled_break_outside_loop
.
I think, something like
if (S->getTargetName().empty() &&
std::any_of(ActiveLabeledStmts.rbegin(), ActiveLabeledStmts.rend(),
[&](Stmt *S) -> bool { return isa<IfStmt>(S) || isa<DoStmt>(S); }))
should work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are absolutely right, I would change accordingly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've made the change and updated the test cases. :-)
diagid = diag::unlabeled_break_outside_loop; | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant, this whole if
block can be replaced with:
if (S->getTargetName().empty() &&
std::any_of(ActiveLabeledStmts.rbegin(), ActiveLabeledStmts.rend(),
[&](Stmt *S) -> bool { return isa<IfStmt>(S) || isa<DoStmt>(S); }))
diagid = diag::unlabeled_break_outside_loop;
I think we don't need to care about guard
statement here.
Am I missing something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh! duh, (to myself) what were you thinking. Thanks for pointing out. I've stolen your snippet and copied-pasted and pushed. :)
The intent of "return or break" is to break out of a loop being guarded, not to exit the |
@jrose-apple I don't understand the point. What do you mean?
|
Sorry, yes, you can. But to have the error message suggest a labeled break (per @xwu) might imply that you can't use it with unlabeled break, which of course you can if there's a loop: for person in friends {
guard person.name != "Jordan" else { break }
} |
(D'oh!) |
Ah, make sense. You are replying to @xwu's comment 😄 |
isa<DoStmt>(ActiveLabeledStmts.back()))) | ||
if (S->getTargetName().empty() && | ||
std::any_of(ActiveLabeledStmts.rbegin(), ActiveLabeledStmts.rend(), | ||
[&](Stmt *S) -> bool { return isa<IfStmt>(S) || isa<DoStmt>(S); })) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: swiftc style limits lines to 80 columns. Can you reflow this, or use a helper variable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I've inserted a few new lines in between.
…d' inside 'do' or 'if'
@swift-ci Please test |
Test passed. |
Force-merging. Thanks, Paul! |
@MnO2 please create a pull request for |
I cherry-picked the change and created pull-request against |
What's in this pull request?
Improve the error message what SR-2327 has described.
With
prompt the more helpful error message of
error: unlabeled 'break' is only allowed inside a loop or switch, a labeled break is required to exit an if or do
Resolved bug number: (SR-2327)
Before merging this pull request to apple/swift repository:
Triggering Swift CI
The swift-ci is triggered by writing a comment on this PR addressed to the GitHub user @swift-ci. Different tests will run depending on the specific comment that you use. The currently available comments are:
Smoke Testing
A smoke test on macOS does the following:
device standard libraries are not built.
version of these tests are not run.
A smoke test on Linux does the following:
tests are not run.
Validation Testing
Lint Testing
Note: Only members of the Apple organization can trigger swift-ci.
…d' inside 'do' or 'if'