Auto merge of #57761 - Centril:rollup, r=Centril

Rollup of 4 pull requests

Successful merges:

 - #57452 (Improve docs for Formatter)
 - #57689 (Redo `hir::Stmt`)
 - #57723 (Point at cause for expectation in return type type error)
 - #57736 (Remove delay_span_bug from qualify_min_const_fn)

Failed merges:

r? @ghost
diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs
index 214b5d3..5221d6f 100644
--- a/src/libcore/fmt/mod.rs
+++ b/src/libcore/fmt/mod.rs
@@ -211,9 +211,18 @@
     }
 }
 
-/// A struct to represent both where to emit formatting strings to and how they
-/// should be formatted. A mutable version of this is passed to all formatting
-/// traits.
+/// Configuration for formatting.
+///
+/// A `Formatter` represents various options related to formatting. Users do not
+/// construct `Formatter`s directly; a mutable reference to one is passed to
+/// the `fmt` method of all formatting traits, like [`Debug`] and [`Display`].
+///
+/// To interact with a `Formatter`, you'll call various methods to change the
+/// various options related to formatting. For examples, please see the
+/// documentation of the methods defined on `Formatter` below.
+///
+/// [`Debug`]: trait.Debug.html
+/// [`Display`]: trait.Display.html
 #[allow(missing_debug_implementations)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Formatter<'a> {
diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs
index 978d20e..6122fe6 100644
--- a/src/librustc/cfg/construct.rs
+++ b/src/librustc/cfg/construct.rs
@@ -99,30 +99,21 @@
     }
 
     fn stmt(&mut self, stmt: &hir::Stmt, pred: CFGIndex) -> CFGIndex {
-        let hir_id = self.tcx.hir().node_to_hir_id(stmt.node.id());
-        match stmt.node {
-            hir::StmtKind::Decl(ref decl, _) => {
-                let exit = self.decl(&decl, pred);
-                self.add_ast_node(hir_id.local_id, &[exit])
-            }
-
-            hir::StmtKind::Expr(ref expr, _) |
-            hir::StmtKind::Semi(ref expr, _) => {
-                let exit = self.expr(&expr, pred);
-                self.add_ast_node(hir_id.local_id, &[exit])
-            }
-        }
-    }
-
-    fn decl(&mut self, decl: &hir::Decl, pred: CFGIndex) -> CFGIndex {
-        match decl.node {
-            hir::DeclKind::Local(ref local) => {
+        let hir_id = self.tcx.hir().node_to_hir_id(stmt.id);
+        let exit = match stmt.node {
+            hir::StmtKind::Local(ref local) => {
                 let init_exit = self.opt_expr(&local.init, pred);
                 self.pat(&local.pat, init_exit)
             }
-
-            hir::DeclKind::Item(_) => pred,
-        }
+            hir::StmtKind::Item(_) => {
+                pred
+            }
+            hir::StmtKind::Expr(ref expr) |
+            hir::StmtKind::Semi(ref expr) => {
+                self.expr(&expr, pred)
+            }
+        };
+        self.add_ast_node(hir_id.local_id, &[exit])
     }
 
     fn pat(&mut self, pat: &hir::Pat, pred: CFGIndex) -> CFGIndex {
diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs
index b4a0071..df111b2 100644
--- a/src/librustc/hir/check_attr.rs
+++ b/src/librustc/hir/check_attr.rs
@@ -283,8 +283,8 @@
 
     fn check_stmt_attributes(&self, stmt: &hir::Stmt) {
         // When checking statements ignore expressions, they will be checked later
-        if let hir::StmtKind::Decl(_, _) = stmt.node {
-            for attr in stmt.node.attrs() {
+        if let hir::StmtKind::Local(ref l) = stmt.node {
+            for attr in l.attrs.iter() {
                 if attr.check_name("inline") {
                     self.check_inline(attr, &stmt.span, Target::Statement);
                 }
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 041291e..592fb78 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -258,9 +258,6 @@
     fn visit_pat(&mut self, p: &'v Pat) {
         walk_pat(self, p)
     }
-    fn visit_decl(&mut self, d: &'v Decl) {
-        walk_decl(self, d)
-    }
     fn visit_anon_const(&mut self, c: &'v AnonConst) {
         walk_anon_const(self, c)
     }
@@ -951,26 +948,17 @@
 }
 
 pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt) {
+    visitor.visit_id(statement.id);
     match statement.node {
-        StmtKind::Decl(ref declaration, id) => {
-            visitor.visit_id(id);
-            visitor.visit_decl(declaration)
-        }
-        StmtKind::Expr(ref expression, id) |
-        StmtKind::Semi(ref expression, id) => {
-            visitor.visit_id(id);
+        StmtKind::Local(ref local) => visitor.visit_local(local),
+        StmtKind::Item(ref item) => visitor.visit_nested_item(**item),
+        StmtKind::Expr(ref expression) |
+        StmtKind::Semi(ref expression) => {
             visitor.visit_expr(expression)
         }
     }
 }
 
-pub fn walk_decl<'v, V: Visitor<'v>>(visitor: &mut V, declaration: &'v Decl) {
-    match declaration.node {
-        DeclKind::Local(ref local) => visitor.visit_local(local),
-        DeclKind::Item(item) => visitor.visit_nested_item(item),
-    }
-}
-
 pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) {
     visitor.visit_id(constant.id);
     visitor.visit_nested_body(constant.body);
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 8cdc493..2f7d8f0 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -1957,7 +1957,7 @@
         )
     }
 
-    fn lower_local(&mut self, l: &Local) -> (P<hir::Local>, SmallVec<[hir::ItemId; 1]>) {
+    fn lower_local(&mut self, l: &Local) -> (hir::Local, SmallVec<[hir::ItemId; 1]>) {
         let LoweredNodeId { node_id, hir_id } = self.lower_node_id(l.id);
         let mut ids = SmallVec::<[hir::ItemId; 1]>::new();
         if self.sess.features_untracked().impl_trait_in_bindings {
@@ -1967,7 +1967,7 @@
             }
         }
         let parent_def_id = DefId::local(self.current_hir_id_owner.last().unwrap().0);
-        (P(hir::Local {
+        (hir::Local {
             id: node_id,
             hir_id,
             ty: l.ty
@@ -1984,7 +1984,7 @@
             span: l.span,
             attrs: l.attrs.clone(),
             source: hir::LocalSource::Normal,
-        }), ids)
+        }, ids)
     }
 
     fn lower_mutability(&mut self, m: Mutability) -> hir::Mutability {
@@ -4331,10 +4331,11 @@
                         ThinVec::new(),
                     ))
                 };
-                let match_stmt = respan(
-                    head_sp,
-                    hir::StmtKind::Expr(match_expr, self.next_id().node_id)
-                );
+                let match_stmt = hir::Stmt {
+                    id: self.next_id().node_id,
+                    node: hir::StmtKind::Expr(match_expr),
+                    span: head_sp,
+                };
 
                 let next_expr = P(self.expr_ident(head_sp, next_ident, next_pat.id));
 
@@ -4357,10 +4358,11 @@
 
                 let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false));
                 let body_expr = P(self.expr_block(body_block, ThinVec::new()));
-                let body_stmt = respan(
-                    body.span,
-                    hir::StmtKind::Expr(body_expr, self.next_id().node_id)
-                );
+                let body_stmt = hir::Stmt {
+                    id: self.next_id().node_id,
+                    node: hir::StmtKind::Expr(body_expr),
+                    span: body.span,
+                };
 
                 let loop_block = P(self.block_all(
                     e.span,
@@ -4533,25 +4535,15 @@
                 let (l, item_ids) = self.lower_local(l);
                 let mut ids: SmallVec<[hir::Stmt; 1]> = item_ids
                     .into_iter()
-                    .map(|item_id| Spanned {
-                        node: hir::StmtKind::Decl(
-                            P(Spanned {
-                                node: hir::DeclKind::Item(item_id),
-                                span: s.span,
-                            }),
-                            self.next_id().node_id,
-                        ),
+                    .map(|item_id| hir::Stmt {
+                        id: self.next_id().node_id,
+                        node: hir::StmtKind::Item(P(item_id)),
                         span: s.span,
                     })
                     .collect();
-                ids.push(Spanned {
-                    node: hir::StmtKind::Decl(
-                        P(Spanned {
-                            node: hir::DeclKind::Local(l),
-                            span: s.span,
-                        }),
-                        self.lower_node_id(s.id).node_id,
-                    ),
+                ids.push(hir::Stmt {
+                    id: self.lower_node_id(s.id).node_id,
+                    node: hir::StmtKind::Local(P(l)),
                     span: s.span,
                 });
                 return ids;
@@ -4561,26 +4553,23 @@
                 let mut id = Some(s.id);
                 return self.lower_item_id(it)
                     .into_iter()
-                    .map(|item_id| Spanned {
-                        node: hir::StmtKind::Decl(
-                            P(Spanned {
-                                node: hir::DeclKind::Item(item_id),
-                                span: s.span,
-                            }),
-                            id.take()
+                    .map(|item_id| hir::Stmt {
+                        id: id.take()
                               .map(|id| self.lower_node_id(id).node_id)
                               .unwrap_or_else(|| self.next_id().node_id),
-                        ),
+                        node: hir::StmtKind::Item(P(item_id)),
                         span: s.span,
                     })
                     .collect();
             }
-            StmtKind::Expr(ref e) => Spanned {
-                node: hir::StmtKind::Expr(P(self.lower_expr(e)), self.lower_node_id(s.id).node_id),
+            StmtKind::Expr(ref e) => hir::Stmt {
+                id: self.lower_node_id(s.id).node_id,
+                node: hir::StmtKind::Expr(P(self.lower_expr(e))),
                 span: s.span,
             },
-            StmtKind::Semi(ref e) => Spanned {
-                node: hir::StmtKind::Semi(P(self.lower_expr(e)), self.lower_node_id(s.id).node_id),
+            StmtKind::Semi(ref e) => hir::Stmt {
+                id: self.lower_node_id(s.id).node_id,
+                node: hir::StmtKind::Semi(P(self.lower_expr(e))),
                 span: s.span,
             },
             StmtKind::Mac(..) => panic!("Shouldn't exist here"),
@@ -4795,7 +4784,7 @@
     ) -> hir::Stmt {
         let LoweredNodeId { node_id, hir_id } = self.next_id();
 
-        let local = P(hir::Local {
+        let local = hir::Local {
             pat,
             ty: None,
             init: ex,
@@ -4804,9 +4793,12 @@
             span: sp,
             attrs: ThinVec::new(),
             source,
-        });
-        let decl = respan(sp, hir::DeclKind::Local(local));
-        respan(sp, hir::StmtKind::Decl(P(decl), self.next_id().node_id))
+        };
+        hir::Stmt {
+            id: self.next_id().node_id,
+            node: hir::StmtKind::Local(P(local)),
+            span: sp
+        }
     }
 
     fn stmt_let(
diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs
index ae9bb37..7cc5d75 100644
--- a/src/librustc/hir/map/collector.rs
+++ b/src/librustc/hir/map/collector.rs
@@ -426,7 +426,7 @@
     }
 
     fn visit_stmt(&mut self, stmt: &'hir Stmt) {
-        let id = stmt.node.id();
+        let id = stmt.id;
         self.insert(stmt.span, id, Node::Stmt(stmt));
 
         self.with_parent(id, |this| {
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 4fc50bc..65d9d5a 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -17,7 +17,7 @@
 use mir::mono::Linkage;
 
 use syntax_pos::{Span, DUMMY_SP, symbol::InternedString};
-use syntax::source_map::{self, Spanned};
+use syntax::source_map::Spanned;
 use rustc_target::spec::abi::Abi;
 use syntax::ast::{self, CrateSugar, Ident, Name, NodeId, DUMMY_NODE_ID, AsmDialect};
 use syntax::ast::{Attribute, Label, Lit, StrStyle, FloatTy, IntTy, UintTy};
@@ -1134,45 +1134,41 @@
 }
 
 /// A statement
-pub type Stmt = Spanned<StmtKind>;
+#[derive(Clone, RustcEncodable, RustcDecodable)]
+pub struct Stmt {
+    pub id: NodeId,
+    pub node: StmtKind,
+    pub span: Span,
+}
 
-impl fmt::Debug for StmtKind {
+impl fmt::Debug for Stmt {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        // Sadness.
-        let spanned = source_map::dummy_spanned(self.clone());
-        write!(f,
-               "stmt({}: {})",
-               spanned.node.id(),
-               print::to_string(print::NO_ANN, |s| s.print_stmt(&spanned)))
+        write!(f, "stmt({}: {})", self.id,
+               print::to_string(print::NO_ANN, |s| s.print_stmt(self)))
     }
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable)]
 pub enum StmtKind {
-    /// Could be an item or a local (let) binding:
-    Decl(P<Decl>, NodeId),
+    /// A local (let) binding:
+    Local(P<Local>),
+    /// An item binding:
+    Item(P<ItemId>),
 
     /// Expr without trailing semi-colon (must have unit type):
-    Expr(P<Expr>, NodeId),
+    Expr(P<Expr>),
 
     /// Expr with trailing semi-colon (may have any type):
-    Semi(P<Expr>, NodeId),
+    Semi(P<Expr>),
 }
 
 impl StmtKind {
     pub fn attrs(&self) -> &[Attribute] {
         match *self {
-            StmtKind::Decl(ref d, _) => d.node.attrs(),
-            StmtKind::Expr(ref e, _) |
-            StmtKind::Semi(ref e, _) => &e.attrs,
-        }
-    }
-
-    pub fn id(&self) -> NodeId {
-        match *self {
-            StmtKind::Decl(_, id) |
-            StmtKind::Expr(_, id) |
-            StmtKind::Semi(_, id) => id,
+            StmtKind::Local(ref l) => &l.attrs,
+            StmtKind::Item(_) => &[],
+            StmtKind::Expr(ref e) |
+            StmtKind::Semi(ref e) => &e.attrs,
         }
     }
 }
@@ -1191,32 +1187,6 @@
     pub source: LocalSource,
 }
 
-pub type Decl = Spanned<DeclKind>;
-
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
-pub enum DeclKind {
-    /// A local (let) binding:
-    Local(P<Local>),
-    /// An item binding:
-    Item(ItemId),
-}
-
-impl DeclKind {
-    pub fn attrs(&self) -> &[Attribute] {
-        match *self {
-            DeclKind::Local(ref l) => &l.attrs,
-            DeclKind::Item(_) => &[]
-        }
-    }
-
-    pub fn is_local(&self) -> bool {
-        match *self {
-            DeclKind::Local(_) => true,
-            _ => false,
-        }
-    }
-}
-
 /// represents one arm of a 'match'
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct Arm {
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index d7acdef..e950f25 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -992,14 +992,29 @@
     pub fn print_stmt(&mut self, st: &hir::Stmt) -> io::Result<()> {
         self.maybe_print_comment(st.span.lo())?;
         match st.node {
-            hir::StmtKind::Decl(ref decl, _) => {
-                self.print_decl(&decl)?;
+            hir::StmtKind::Local(ref loc) => {
+                self.space_if_not_bol()?;
+                self.ibox(indent_unit)?;
+                self.word_nbsp("let")?;
+
+                self.ibox(indent_unit)?;
+                self.print_local_decl(&loc)?;
+                self.end()?;
+                if let Some(ref init) = loc.init {
+                    self.nbsp()?;
+                    self.word_space("=")?;
+                    self.print_expr(&init)?;
+                }
+                self.end()?
             }
-            hir::StmtKind::Expr(ref expr, _) => {
+            hir::StmtKind::Item(ref item) => {
+                self.ann.nested(self, Nested::Item(**item))?
+            }
+            hir::StmtKind::Expr(ref expr) => {
                 self.space_if_not_bol()?;
                 self.print_expr(&expr)?;
             }
-            hir::StmtKind::Semi(ref expr, _) => {
+            hir::StmtKind::Semi(ref expr) => {
                 self.space_if_not_bol()?;
                 self.print_expr(&expr)?;
                 self.s.word(";")?;
@@ -1562,30 +1577,6 @@
         Ok(())
     }
 
-    pub fn print_decl(&mut self, decl: &hir::Decl) -> io::Result<()> {
-        self.maybe_print_comment(decl.span.lo())?;
-        match decl.node {
-            hir::DeclKind::Local(ref loc) => {
-                self.space_if_not_bol()?;
-                self.ibox(indent_unit)?;
-                self.word_nbsp("let")?;
-
-                self.ibox(indent_unit)?;
-                self.print_local_decl(&loc)?;
-                self.end()?;
-                if let Some(ref init) = loc.init {
-                    self.nbsp()?;
-                    self.word_space("=")?;
-                    self.print_expr(&init)?;
-                }
-                self.end()
-            }
-            hir::DeclKind::Item(item) => {
-                self.ann.nested(self, Nested::Item(item))
-            }
-        }
-    }
-
     pub fn print_usize(&mut self, i: usize) -> io::Result<()> {
         self.s.word(i.to_string())
     }
@@ -2401,18 +2392,10 @@
 /// seen the semicolon, and thus don't need another.
 fn stmt_ends_with_semi(stmt: &hir::StmtKind) -> bool {
     match *stmt {
-        hir::StmtKind::Decl(ref d, _) => {
-            match d.node {
-                hir::DeclKind::Local(_) => true,
-                hir::DeclKind::Item(_) => false,
-            }
-        }
-        hir::StmtKind::Expr(ref e, _) => {
-            expr_requires_semi_to_be_stmt(&e)
-        }
-        hir::StmtKind::Semi(..) => {
-            false
-        }
+        hir::StmtKind::Local(_) => true,
+        hir::StmtKind::Item(_) => false,
+        hir::StmtKind::Expr(ref e) => expr_requires_semi_to_be_stmt(&e),
+        hir::StmtKind::Semi(..) => false,
     }
 }
 
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
index f48059b..1590676 100644
--- a/src/librustc/ich/impls_hir.rs
+++ b/src/librustc/ich/impls_hir.rs
@@ -483,7 +483,12 @@
     UnNeg
 });
 
-impl_stable_hash_for_spanned!(hir::StmtKind);
+impl_stable_hash_for!(struct hir::Stmt {
+    id,
+    node,
+    span,
+});
+
 
 impl_stable_hash_for!(struct hir::Local {
     pat,
@@ -496,12 +501,6 @@
     source
 });
 
-impl_stable_hash_for_spanned!(hir::DeclKind);
-impl_stable_hash_for!(enum hir::DeclKind {
-    Local(local),
-    Item(item_id)
-});
-
 impl_stable_hash_for!(struct hir::Arm {
     attrs,
     pats,
@@ -941,9 +940,10 @@
 });
 
 impl_stable_hash_for!(enum hir::StmtKind {
-    Decl(decl, id),
-    Expr(expr, id),
-    Semi(expr, id)
+    Local(local),
+    Item(item_id),
+    Expr(expr),
+    Semi(expr)
 });
 
 impl_stable_hash_for!(struct hir::Arg {
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index f5a7919..837a364 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -941,11 +941,6 @@
         hir_visit::walk_arm(self, a);
     }
 
-    fn visit_decl(&mut self, d: &'tcx hir::Decl) {
-        run_lints!(self, check_decl, d);
-        hir_visit::walk_decl(self, d);
-    }
-
     fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam) {
         run_lints!(self, check_generic_param, p);
         hir_visit::walk_generic_param(self, p);
diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs
index 730ce91..e83ba74 100644
--- a/src/librustc/lint/mod.rs
+++ b/src/librustc/lint/mod.rs
@@ -192,7 +192,6 @@
             fn check_stmt(a: &$hir hir::Stmt);
             fn check_arm(a: &$hir hir::Arm);
             fn check_pat(a: &$hir hir::Pat);
-            fn check_decl(a: &$hir hir::Decl);
             fn check_expr(a: &$hir hir::Expr);
             fn check_expr_post(a: &$hir hir::Expr);
             fn check_ty(a: &$hir hir::Ty);
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index c1aa25b..08210c3 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -589,21 +589,17 @@
 
     fn walk_stmt(&mut self, stmt: &hir::Stmt) {
         match stmt.node {
-            hir::StmtKind::Decl(ref decl, _) => {
-                match decl.node {
-                    hir::DeclKind::Local(ref local) => {
-                        self.walk_local(&local);
-                    }
-
-                    hir::DeclKind::Item(_) => {
-                        // we don't visit nested items in this visitor,
-                        // only the fn body we were given.
-                    }
-                }
+            hir::StmtKind::Local(ref local) => {
+                self.walk_local(&local);
             }
 
-            hir::StmtKind::Expr(ref expr, _) |
-            hir::StmtKind::Semi(ref expr, _) => {
+            hir::StmtKind::Item(_) => {
+                // we don't visit nested items in this visitor,
+                // only the fn body we were given.
+            }
+
+            hir::StmtKind::Expr(ref expr) |
+            hir::StmtKind::Semi(ref expr) => {
                 self.consume_expr(&expr);
             }
         }
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index e73677d..220bec7 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -962,46 +962,31 @@
     fn propagate_through_stmt(&mut self, stmt: &hir::Stmt, succ: LiveNode)
                               -> LiveNode {
         match stmt.node {
-            hir::StmtKind::Decl(ref decl, _) => {
-                self.propagate_through_decl(&decl, succ)
-            }
+            hir::StmtKind::Local(ref local) => {
+                // Note: we mark the variable as defined regardless of whether
+                // there is an initializer.  Initially I had thought to only mark
+                // the live variable as defined if it was initialized, and then we
+                // could check for uninit variables just by scanning what is live
+                // at the start of the function. But that doesn't work so well for
+                // immutable variables defined in a loop:
+                //     loop { let x; x = 5; }
+                // because the "assignment" loops back around and generates an error.
+                //
+                // So now we just check that variables defined w/o an
+                // initializer are not live at the point of their
+                // initialization, which is mildly more complex than checking
+                // once at the func header but otherwise equivalent.
 
-            hir::StmtKind::Expr(ref expr, _) | hir::StmtKind::Semi(ref expr, _) => {
+                let succ = self.propagate_through_opt_expr(local.init.as_ref().map(|e| &**e), succ);
+                self.define_bindings_in_pat(&local.pat, succ)
+            }
+            hir::StmtKind::Item(..) => succ,
+            hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => {
                 self.propagate_through_expr(&expr, succ)
             }
         }
     }
 
-    fn propagate_through_decl(&mut self, decl: &hir::Decl, succ: LiveNode)
-                              -> LiveNode {
-        match decl.node {
-            hir::DeclKind::Local(ref local) => {
-                self.propagate_through_local(&local, succ)
-            }
-            hir::DeclKind::Item(_) => succ,
-        }
-    }
-
-    fn propagate_through_local(&mut self, local: &hir::Local, succ: LiveNode)
-                               -> LiveNode {
-        // Note: we mark the variable as defined regardless of whether
-        // there is an initializer.  Initially I had thought to only mark
-        // the live variable as defined if it was initialized, and then we
-        // could check for uninit variables just by scanning what is live
-        // at the start of the function. But that doesn't work so well for
-        // immutable variables defined in a loop:
-        //     loop { let x; x = 5; }
-        // because the "assignment" loops back around and generates an error.
-        //
-        // So now we just check that variables defined w/o an
-        // initializer are not live at the point of their
-        // initialization, which is mildly more complex than checking
-        // once at the func header but otherwise equivalent.
-
-        let succ = self.propagate_through_opt_expr(local.init.as_ref().map(|e| &**e), succ);
-        self.define_bindings_in_pat(&local.pat, succ)
-    }
-
     fn propagate_through_exprs(&mut self, exprs: &[Expr], succ: LiveNode)
                                -> LiveNode {
         exprs.iter().rev().fold(succ, |succ, expr| {
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index ce2a348..819dd8a 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -784,20 +784,25 @@
         // index information.)
 
         for (i, statement) in blk.stmts.iter().enumerate() {
-            if let hir::StmtKind::Decl(..) = statement.node {
-                // Each StmtKind::Decl introduces a subscope for bindings
-                // introduced by the declaration; this subscope covers
-                // a suffix of the block . Each subscope in a block
-                // has the previous subscope in the block as a parent,
-                // except for the first such subscope, which has the
-                // block itself as a parent.
-                visitor.enter_scope(
-                    Scope {
-                        id: blk.hir_id.local_id,
-                        data: ScopeData::Remainder(FirstStatementIndex::new(i))
-                    }
-                );
-                visitor.cx.var_parent = visitor.cx.parent;
+            match statement.node {
+                hir::StmtKind::Local(..) |
+                hir::StmtKind::Item(..) => {
+                    // Each declaration introduces a subscope for bindings
+                    // introduced by the declaration; this subscope covers a
+                    // suffix of the block. Each subscope in a block has the
+                    // previous subscope in the block as a parent, except for
+                    // the first such subscope, which has the block itself as a
+                    // parent.
+                    visitor.enter_scope(
+                        Scope {
+                            id: blk.hir_id.local_id,
+                            data: ScopeData::Remainder(FirstStatementIndex::new(i))
+                        }
+                    );
+                    visitor.cx.var_parent = visitor.cx.parent;
+                }
+                hir::StmtKind::Expr(..) |
+                hir::StmtKind::Semi(..) => {}
             }
             visitor.visit_stmt(statement)
         }
@@ -835,7 +840,7 @@
 }
 
 fn resolve_stmt<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, stmt: &'tcx hir::Stmt) {
-    let stmt_id = visitor.tcx.hir().node_to_hir_id(stmt.node.id()).local_id;
+    let stmt_id = visitor.tcx.hir().node_to_hir_id(stmt.id).local_id;
     debug!("resolve_stmt(stmt.id={:?})", stmt_id);
 
     // Every statement will clean up the temporaries created during
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index bc29020..8a68f1b 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -41,7 +41,7 @@
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
     fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) {
         let expr = match s.node {
-            hir::StmtKind::Semi(ref expr, _) => &**expr,
+            hir::StmtKind::Semi(ref expr) => &**expr,
             _ => return,
         };
 
@@ -205,7 +205,7 @@
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PathStatements {
     fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) {
-        if let hir::StmtKind::Semi(ref expr, _) = s.node {
+        if let hir::StmtKind::Semi(ref expr) = s.node {
             if let hir::ExprKind::Path(_) = expr.node {
                 cx.span_lint(PATH_STATEMENTS, s.span, "path statement with no effect");
             }
diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs
index ea8b282..c50d9dd 100644
--- a/src/librustc_mir/hair/cx/block.rs
+++ b/src/librustc_mir/hair/cx/block.rs
@@ -46,12 +46,12 @@
                                 -> Vec<StmtRef<'tcx>> {
     let mut result = vec![];
     for (index, stmt) in stmts.iter().enumerate() {
-        let hir_id = cx.tcx.hir().node_to_hir_id(stmt.node.id());
+        let hir_id = cx.tcx.hir().node_to_hir_id(stmt.id);
         let opt_dxn_ext = cx.region_scope_tree.opt_destruction_scope(hir_id.local_id);
-        let stmt_span = StatementSpan(cx.tcx.hir().span(stmt.node.id()));
+        let stmt_span = StatementSpan(cx.tcx.hir().span(stmt.id));
         match stmt.node {
-            hir::StmtKind::Expr(ref expr, _) |
-            hir::StmtKind::Semi(ref expr, _) => {
+            hir::StmtKind::Expr(ref expr) |
+            hir::StmtKind::Semi(ref expr) => {
                 result.push(StmtRef::Mirror(Box::new(Stmt {
                     kind: StmtKind::Expr {
                         scope: region::Scope {
@@ -64,52 +64,48 @@
                     span: stmt_span,
                 })))
             }
-            hir::StmtKind::Decl(ref decl, _) => {
-                match decl.node {
-                    hir::DeclKind::Item(..) => {
-                        // ignore for purposes of the MIR
-                    }
-                    hir::DeclKind::Local(ref local) => {
-                        let remainder_scope = region::Scope {
-                            id: block_id,
-                            data: region::ScopeData::Remainder(
-                                region::FirstStatementIndex::new(index)),
+            hir::StmtKind::Item(..) => {
+                // ignore for purposes of the MIR
+            }
+            hir::StmtKind::Local(ref local) => {
+                let remainder_scope = region::Scope {
+                    id: block_id,
+                    data: region::ScopeData::Remainder(
+                        region::FirstStatementIndex::new(index)),
+                };
+
+                let mut pattern = cx.pattern_from_hir(&local.pat);
+
+                if let Some(ty) = &local.ty {
+                    if let Some(&user_ty) = cx.tables.user_provided_types().get(ty.hir_id) {
+                        debug!("mirror_stmts: user_ty={:?}", user_ty);
+                        pattern = Pattern {
+                            ty: pattern.ty,
+                            span: pattern.span,
+                            kind: Box::new(PatternKind::AscribeUserType {
+                                user_ty: PatternTypeProjection::from_user_type(user_ty),
+                                user_ty_span: ty.span,
+                                subpattern: pattern,
+                                variance: ty::Variance::Covariant,
+                            })
                         };
-
-                        let mut pattern = cx.pattern_from_hir(&local.pat);
-
-                        if let Some(ty) = &local.ty {
-                            if let Some(&user_ty) = cx.tables.user_provided_types().get(ty.hir_id) {
-                                debug!("mirror_stmts: user_ty={:?}", user_ty);
-                                pattern = Pattern {
-                                    ty: pattern.ty,
-                                    span: pattern.span,
-                                    kind: Box::new(PatternKind::AscribeUserType {
-                                        user_ty: PatternTypeProjection::from_user_type(user_ty),
-                                        user_ty_span: ty.span,
-                                        subpattern: pattern,
-                                        variance: ty::Variance::Covariant,
-                                    })
-                                };
-                            }
-                        }
-
-                        result.push(StmtRef::Mirror(Box::new(Stmt {
-                            kind: StmtKind::Let {
-                                remainder_scope: remainder_scope,
-                                init_scope: region::Scope {
-                                    id: hir_id.local_id,
-                                    data: region::ScopeData::Node
-                                },
-                                pattern,
-                                initializer: local.init.to_ref(),
-                                lint_level: cx.lint_level_of(local.id),
-                            },
-                            opt_destruction_scope: opt_dxn_ext,
-                            span: stmt_span,
-                        })));
                     }
                 }
+
+                result.push(StmtRef::Mirror(Box::new(Stmt {
+                    kind: StmtKind::Let {
+                        remainder_scope: remainder_scope,
+                        init_scope: region::Scope {
+                            id: hir_id.local_id,
+                            data: region::ScopeData::Node
+                        },
+                        pattern,
+                        initializer: local.init.to_ref(),
+                        lint_level: cx.lint_level_of(local.id),
+                    },
+                    opt_destruction_scope: opt_dxn_ext,
+                    span: stmt_span,
+                })));
             }
         }
     }
diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs
index 059b88a..85bf1e7 100644
--- a/src/librustc_mir/transform/qualify_min_const_fn.rs
+++ b/src/librustc_mir/transform/qualify_min_const_fn.rs
@@ -21,6 +21,7 @@
                 | Predicate::RegionOutlives(_)
                 | Predicate::TypeOutlives(_)
                 | Predicate::WellFormed(_)
+                | Predicate::Projection(_)
                 | Predicate::ConstEvaluatable(..) => continue,
                 | Predicate::ObjectSafe(_) => {
                     bug!("object safe predicate on function: {:#?}", predicate)
@@ -29,13 +30,6 @@
                     bug!("closure kind predicate on function: {:#?}", predicate)
                 }
                 Predicate::Subtype(_) => bug!("subtype predicate on function: {:#?}", predicate),
-                Predicate::Projection(_) => {
-                    let span = tcx.def_span(current);
-                    // we'll hit a `Predicate::Trait` later which will report an error
-                    tcx.sess
-                        .delay_span_bug(span, "projection without trait bound");
-                    continue;
-                }
                 Predicate::Trait(pred) => {
                     if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
                         continue;
diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs
index 604b31e..74d6d75 100644
--- a/src/librustc_passes/hir_stats.rs
+++ b/src/librustc_passes/hir_stats.rs
@@ -144,7 +144,7 @@
     }
 
     fn visit_stmt(&mut self, s: &'v hir::Stmt) {
-        self.record("Stmt", Id::Node(s.node.id()), s);
+        self.record("Stmt", Id::Node(s.id), s);
         hir_visit::walk_stmt(self, s)
     }
 
@@ -158,11 +158,6 @@
         hir_visit::walk_pat(self, p)
     }
 
-    fn visit_decl(&mut self, d: &'v hir::Decl) {
-        self.record("Decl", Id::None, d);
-        hir_visit::walk_decl(self, d)
-    }
-
     fn visit_expr(&mut self, ex: &'v hir::Expr) {
         self.record("Expr", Id::Node(ex.id), ex);
         hir_visit::walk_expr(self, ex)
diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs
index f0b559f..49914dc 100644
--- a/src/librustc_passes/rvalue_promotion.rs
+++ b/src/librustc_passes/rvalue_promotion.rs
@@ -220,26 +220,22 @@
 
     fn check_stmt(&mut self, stmt: &'tcx hir::Stmt) -> Promotability {
         match stmt.node {
-            hir::StmtKind::Decl(ref decl, _node_id) => {
-                match &decl.node {
-                    hir::DeclKind::Local(local) => {
-                        if self.remove_mut_rvalue_borrow(&local.pat) {
-                            if let Some(init) = &local.init {
-                                self.mut_rvalue_borrows.insert(init.id);
-                            }
-                        }
-
-                        if let Some(ref expr) = local.init {
-                            let _ = self.check_expr(&expr);
-                        }
-                        NotPromotable
+            hir::StmtKind::Local(ref local) => {
+                if self.remove_mut_rvalue_borrow(&local.pat) {
+                    if let Some(init) = &local.init {
+                        self.mut_rvalue_borrows.insert(init.id);
                     }
-                    // Item statements are allowed
-                    hir::DeclKind::Item(_) => Promotable
                 }
+
+                if let Some(ref expr) = local.init {
+                    let _ = self.check_expr(&expr);
+                }
+                NotPromotable
             }
-            hir::StmtKind::Expr(ref box_expr, _node_id) |
-            hir::StmtKind::Semi(ref box_expr, _node_id) => {
+            // Item statements are allowed
+            hir::StmtKind::Item(..) => Promotable,
+            hir::StmtKind::Expr(ref box_expr) |
+            hir::StmtKind::Semi(ref box_expr) => {
                 let _ = self.check_expr(box_expr);
                 NotPromotable
             }
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index a82a0d3..dd63b4f 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -1216,7 +1216,7 @@
                                       "supposed to be part of a block tail expression, but the \
                                        expression is empty");
                         });
-                        fcx.suggest_mismatched_types_on_tail(
+                        let pointing_at_return_type = fcx.suggest_mismatched_types_on_tail(
                             &mut db,
                             expr,
                             expected,
@@ -1224,7 +1224,44 @@
                             cause.span,
                             blk_id,
                         );
-                        if let Some(sp) = fcx.ret_coercion_span.borrow().as_ref() {
+                        // FIXME: replace with navigating up the chain until hitting an fn or
+                        // bailing if no "pass-through" Node is found, in order to provide a
+                        // suggestion when encountering something like:
+                        // ```
+                        // fn foo(a: bool) -> impl Debug {
+                        //     if a {
+                        //         bar()?;
+                        //     }
+                        //     {
+                        //         let x = unsafe { bar() };
+                        //         x
+                        //     }
+                        // }
+                        // ```
+                        //
+                        // Verify that this is a tail expression of a function, otherwise the
+                        // label pointing out the cause for the type coercion will be wrong
+                        // as prior return coercions would not be relevant (#57664).
+                        let parent_id = fcx.tcx.hir().get_parent_node(blk_id);
+                        let parent = fcx.tcx.hir().get(fcx.tcx.hir().get_parent_node(parent_id));
+                        if fcx.get_node_fn_decl(parent).is_some() && !pointing_at_return_type {
+                            if let Some(sp) = fcx.ret_coercion_span.borrow().as_ref() {
+                                db.span_label(*sp, reason_label);
+                            }
+                        }
+                    }
+                    ObligationCauseCode::ReturnType(_id) => {
+                        db = fcx.report_mismatched_types(cause, expected, found, err);
+                        let _id = fcx.tcx.hir().get_parent_node(_id);
+                        let mut pointing_at_return_type = false;
+                        if let Some((fn_decl, can_suggest)) = fcx.get_fn_decl(_id) {
+                            pointing_at_return_type = fcx.suggest_missing_return_type(
+                                &mut db, &fn_decl, expected, found, can_suggest);
+                        }
+                        if let (Some(sp), false) = (
+                            fcx.ret_coercion_span.borrow().as_ref(),
+                            pointing_at_return_type,
+                        ) {
                             if !sp.overlaps(cause.span) {
                                 db.span_label(*sp, reason_label);
                             }
@@ -1232,11 +1269,6 @@
                     }
                     _ => {
                         db = fcx.report_mismatched_types(cause, expected, found, err);
-                        if let Some(sp) = fcx.ret_coercion_span.borrow().as_ref() {
-                            if !sp.overlaps(cause.span) {
-                                db.span_label(*sp, reason_label);
-                            }
-                        }
                     }
                 }
 
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 452fd24..c9173df 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -4347,11 +4347,15 @@
                     struct_span_err!(self.tcx.sess, expr.span, E0572,
                                      "return statement outside of function body").emit();
                 } else if let Some(ref e) = *expr_opt {
-                    *self.ret_coercion_span.borrow_mut() = Some(e.span);
+                    if self.ret_coercion_span.borrow().is_none() {
+                        *self.ret_coercion_span.borrow_mut() = Some(e.span);
+                    }
                     self.check_return_expr(e);
                 } else {
                     let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut();
-                    *self.ret_coercion_span.borrow_mut() = Some(expr.span);
+                    if self.ret_coercion_span.borrow().is_none() {
+                        *self.ret_coercion_span.borrow_mut() = Some(expr.span);
+                    }
                     let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression);
                     if let Some((fn_decl, _)) = self.get_fn_decl(expr.id) {
                         coercion.coerce_forced_unit(
@@ -4840,15 +4844,11 @@
     pub fn check_stmt(&self, stmt: &'gcx hir::Stmt) {
         // Don't do all the complex logic below for `DeclItem`.
         match stmt.node {
-            hir::StmtKind::Decl(ref decl, _) => {
-                if let hir::DeclKind::Item(_) = decl.node {
-                    return
-                }
-            }
-            hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {}
+            hir::StmtKind::Item(..) => return,
+            hir::StmtKind::Local(..) | hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {}
         }
 
-        self.warn_if_unreachable(stmt.node.id(), stmt.span, "statement");
+        self.warn_if_unreachable(stmt.id, stmt.span, "statement");
 
         // Hide the outer diverging and `has_errors` flags.
         let old_diverges = self.diverges.get();
@@ -4857,20 +4857,16 @@
         self.has_errors.set(false);
 
         match stmt.node {
-            hir::StmtKind::Decl(ref decl, _) => {
-                match decl.node {
-                    hir::DeclKind::Local(ref l) => {
-                        self.check_decl_local(&l);
-                    }
-                    // Ignore for now.
-                    hir::DeclKind::Item(_) => ()
-                }
+            hir::StmtKind::Local(ref l) => {
+                self.check_decl_local(&l);
             }
-            hir::StmtKind::Expr(ref expr, _) => {
+            // Ignore for now.
+            hir::StmtKind::Item(_) => {}
+            hir::StmtKind::Expr(ref expr) => {
                 // Check with expected type of `()`.
                 self.check_expr_has_type_or_error(&expr, self.tcx.mk_unit());
             }
-            hir::StmtKind::Semi(ref expr, _) => {
+            hir::StmtKind::Semi(ref expr) => {
                 self.check_expr(&expr);
             }
         }
@@ -5089,12 +5085,15 @@
         found: Ty<'tcx>,
         cause_span: Span,
         blk_id: ast::NodeId,
-    ) {
+    ) -> bool {
         self.suggest_missing_semicolon(err, expression, expected, cause_span);
+        let mut pointing_at_return_type = false;
         if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
-            self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest);
+            pointing_at_return_type = self.suggest_missing_return_type(
+                err, &fn_decl, expected, found, can_suggest);
         }
         self.suggest_ref_or_into(err, expression, expected, found);
+        pointing_at_return_type
     }
 
     pub fn suggest_ref_or_into(
@@ -5193,12 +5192,14 @@
     /// This routine checks if the return type is left as default, the method is not part of an
     /// `impl` block and that it isn't the `main` method. If so, it suggests setting the return
     /// type.
-    fn suggest_missing_return_type(&self,
-                                   err: &mut DiagnosticBuilder<'tcx>,
-                                   fn_decl: &hir::FnDecl,
-                                   expected: Ty<'tcx>,
-                                   found: Ty<'tcx>,
-                                   can_suggest: bool) {
+    fn suggest_missing_return_type(
+        &self,
+        err: &mut DiagnosticBuilder<'tcx>,
+        fn_decl: &hir::FnDecl,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+        can_suggest: bool,
+    ) -> bool {
         // Only suggest changing the return type for methods that
         // haven't set a return type at all (and aren't `fn main()` or an impl).
         match (&fn_decl.output, found.is_suggestable(), can_suggest, expected.is_unit()) {
@@ -5208,16 +5209,19 @@
                     "try adding a return type",
                     format!("-> {} ", self.resolve_type_vars_with_obligations(found)),
                     Applicability::MachineApplicable);
+                true
             }
             (&hir::FunctionRetTy::DefaultReturn(span), false, true, true) => {
                 err.span_label(span, "possibly return type missing here?");
+                true
             }
             (&hir::FunctionRetTy::DefaultReturn(span), _, false, true) => {
                 // `fn main()` must return `()`, do not suggest changing return type
                 err.span_label(span, "expected `()` because of default return type");
+                true
             }
             // expectation was caused by something else, not the default return
-            (&hir::FunctionRetTy::DefaultReturn(_), _, _, false) => {}
+            (&hir::FunctionRetTy::DefaultReturn(_), _, _, false) => false,
             (&hir::FunctionRetTy::Return(ref ty), _, _, _) => {
                 // Only point to return type if the expected type is the return type, as if they
                 // are not, the expectation must have been caused by something else.
@@ -5229,7 +5233,9 @@
                 if ty.sty == expected.sty {
                     err.span_label(sp, format!("expected `{}` because of return type",
                                                expected));
+                    return true;
                 }
+                false
             }
         }
     }
@@ -5273,7 +5279,7 @@
             None => return None,
         };
         let last_expr = match last_stmt.node {
-            hir::StmtKind::Semi(ref e, _) => e,
+            hir::StmtKind::Semi(ref e) => e,
             _ => return None,
         };
         let last_expr_ty = self.node_ty(last_expr.hir_id);
diff --git a/src/test/ui/fully-qualified-type/fully-qualified-type-name2.stderr b/src/test/ui/fully-qualified-type/fully-qualified-type-name2.stderr
index 9a33d29..47bb5e4 100644
--- a/src/test/ui/fully-qualified-type/fully-qualified-type-name2.stderr
+++ b/src/test/ui/fully-qualified-type/fully-qualified-type-name2.stderr
@@ -1,6 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/fully-qualified-type-name2.rs:12:12
    |
+LL | fn bar(x: x::Foo) -> y::Foo {
+   |                      ------ expected `y::Foo` because of return type
 LL |     return x;
    |            ^ expected enum `y::Foo`, found enum `x::Foo`
    |
diff --git a/src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr b/src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr
index f03aaa6..b341879 100644
--- a/src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr
+++ b/src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr
@@ -1,6 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/fully-qualified-type-name4.rs:6:12
    |
+LL | fn bar(x: usize) -> Option<usize> {
+   |                     ------------- expected `std::option::Option<usize>` because of return type
 LL |     return x;
    |            ^ expected enum `std::option::Option`, found usize
    |
diff --git a/src/test/ui/liveness/liveness-forgot-ret.stderr b/src/test/ui/liveness/liveness-forgot-ret.stderr
index bbcbbdb..a970b80 100644
--- a/src/test/ui/liveness/liveness-forgot-ret.stderr
+++ b/src/test/ui/liveness/liveness-forgot-ret.stderr
@@ -2,7 +2,7 @@
   --> $DIR/liveness-forgot-ret.rs:3:19
    |
 LL | fn f(a: isize) -> isize { if god_exists(a) { return 5; }; }
-   |    -              ^^^^^ expected isize, found ()    - expected because of this statement
+   |    -              ^^^^^ expected isize, found ()
    |    |
    |    this function's body doesn't return
    |
diff --git a/src/test/ui/point-to-type-err-cause-on-impl-trait-return-2.rs b/src/test/ui/point-to-type-err-cause-on-impl-trait-return-2.rs
new file mode 100644
index 0000000..50f1fe8
--- /dev/null
+++ b/src/test/ui/point-to-type-err-cause-on-impl-trait-return-2.rs
@@ -0,0 +1,17 @@
+fn unrelated() -> Result<(), std::string::ParseError> {  // #57664
+    let x = 0;
+
+    match x {
+        1 => {
+            let property_value_as_string = "a".parse()?;
+        }
+        2 => {
+            let value: &bool = unsafe { &42 };
+            //~^ ERROR mismatched types
+        }
+    };
+
+    Ok(())
+}
+
+fn main() {}
diff --git a/src/test/ui/point-to-type-err-cause-on-impl-trait-return-2.stderr b/src/test/ui/point-to-type-err-cause-on-impl-trait-return-2.stderr
new file mode 100644
index 0000000..edaa60e
--- /dev/null
+++ b/src/test/ui/point-to-type-err-cause-on-impl-trait-return-2.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/point-to-type-err-cause-on-impl-trait-return-2.rs:9:41
+   |
+LL |             let value: &bool = unsafe { &42 };
+   |                                         ^^^ expected bool, found integer
+   |
+   = note: expected type `&bool`
+              found type `&{integer}`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.rs b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.rs
new file mode 100644
index 0000000..95b4036
--- /dev/null
+++ b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.rs
@@ -0,0 +1,36 @@
+fn foo() -> impl std::fmt::Display {
+    if false {
+        return 0i32;
+    }
+    1u32
+    //~^ ERROR mismatched types
+}
+
+fn bar() -> impl std::fmt::Display {
+    if false {
+        return 0i32;
+    } else {
+        return 1u32;
+        //~^ ERROR mismatched types
+    }
+}
+
+fn baz() -> impl std::fmt::Display {
+    if false {
+    //~^ ERROR mismatched types
+        return 0i32;
+    } else {
+        1u32
+    }
+}
+
+fn qux() -> impl std::fmt::Display {
+    if false {
+        0i32
+    } else {
+        1u32
+        //~^ ERROR if and else have incompatible types
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr
new file mode 100644
index 0000000..62da078
--- /dev/null
+++ b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr
@@ -0,0 +1,58 @@
+error[E0308]: mismatched types
+  --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:5:5
+   |
+LL |         return 0i32;
+   |                ---- expected because of this statement
+LL |     }
+LL |     1u32
+   |     ^^^^ expected i32, found u32
+   |
+   = note: expected type `i32`
+              found type `u32`
+
+error[E0308]: mismatched types
+  --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:13:16
+   |
+LL |         return 0i32;
+   |                ---- expected because of this statement
+LL |     } else {
+LL |         return 1u32;
+   |                ^^^^ expected i32, found u32
+   |
+   = note: expected type `i32`
+              found type `u32`
+
+error[E0308]: mismatched types
+  --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:19:5
+   |
+LL | /     if false {
+LL | |     //~^ ERROR mismatched types
+LL | |         return 0i32;
+   | |                ---- expected because of this statement
+LL | |     } else {
+LL | |         1u32
+LL | |     }
+   | |_____^ expected i32, found u32
+   |
+   = note: expected type `i32`
+              found type `u32`
+
+error[E0308]: if and else have incompatible types
+  --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:31:9
+   |
+LL | /     if false {
+LL | |         0i32
+   | |         ---- expected because of this
+LL | |     } else {
+LL | |         1u32
+   | |         ^^^^ expected i32, found u32
+LL | |         //~^ ERROR if and else have incompatible types
+LL | |     }
+   | |_____- if and else have incompatible types
+   |
+   = note: expected type `i32`
+              found type `u32`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/proc-macro/span-preservation.stderr b/src/test/ui/proc-macro/span-preservation.stderr
index 1f9103a..db52490 100644
--- a/src/test/ui/proc-macro/span-preservation.stderr
+++ b/src/test/ui/proc-macro/span-preservation.stderr
@@ -15,6 +15,9 @@
 error[E0308]: mismatched types
   --> $DIR/span-preservation.rs:19:29
    |
+LL | fn b(x: Option<isize>) -> usize {
+   |                           ----- expected `usize` because of return type
+LL |     match x {
 LL |         Some(x) => { return x }, //~ ERROR mismatched types
    |                             ^ expected usize, found isize
 
diff --git a/src/test/ui/return/return-from-diverging.stderr b/src/test/ui/return/return-from-diverging.stderr
index c84dd19..2862ae6 100644
--- a/src/test/ui/return/return-from-diverging.stderr
+++ b/src/test/ui/return/return-from-diverging.stderr
@@ -1,6 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/return-from-diverging.rs:4:12
    |
+LL | fn fail() -> ! {
+   |              - expected `!` because of return type
 LL |     return "wow"; //~ ERROR mismatched types
    |            ^^^^^ expected !, found reference
    |
diff --git a/src/test/ui/tail-typeck.stderr b/src/test/ui/tail-typeck.stderr
index eadf3d6..1170f5c 100644
--- a/src/test/ui/tail-typeck.stderr
+++ b/src/test/ui/tail-typeck.stderr
@@ -2,7 +2,9 @@
   --> $DIR/tail-typeck.rs:3:26
    |
 LL | fn f() -> isize { return g(); }
-   |                          ^^^ expected isize, found usize
+   |           -----          ^^^ expected isize, found usize
+   |           |
+   |           expected `isize` because of return type
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wrong-ret-type.stderr b/src/test/ui/wrong-ret-type.stderr
index 221806f..cf59f42 100644
--- a/src/test/ui/wrong-ret-type.stderr
+++ b/src/test/ui/wrong-ret-type.stderr
@@ -2,7 +2,9 @@
   --> $DIR/wrong-ret-type.rs:2:49
    |
 LL | fn mk_int() -> usize { let i: isize = 3; return i; }
-   |                                                 ^ expected usize, found isize
+   |                -----                            ^ expected usize, found isize
+   |                |
+   |                expected `usize` because of return type
 
 error: aborting due to previous error