-
Notifications
You must be signed in to change notification settings - Fork 14k
Fix check_expr_if to point to a more accurate location of the compilation error in some cases #147484
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
base: master
Are you sure you want to change the base?
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
5212a66 to
ebfaecc
Compare
…ation error in some cases
ebfaecc to
5c38b51
Compare
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
|
r? @SparrowLii rustbot has assigned @SparrowLii. Use |
|
|
r? types |
|
Sorry for the delay here. Before I do an actual review here, I want to check perf. @bors2 try @rust-timer build |
|
Cannot parse build command: Missing SHA in build command |
This comment has been minimized.
This comment has been minimized.
Fix check_expr_if to point to a more accurate location of the compilation error in some cases
|
@rust-timer build 9877dbd |
This comment has been minimized.
This comment has been minimized.
|
Finished benchmarking commit (9877dbd): comparison URL. Overall result: ✅ improvements - no action neededBenchmarking this pull request means it may be perf-sensitive – we'll automatically label it not fit for rolling up. You can override this, but we strongly advise not to, due to possible changes in compiler perf. @bors rollup=never Instruction countOur most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.
Max RSS (memory usage)Results (primary 0.0%, secondary -2.1%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesResults (secondary 1.7%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeResults (primary 0.0%, secondary 0.1%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Bootstrap: 474.307s -> 475.954s (0.35%) |
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.
Perf looks good, so that's good to see.
Haven't yet reviewed the meat of this, but some comments. If you want to try to address them, that's great. If you want to wait until I review the meat of this, that's okay too.
I'll try to get back to this later today or this weekend, but want to share what I have.
| .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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. This went from non-opt to opt. Is this actually ever going to be none? I guess, I would expect so, but surprised the previous never bug!ed.
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, this isn't right :)
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.
Same
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, another round of review. These changes I am going to pause for you to address before I get back to this.
compiler/rustc_hir_typeck/src/_if.rs
Outdated
| fn set_diverges( | ||
| &self, | ||
| initial_diverges: Diverges, | ||
| guarded: &IfGuardedBranches<'tcx>, | ||
| tail: &IfChainTail<'tcx>, | ||
| ) { | ||
| let mut tail_diverges = tail.diverges(); | ||
| for branch in guarded.branches.iter().rev() { | ||
| tail_diverges = branch.cond_diverges | (branch.body.diverges & tail_diverges); | ||
| } | ||
| self.diverges.set(initial_diverges | tail_diverges); | ||
| } | ||
| } |
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'm actually not a fan of splitting this (along with reset_diverges_to_maybe and take_diverges) into separate functions.
I guess, the more I look over this, I also am not a huge fan of explain_if_branch_mismatch either.
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.
removed those methods in this commit!
refactor: remove set_diverges, reset_diverges_to_maybe, take_diverges…
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 will check other comments tomorrow 🙇
| sp: Span, | ||
| orig_expected: Expectation<'tcx>, | ||
| ) -> Ty<'tcx> { | ||
| let root_if_expr = self.tcx.hir_expect_expr(expr_id); |
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 don't particularly like the change to not take in the fields of ExprKind::If - and I think that these fields should be passed through too (to avoid the bug! path in collect_if_branch.
Instead of passing the fields separately, could just make a new struct in this module to keep things clean.
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 made a struct to avoid the bug! in collect_if_branch
compiler/rustc_hir_typeck/src/_if.rs
Outdated
| let Some(else_expr) = self.collect_if_branch(current_if, expected, &mut chain) else { | ||
| return (chain, IfChainTail::Missing(current_if)); | ||
| }; | ||
|
|
||
| if let hir::ExprKind::If(..) = else_expr.kind { | ||
| current_if = else_expr; | ||
| continue; | ||
| } |
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.
Something seems weird to me...what is there both an optional return in collect_if_branch and a check for ExprKind::If for the kind?
I guess, perhaps, I could see some duplicate logic here - you should be able to maintain all the state in chain, I think.
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.
removed duplicate logics and added some extra refactorings(sorry it if is hard to check diffs....)
refactor: remove duplicate logic for checking Expr content. and some …
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