-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Properly handle async
block and async fn
in if
exprs without else
#120696
Conversation
r? @oli-obk (rustbot has picked a reviewer for you, use r? to override) |
e753c31
to
6add192
Compare
let ret_ty = ret_coercion.borrow().expected_ty(); | ||
rets.push(ret_ty); | ||
} | ||
let mut visitor = CollectRetsVisitor { ret_exprs: vec![] }; |
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.
Why do you need to do this? If the ret_coercion
has a type, then it will have already been coerced with all of these ret_exprs
collected below.
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.
Like, the whole point of ret_coercion
is to be the type that all of the return
expressions in the body are coerced into
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.
ret_coercion
is (always?) an inference type. I could likely just remove that first type push entirely and the logic wouldn't change.
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.
It's not always an inference type. It may appear to be an inference type if you print it without calling resolve_vars_if_possible
on it (which you don't need to do here), but it gets equated with another type as soon as the first return
statement is type checked, and can_coerce
will handle it properly below.
Applying this diff makes no changes to the UI tests:
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index afe5d0d4880..0a03429b37f 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -1,6 +1,5 @@
use super::FnCtxt;
-use crate::coercion::CollectRetsVisitor;
use crate::errors;
use crate::fluent_generated as fluent;
use crate::fn_ctxt::rustc_span::BytePos;
@@ -17,7 +16,6 @@
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::def::{CtorKind, CtorOf, DefKind};
-use rustc_hir::intravisit::{Map, Visitor};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{
CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, GenericBound, HirId, Node,
@@ -1082,23 +1080,6 @@ pub(in super::super) fn suggest_missing_break_or_return_expr(
let ret_ty = ret_coercion.borrow().expected_ty();
rets.push(ret_ty);
}
- let mut visitor = CollectRetsVisitor { ret_exprs: vec![] };
- if let Some(item) = self.tcx.hir().find(id)
- && let Node::Expr(expr) = item
- {
- visitor.visit_expr(expr);
- for expr in visitor.ret_exprs {
- if let Some(ty) = self.typeck_results.borrow().node_type_opt(expr.hir_id) {
- rets.push(ty);
- }
- }
- if let hir::ExprKind::Block(hir::Block { expr: Some(expr), .. }, _) = expr.kind
- {
- if let Some(ty) = self.typeck_results.borrow().node_type_opt(expr.hir_id) {
- rets.push(ty);
- }
- }
- }
rets.into_iter().all(|ty| self.can_coerce(found, ty))
}
_ => false,
Unless I am mistaken, pls remove the CollectRetsVisitor
usage (and the changes to it).
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.
For the record, that diff is to just demonstrate that it works without the usage of CollectRetsVisitor
. The code should be simplified into a single can_coerce
call.
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.
Actually, I think none of your tests aren't actually exercising this behavior of a previous return statement having constrained the ret_coercion
?
Anyways, you should also be using .merged_ty()
from the ret_coercion
instead of .expected_ty()
, but you still shouldn't need to look at any of the node_ty
s of the return expressions. You should write a test that exercises that the lint will not be made if the type is incompatible with other returns.
edit: actually, it's not that big of a deal which of merged-ty or expected-ty you use.
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 wanted to avoid an incorrect suggestion in the face of
pub fn baz() -> Pin<Box<dyn Future<Output = Result<S, ()>> + 'static>> {
Box::pin(async move {
if true {
Some(S) //~ ERROR mismatched types
}
Err(())
})
}
Now, looking into it, not only the logic is now wrong (after doing some changes cleaning up for publication), but the type for the returning expressions isn't actually available. For some reason, I had gotten a value for them, but now with the code as is now. Given that, yes, the entire visitor thing is useless and can be removed. I was hoping to avoid nonsensical suggestions like the one above, but oh well.
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.
Keeping around a single can_coerce call for the ret_coercion.expected_ty()
should avoid such a nonsensical suggestion, at least according to local testing.
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 think I know why I had something that seemed to be working earlier. I tried using check_expr
at some point, which "worked", but trying it again now it does cause multiple issues that make it more of a pain in the neck than we want to deal with.
@@ -92,14 +92,16 @@ impl<'a, 'tcx> Deref for Coerce<'a, 'tcx> { | |||
|
|||
type CoerceResult<'tcx> = InferResult<'tcx, (Vec<Adjustment<'tcx>>, Ty<'tcx>)>; | |||
|
|||
struct CollectRetsVisitor<'tcx> { | |||
ret_exprs: Vec<&'tcx hir::Expr<'tcx>>, | |||
pub struct CollectRetsVisitor<'tcx> { |
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.
this isn't needed
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.
Done.
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, shit, had in flight changes... let me clean up the mess first.
bd40a05
to
6413e9b
Compare
This comment has been minimized.
This comment has been minimized.
6413e9b
to
ddd2a73
Compare
☔ The latest upstream changes (presumably #120767) made this pull request unmergeable. Please resolve the merge conflicts. |
ddd2a73
to
d1f8f7f
Compare
This comment has been minimized.
This comment has been minimized.
d1f8f7f
to
9ca9e1d
Compare
@bor@ r+ |
☔ The latest upstream changes (presumably #120951) made this pull request unmergeable. Please resolve the merge conflicts. |
When encountering a tail expression in the then arm of an `if` expression without an `else` arm, account for `async fn` and `async` blocks to suggest `return`ing the value and pointing at the return type of the `async fn`. We now also account for AFIT when looking for the return type to point at. Fix rust-lang#115405.
9ca9e1d
to
d07195f
Compare
@bors r=oli-obk |
…iaskrgr Rollup of 10 pull requests Successful merges: - rust-lang#120696 (Properly handle `async` block and `async fn` in `if` exprs without `else`) - rust-lang#120751 (Provide more suggestions on invalid equality where bounds) - rust-lang#120802 (Bail out of drop elaboration when encountering error types) - rust-lang#120967 (docs: mention round-to-even in precision formatting) - rust-lang#120973 (allow static_mut_ref in some tests that specifically test mutable statics) - rust-lang#120974 (llvm-wrapper: adapt for LLVM API change: Add support for EXPORTAS name types) - rust-lang#120986 (iterator.rs: remove "Basic usage" text) - rust-lang#120987 (remove redundant logic) - rust-lang#120988 (fix comment) - rust-lang#120995 (PassWrapper: adapt for llvm/llvm-project@93cdd1b5cfa3735c) r? `@ghost` `@rustbot` modify labels: rollup
Rollup merge of rust-lang#120696 - estebank:issue-115405, r=oli-obk Properly handle `async` block and `async fn` in `if` exprs without `else` When encountering a tail expression in the then arm of an `if` expression without an `else` arm, account for `async fn` and `async` blocks to suggest `return`ing the value and pointing at the return type of the `async fn`. We now also account for AFIT when looking for the return type to point at. Fix rust-lang#115405.
When encountering a tail expression in the then arm of an
if
expression without anelse
arm, account forasync fn
andasync
blocks to suggestreturn
ing the value and pointing at the return type of theasync fn
.We now also account for AFIT when looking for the return type to point at.
Fix #115405.