diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 1493abbde765..703499a1270e 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -92,8 +92,8 @@ impl<'a, 'tcx> Deref for Coerce<'a, 'tcx> { type CoerceResult<'tcx> = InferResult<'tcx, (Vec>, Ty<'tcx>)>; -pub struct CollectRetsVisitor<'tcx> { - pub ret_exprs: Vec<&'tcx hir::Expr<'tcx>>, +struct CollectRetsVisitor<'tcx> { + ret_exprs: Vec<&'tcx hir::Expr<'tcx>>, } impl<'tcx> Visitor<'tcx> for CollectRetsVisitor<'tcx> { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index afe5d0d48802..7892c1598d3f 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1040,22 +1040,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } - let in_closure = matches!( - self.tcx - .hir() - .parent_iter(id) - .filter(|(_, node)| { - matches!( - node, - Node::Expr(Expr { kind: ExprKind::Closure(..), .. }) - | Node::Item(_) - | Node::TraitItem(_) - | Node::ImplItem(_) - ) - }) - .next(), - Some((_, Node::Expr(Expr { kind: ExprKind::Closure(..), .. }))) - ); + let scope = self + .tcx + .hir() + .parent_iter(id) + .filter(|(_, node)| { + matches!( + node, + Node::Expr(Expr { kind: ExprKind::Closure(..), .. }) + | Node::Item(_) + | Node::TraitItem(_) + | Node::ImplItem(_) + ) + }) + .next(); + let in_closure = + matches!(scope, Some((_, Node::Expr(Expr { kind: ExprKind::Closure(..), .. })))); let can_return = match fn_decl.output { hir::FnRetTy::Return(ty) => { @@ -1083,20 +1083,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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 + if let Some((_, Node::Expr(expr))) = scope + && let ExprKind::Closure(closure) = expr.kind + && let Some(node) = self.tcx.hir().find(closure.body.hir_id) + && let Node::Expr(expr) = node { 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); - } + rets.push(self.check_expr(expr)); } 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.push(self.check_expr(expr)); } } rets.into_iter().all(|ty| self.can_coerce(found, ty)) diff --git a/tests/ui/async-await/missing-return-in-async-block-mismatched-types.rs b/tests/ui/async-await/missing-return-in-async-block-mismatched-types.rs new file mode 100644 index 000000000000..9d657be4529d --- /dev/null +++ b/tests/ui/async-await/missing-return-in-async-block-mismatched-types.rs @@ -0,0 +1,19 @@ +// edition:2021 +use std::future::Future; +use std::pin::Pin; +pub struct S; +pub fn baz() -> Pin> + 'static>> { + Box::pin(async move { + if true { + Some(S) //~ ERROR mismatched types + // Do *not* suggest returning this value, because it doesn't unify with the others. + } + if false { + return Err(()); + } + Err(()) //~ WARN unreachable + // The warning above is *incorrect* and a consequence of using `check_expr` incorrectly + // during error recovery. + }) +} +fn main() {} diff --git a/tests/ui/async-await/missing-return-in-async-block-mismatched-types.stderr b/tests/ui/async-await/missing-return-in-async-block-mismatched-types.stderr new file mode 100644 index 000000000000..c74dceab7482 --- /dev/null +++ b/tests/ui/async-await/missing-return-in-async-block-mismatched-types.stderr @@ -0,0 +1,21 @@ +error[E0308]: mismatched types + --> $DIR/missing-return-in-async-block-mismatched-types.rs:8:13 + | +LL | / if true { +LL | | Some(S) + | | ^^^^^^^ expected `()`, found `Option` +LL | | // Do *not* suggest returning this value, because it doesn't unify with the others. +LL | | } + | |_________- expected this to be `()` + | + = note: expected unit type `()` + found enum `Option` +note: return type inferred to be `()` here + --> $DIR/missing-return-in-async-block-mismatched-types.rs:12:20 + | +LL | return Err(()); + | ^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`.