about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/dep_graph/graph.rs2
-rw-r--r--src/librustc/infer/error_reporting/mod.rs5
-rw-r--r--src/librustc/traits/error_reporting.rs4
-rw-r--r--src/librustc/traits/mod.rs9
-rw-r--r--src/librustc/traits/structural_impls.rs3
-rw-r--r--src/librustc/ty/context.rs15
-rw-r--r--src/librustc/ty/query/job.rs5
-rw-r--r--src/librustc/ty/query/on_disk_cache.rs17
-rw-r--r--src/librustc/ty/query/plumbing.rs74
-rw-r--r--src/librustc_mir/hair/pattern/_match.rs9
-rw-r--r--src/librustc_typeck/check/_match.rs173
-rw-r--r--src/librustc_typeck/check/demand.rs21
-rw-r--r--src/librustc_typeck/check/mod.rs17
-rw-r--r--src/librustdoc/html/render.rs70
-rw-r--r--src/librustdoc/html/static/main.js11
-rw-r--r--src/librustdoc/html/static/rustdoc.css53
-rw-r--r--src/test/rustdoc/assoc-consts-version.rs2
-rw-r--r--src/test/rustdoc/const.rs2
-rw-r--r--src/test/rustdoc/issue-25001.rs6
-rw-r--r--src/test/rustdoc/issue-51236.rs2
-rw-r--r--src/test/rustdoc/issue-54705.rs4
-rw-r--r--src/test/rustdoc/issue-55321.rs8
-rw-r--r--src/test/rustdoc/issue-56822.rs2
-rw-r--r--src/test/rustdoc/synthetic_auto/complex.rs2
-rw-r--r--src/test/rustdoc/synthetic_auto/lifetimes.rs4
-rw-r--r--src/test/rustdoc/synthetic_auto/manual.rs4
-rw-r--r--src/test/rustdoc/synthetic_auto/negative.rs4
-rw-r--r--src/test/rustdoc/synthetic_auto/nested.rs4
-rw-r--r--src/test/rustdoc/synthetic_auto/no-redundancy.rs2
-rw-r--r--src/test/rustdoc/synthetic_auto/project.rs4
-rw-r--r--src/test/rustdoc/synthetic_auto/self-referential.rs2
-rw-r--r--src/test/rustdoc/synthetic_auto/static-region.rs2
-rw-r--r--src/test/ui/block-result/issue-13624.stderr2
-rw-r--r--src/test/ui/error-codes/E0308-4.stderr2
-rw-r--r--src/test/ui/issues/issue-11844.stderr2
-rw-r--r--src/test/ui/issues/issue-12552.stderr2
-rw-r--r--src/test/ui/issues/issue-13466.stderr5
-rw-r--r--src/test/ui/issues/issue-15896.stderr3
-rw-r--r--src/test/ui/issues/issue-16401.stderr2
-rw-r--r--src/test/ui/issues/issue-3680.stderr2
-rw-r--r--src/test/ui/issues/issue-5100.stderr2
-rw-r--r--src/test/ui/issues/issue-5358-1.stderr2
-rw-r--r--src/test/ui/issues/issue-57472.rs35
-rw-r--r--src/test/ui/issues/issue-57472.stderr20
-rw-r--r--src/test/ui/issues/issue-7092.stderr2
-rw-r--r--src/test/ui/match/match-struct.stderr2
-rw-r--r--src/test/ui/match/match-tag-unary.stderr4
-rw-r--r--src/test/ui/pattern/pattern-error-continue.stderr2
-rw-r--r--src/test/ui/pattern/pattern-tyvar.stderr2
-rw-r--r--src/test/ui/structs/structure-constructor-type-mismatch.stderr6
50 files changed, 419 insertions, 220 deletions
diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs
index 71cacfe3706..501ef01d74c 100644
--- a/src/librustc/dep_graph/graph.rs
+++ b/src/librustc/dep_graph/graph.rs
@@ -696,7 +696,7 @@ impl DepGraph {
 
                 // Promote the previous diagnostics to the current session.
                 tcx.queries.on_disk_cache
-                   .store_diagnostics(dep_node_index, diagnostics.clone());
+                   .store_diagnostics(dep_node_index, diagnostics.clone().into());
 
                 for diagnostic in diagnostics {
                     DiagnosticBuilder::new_diagnostic(handle, diagnostic).emit();
diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index 4cce8343c02..f71cce8273c 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -487,6 +487,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
     fn note_error_origin(&self, err: &mut DiagnosticBuilder<'tcx>, cause: &ObligationCause<'tcx>) {
         match cause.code {
+            ObligationCauseCode::MatchExpressionArmPattern { span, ty } => {
+                if ty.is_suggestable() {  // don't show type `_`
+                    err.span_label(span, format!("this match expression has type `{}`", ty));
+                }
+            }
             ObligationCauseCode::MatchExpressionArm { arm_span, source } => match source {
                 hir::MatchSource::IfLetDesugar { .. } => {
                     let msg = "`if let` arm with an incompatible type";
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 7ce5960b9b3..7d9e80fd60f 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -1444,6 +1444,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         match *cause_code {
             ObligationCauseCode::ExprAssignable |
             ObligationCauseCode::MatchExpressionArm { .. } |
+            ObligationCauseCode::MatchExpressionArmPattern { .. } |
             ObligationCauseCode::IfExpression |
             ObligationCauseCode::IfExpressionWithNoElse |
             ObligationCauseCode::MainFunctionType |
@@ -1451,8 +1452,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             ObligationCauseCode::IntrinsicType |
             ObligationCauseCode::MethodReceiver |
             ObligationCauseCode::ReturnNoExpression |
-            ObligationCauseCode::MiscObligation => {
-            }
+            ObligationCauseCode::MiscObligation => {}
             ObligationCauseCode::SliceOrArrayElem => {
                 err.note("slice and array elements must have `Sized` type");
             }
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index b42d742b7f8..14c25b77a1b 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -220,8 +220,13 @@ pub enum ObligationCauseCode<'tcx> {
     ExprAssignable,
 
     /// Computing common supertype in the arms of a match expression
-    MatchExpressionArm { arm_span: Span,
-                         source: hir::MatchSource },
+    MatchExpressionArm {
+        arm_span: Span,
+        source: hir::MatchSource,
+    },
+
+    /// Computing common supertype in the pattern guard for the arms of a match expression
+    MatchExpressionArmPattern { span: Span, ty: Ty<'tcx> },
 
     /// Computing common supertype in an if expression
     IfExpression,
diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs
index ae2b83e1057..277e2ed0e87 100644
--- a/src/librustc/traits/structural_impls.rs
+++ b/src/librustc/traits/structural_impls.rs
@@ -517,6 +517,9 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
                 arm_span,
                 source: source,
             }),
+            super::MatchExpressionArmPattern { span, ty } => {
+                tcx.lift(&ty).map(|ty| super::MatchExpressionArmPattern { span, ty })
+            }
             super::IfExpression => Some(super::IfExpression),
             super::IfExpressionWithNoElse => Some(super::IfExpressionWithNoElse),
             super::MainFunctionType => Some(super::MainFunctionType),
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 032a1621fe6..d69219efbd8 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -1682,6 +1682,7 @@ impl<'gcx> GlobalCtxt<'gcx> {
             let new_icx = ty::tls::ImplicitCtxt {
                 tcx,
                 query: icx.query.clone(),
+                diagnostics: icx.diagnostics,
                 layout_depth: icx.layout_depth,
                 task_deps: icx.task_deps,
             };
@@ -1792,6 +1793,7 @@ pub mod tls {
     use errors::{Diagnostic, TRACK_DIAGNOSTICS};
     use rustc_data_structures::OnDrop;
     use rustc_data_structures::sync::{self, Lrc, Lock};
+    use rustc_data_structures::thin_vec::ThinVec;
     use dep_graph::TaskDeps;
 
     #[cfg(not(parallel_queries))]
@@ -1811,10 +1813,14 @@ pub mod tls {
         /// by `enter_local` with a new local interner
         pub tcx: TyCtxt<'tcx, 'gcx, 'tcx>,
 
-        /// The current query job, if any. This is updated by start_job in
+        /// The current query job, if any. This is updated by JobOwner::start in
         /// ty::query::plumbing when executing a query
         pub query: Option<Lrc<query::QueryJob<'gcx>>>,
 
+        /// Where to store diagnostics for the current query job, if any.
+        /// This is updated by JobOwner::start in ty::query::plumbing when executing a query
+        pub diagnostics: Option<&'a Lock<ThinVec<Diagnostic>>>,
+
         /// Used to prevent layout from recursing too deeply.
         pub layout_depth: usize,
 
@@ -1880,8 +1886,9 @@ pub mod tls {
     fn track_diagnostic(diagnostic: &Diagnostic) {
         with_context_opt(|icx| {
             if let Some(icx) = icx {
-                if let Some(ref query) = icx.query {
-                    query.diagnostics.lock().push(diagnostic.clone());
+                if let Some(ref diagnostics) = icx.diagnostics {
+                    let mut diagnostics = diagnostics.lock();
+                    diagnostics.extend(Some(diagnostic.clone()));
                 }
             }
         })
@@ -1948,6 +1955,7 @@ pub mod tls {
             let icx = ImplicitCtxt {
                 tcx,
                 query: None,
+                diagnostics: None,
                 layout_depth: 0,
                 task_deps: None,
             };
@@ -1977,6 +1985,7 @@ pub mod tls {
         };
         let icx = ImplicitCtxt {
             query: None,
+            diagnostics: None,
             tcx,
             layout_depth: 0,
             task_deps: None,
diff --git a/src/librustc/ty/query/job.rs b/src/librustc/ty/query/job.rs
index 0063794727f..d794429a8a7 100644
--- a/src/librustc/ty/query/job.rs
+++ b/src/librustc/ty/query/job.rs
@@ -14,7 +14,6 @@ use ty::query::{
     config::QueryDescription,
 };
 use ty::context::TyCtxt;
-use errors::Diagnostic;
 use std::process;
 use std::{fmt, ptr};
 
@@ -54,9 +53,6 @@ pub struct QueryJob<'tcx> {
     /// The parent query job which created this job and is implicitly waiting on it.
     pub parent: Option<Lrc<QueryJob<'tcx>>>,
 
-    /// Diagnostic messages which are emitted while the query executes
-    pub diagnostics: Lock<Vec<Diagnostic>>,
-
     /// The latch which is used to wait on this job
     #[cfg(parallel_queries)]
     latch: QueryLatch<'tcx>,
@@ -66,7 +62,6 @@ impl<'tcx> QueryJob<'tcx> {
     /// Creates a new query job
     pub fn new(info: QueryInfo<'tcx>, parent: Option<Lrc<QueryJob<'tcx>>>) -> Self {
         QueryJob {
-            diagnostics: Lock::new(Vec::new()),
             info,
             parent,
             #[cfg(parallel_queries)]
diff --git a/src/librustc/ty/query/on_disk_cache.rs b/src/librustc/ty/query/on_disk_cache.rs
index 3432aba7ee0..a674e942b38 100644
--- a/src/librustc/ty/query/on_disk_cache.rs
+++ b/src/librustc/ty/query/on_disk_cache.rs
@@ -7,6 +7,7 @@ use ich::{CachingSourceMapView, Fingerprint};
 use mir::{self, interpret};
 use mir::interpret::{AllocDecodingSession, AllocDecodingState};
 use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::thin_vec::ThinVec;
 use rustc_data_structures::sync::{Lrc, Lock, HashMapExt, Once};
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque,
@@ -341,11 +342,13 @@ impl<'sess> OnDiskCache<'sess> {
     /// Store a diagnostic emitted during the current compilation session.
     /// Anything stored like this will be available via `load_diagnostics` in
     /// the next compilation session.
+    #[inline(never)]
+    #[cold]
     pub fn store_diagnostics(&self,
                              dep_node_index: DepNodeIndex,
-                             diagnostics: Vec<Diagnostic>) {
+                             diagnostics: ThinVec<Diagnostic>) {
         let mut current_diagnostics = self.current_diagnostics.borrow_mut();
-        let prev = current_diagnostics.insert(dep_node_index, diagnostics);
+        let prev = current_diagnostics.insert(dep_node_index, diagnostics.into());
         debug_assert!(prev.is_none());
     }
 
@@ -367,16 +370,16 @@ impl<'sess> OnDiskCache<'sess> {
     /// Since many anonymous queries can share the same `DepNode`, we aggregate
     /// them -- as opposed to regular queries where we assume that there is a
     /// 1:1 relationship between query-key and `DepNode`.
+    #[inline(never)]
+    #[cold]
     pub fn store_diagnostics_for_anon_node(&self,
                                            dep_node_index: DepNodeIndex,
-                                           mut diagnostics: Vec<Diagnostic>) {
+                                           diagnostics: ThinVec<Diagnostic>) {
         let mut current_diagnostics = self.current_diagnostics.borrow_mut();
 
-        let x = current_diagnostics.entry(dep_node_index).or_insert_with(|| {
-            mem::replace(&mut diagnostics, Vec::new())
-        });
+        let x = current_diagnostics.entry(dep_node_index).or_insert(Vec::new());
 
-        x.extend(diagnostics.into_iter());
+        x.extend(Into::<Vec<_>>::into(diagnostics));
     }
 
     fn load_indexed<'tcx, T>(&self,
diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs
index af23bf3c590..32d4070dfed 100644
--- a/src/librustc/ty/query/plumbing.rs
+++ b/src/librustc/ty/query/plumbing.rs
@@ -18,6 +18,7 @@ use util::common::{profq_msg, ProfileQueriesMsg, QueryMsg};
 
 use rustc_data_structures::fx::{FxHashMap};
 use rustc_data_structures::sync::{Lrc, Lock};
+use rustc_data_structures::thin_vec::ThinVec;
 use std::mem;
 use std::ptr;
 use std::collections::hash_map::Entry;
@@ -195,19 +196,21 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> {
     pub(super) fn start<'lcx, F, R>(
         &self,
         tcx: TyCtxt<'_, 'tcx, 'lcx>,
+        diagnostics: Option<&Lock<ThinVec<Diagnostic>>>,
         compute: F)
-    -> (R, Vec<Diagnostic>)
+    -> R
     where
         F: for<'b> FnOnce(TyCtxt<'b, 'tcx, 'lcx>) -> R
     {
         // The TyCtxt stored in TLS has the same global interner lifetime
         // as `tcx`, so we use `with_related_context` to relate the 'gcx lifetimes
         // when accessing the ImplicitCtxt
-        let r = tls::with_related_context(tcx, move |current_icx| {
+        tls::with_related_context(tcx, move |current_icx| {
             // Update the ImplicitCtxt to point to our new query job
             let new_icx = tls::ImplicitCtxt {
                 tcx: tcx.global_tcx(),
                 query: Some(self.job.clone()),
+                diagnostics,
                 layout_depth: current_icx.layout_depth,
                 task_deps: current_icx.task_deps,
             };
@@ -216,13 +219,19 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> {
             tls::enter_context(&new_icx, |_| {
                 compute(tcx)
             })
-        });
+        })
+    }
 
-        // Extract the diagnostic from the job
-        let diagnostics = mem::replace(&mut *self.job.diagnostics.lock(), Vec::new());
+}
 
-        (r, diagnostics)
-    }
+#[inline(always)]
+fn with_diagnostics<F, R>(f: F) -> (R, ThinVec<Diagnostic>)
+where
+    F: FnOnce(Option<&Lock<ThinVec<Diagnostic>>>) -> R
+{
+    let diagnostics = Lock::new(ThinVec::new());
+    let result = f(Some(&diagnostics));
+    (result, diagnostics.into_inner())
 }
 
 impl<'a, 'tcx, Q: QueryDescription<'tcx>> Drop for JobOwner<'a, 'tcx, Q> {
@@ -402,20 +411,23 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             profq_msg!(self, ProfileQueriesMsg::ProviderBegin);
             self.sess.profiler(|p| p.start_activity(Q::CATEGORY));
 
-            let res = job.start(self, |tcx| {
-                tcx.dep_graph.with_anon_task(dep_node.kind, || {
-                    Q::compute(tcx.global_tcx(), key)
+            let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| {
+                job.start(self, diagnostics, |tcx| {
+                    tcx.dep_graph.with_anon_task(dep_node.kind, || {
+                        Q::compute(tcx.global_tcx(), key)
+                    })
                 })
             });
 
             self.sess.profiler(|p| p.end_activity(Q::CATEGORY));
             profq_msg!(self, ProfileQueriesMsg::ProviderEnd);
-            let ((result, dep_node_index), diagnostics) = res;
 
             self.dep_graph.read_index(dep_node_index);
 
-            self.queries.on_disk_cache
-                .store_diagnostics_for_anon_node(dep_node_index, diagnostics);
+            if unlikely!(!diagnostics.is_empty()) {
+                self.queries.on_disk_cache
+                    .store_diagnostics_for_anon_node(dep_node_index, diagnostics);
+            }
 
             job.complete(&result, dep_node_index);
 
@@ -487,7 +499,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             // The diagnostics for this query have already been
             // promoted to the current session during
             // try_mark_green(), so we can ignore them here.
-            let (result, _) = job.start(self, |tcx| {
+            let result = job.start(self, None, |tcx| {
                 // The dep-graph for this computation is already in
                 // place
                 tcx.dep_graph.with_ignore(|| {
@@ -566,32 +578,34 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         profq_msg!(self, ProfileQueriesMsg::ProviderBegin);
         self.sess.profiler(|p| p.start_activity(Q::CATEGORY));
 
-        let res = job.start(self, |tcx| {
-            if dep_node.kind.is_eval_always() {
-                tcx.dep_graph.with_eval_always_task(dep_node,
-                                                    tcx,
-                                                    key,
-                                                    Q::compute)
-            } else {
-                tcx.dep_graph.with_task(dep_node,
-                                        tcx,
-                                        key,
-                                        Q::compute)
-            }
+        let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| {
+            job.start(self, diagnostics, |tcx| {
+                if dep_node.kind.is_eval_always() {
+                    tcx.dep_graph.with_eval_always_task(dep_node,
+                                                        tcx,
+                                                        key,
+                                                        Q::compute)
+                } else {
+                    tcx.dep_graph.with_task(dep_node,
+                                            tcx,
+                                            key,
+                                            Q::compute)
+                }
+            })
         });
 
         self.sess.profiler(|p| p.end_activity(Q::CATEGORY));
         profq_msg!(self, ProfileQueriesMsg::ProviderEnd);
 
-        let ((result, dep_node_index), diagnostics) = res;
-
         if unlikely!(self.sess.opts.debugging_opts.query_dep_graph) {
             self.dep_graph.mark_loaded_from_cache(dep_node_index, false);
         }
 
         if dep_node.kind != ::dep_graph::DepKind::Null {
-            self.queries.on_disk_cache
-                .store_diagnostics(dep_node_index, diagnostics);
+            if unlikely!(!diagnostics.is_empty()) {
+                self.queries.on_disk_cache
+                    .store_diagnostics(dep_node_index, diagnostics);
+            }
         }
 
         job.complete(&result, dep_node_index);
diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs
index b25d47b3901..188a1120442 100644
--- a/src/librustc_mir/hair/pattern/_match.rs
+++ b/src/librustc_mir/hair/pattern/_match.rs
@@ -1372,7 +1372,14 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
                     let is_visible = adt.is_enum()
                         || field.vis.is_accessible_from(cx.module, cx.tcx);
                     if is_visible {
-                        field.ty(cx.tcx, substs)
+                        let ty = field.ty(cx.tcx, substs);
+                        match ty.sty {
+                            // If the field type returned is an array of an unknown
+                            // size return an TyErr.
+                            ty::Array(_, len) if len.assert_usize(cx.tcx).is_none() =>
+                                cx.tcx.types.err,
+                            _ => ty,
+                        }
                     } else {
                         // Treat all non-visible fields as TyErr. They
                         // can't appear in any other pattern from
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index b66c383edb5..1767af4870d 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -20,21 +20,33 @@ use std::cmp;
 use super::report_unexpected_variant_def;
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-    /// The `is_arg` argument indicates whether this pattern is the
-    /// *outermost* pattern in an argument (e.g., in `fn foo(&x:
-    /// &u32)`, it is true for the `&x` pattern but not `x`). This is
-    /// used to tailor error reporting.
+    /// `match_discrim_span` argument having a `Span` indicates that this pattern is part of
+    /// a match expression arm guard, and it points to the match discriminant to add context
+    /// in type errors. In the folloowing example, `match_discrim_span` corresponds to the
+    /// `a + b` expression:
+    ///
+    /// ```text
+    /// error[E0308]: mismatched types
+    ///  --> src/main.rs:5:9
+    ///   |
+    /// 4 |    let temp: usize = match a + b {
+    ///   |                            ----- this expression has type `usize`
+    /// 5 |         Ok(num) => num,
+    ///   |         ^^^^^^^ expected usize, found enum `std::result::Result`
+    ///   |
+    ///   = note: expected type `usize`
+    ///              found type `std::result::Result<_, _>`
+    /// ```
     pub fn check_pat_walk(
         &self,
         pat: &'gcx hir::Pat,
         mut expected: Ty<'tcx>,
         mut def_bm: ty::BindingMode,
-        is_arg: bool)
-    {
+        match_discrim_span: Option<Span>,
+    ) {
         let tcx = self.tcx;
 
-        debug!("check_pat_walk(pat={:?},expected={:?},def_bm={:?},is_arg={})",
-            pat, expected, def_bm, is_arg);
+        debug!("check_pat_walk(pat={:?},expected={:?},def_bm={:?})", pat, expected, def_bm);
 
         let is_non_ref_pat = match pat.node {
             PatKind::Struct(..) |
@@ -210,8 +222,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 let common_type = self.resolve_type_vars_if_possible(&lhs_ty);
 
                 // subtyping doesn't matter here, as the value is some kind of scalar
-                self.demand_eqtype(pat.span, expected, lhs_ty);
-                self.demand_eqtype(pat.span, expected, rhs_ty);
+                self.demand_eqtype_pat(pat.span, expected, lhs_ty, match_discrim_span);
+                self.demand_eqtype_pat(pat.span, expected, rhs_ty, match_discrim_span);
                 common_type
             }
             PatKind::Binding(ba, var_id, _, ref sub) => {
@@ -240,13 +252,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         // `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` is
                         // required. However, we use equality, which is stronger. See (*) for
                         // an explanation.
-                        self.demand_eqtype(pat.span, region_ty, local_ty);
+                        self.demand_eqtype_pat(pat.span, region_ty, local_ty, match_discrim_span);
                     }
                     // otherwise the type of x is the expected type T
                     ty::BindByValue(_) => {
                         // As above, `T <: typeof(x)` is required but we
                         // use equality, see (*) below.
-                        self.demand_eqtype(pat.span, expected, local_ty);
+                        self.demand_eqtype_pat(pat.span, expected, local_ty, match_discrim_span);
                     }
                 }
 
@@ -254,23 +266,31 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // what the type of the binding `x` ought to be
                 if var_id != pat.id {
                     let vt = self.local_ty(pat.span, var_id).decl_ty;
-                    self.demand_eqtype(pat.span, vt, local_ty);
+                    self.demand_eqtype_pat(pat.span, vt, local_ty, match_discrim_span);
                 }
 
                 if let Some(ref p) = *sub {
-                    self.check_pat_walk(&p, expected, def_bm, true);
+                    self.check_pat_walk(&p, expected, def_bm, match_discrim_span);
                 }
 
                 local_ty
             }
             PatKind::TupleStruct(ref qpath, ref subpats, ddpos) => {
-                self.check_pat_tuple_struct(pat, qpath, &subpats, ddpos, expected, def_bm)
+                self.check_pat_tuple_struct(
+                    pat,
+                    qpath,
+                    &subpats,
+                    ddpos,
+                    expected,
+                    def_bm,
+                    match_discrim_span,
+                )
             }
             PatKind::Path(ref qpath) => {
                 self.check_pat_path(pat, qpath, expected)
             }
             PatKind::Struct(ref qpath, ref fields, etc) => {
-                self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm)
+                self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm, match_discrim_span)
             }
             PatKind::Tuple(ref elements, ddpos) => {
                 let mut expected_len = elements.len();
@@ -295,12 +315,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     // further errors being emitted when using the bindings. #50333
                     let element_tys_iter = (0..max_len).map(|_| tcx.types.err);
                     for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
-                        self.check_pat_walk(elem, &tcx.types.err, def_bm, true);
+                        self.check_pat_walk(elem, &tcx.types.err, def_bm, match_discrim_span);
                     }
                     tcx.mk_tup(element_tys_iter)
                 } else {
                     for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
-                        self.check_pat_walk(elem, &element_tys[i], def_bm, true);
+                        self.check_pat_walk(elem, &element_tys[i], def_bm, match_discrim_span);
                     }
                     pat_ty
                 }
@@ -313,11 +333,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     // Here, `demand::subtype` is good enough, but I don't
                     // think any errors can be introduced by using
                     // `demand::eqtype`.
-                    self.demand_eqtype(pat.span, expected, uniq_ty);
-                    self.check_pat_walk(&inner, inner_ty, def_bm, true);
+                    self.demand_eqtype_pat(pat.span, expected, uniq_ty, match_discrim_span);
+                    self.check_pat_walk(&inner, inner_ty, def_bm, match_discrim_span);
                     uniq_ty
                 } else {
-                    self.check_pat_walk(&inner, tcx.types.err, def_bm, true);
+                    self.check_pat_walk(&inner, tcx.types.err, def_bm, match_discrim_span);
                     tcx.types.err
                 }
             }
@@ -349,15 +369,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             // Look for a case like `fn foo(&foo: u32)` and suggest
                             // `fn foo(foo: &u32)`
                             if let Some(mut err) = err {
-                                if is_arg {
-                                    if let PatKind::Binding(..) = inner.node {
-                                        if let Ok(snippet) = tcx.sess.source_map()
-                                                                     .span_to_snippet(pat.span)
-                                        {
-                                            err.help(&format!("did you mean `{}: &{}`?",
-                                                              &snippet[1..],
-                                                              expected));
-                                        }
+                                if let PatKind::Binding(..) = inner.node {
+                                    if let Ok(snippet) = tcx.sess.source_map()
+                                                                    .span_to_snippet(pat.span)
+                                    {
+                                        err.help(&format!("did you mean `{}: &{}`?",
+                                                            &snippet[1..],
+                                                            expected));
                                     }
                                 }
                                 err.emit();
@@ -366,10 +384,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         }
                     };
 
-                    self.check_pat_walk(&inner, inner_ty, def_bm, true);
+                    self.check_pat_walk(&inner, inner_ty, def_bm, match_discrim_span);
                     rptr_ty
                 } else {
-                    self.check_pat_walk(&inner, tcx.types.err, def_bm, true);
+                    self.check_pat_walk(&inner, tcx.types.err, def_bm, match_discrim_span);
                     tcx.types.err
                 }
             }
@@ -427,13 +445,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 };
 
                 for elt in before {
-                    self.check_pat_walk(&elt, inner_ty, def_bm, true);
+                    self.check_pat_walk(&elt, inner_ty, def_bm, match_discrim_span);
                 }
                 if let Some(ref slice) = *slice {
-                    self.check_pat_walk(&slice, slice_ty, def_bm, true);
+                    self.check_pat_walk(&slice, slice_ty, def_bm, match_discrim_span);
                 }
                 for elt in after {
-                    self.check_pat_walk(&elt, inner_ty, def_bm, true);
+                    self.check_pat_walk(&elt, inner_ty, def_bm, match_discrim_span);
                 }
                 expected_ty
             }
@@ -524,12 +542,14 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
         true
     }
 
-    pub fn check_match(&self,
-                       expr: &'gcx hir::Expr,
-                       discrim: &'gcx hir::Expr,
-                       arms: &'gcx [hir::Arm],
-                       expected: Expectation<'tcx>,
-                       match_src: hir::MatchSource) -> Ty<'tcx> {
+    pub fn check_match(
+        &self,
+        expr: &'gcx hir::Expr,
+        discrim: &'gcx hir::Expr,
+        arms: &'gcx [hir::Arm],
+        expected: Expectation<'tcx>,
+        match_src: hir::MatchSource,
+    ) -> Ty<'tcx> {
         let tcx = self.tcx;
 
         // Not entirely obvious: if matches may create ref bindings, we want to
@@ -624,8 +644,12 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
             let mut all_pats_diverge = Diverges::WarnedAlways;
             for p in &arm.pats {
                 self.diverges.set(Diverges::Maybe);
-                self.check_pat_walk(&p, discrim_ty,
-                    ty::BindingMode::BindByValue(hir::Mutability::MutImmutable), true);
+                self.check_pat_walk(
+                    &p,
+                    discrim_ty,
+                    ty::BindingMode::BindByValue(hir::Mutability::MutImmutable),
+                    Some(discrim.span),
+                );
                 all_pats_diverge &= self.diverges.get();
             }
 
@@ -703,26 +727,34 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
         coercion.complete(self)
     }
 
-    fn check_pat_struct(&self,
-                        pat: &'gcx hir::Pat,
-                        qpath: &hir::QPath,
-                        fields: &'gcx [Spanned<hir::FieldPat>],
-                        etc: bool,
-                        expected: Ty<'tcx>,
-                        def_bm: ty::BindingMode) -> Ty<'tcx>
+    fn check_pat_struct(
+        &self,
+        pat: &'gcx hir::Pat,
+        qpath: &hir::QPath,
+        fields: &'gcx [Spanned<hir::FieldPat>],
+        etc: bool,
+        expected: Ty<'tcx>,
+        def_bm: ty::BindingMode,
+        match_discrim_span: Option<Span>,
+    ) -> Ty<'tcx>
     {
         // Resolve the path and check the definition for errors.
         let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(qpath, pat.id) {
             variant_ty
         } else {
             for field in fields {
-                self.check_pat_walk(&field.node.pat, self.tcx.types.err, def_bm, true);
+                self.check_pat_walk(
+                    &field.node.pat,
+                    self.tcx.types.err,
+                    def_bm,
+                    match_discrim_span,
+                );
             }
             return self.tcx.types.err;
         };
 
         // Type-check the path.
-        self.demand_eqtype(pat.span, expected, pat_ty);
+        self.demand_eqtype_pat(pat.span, expected, pat_ty, match_discrim_span);
 
         // Type-check subpatterns.
         if self.check_struct_pat_fields(pat_ty, pat.id, pat.span, variant, fields, etc, def_bm) {
@@ -732,11 +764,12 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
         }
     }
 
-    fn check_pat_path(&self,
-                      pat: &hir::Pat,
-                      qpath: &hir::QPath,
-                      expected: Ty<'tcx>) -> Ty<'tcx>
-    {
+    fn check_pat_path(
+        &self,
+        pat: &hir::Pat,
+        qpath: &hir::QPath,
+        expected: Ty<'tcx>,
+    ) -> Ty<'tcx> {
         let tcx = self.tcx;
 
         // Resolve the path and check the definition for errors.
@@ -767,18 +800,20 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
         pat_ty
     }
 
-    fn check_pat_tuple_struct(&self,
-                              pat: &hir::Pat,
-                              qpath: &hir::QPath,
-                              subpats: &'gcx [P<hir::Pat>],
-                              ddpos: Option<usize>,
-                              expected: Ty<'tcx>,
-                              def_bm: ty::BindingMode) -> Ty<'tcx>
-    {
+    fn check_pat_tuple_struct(
+        &self,
+        pat: &hir::Pat,
+        qpath: &hir::QPath,
+        subpats: &'gcx [P<hir::Pat>],
+        ddpos: Option<usize>,
+        expected: Ty<'tcx>,
+        def_bm: ty::BindingMode,
+        match_arm_pat_span: Option<Span>,
+    ) -> Ty<'tcx> {
         let tcx = self.tcx;
         let on_error = || {
             for pat in subpats {
-                self.check_pat_walk(&pat, tcx.types.err, def_bm, true);
+                self.check_pat_walk(&pat, tcx.types.err, def_bm, match_arm_pat_span);
             }
         };
         let report_unexpected_def = |def: Def| {
@@ -826,7 +861,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
         let pat_ty = pat_ty.fn_sig(tcx).output();
         let pat_ty = pat_ty.no_bound_vars().expect("expected fn type");
 
-        self.demand_eqtype(pat.span, expected, pat_ty);
+        self.demand_eqtype_pat(pat.span, expected, pat_ty, match_arm_pat_span);
 
         // Type-check subpatterns.
         if subpats.len() == variant.fields.len() ||
@@ -837,7 +872,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
             };
             for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) {
                 let field_ty = self.field_ty(subpat.span, &variant.fields[i], substs);
-                self.check_pat_walk(&subpat, field_ty, def_bm, true);
+                self.check_pat_walk(&subpat, field_ty, def_bm, match_arm_pat_span);
 
                 self.tcx.check_stability(variant.fields[i].did, Some(pat.id), subpat.span);
             }
@@ -917,7 +952,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
                 }
             };
 
-            self.check_pat_walk(&field.pat, field_ty, def_bm, true);
+            self.check_pat_walk(&field.pat, field_ty, def_bm, None);
         }
         let mut unmentioned_fields = variant.fields
                 .iter()
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index 41f2b0ec7d2..c0cedd77440 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -1,6 +1,6 @@
 use check::FnCtxt;
 use rustc::infer::InferOk;
-use rustc::traits::ObligationCause;
+use rustc::traits::{ObligationCause, ObligationCauseCode};
 
 use syntax::ast;
 use syntax::util::parser::PREC_POSTFIX;
@@ -66,6 +66,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
+    pub fn demand_eqtype_pat(
+        &self,
+        cause_span: Span,
+        expected: Ty<'tcx>,
+        actual: Ty<'tcx>,
+        match_expr_span: Option<Span>,
+    ) {
+        let cause = if let Some(span) = match_expr_span {
+            self.cause(
+                cause_span,
+                ObligationCauseCode::MatchExpressionArmPattern { span, ty: expected },
+            )
+        } else {
+            self.misc(cause_span)
+        };
+        self.demand_eqtype_with_origin(&cause, expected, actual).map(|mut err| err.emit());
+    }
+
+
     pub fn demand_coerce(&self,
                          expr: &hir::Expr,
                          checked_ty: Ty<'tcx>,
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 8790d718f53..dbbb7f42feb 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1092,8 +1092,12 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
     // Add formal parameters.
     for (arg_ty, arg) in fn_sig.inputs().iter().zip(&body.arguments) {
         // Check the pattern.
-        fcx.check_pat_walk(&arg.pat, arg_ty,
-            ty::BindingMode::BindByValue(hir::Mutability::MutImmutable), true);
+        fcx.check_pat_walk(
+            &arg.pat,
+            arg_ty,
+            ty::BindingMode::BindByValue(hir::Mutability::MutImmutable),
+            None,
+        );
 
         // Check that argument is Sized.
         // The check for a non-trivial pattern is a hack to avoid duplicate warnings
@@ -4731,9 +4735,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
         }
 
-        self.check_pat_walk(&local.pat, t,
-                            ty::BindingMode::BindByValue(hir::Mutability::MutImmutable),
-                            true);
+        self.check_pat_walk(
+            &local.pat,
+            t,
+            ty::BindingMode::BindByValue(hir::Mutability::MutImmutable),
+            None,
+        );
         let pat_ty = self.node_ty(local.pat.hir_id);
         if pat_ty.references_error() {
             self.write_ty(local.hir_id, pat_ty);
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index b48951d7593..31e06cb1a04 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -3059,7 +3059,7 @@ fn item_trait(
         let item_type = m.type_();
         let id = cx.derive_id(format!("{}.{}", item_type, name));
         let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
-        write!(w, "{extra}<h3 id='{id}' class='method'><code id='{ns_id}'>",
+        write!(w, "<h3 id='{id}' class='method'>{extra}<code id='{ns_id}'>",
                extra = render_spotlight_traits(m)?,
                id = id,
                ns_id = ns_id)?;
@@ -3444,7 +3444,7 @@ fn item_union(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
             let id = format!("{}.{}", ItemType::StructField, name);
             write!(w, "<span id=\"{id}\" class=\"{shortty} small-section-header\">\
                            <a href=\"#{id}\" class=\"anchor field\"></a>\
-                           <span class='invisible'><code>{name}: {ty}</code></span>\
+                           <code>{name}: {ty}</code>\
                        </span>",
                    id = id,
                    name = name,
@@ -3999,8 +3999,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
             None => "impl".to_string(),
         });
         if let Some(use_absolute) = use_absolute {
-            write!(w, "<h3 id='{}' class='impl'><span class='in-band'><table class='table-display'>\
-                       <tbody><tr><td><code>", id)?;
+            write!(w, "<h3 id='{}' class='impl'><code class='in-band'>", id)?;
             fmt_impl_for_trait_page(&i.inner_impl(), w, use_absolute)?;
             if show_def_docs {
                 for it in &i.inner_impl().items {
@@ -4014,22 +4013,18 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
             }
             write!(w, "</code>")?;
         } else {
-            write!(w, "<h3 id='{}' class='impl'><span class='in-band'><table class='table-display'>\
-                       <tbody><tr><td><code>{}</code>",
-                   id, i.inner_impl())?;
+            write!(w, "<h3 id='{}' class='impl'><code class='in-band'>{}</code>",
+                id, i.inner_impl()
+            )?;
         }
         write!(w, "<a href='#{}' class='anchor'></a>", id)?;
-        write!(w, "</td><td><span class='out-of-band'>")?;
         let since = i.impl_item.stability.as_ref().map(|s| &s.since[..]);
+        render_stability_since_raw(w, since, outer_version)?;
         if let Some(l) = (Item { item: &i.impl_item, cx: cx }).src_href() {
-            write!(w, "<div class='ghost'></div>")?;
-            render_stability_since_raw(w, since, outer_version)?;
             write!(w, "<a class='srclink' href='{}' title='{}'>[src]</a>",
                    l, "goto source code")?;
-        } else {
-            render_stability_since_raw(w, since, outer_version)?;
         }
-        write!(w, "</span></td></tr></tbody></table></span></h3>")?;
+        write!(w, "</h3>")?;
         if let Some(ref dox) = cx.shared.maybe_collapsed_doc_value(&i.impl_item) {
             let mut ids = cx.id_map.borrow_mut();
             write!(w, "<div class='docblock'>{}</div>",
@@ -4065,20 +4060,15 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
                     let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
                     write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?;
                     write!(w, "{}", spotlight_decl(decl)?)?;
-                    write!(w, "<table id='{}' class='table-display'><tbody><tr><td><code>", ns_id)?;
+                    write!(w, "<code id='{}'>", ns_id)?;
                     render_assoc_item(w, item, link.anchor(&id), ItemType::Impl)?;
                     write!(w, "</code>")?;
+                    render_stability_since_raw(w, item.stable_since(), outer_version)?;
                     if let Some(l) = (Item { cx, item }).src_href() {
-                        write!(w, "</td><td><span class='out-of-band'>")?;
-                        write!(w, "<div class='ghost'></div>")?;
-                        render_stability_since_raw(w, item.stable_since(), outer_version)?;
-                        write!(w, "<a class='srclink' href='{}' title='{}'>[src]</a></span>",
+                        write!(w, "<a class='srclink' href='{}' title='{}'>[src]</a>",
                                l, "goto source code")?;
-                    } else {
-                        write!(w, "</td><td>")?;
-                        render_stability_since_raw(w, item.stable_since(), outer_version)?;
                     }
-                    write!(w, "</td></tr></tbody></table></h4>")?;
+                    write!(w, "</h4>")?;
                 }
             }
             clean::TypedefItem(ref tydef, _) => {
@@ -4090,40 +4080,18 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
                 write!(w, "</code></h4>")?;
             }
             clean::AssociatedConstItem(ref ty, ref default) => {
-                let mut version = String::new();
-
-                render_stability_since_raw(&mut version, item.stable_since(), outer_version)?;
-
                 let id = cx.derive_id(format!("{}.{}", item_type, name));
                 let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
                 write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?;
-                if !version.is_empty() {
-                    write!(w, "<table id='{}' class='table-display'><tbody><tr><td><code>", ns_id)?;
-                } else {
-                    write!(w, "<code id='{}'>", ns_id)?;
-                }
+                write!(w, "<code id='{}'>", ns_id)?;
                 assoc_const(w, item, ty, default.as_ref(), link.anchor(&id))?;
-                if !version.is_empty() {
-                    write!(w, "</code>")?;
-                }
-                let src = if let Some(l) = (Item { cx, item }).src_href() {
-                    if !version.is_empty() {
-                        write!(w, "</td><td><span class='out-of-band'>")?;
-                        write!(w, "<div class='ghost'></div>{}", version)?;
-                    }
-                    format!("<a class='srclink' href='{}' title='{}'>[src]</a>",
-                            l, "goto source code")
-                } else {
-                    if !version.is_empty() {
-                        write!(w, "</td><td>{}", version)?;
-                    }
-                    String::new()
-                };
-                if version.is_empty() {
-                    write!(w, "</code>{}</h4>", src)?;
-                } else {
-                    write!(w, "{}</span></td></tr></tbody></table></h4>", src)?;
+                write!(w, "</code>")?;
+                render_stability_since_raw(w, item.stable_since(), outer_version)?;
+                if let Some(l) = (Item { cx, item }).src_href() {
+                    write!(w, "<a class='srclink' href='{}' title='{}'>[src]</a>",
+                            l, "goto source code")?;
                 }
+                write!(w, "</h4>")?;
             }
             clean::AssociatedTypeItem(ref bounds, ref default) => {
                 let id = cx.derive_id(format!("{}.{}", item_type, name));
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index 75b0f5df0d8..9db1c686090 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -2409,8 +2409,17 @@ if (!DOMTokenList.prototype.remove) {
             e.remove();
         });
         onEachLazy(main.childNodes, function(e) {
+            // Unhide the actual content once loading is complete. Headers get
+            // flex treatment for their horizontal layout, divs get block treatment
+            // for vertical layout (column-oriented flex layout for divs caused
+            // errors in mobile browsers).
             if (e.tagName === "H2" || e.tagName === "H3") {
-                e.nextElementSibling.style.display = "block";
+                let nextTagName = e.nextElementSibling.tagName;
+                if (nextTagName == "H2" || nextTagName == "H3") {
+                    e.nextElementSibling.style.display = "flex";
+                } else {
+                    e.nextElementSibling.style.display = "block";
+                }
             }
         });
     }
diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css
index 14273c6b1db..8a8b7adcf7d 100644
--- a/src/librustdoc/html/static/rustdoc.css
+++ b/src/librustdoc/html/static/rustdoc.css
@@ -89,8 +89,9 @@ h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.t
 	border-bottom: 1px solid;
 }
 h3.impl, h3.method, h4.method, h3.type, h4.type, h4.associatedconstant {
+	flex-basis: 100%;
 	font-weight: 600;
-	margin-top: 10px;
+	margin-top: 16px;
 	margin-bottom: 10px;
 	position: relative;
 }
@@ -356,7 +357,8 @@ nav.sub {
 #main > .docblock h3, #main > .docblock h4, #main > .docblock h5 { font-size: 1em; }
 
 #main > h2 + div, #main > h2 + h3, #main > h3 + div {
-	display: none;
+	display: none; /* Changed to flex or block via js once the page is loaded */
+	flex-wrap: wrap;
 }
 
 .docblock h1 { font-size: 1em; }
@@ -390,7 +392,7 @@ h4 > code, h3 > code, .invisible > code {
 }
 
 .in-band, code {
-	z-index: 5;
+	z-index: -5;
 }
 
 .invisible {
@@ -534,6 +536,10 @@ h4 > code, h3 > code, .invisible > code {
 	margin-top: -8px;
 }
 
+.impl-items {
+	flex-basis: 100%;
+}
+
 #main > .stability {
 	margin-top: 0;
 }
@@ -784,6 +790,33 @@ body.blur > :not(#help) {
 	top: 0;
 }
 
+.impl-items .since, .impl .since {
+	flex-grow: 0;
+	padding-left: 12px;
+	padding-right: 2px;
+	position: initial;
+}
+
+.impl-items .srclink, .impl .srclink {
+	flex-grow: 0;
+	/* Override header settings otherwise it's too bold */
+	font-size: 17px;
+	font-weight: normal;
+}
+
+.impl-items code, .impl code {
+	flex-grow: 1;
+}
+
+.impl-items h4, h4.impl, h3.impl {
+	display: flex;
+	flex-basis: 100%;
+	font-size: 16px;
+	margin-bottom: 12px;
+	/* Push the src link out to the right edge consistently */
+	justify-content: space-between;
+}
+
 .variants_table {
 	width: 100%;
 }
@@ -871,15 +904,6 @@ h3 > .collapse-toggle, h4 > .collapse-toggle {
 	margin-left: 20px;
 }
 
-.ghost {
-	display: none;
-}
-
-.ghost + .since {
-	position: initial;
-	display: table-cell;
-}
-
 .since + .srclink {
 	display: table-cell;
 	padding-left: 10px;
@@ -1119,7 +1143,7 @@ span.since {
 	margin-left: 5px;
 	top: -5px;
 	left: 105%;
-	z-index: 1;
+	z-index: 10;
 }
 
 .tooltip:hover .tooltiptext {
@@ -1361,8 +1385,9 @@ h3.important {
 	margin-top: 16px;
 }
 
-.content > .methods > div.important-traits {
+.content > .methods > .method > div.important-traits {
 	position: absolute;
+	font-weight: 400;
 	left: -42px;
 	margin-top: 2px;
 }
diff --git a/src/test/rustdoc/assoc-consts-version.rs b/src/test/rustdoc/assoc-consts-version.rs
index 3f3c2516299..c561269cf9a 100644
--- a/src/test/rustdoc/assoc-consts-version.rs
+++ b/src/test/rustdoc/assoc-consts-version.rs
@@ -10,7 +10,7 @@
 pub struct SomeStruct;
 
 impl SomeStruct {
-    // @has 'foo/struct.SomeStruct.html' '//*[@id="SOME_CONST.v"]//div[@class="since"]' '1.1.2'
+    // @has 'foo/struct.SomeStruct.html' '//*[@id="associatedconstant.SOME_CONST"]//div[@class="since"]' '1.1.2'
     #[stable(since="1.1.2", feature="rust2")]
     pub const SOME_CONST: usize = 0;
 }
diff --git a/src/test/rustdoc/const.rs b/src/test/rustdoc/const.rs
index f3118bb6066..c33db5809cc 100644
--- a/src/test/rustdoc/const.rs
+++ b/src/test/rustdoc/const.rs
@@ -3,7 +3,7 @@
 pub struct Foo;
 
 impl Foo {
-    // @has const/struct.Foo.html '//*[@id="new.v"]//code' 'const unsafe fn new'
+    // @has const/struct.Foo.html '//code[@id="new.v"]' 'const unsafe fn new'
     pub const unsafe fn new() -> Foo {
         Foo
     }
diff --git a/src/test/rustdoc/issue-25001.rs b/src/test/rustdoc/issue-25001.rs
index 3c1580f3786..55d8ee39438 100644
--- a/src/test/rustdoc/issue-25001.rs
+++ b/src/test/rustdoc/issue-25001.rs
@@ -9,17 +9,17 @@ pub trait Bar {
 
 impl Foo<u8> {
     // @has - '//*[@id="method.pass"]//code' 'fn pass()'
-    // @has - '//*[@id="pass.v"]//code' 'fn pass()'
+    // @has - '//code[@id="pass.v"]' 'fn pass()'
     pub fn pass() {}
 }
 impl Foo<u16> {
     // @has - '//*[@id="method.pass-1"]//code' 'fn pass() -> usize'
-    // @has - '//*[@id="pass.v-1"]//code' 'fn pass() -> usize'
+    // @has - '//code[@id="pass.v-1"]' 'fn pass() -> usize'
     pub fn pass() -> usize { 42 }
 }
 impl Foo<u32> {
     // @has - '//*[@id="method.pass-2"]//code' 'fn pass() -> isize'
-    // @has - '//*[@id="pass.v-2"]//code' 'fn pass() -> isize'
+    // @has - '//code[@id="pass.v-2"]' 'fn pass() -> isize'
     pub fn pass() -> isize { 42 }
 }
 
diff --git a/src/test/rustdoc/issue-51236.rs b/src/test/rustdoc/issue-51236.rs
index b57a067f3d9..d9accf9c599 100644
--- a/src/test/rustdoc/issue-51236.rs
+++ b/src/test/rustdoc/issue-51236.rs
@@ -7,7 +7,7 @@ pub mod traits {
 }
 
 // @has issue_51236/struct.Owned.html
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl<T> Send for \
+// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<T> Send for \
 // Owned<T> where <T as Owned<'static>>::Reader: Send"
 pub struct Owned<T> where T: for<'a> ::traits::Owned<'a> {
     marker: PhantomData<<T as ::traits::Owned<'static>>::Reader>,
diff --git a/src/test/rustdoc/issue-54705.rs b/src/test/rustdoc/issue-54705.rs
index 34f71fab0cc..263b1eb0bd6 100644
--- a/src/test/rustdoc/issue-54705.rs
+++ b/src/test/rustdoc/issue-54705.rs
@@ -3,10 +3,10 @@ pub trait ScopeHandle<'scope> {}
 
 
 // @has issue_54705/struct.ScopeFutureContents.html
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl<'scope, S> \
+// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'scope, S> \
 // Send for ScopeFutureContents<'scope, S> where S: Sync"
 //
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl<'scope, S> \
+// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'scope, S> \
 // Sync for ScopeFutureContents<'scope, S> where S: Sync"
 pub struct ScopeFutureContents<'scope, S>
     where S: ScopeHandle<'scope>,
diff --git a/src/test/rustdoc/issue-55321.rs b/src/test/rustdoc/issue-55321.rs
index 5c34a4d34ab..257cb32c65c 100644
--- a/src/test/rustdoc/issue-55321.rs
+++ b/src/test/rustdoc/issue-55321.rs
@@ -1,16 +1,16 @@
 #![feature(optin_builtin_traits)]
 
 // @has issue_55321/struct.A.html
-// @has - '//*[@id="implementations-list"]/*[@class="impl"]//*/code' "impl !Send for A"
-// @has - '//*[@id="implementations-list"]/*[@class="impl"]//*/code' "impl !Sync for A"
+// @has - '//*[@id="implementations-list"]/*[@class="impl"]//code' "impl !Send for A"
+// @has - '//*[@id="implementations-list"]/*[@class="impl"]//code' "impl !Sync for A"
 pub struct A();
 
 impl !Send for A {}
 impl !Sync for A {}
 
 // @has issue_55321/struct.B.html
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl<T> !Send for \
+// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<T> !Send for \
 // B<T>"
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl<T> !Sync for \
+// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<T> !Sync for \
 // B<T>"
 pub struct B<T: ?Sized>(A, Box<T>);
diff --git a/src/test/rustdoc/issue-56822.rs b/src/test/rustdoc/issue-56822.rs
index 2d6cb1368d1..5b67817fa4c 100644
--- a/src/test/rustdoc/issue-56822.rs
+++ b/src/test/rustdoc/issue-56822.rs
@@ -17,7 +17,7 @@ impl<'a, T> MyTrait for Inner<'a, T> {
 }
 
 // @has issue_56822/struct.Parser.html
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl<'a> Send for \
+// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'a> Send for \
 // Parser<'a>"
 pub struct Parser<'a> {
     field: <Wrapper<Inner<'a, u8>> as MyTrait>::Output
diff --git a/src/test/rustdoc/synthetic_auto/complex.rs b/src/test/rustdoc/synthetic_auto/complex.rs
index d2533a2dd39..609cefc7115 100644
--- a/src/test/rustdoc/synthetic_auto/complex.rs
+++ b/src/test/rustdoc/synthetic_auto/complex.rs
@@ -20,7 +20,7 @@ mod foo {
 }
 
 // @has complex/struct.NotOuter.html
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl<'a, T, K: \
+// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'a, T, K: \
 // ?Sized> Send for NotOuter<'a, T, K> where K: for<'b> Fn((&'b bool, &'a u8)) \
 // -> &'b i8, T: MyTrait<'a>, <T as MyTrait<'a>>::MyItem: Copy, 'a: 'static"
 
diff --git a/src/test/rustdoc/synthetic_auto/lifetimes.rs b/src/test/rustdoc/synthetic_auto/lifetimes.rs
index 03b84c7838e..6d0a68f9b07 100644
--- a/src/test/rustdoc/synthetic_auto/lifetimes.rs
+++ b/src/test/rustdoc/synthetic_auto/lifetimes.rs
@@ -9,10 +9,10 @@ where
 {}
 
 // @has lifetimes/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl<'c, K> Send \
+// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'c, K> Send \
 // for Foo<'c, K> where K: for<'b> Fn(&'b bool) -> &'c u8, 'c: 'static"
 //
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl<'c, K> Sync \
+// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'c, K> Sync \
 // for Foo<'c, K> where K: Sync"
 pub struct Foo<'c, K: 'c> {
     inner_field: Inner<'c, K>,
diff --git a/src/test/rustdoc/synthetic_auto/manual.rs b/src/test/rustdoc/synthetic_auto/manual.rs
index c7cfa0c0fa1..413ba187f45 100644
--- a/src/test/rustdoc/synthetic_auto/manual.rs
+++ b/src/test/rustdoc/synthetic_auto/manual.rs
@@ -1,8 +1,8 @@
 // @has manual/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' 'impl<T> Sync for \
+// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' 'impl<T> Sync for \
 // Foo<T> where T: Sync'
 //
-// @has - '//*[@id="implementations-list"]/*[@class="impl"]//*/code' \
+// @has - '//*[@id="implementations-list"]/*[@class="impl"]//code' \
 // 'impl<T> Send for Foo<T>'
 //
 // @count - '//*[@id="implementations-list"]/*[@class="impl"]' 1
diff --git a/src/test/rustdoc/synthetic_auto/negative.rs b/src/test/rustdoc/synthetic_auto/negative.rs
index 5b6304ed4e4..30713849da2 100644
--- a/src/test/rustdoc/synthetic_auto/negative.rs
+++ b/src/test/rustdoc/synthetic_auto/negative.rs
@@ -3,10 +3,10 @@ pub struct Inner<T: Copy> {
 }
 
 // @has negative/struct.Outer.html
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl<T> !Send for \
+// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<T> !Send for \
 // Outer<T>"
 //
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl<T> \
+// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<T> \
 // !Sync for Outer<T>"
 pub struct Outer<T: Copy> {
     inner_field: Inner<T>,
diff --git a/src/test/rustdoc/synthetic_auto/nested.rs b/src/test/rustdoc/synthetic_auto/nested.rs
index 75d2ff2af13..e710ce1c2ed 100644
--- a/src/test/rustdoc/synthetic_auto/nested.rs
+++ b/src/test/rustdoc/synthetic_auto/nested.rs
@@ -9,10 +9,10 @@ where
 }
 
 // @has nested/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' 'impl<T> Send for \
+// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' 'impl<T> Send for \
 // Foo<T> where T: Copy'
 //
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' \
+// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' \
 // 'impl<T> Sync for Foo<T> where T: Sync'
 pub struct Foo<T> {
     inner_field: Inner<T>,
diff --git a/src/test/rustdoc/synthetic_auto/no-redundancy.rs b/src/test/rustdoc/synthetic_auto/no-redundancy.rs
index 92402714b9d..cf173111ec1 100644
--- a/src/test/rustdoc/synthetic_auto/no-redundancy.rs
+++ b/src/test/rustdoc/synthetic_auto/no-redundancy.rs
@@ -9,7 +9,7 @@ where
 }
 
 // @has no_redundancy/struct.Outer.html
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl<T> Send for \
+// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<T> Send for \
 // Outer<T> where T: Copy + Send"
 pub struct Outer<T> {
     inner_field: Inner<T>,
diff --git a/src/test/rustdoc/synthetic_auto/project.rs b/src/test/rustdoc/synthetic_auto/project.rs
index 6be6b44a440..5346521f8d2 100644
--- a/src/test/rustdoc/synthetic_auto/project.rs
+++ b/src/test/rustdoc/synthetic_auto/project.rs
@@ -23,10 +23,10 @@ where
 }
 
 // @has project/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl<'c, K> Send \
+// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'c, K> Send \
 // for Foo<'c, K> where K: MyTrait<MyItem = bool>, 'c: 'static"
 //
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl<'c, K> Sync \
+// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'c, K> Sync \
 // for Foo<'c, K> where K: MyTrait, <K as MyTrait>::MyItem: OtherTrait, 'c: 'static,"
 pub struct Foo<'c, K: 'c> {
     inner_field: Inner<'c, K>,
diff --git a/src/test/rustdoc/synthetic_auto/self-referential.rs b/src/test/rustdoc/synthetic_auto/self-referential.rs
index 0dca8fe2978..7d15434afe6 100644
--- a/src/test/rustdoc/synthetic_auto/self-referential.rs
+++ b/src/test/rustdoc/synthetic_auto/self-referential.rs
@@ -23,7 +23,7 @@ impl<T> Pattern for Wrapper<T> {
 
 
 // @has self_referential/struct.WriteAndThen.html
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl<P1> Send for \
+// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<P1> Send for \
 // WriteAndThen<P1>  where  <P1 as Pattern>::Value: Send"
 pub struct WriteAndThen<P1>(pub P1::Value,pub <Constrain<P1, Wrapper<P1::Value>> as Pattern>::Value)
     where P1: Pattern;
diff --git a/src/test/rustdoc/synthetic_auto/static-region.rs b/src/test/rustdoc/synthetic_auto/static-region.rs
index d1d50fbc6ba..59493744b62 100644
--- a/src/test/rustdoc/synthetic_auto/static-region.rs
+++ b/src/test/rustdoc/synthetic_auto/static-region.rs
@@ -3,7 +3,7 @@ pub trait OwnedTrait<'a> {
 }
 
 // @has static_region/struct.Owned.html
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//*/code' "impl<T> Send for \
+// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<T> Send for \
 // Owned<T> where <T as OwnedTrait<'static>>::Reader: Send"
 pub struct Owned<T> where T: OwnedTrait<'static> {
     marker: <T as OwnedTrait<'static>>::Reader,
diff --git a/src/test/ui/block-result/issue-13624.stderr b/src/test/ui/block-result/issue-13624.stderr
index b38633b0ffe..417667a5354 100644
--- a/src/test/ui/block-result/issue-13624.stderr
+++ b/src/test/ui/block-result/issue-13624.stderr
@@ -12,6 +12,8 @@ LL |     Enum::EnumStructVariant { x: 1, y: 2, z: 3 }
 error[E0308]: mismatched types
   --> $DIR/issue-13624.rs:22:9
    |
+LL |       match enum_struct_variant {
+   |             ------------------- this match expression has type `()`
 LL |         a::Enum::EnumStructVariant { x, y, z } => {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found enum `a::Enum`
    |
diff --git a/src/test/ui/error-codes/E0308-4.stderr b/src/test/ui/error-codes/E0308-4.stderr
index 8117bc754b6..f69a3893365 100644
--- a/src/test/ui/error-codes/E0308-4.stderr
+++ b/src/test/ui/error-codes/E0308-4.stderr
@@ -1,6 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/E0308-4.rs:4:9
    |
+LL |     match x {
+   |           - this match expression has type `u8`
 LL |         0u8..=3i8 => (), //~ ERROR E0308
    |         ^^^^^^^^^ expected u8, found i8
 
diff --git a/src/test/ui/issues/issue-11844.stderr b/src/test/ui/issues/issue-11844.stderr
index 05d2685958e..683ad48ff52 100644
--- a/src/test/ui/issues/issue-11844.stderr
+++ b/src/test/ui/issues/issue-11844.stderr
@@ -1,6 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/issue-11844.rs:6:9
    |
+LL |     match a {
+   |           - this match expression has type `std::option::Option<std::boxed::Box<{integer}>>`
 LL |         Ok(a) => //~ ERROR: mismatched types
    |         ^^^^^ expected enum `std::option::Option`, found enum `std::result::Result`
    |
diff --git a/src/test/ui/issues/issue-12552.stderr b/src/test/ui/issues/issue-12552.stderr
index ca5efcdc472..768d11bf899 100644
--- a/src/test/ui/issues/issue-12552.stderr
+++ b/src/test/ui/issues/issue-12552.stderr
@@ -1,6 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/issue-12552.rs:6:5
    |
+LL |   match t {
+   |         - this match expression has type `std::result::Result<_, {integer}>`
 LL |     Some(k) => match k { //~ ERROR mismatched types
    |     ^^^^^^^ expected enum `std::result::Result`, found enum `std::option::Option`
    |
diff --git a/src/test/ui/issues/issue-13466.stderr b/src/test/ui/issues/issue-13466.stderr
index 2f60070337b..66255891f46 100644
--- a/src/test/ui/issues/issue-13466.stderr
+++ b/src/test/ui/issues/issue-13466.stderr
@@ -1,6 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/issue-13466.rs:8:9
    |
+LL |     let _x: usize = match Some(1) {
+   |                           ------- this match expression has type `std::option::Option<{integer}>`
 LL |         Ok(u) => u,
    |         ^^^^^ expected enum `std::option::Option`, found enum `std::result::Result`
    |
@@ -10,6 +12,9 @@ LL |         Ok(u) => u,
 error[E0308]: mismatched types
   --> $DIR/issue-13466.rs:14:9
    |
+LL |     let _x: usize = match Some(1) {
+   |                           ------- this match expression has type `std::option::Option<{integer}>`
+...
 LL |         Err(e) => panic!(e)
    |         ^^^^^^ expected enum `std::option::Option`, found enum `std::result::Result`
    |
diff --git a/src/test/ui/issues/issue-15896.stderr b/src/test/ui/issues/issue-15896.stderr
index cd629841fee..de9757d5d32 100644
--- a/src/test/ui/issues/issue-15896.stderr
+++ b/src/test/ui/issues/issue-15896.stderr
@@ -1,6 +1,9 @@
 error[E0308]: mismatched types
   --> $DIR/issue-15896.rs:11:11
    |
+LL |     let u = match e {
+   |                   - this match expression has type `main::R`
+LL |         E::B(
 LL |           Tau{t: x},
    |           ^^^^^^^^^ expected enum `main::R`, found struct `main::Tau`
    |
diff --git a/src/test/ui/issues/issue-16401.stderr b/src/test/ui/issues/issue-16401.stderr
index a1cf6c98705..1779d0befd8 100644
--- a/src/test/ui/issues/issue-16401.stderr
+++ b/src/test/ui/issues/issue-16401.stderr
@@ -1,6 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/issue-16401.rs:8:9
    |
+LL |     match () {
+   |           -- this match expression has type `()`
 LL |         Slice { data: data, len: len } => (),
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found struct `Slice`
    |
diff --git a/src/test/ui/issues/issue-3680.stderr b/src/test/ui/issues/issue-3680.stderr
index 78c3f92fb53..51903cfadab 100644
--- a/src/test/ui/issues/issue-3680.stderr
+++ b/src/test/ui/issues/issue-3680.stderr
@@ -1,6 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/issue-3680.rs:3:9
    |
+LL |     match None {
+   |           ---- this match expression has type `std::option::Option<_>`
 LL |         Err(_) => ()
    |         ^^^^^^ expected enum `std::option::Option`, found enum `std::result::Result`
    |
diff --git a/src/test/ui/issues/issue-5100.stderr b/src/test/ui/issues/issue-5100.stderr
index a6f6229fe78..0a918a78970 100644
--- a/src/test/ui/issues/issue-5100.stderr
+++ b/src/test/ui/issues/issue-5100.stderr
@@ -28,6 +28,8 @@ LL |         (true, false, false) => ()
 error[E0308]: mismatched types
   --> $DIR/issue-5100.rs:33:9
    |
+LL |     match (true, false) {
+   |           ------------- this match expression has type `(bool, bool)`
 LL |         box (true, false) => ()
    |         ^^^^^^^^^^^^^^^^^ expected tuple, found struct `std::boxed::Box`
    |
diff --git a/src/test/ui/issues/issue-5358-1.stderr b/src/test/ui/issues/issue-5358-1.stderr
index dbbafb38e65..649a0c1581a 100644
--- a/src/test/ui/issues/issue-5358-1.stderr
+++ b/src/test/ui/issues/issue-5358-1.stderr
@@ -1,6 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/issue-5358-1.rs:6:9
    |
+LL |     match S(Either::Left(5)) {
+   |           ------------------ this match expression has type `S`
 LL |         Either::Right(_) => {}
    |         ^^^^^^^^^^^^^^^^ expected struct `S`, found enum `Either`
    |
diff --git a/src/test/ui/issues/issue-57472.rs b/src/test/ui/issues/issue-57472.rs
new file mode 100644
index 00000000000..1131006374c
--- /dev/null
+++ b/src/test/ui/issues/issue-57472.rs
@@ -0,0 +1,35 @@
+#![crate_type="lib"]
+#![deny(unreachable_patterns)]
+
+mod test_struct {
+    // Test the exact copy of the minimal example
+    // posted in the issue.
+    pub struct Punned {
+        foo: [u8; 1],
+        bar: [u8; 1],
+    }
+
+    pub fn test(punned: Punned) {
+        match punned {
+            Punned { foo: [_], .. } => println!("foo"),
+            Punned { bar: [_], .. } => println!("bar"),
+            //~^ ERROR unreachable pattern [unreachable_patterns]
+        }
+    }
+}
+
+mod test_union {
+    // Test the same thing using a union.
+    pub union Punned {
+        foo: [u8; 1],
+        bar: [u8; 1],
+    }
+
+    pub fn test(punned: Punned) {
+        match punned {
+            Punned { foo: [_] } => println!("foo"),
+            Punned { bar: [_] } => println!("bar"),
+            //~^ ERROR unreachable pattern [unreachable_patterns]
+        }
+    }
+}
diff --git a/src/test/ui/issues/issue-57472.stderr b/src/test/ui/issues/issue-57472.stderr
new file mode 100644
index 00000000000..b6dd7e24941
--- /dev/null
+++ b/src/test/ui/issues/issue-57472.stderr
@@ -0,0 +1,20 @@
+error: unreachable pattern
+  --> $DIR/issue-57472.rs:15:13
+   |
+LL |             Punned { bar: [_], .. } => println!("bar"),
+   |             ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: lint level defined here
+  --> $DIR/issue-57472.rs:2:9
+   |
+LL | #![deny(unreachable_patterns)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/issue-57472.rs:31:13
+   |
+LL |             Punned { bar: [_] } => println!("bar"),
+   |             ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/issues/issue-7092.stderr b/src/test/ui/issues/issue-7092.stderr
index aa24182e3a3..7bb68202874 100644
--- a/src/test/ui/issues/issue-7092.stderr
+++ b/src/test/ui/issues/issue-7092.stderr
@@ -1,6 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/issue-7092.rs:6:9
    |
+LL |     match x {
+   |           - this match expression has type `Whatever`
 LL |         Some(field) =>
    |         ^^^^^^^^^^^ expected enum `Whatever`, found enum `std::option::Option`
    |
diff --git a/src/test/ui/match/match-struct.stderr b/src/test/ui/match/match-struct.stderr
index bad41485a53..2a24a293e98 100644
--- a/src/test/ui/match/match-struct.stderr
+++ b/src/test/ui/match/match-struct.stderr
@@ -1,6 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/match-struct.rs:6:9
    |
+LL |     match (S { a: 1 }) {
+   |           ------------ this match expression has type `S`
 LL |         E::C(_) => (),
    |         ^^^^^^^ expected struct `S`, found enum `E`
    |
diff --git a/src/test/ui/match/match-tag-unary.stderr b/src/test/ui/match/match-tag-unary.stderr
index c90029b2fa1..53b66351369 100644
--- a/src/test/ui/match/match-tag-unary.stderr
+++ b/src/test/ui/match/match-tag-unary.stderr
@@ -2,7 +2,9 @@ error[E0308]: mismatched types
   --> $DIR/match-tag-unary.rs:4:43
    |
 LL | fn main() { let x: A = A::A(0); match x { B::B(y) => { } } } //~ ERROR mismatched types
-   |                                           ^^^^^^^ expected enum `A`, found enum `B`
+   |                                       -   ^^^^^^^ expected enum `A`, found enum `B`
+   |                                       |
+   |                                       this match expression has type `A`
    |
    = note: expected type `A`
               found type `B`
diff --git a/src/test/ui/pattern/pattern-error-continue.stderr b/src/test/ui/pattern/pattern-error-continue.stderr
index c17d4b70f0b..c2810d764c2 100644
--- a/src/test/ui/pattern/pattern-error-continue.stderr
+++ b/src/test/ui/pattern/pattern-error-continue.stderr
@@ -21,6 +21,8 @@ LL |         A::B(_, _, _) => (), //~ ERROR this pattern has 3 fields, but
 error[E0308]: mismatched types
   --> $DIR/pattern-error-continue.rs:22:9
    |
+LL |     match 'c' {
+   |           --- this match expression has type `char`
 LL |         S { .. } => (),
    |         ^^^^^^^^ expected char, found struct `S`
    |
diff --git a/src/test/ui/pattern/pattern-tyvar.stderr b/src/test/ui/pattern/pattern-tyvar.stderr
index dae17fa5166..69cd552aabd 100644
--- a/src/test/ui/pattern/pattern-tyvar.stderr
+++ b/src/test/ui/pattern/pattern-tyvar.stderr
@@ -1,6 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/pattern-tyvar.rs:5:18
    |
+LL |     match t {
+   |           - this match expression has type `std::option::Option<std::vec::Vec<isize>>`
 LL |       Bar::T1(_, Some::<isize>(x)) => { //~ ERROR mismatched types
    |                  ^^^^^^^^^^^^^^^^ expected struct `std::vec::Vec`, found isize
    |
diff --git a/src/test/ui/structs/structure-constructor-type-mismatch.stderr b/src/test/ui/structs/structure-constructor-type-mismatch.stderr
index 3c1ed8e69a6..cc62316bec1 100644
--- a/src/test/ui/structs/structure-constructor-type-mismatch.stderr
+++ b/src/test/ui/structs/structure-constructor-type-mismatch.stderr
@@ -109,6 +109,8 @@ LL |         PointF::<u32> { .. } => {} //~ ERROR wrong number of type arguments
 error[E0308]: mismatched types
   --> $DIR/structure-constructor-type-mismatch.rs:54:9
    |
+LL |     match (Point { x: 1, y: 2 }) {
+   |           ---------------------- this match expression has type `Point<{integer}>`
 LL |         PointF::<u32> { .. } => {} //~ ERROR wrong number of type arguments
    |         ^^^^^^^^^^^^^^^^^^^^ expected integer, found f32
    |
@@ -118,6 +120,8 @@ LL |         PointF::<u32> { .. } => {} //~ ERROR wrong number of type arguments
 error[E0308]: mismatched types
   --> $DIR/structure-constructor-type-mismatch.rs:59:9
    |
+LL |     match (Point { x: 1, y: 2 }) {
+   |           ---------------------- this match expression has type `Point<{integer}>`
 LL |         PointF { .. } => {} //~ ERROR mismatched types
    |         ^^^^^^^^^^^^^ expected integer, found f32
    |
@@ -127,6 +131,8 @@ LL |         PointF { .. } => {} //~ ERROR mismatched types
 error[E0308]: mismatched types
   --> $DIR/structure-constructor-type-mismatch.rs:67:9
    |
+LL |     match (Pair { x: 1, y: 2 }) {
+   |           --------------------- this match expression has type `Pair<{integer}, {integer}>`
 LL |         PairF::<u32> { .. } => {} //~ ERROR mismatched types
    |         ^^^^^^^^^^^^^^^^^^^ expected integer, found f32
    |