-
-
Notifications
You must be signed in to change notification settings - Fork 415
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
Error on unreachable cases in match expressions and illegal as expressions. #2289
Conversation
Before this gets merged, can you write up release notes for this and add to this PR as a comment. What I'm looking for is an explanation of invalid code that folks might have in the wild and how they fix it. Also an explanation of why this breaking change is required, and what "eek!" it fixes. Thanks. |
499f9af
to
6a9d3f9
Compare
this checks for exhaustive matches that have an else clause, which is unreachable, this also checks for cases that are unreachable because previous cases are already exhaustive, this also affects the 'as' clause as it is rewritten to a match internally: this checks for 'as' clauses that try to cast to the same type or a subtype which would result in an exhaustive match internally and can be considered illegal use of 'as'.
6a9d3f9
to
2dfe4fd
Compare
Possible Release Notes Entry: This change is adding some sanity checks to usages of Match ExpressionsIt validates that there is no unreachable code left in your match expressions. This was a subtle source of bugs and left dead code linger in your codebase. Unreachable cases or Example: class Foo
fun ex_match(a: (String| Bool)): String =>
match a
| let a: Stringable => a.string()
| let b: Bool => if b then "true" else "false" end // unreachable already
else
"unreachable"
end The second branch and the else clause are both unreachable and thus can (and should) be safely removed. In some cases it might instead make sense to rewrite the As ExpressionsIt also validates correct use of Example: class Foo
fun subtype_cast(a: String): Stringable ? =>
a as Stringable // useless as, is actually not partial
fun eq_cast(a: Array[String]) =>
let tmp = a as Array[String] // no as needed
... This error can easily be fixed by removing the |
This finally fixes #2253 |
src/libponyc/expr/operator.c
Outdated
@@ -549,6 +549,23 @@ bool expr_as(pass_opt_t* opt, ast_t** astp) | |||
return false; | |||
} | |||
|
|||
if(is_eqtype(expr_type, type, NULL, opt)) |
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.
Note that the definition of is_eqtype
is equivalent to an is_subtype
call in each direction:
bool is_eqtype(ast_t* a, ast_t* b, errorframe_t* errorf, pass_opt_t* opt)
{
return is_subtype(a, b, errorf, opt) && is_subtype(b, a, errorf, opt);
}
Therefore, this strategy of testing is_eqtype
, then testing is_subtype
is kind of wasteful - because we are doing three is_subtype
checks every time, even in the "happy path". I've found that excess is_subtype
calls can sometimes be very costly to compilation time and memory.
I'd suggest an approach of testing is_subtype
first, then if that is true, continuing on to test is_subtype
in the other direction to determine the appropriate error message. This approach would only have one is_subtype
check in the "happy path", and two is_subtype
checks in the error path.
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.
thank you!
this checks for exhaustive matches that have an else clause, which is unreachable,
this also checks for cases that are unreachable because previous cases are already exhaustive,
this also affects the 'as' clause as it is rewritten to a match internally:
this checks for 'as' clauses that try to cast to the same type or a subtype
which would result in an exhaustive match internally and can be considered illegal use of 'as'.
This is a breaking change, but for good. If it affects any pony codebase, then it had a possible source of bugs.
The following examples will be invalid with this PR: