Fix check_expr_if to point to a more accurate location of the compilation error in some cases#147484
Fix check_expr_if to point to a more accurate location of the compilation error in some cases#147484sgasho wants to merge 3 commits intorust-lang:mainfrom
Conversation
This comment was marked as outdated.
This comment was marked as outdated.
This comment has been minimized.
This comment has been minimized.
This comment was marked as outdated.
This comment was marked as outdated.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
f309ba8 to
98bc078
Compare
This comment has been minimized.
This comment has been minimized.
98bc078 to
c50157b
Compare
This comment has been minimized.
This comment has been minimized.
c50157b to
b522404
Compare
ebfaecc to
5c38b51
Compare
There was a problem hiding this comment.
Was "if and else (have incompatible types) " appropriate for this case?
I think this else if branch has expression of type ! and it is compatible for any type. (source: "Expressions of type ! can be coerced into any other type." at https://doc.rust-lang.org/reference/types/never.html ).
I could be wrong but my understanding is showing "if may be missing an else clause" for this case (all if-else-if have compatible types and the only problem is missing else branch, which would be evaluated to ())
There was a problem hiding this comment.
So,
Hmm, well, I wouldn't expect the incompatible types error. But I also wouldn't expect to see an expected .. found ... here.
I guess, the found () is possibly the type of the entire if/else if expression.
There was a problem hiding this comment.
The expected … found … label in this case isn’t new with this PR. I saw that current nightly already emits expected integer, found () for error[E0317]: if may be missing an else clause. e.g. tests/ui/expr/if/issue-4201.rs
Should this be discussed or fixed in another issue?
|
r? @SparrowLii rustbot has assigned @SparrowLii. Use |
This comment has been minimized.
This comment has been minimized.
|
r? types |
|
Sorry for the delay here. Before I do an actual review here, I want to check perf. @bors2 try @rust-timer build |
| if let hir::ExprKind::Block(block, _) = &expr.kind | ||
| && block.expr.is_none() | ||
| { | ||
| return None; | ||
| } | ||
|
|
There was a problem hiding this comment.
Why did you add this? Is there a test difference that you can comment and link to?
| &self, | ||
| expr_id: HirId, | ||
| sp: Span, | ||
| parts: &IfExprParts<'tcx>, |
There was a problem hiding this comment.
here, and elsewhere in the file, these are Copy and so shouldn't be passed by ref
| parts: &IfExprParts<'tcx>, | ||
| orig_expected: Expectation<'tcx>, | ||
| ) -> Ty<'tcx> { | ||
| let root_if_expr = self.tcx.hir_expect_expr(expr_id); |
There was a problem hiding this comment.
Could pass this in instead of expr_id and sp
| .get(idx + 1) | ||
| .map(|next| next.expr_with_parts.expr) | ||
| .or(chain.last_expr().into()); |
There was a problem hiding this comment.
Hmm, this doesn't seem right (or at least, is too subtle for my liking): when idx is len-1, chain.last_expr() is called and there is no final else, uses the current expr (since it is the last one).
| self.misc(branch_body.span) | ||
| }; | ||
| let cause_span = | ||
| if idx == 0 { Some(root_if_expr.span) } else { Some(branch_body.span) }; |
There was a problem hiding this comment.
If idx == 0, isn't branch_body.span == root_if_expr.span?
| .typeck_results | ||
| .as_ref() | ||
| .expect("if expression only expected inside FnCtxt") | ||
| .expr_ty(else_expr); | ||
| if let hir::ExprKind::If(_cond, _then, None) = else_expr.kind | ||
| .expr_ty_opt(else_expr); |
There was a problem hiding this comment.
Hmm, so...is this ever going to return Some?
|
@rustbot author |
|
Reminder, once the PR becomes ready for a review, use |
|
Ping @sgasho. Are you still working on this? |
|
No worries - this can wait. (If anyone else wants to pick this up, let me know.) |
fdd59f6 to
71919dc
Compare
This comment has been minimized.
This comment has been minimized.
71919dc to
da8de8f
Compare
This reverts commit ac49139.
da8de8f to
dddffd2
Compare
|
This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
This comment has been minimized.
This comment has been minimized.
dddffd2 to
1f3fe1e
Compare
This comment has been minimized.
This comment has been minimized.
1f3fe1e to
57eeb19
Compare
This comment has been minimized.
This comment has been minimized.
…t from depth first approach
57eeb19 to
7d6060c
Compare
|
@rustbot ready |


View all comments
closes #146190
The problem linked on the issue above lays on how Expr::If is processed.
Currently, Expr::If is processed by depth-first like approach, which is natural considering that Expr::If is a nested structure.
e.g.
Simplified Expr::If structure for this code is like below.
Current check_expr_if processes this Expr::If by depth-first-search like approach, that is why "
ifandelsehave incompatible types" occurs between else if let Some(a) = oa2 and else, not between if let Some(a) = oa and if let Some(a) = oa2.New approach on this PR is first flatten the Expr::If nested nodes, then process forward.
I created _if.rs and moved the check_expr_if becase this new approach requires a bit more lines of codes.
I added a test case that guarantees the problem on the linked issue has been resolved.
tests/ui/expr/if/if-multi-else-if-incompatible-types-issue-146190.rs
Discussion on Zulip: https://rust-lang.zulipchat.com/#narrow/channel/182449-t-compiler.2Fhelp/topic/Struggling.20to.20fix.20issue.20.23146190.20check_expr_if/with/540960074