about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2017-05-08 19:45:27 +0300
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2017-06-14 23:33:47 +0300
commit7b9519a5d47879c37f0ac6871cee2e1cb8eca1cc (patch)
tree1b8bb3473a2bb99d18f8a84e2a1ae5643672a8aa
parentdfa7e21e4ee555d04c0fb86069f5acffee3550ad (diff)
downloadrust-7b9519a5d47879c37f0ac6871cee2e1cb8eca1cc.tar.gz
rust-7b9519a5d47879c37f0ac6871cee2e1cb8eca1cc.zip
suppress trait errors that are implied by other errors
Instead of suppressing only trait errors that are "exact duplicates",
display only the "most high-level" error when there are multiple trait
errors with the same span that imply each-other.

e.g. when there are both `[closure]: Fn` and `[closure]: FnOnce`, omit
displaying the `[closure]: FnOnce` bound.
-rw-r--r--src/librustc/infer/error_reporting/mod.rs1
-rw-r--r--src/librustc/infer/error_reporting/need_type_info.rs153
-rw-r--r--src/librustc/infer/mod.rs7
-rw-r--r--src/librustc/traits/error_reporting.rs246
-rw-r--r--src/librustc/traits/mod.rs1
-rw-r--r--src/librustc_driver/lib.rs5
-rw-r--r--src/test/compile-fail/extern-wrong-value-type.rs1
-rw-r--r--src/test/compile-fail/fn-trait-formatting.rs1
-rw-r--r--src/test/compile-fail/issue-22034.rs1
-rw-r--r--src/test/compile-fail/issue-23966.rs1
-rw-r--r--src/test/compile-fail/range_traits-1.rs31
-rw-r--r--src/test/compile-fail/str-mut-idx.rs3
-rw-r--r--src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs2
-rw-r--r--src/test/compile-fail/unboxed-closures-wrong-abi.rs2
-rw-r--r--src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs2
-rw-r--r--src/test/compile-fail/unsized6.rs12
-rw-r--r--src/test/ui/mismatched_types/E0281.stderr11
-rw-r--r--src/test/ui/mismatched_types/binops.stderr8
-rw-r--r--src/test/ui/mismatched_types/closure-arg-count.stderr24
-rw-r--r--src/test/ui/mismatched_types/issue-36053-2.stderr9
-rw-r--r--src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.rs1
-rw-r--r--src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr14
-rw-r--r--src/test/ui/type-check/issue-40294.stderr6
23 files changed, 277 insertions, 265 deletions
diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index 0515e1cc304..11bac21bc42 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -74,6 +74,7 @@ use syntax_pos::{Pos, Span};
 use errors::{DiagnosticBuilder, DiagnosticStyledString};
 
 mod note;
+mod need_type_info;
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn note_and_explain_region(self,
diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs
new file mode 100644
index 00000000000..7361d66428f
--- /dev/null
+++ b/src/librustc/infer/error_reporting/need_type_info.rs
@@ -0,0 +1,153 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use hir::{self, map, Local, Pat, Body};
+use hir::intravisit::{self, Visitor, NestedVisitorMap};
+use infer::InferCtxt;
+use infer::type_variable::TypeVariableOrigin;
+use ty::{self, Ty, TyInfer, TyVar};
+
+use syntax::ast::NodeId;
+use syntax_pos::Span;
+
+struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
+    infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+    target_ty: &'a Ty<'tcx>,
+    hir_map: &'a hir::map::Map<'gcx>,
+    found_local_pattern: Option<&'gcx Pat>,
+    found_arg_pattern: Option<&'gcx Pat>,
+}
+
+impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
+    fn node_matches_type(&mut self, node_id: NodeId) -> bool {
+        let ty_opt = self.infcx.in_progress_tables.and_then(|tables| {
+            tables.borrow().node_id_to_type_opt(node_id)
+        });
+        match ty_opt {
+            Some(ty) => {
+                let ty = self.infcx.resolve_type_vars_if_possible(&ty);
+                ty.walk().any(|inner_ty| {
+                    inner_ty == *self.target_ty || match (&inner_ty.sty, &self.target_ty.sty) {
+                        (&TyInfer(TyVar(a_vid)), &TyInfer(TyVar(b_vid))) => {
+                            self.infcx
+                                .type_variables
+                                .borrow_mut()
+                                .sub_unified(a_vid, b_vid)
+                        }
+                        _ => false,
+                    }
+                })
+            }
+            None => false,
+        }
+    }
+}
+
+impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
+        NestedVisitorMap::OnlyBodies(&self.hir_map)
+    }
+
+    fn visit_local(&mut self, local: &'gcx Local) {
+        if self.found_local_pattern.is_none() && self.node_matches_type(local.id) {
+            self.found_local_pattern = Some(&*local.pat);
+        }
+        intravisit::walk_local(self, local);
+    }
+
+    fn visit_body(&mut self, body: &'gcx Body) {
+        for argument in &body.arguments {
+            if self.found_arg_pattern.is_none() && self.node_matches_type(argument.id) {
+                self.found_arg_pattern = Some(&*argument.pat);
+            }
+        }
+        intravisit::walk_body(self, body);
+    }
+}
+
+
+impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
+    fn extract_type_name(&self, ty: &'a Ty<'tcx>) -> String {
+        if let ty::TyInfer(ty::TyVar(ty_vid)) = (*ty).sty {
+            let ty_vars = self.type_variables.borrow();
+            if let TypeVariableOrigin::TypeParameterDefinition(_, name) =
+                *ty_vars.var_origin(ty_vid) {
+                name.to_string()
+            } else {
+                ty.to_string()
+            }
+        } else {
+            ty.to_string()
+        }
+    }
+
+    pub fn need_type_info(&self, body_id: hir::BodyId, span: Span, ty: Ty<'tcx>) {
+        let ty = self.resolve_type_vars_if_possible(&ty);
+        let name = self.extract_type_name(&ty);
+
+        let mut err_span = span;
+        let mut labels = vec![(span, format!("cannot infer type for `{}`", name))];
+
+        let mut local_visitor = FindLocalByTypeVisitor {
+            infcx: &self,
+            target_ty: &ty,
+            hir_map: &self.tcx.hir,
+            found_local_pattern: None,
+            found_arg_pattern: None,
+        };
+
+        // #40294: cause.body_id can also be a fn declaration.
+        // Currently, if it's anything other than NodeExpr, we just ignore it
+        match self.tcx.hir.find(body_id.node_id) {
+            Some(map::NodeExpr(expr)) => local_visitor.visit_expr(expr),
+            _ => ()
+        }
+
+        if let Some(pattern) = local_visitor.found_arg_pattern {
+            err_span = pattern.span;
+            // We don't want to show the default label for closures.
+            //
+            // So, before clearing, the output would look something like this:
+            // ```
+            // let x = |_| {  };
+            //          -  ^^^^ cannot infer type for `[_; 0]`
+            //          |
+            //          consider giving this closure parameter a type
+            // ```
+            //
+            // After clearing, it looks something like this:
+            // ```
+            // let x = |_| {  };
+            //          ^ consider giving this closure parameter a type
+            // ```
+            labels.clear();
+            labels.push((pattern.span, format!("consider giving this closure parameter a type")));
+        }
+
+        if let Some(pattern) = local_visitor.found_local_pattern {
+            if let Some(simple_name) = pattern.simple_name() {
+                labels.push((pattern.span, format!("consider giving `{}` a type", simple_name)));
+            } else {
+                labels.push((pattern.span, format!("consider giving the pattern a type")));
+            }
+        }
+
+        let mut err = struct_span_err!(self.tcx.sess,
+                                       err_span,
+                                       E0282,
+                                       "type annotations needed");
+
+        for (target_span, label_message) in labels {
+            err.span_label(target_span, label_message);
+        }
+
+        err.emit();
+    }
+}
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 4bc0005d568..f96e8c389d6 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -36,7 +36,7 @@ use std::fmt;
 use syntax::ast;
 use errors::DiagnosticBuilder;
 use syntax_pos::{self, Span, DUMMY_SP};
-use util::nodemap::{FxHashMap, FxHashSet};
+use util::nodemap::FxHashMap;
 use arena::DroplessArena;
 
 use self::combine::CombineFields;
@@ -110,7 +110,7 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 
     // the set of predicates on which errors have been reported, to
     // avoid reporting the same error twice.
-    pub reported_trait_errors: RefCell<FxHashSet<traits::TraitErrorKey<'tcx>>>,
+    pub reported_trait_errors: RefCell<FxHashMap<Span, Vec<ty::Predicate<'tcx>>>>,
 
     // When an error occurs, we want to avoid reporting "derived"
     // errors that are due to this original failure. Normally, we
@@ -350,6 +350,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
             global_tcx: self,
             arena: DroplessArena::new(),
             fresh_tables: None,
+
         }
     }
 }
@@ -381,7 +382,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
             region_vars: RegionVarBindings::new(tcx),
             selection_cache: traits::SelectionCache::new(),
             evaluation_cache: traits::EvaluationCache::new(),
-            reported_trait_errors: RefCell::new(FxHashSet()),
+            reported_trait_errors: RefCell::new(FxHashMap()),
             tainted_by_errors_flag: Cell::new(false),
             err_count_on_creation: tcx.sess.err_count(),
             in_snapshot: Cell::new(false),
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 64438f586d7..247fb079fe7 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -18,6 +18,7 @@ use super::{
     OutputTypeParameterMismatch,
     TraitNotObjectSafe,
     PredicateObligation,
+    Reveal,
     SelectionContext,
     SelectionError,
     ObjectSafetyViolation,
@@ -25,16 +26,14 @@ use super::{
 
 use errors::DiagnosticBuilder;
 use fmt_macros::{Parser, Piece, Position};
-use hir::{self, intravisit, Local, Pat, Body};
-use hir::intravisit::{Visitor, NestedVisitorMap};
-use hir::map::NodeExpr;
+use hir;
 use hir::def_id::DefId;
 use infer::{self, InferCtxt};
 use infer::type_variable::TypeVariableOrigin;
 use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL;
 use std::fmt;
-use syntax::ast::{self, NodeId};
-use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable, TyInfer, TyVar};
+use syntax::ast;
+use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
 use ty::error::{ExpectedFound, TypeError};
 use ty::fast_reject;
 use ty::fold::TypeFolder;
@@ -44,96 +43,113 @@ use util::nodemap::{FxHashMap, FxHashSet};
 
 use syntax_pos::{DUMMY_SP, Span};
 
+impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
+    pub fn report_fulfillment_errors(&self,
+                                     errors: &Vec<FulfillmentError<'tcx>>) {
+        #[derive(Debug)]
+        struct ErrorDescriptor<'tcx> {
+            predicate: ty::Predicate<'tcx>,
+            index: Option<usize>, // None if this is an old error
+        }
 
-#[derive(Debug, PartialEq, Eq, Hash)]
-pub struct TraitErrorKey<'tcx> {
-    span: Span,
-    predicate: ty::Predicate<'tcx>
-}
+        let mut error_map : FxHashMap<_, _> =
+            self.reported_trait_errors.borrow().iter().map(|(&span, predicates)| {
+                (span, predicates.iter().map(|predicate| ErrorDescriptor {
+                    predicate: predicate.clone(),
+                    index: None
+                }).collect())
+            }).collect();
+
+        for (index, error) in errors.iter().enumerate() {
+            error_map.entry(error.obligation.cause.span).or_insert(Vec::new()).push(
+                ErrorDescriptor {
+                    predicate: error.obligation.predicate.clone(),
+                    index: Some(index)
+                });
 
-impl<'a, 'gcx, 'tcx> TraitErrorKey<'tcx> {
-    fn from_error(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
-                  e: &FulfillmentError<'tcx>) -> Self {
-        let predicate =
-            infcx.resolve_type_vars_if_possible(&e.obligation.predicate);
-        TraitErrorKey {
-            span: e.obligation.cause.span,
-            predicate: infcx.tcx.erase_regions(&predicate)
+            self.reported_trait_errors.borrow_mut()
+                .entry(error.obligation.cause.span).or_insert(Vec::new())
+                .push(error.obligation.predicate.clone());
         }
-    }
-}
 
-struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
-    infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
-    target_ty: &'a Ty<'tcx>,
-    hir_map: &'a hir::map::Map<'gcx>,
-    found_local_pattern: Option<&'gcx Pat>,
-    found_arg_pattern: Option<&'gcx Pat>,
-}
+        // We do this in 2 passes because we want to display errors in order, tho
+        // maybe it *is* better to sort errors by span or something.
+        let mut is_suppressed: Vec<bool> = errors.iter().map(|_| false).collect();
+        for (_, error_set) in error_map.iter() {
+            // We want to suppress "duplicate" errors with the same span.
+            for error in error_set {
+                if let Some(index) = error.index {
+                    // Suppress errors that are either:
+                    // 1) strictly implied by another error.
+                    // 2) implied by an error with a smaller index.
+                    for error2 in error_set {
+                        if error2.index.map_or(false, |index2| is_suppressed[index2]) {
+                            // Avoid errors being suppressed by already-suppressed
+                            // errors, to prevent all errors from being suppressed
+                            // at once.
+                            continue
+                        }
 
-impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
-    fn node_matches_type(&mut self, node_id: NodeId) -> bool {
-        let ty_opt = self.infcx.in_progress_tables.and_then(|tables| {
-            tables.borrow().node_id_to_type_opt(node_id)
-        });
-        match ty_opt {
-            Some(ty) => {
-                let ty = self.infcx.resolve_type_vars_if_possible(&ty);
-                ty.walk().any(|inner_ty| {
-                    inner_ty == *self.target_ty || match (&inner_ty.sty, &self.target_ty.sty) {
-                        (&TyInfer(TyVar(a_vid)), &TyInfer(TyVar(b_vid))) => {
-                            self.infcx
-                                .type_variables
-                                .borrow_mut()
-                                .sub_unified(a_vid, b_vid)
+                        if self.error_implies(&error2.predicate, &error.predicate) &&
+                            !(error2.index >= error.index &&
+                              self.error_implies(&error.predicate, &error2.predicate))
+                        {
+                            info!("skipping {:?} (implied by {:?})", error, error2);
+                            is_suppressed[index] = true;
+                            break
                         }
-                        _ => false,
                     }
-                })
+                }
             }
-            None => false,
         }
-    }
-}
 
-impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
-        NestedVisitorMap::OnlyBodies(&self.hir_map)
+        for (error, suppressed) in errors.iter().zip(is_suppressed) {
+            if !suppressed {
+                self.report_fulfillment_error(error);
+            }
+        }
     }
 
-    fn visit_local(&mut self, local: &'gcx Local) {
-        if self.found_local_pattern.is_none() && self.node_matches_type(local.id) {
-            self.found_local_pattern = Some(&*local.pat);
+    // returns if `cond` not occuring implies that `error` does not occur - i.e. that
+    // `error` occuring implies that `cond` occurs.
+    fn error_implies(&self,
+                     cond: &ty::Predicate<'tcx>,
+                     error: &ty::Predicate<'tcx>)
+                     -> bool
+    {
+        if cond == error {
+            return true
         }
-        intravisit::walk_local(self, local);
-    }
 
-    fn visit_body(&mut self, body: &'gcx Body) {
-        for argument in &body.arguments {
-            if self.found_arg_pattern.is_none() && self.node_matches_type(argument.id) {
-                self.found_arg_pattern = Some(&*argument.pat);
+        let (cond, error) = match (cond, error) {
+            (&ty::Predicate::Trait(..), &ty::Predicate::Trait(ref error))
+                => (cond, error),
+            _ => {
+                // FIXME: make this work in other cases too.
+                return false
             }
-        }
-        intravisit::walk_body(self, body);
-    }
-}
+        };
 
-impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
-    pub fn report_fulfillment_errors(&self, errors: &Vec<FulfillmentError<'tcx>>) {
-        for error in errors {
-            self.report_fulfillment_error(error);
+        for implication in super::elaborate_predicates(self.tcx, vec![cond.clone()]) {
+            if let ty::Predicate::Trait(implication) = implication {
+                let error = error.to_poly_trait_ref();
+                let implication = implication.to_poly_trait_ref();
+                // FIXME: I'm just not taking associated types at all here.
+                // Eventually I'll need to implement param-env-aware
+                // `Γ₁ ⊦ φ₁ => Γ₂ ⊦ φ₂` logic.
+                let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
+                if let Ok(_) = self.can_sub(param_env, error, implication) {
+                    debug!("error_implies: {:?} -> {:?} -> {:?}", cond, error, implication);
+                    return true
+                }
+            }
         }
+
+        false
     }
 
-    fn report_fulfillment_error(&self,
-                                error: &FulfillmentError<'tcx>) {
-        let error_key = TraitErrorKey::from_error(self, error);
-        debug!("report_fulfillment_errors({:?}) - key={:?}",
-               error, error_key);
-        if !self.reported_trait_errors.borrow_mut().insert(error_key) {
-            debug!("report_fulfillment_errors: skipping duplicate");
-            return;
-        }
+    fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) {
+        debug!("report_fulfillment_errors({:?})", error);
         match error.code {
             FulfillmentErrorCode::CodeSelectionError(ref e) => {
                 self.report_selection_error(&error.obligation, e);
@@ -1008,83 +1024,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         })
     }
 
-    fn extract_type_name(&self, ty: &'a Ty<'tcx>) -> String {
-        if let ty::TyInfer(ty::TyVar(ty_vid)) = (*ty).sty {
-            let ty_vars = self.type_variables.borrow();
-            if let TypeVariableOrigin::TypeParameterDefinition(_, name) =
-                *ty_vars.var_origin(ty_vid) {
-                name.to_string()
-            } else {
-                ty.to_string()
-            }
-        } else {
-            ty.to_string()
-        }
-    }
-
-    pub fn need_type_info(&self, body_id: hir::BodyId, span: Span, ty: Ty<'tcx>) {
-        let ty = self.resolve_type_vars_if_possible(&ty);
-        let name = self.extract_type_name(&ty);
-
-        let mut err_span = span;
-        let mut labels = vec![(span, format!("cannot infer type for `{}`", name))];
-
-        let mut local_visitor = FindLocalByTypeVisitor {
-            infcx: &self,
-            target_ty: &ty,
-            hir_map: &self.tcx.hir,
-            found_local_pattern: None,
-            found_arg_pattern: None,
-        };
-
-        // #40294: cause.body_id can also be a fn declaration.
-        // Currently, if it's anything other than NodeExpr, we just ignore it
-        match self.tcx.hir.find(body_id.node_id) {
-            Some(NodeExpr(expr)) => local_visitor.visit_expr(expr),
-            _ => ()
-        }
-
-        if let Some(pattern) = local_visitor.found_arg_pattern {
-            err_span = pattern.span;
-            // We don't want to show the default label for closures.
-            //
-            // So, before clearing, the output would look something like this:
-            // ```
-            // let x = |_| {  };
-            //          -  ^^^^ cannot infer type for `[_; 0]`
-            //          |
-            //          consider giving this closure parameter a type
-            // ```
-            //
-            // After clearing, it looks something like this:
-            // ```
-            // let x = |_| {  };
-            //          ^ consider giving this closure parameter a type
-            // ```
-            labels.clear();
-            labels.push((pattern.span, format!("consider giving this closure parameter a type")));
-        }
-
-        if let Some(pattern) = local_visitor.found_local_pattern {
-            if let Some(simple_name) = pattern.simple_name() {
-                labels.push((pattern.span, format!("consider giving `{}` a type", simple_name)));
-            } else {
-                labels.push((pattern.span, format!("consider giving the pattern a type")));
-            }
-        }
-
-        let mut err = struct_span_err!(self.tcx.sess,
-                                       err_span,
-                                       E0282,
-                                       "type annotations needed");
-
-        for (target_span, label_message) in labels {
-            err.span_label(target_span, label_message);
-        }
-
-        err.emit();
-    }
-
     fn note_obligation_cause<T>(&self,
                                 err: &mut DiagnosticBuilder,
                                 obligation: &Obligation<'tcx, T>)
@@ -1205,4 +1144,3 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                           suggested_limit));
     }
 }
-
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index 3ce7ee847cc..e9196cd1243 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -28,7 +28,6 @@ use std::rc::Rc;
 use syntax::ast;
 use syntax_pos::{Span, DUMMY_SP};
 
-pub use self::error_reporting::TraitErrorKey;
 pub use self::coherence::orphan_check;
 pub use self::coherence::overlapping_impls;
 pub use self::coherence::OrphanCheckErr;
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index c5f89e861fa..8bd992b12e6 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -1101,7 +1101,10 @@ pub fn monitor<F: FnOnce() + Send + 'static>(f: F) {
             }
 
             let xs = ["the compiler unexpectedly panicked. this is a bug.".to_string(),
-                      format!("we would appreciate a bug report: {}", BUG_REPORT_URL)];
+                      format!("we would appreciate a bug report: {}", BUG_REPORT_URL),
+                      format!("rustc {} running on {}",
+                              option_env!("CFG_VERSION").unwrap_or("unknown_version"),
+                              config::host_triple())];
             for note in &xs {
                 handler.emit(&MultiSpan::new(),
                              &note,
diff --git a/src/test/compile-fail/extern-wrong-value-type.rs b/src/test/compile-fail/extern-wrong-value-type.rs
index 576368aef31..66b06c505e4 100644
--- a/src/test/compile-fail/extern-wrong-value-type.rs
+++ b/src/test/compile-fail/extern-wrong-value-type.rs
@@ -18,5 +18,4 @@ fn main() {
     let _x: extern "C" fn() = f; // OK
     is_fn(f);
     //~^ ERROR `extern "C" fn() {f}: std::ops::Fn<()>` is not satisfied
-    //~| ERROR `extern "C" fn() {f}: std::ops::FnOnce<()>` is not satisfied
 }
diff --git a/src/test/compile-fail/fn-trait-formatting.rs b/src/test/compile-fail/fn-trait-formatting.rs
index 6377550d3d2..6d70f54edb4 100644
--- a/src/test/compile-fail/fn-trait-formatting.rs
+++ b/src/test/compile-fail/fn-trait-formatting.rs
@@ -28,5 +28,4 @@ fn main() {
 
     needs_fn(1);
     //~^ ERROR : std::ops::Fn<(isize,)>`
-    //~| ERROR : std::ops::FnOnce<(isize,)>`
 }
diff --git a/src/test/compile-fail/issue-22034.rs b/src/test/compile-fail/issue-22034.rs
index dfa9520f38b..5271ea79917 100644
--- a/src/test/compile-fail/issue-22034.rs
+++ b/src/test/compile-fail/issue-22034.rs
@@ -17,6 +17,5 @@ fn main() {
     let _: &mut Fn() = unsafe {
         &mut *(ptr as *mut Fn())
         //~^ ERROR `(): std::ops::Fn<()>` is not satisfied
-        //~| ERROR `(): std::ops::FnOnce<()>` is not satisfied
     };
 }
diff --git a/src/test/compile-fail/issue-23966.rs b/src/test/compile-fail/issue-23966.rs
index 7f9c7a292f2..544d3c8af20 100644
--- a/src/test/compile-fail/issue-23966.rs
+++ b/src/test/compile-fail/issue-23966.rs
@@ -11,5 +11,4 @@
 fn main() {
     "".chars().fold(|_, _| (), ());
     //~^ ERROR E0277
-    //~| ERROR E0277
 }
diff --git a/src/test/compile-fail/range_traits-1.rs b/src/test/compile-fail/range_traits-1.rs
index 85219717758..cf5c40bd176 100644
--- a/src/test/compile-fail/range_traits-1.rs
+++ b/src/test/compile-fail/range_traits-1.rs
@@ -17,8 +17,8 @@ use std::ops::*;
 struct AllTheRanges {
     a: Range<usize>,
     //~^ ERROR PartialOrd
-    //~^^ ERROR PartialOrd
-    //~^^^ ERROR Ord
+    //~^^ ERROR Ord
+    //~^^^ ERROR binary operation
     //~^^^^ ERROR binary operation
     //~^^^^^ ERROR binary operation
     //~^^^^^^ ERROR binary operation
@@ -26,11 +26,10 @@ struct AllTheRanges {
     //~^^^^^^^^ ERROR binary operation
     //~^^^^^^^^^ ERROR binary operation
     //~^^^^^^^^^^ ERROR binary operation
-    //~^^^^^^^^^^^ ERROR binary operation
     b: RangeTo<usize>,
     //~^ ERROR PartialOrd
-    //~^^ ERROR PartialOrd
-    //~^^^ ERROR Ord
+    //~^^ ERROR Ord
+    //~^^^ ERROR binary operation
     //~^^^^ ERROR binary operation
     //~^^^^^ ERROR binary operation
     //~^^^^^^ ERROR binary operation
@@ -38,11 +37,10 @@ struct AllTheRanges {
     //~^^^^^^^^ ERROR binary operation
     //~^^^^^^^^^ ERROR binary operation
     //~^^^^^^^^^^ ERROR binary operation
-    //~^^^^^^^^^^^ ERROR binary operation
     c: RangeFrom<usize>,
     //~^ ERROR PartialOrd
-    //~^^ ERROR PartialOrd
-    //~^^^ ERROR Ord
+    //~^^ ERROR Ord
+    //~^^^ ERROR binary operation
     //~^^^^ ERROR binary operation
     //~^^^^^ ERROR binary operation
     //~^^^^^^ ERROR binary operation
@@ -50,11 +48,10 @@ struct AllTheRanges {
     //~^^^^^^^^ ERROR binary operation
     //~^^^^^^^^^ ERROR binary operation
     //~^^^^^^^^^^ ERROR binary operation
-    //~^^^^^^^^^^^ ERROR binary operation
     d: RangeFull,
     //~^ ERROR PartialOrd
-    //~^^ ERROR PartialOrd
-    //~^^^ ERROR Ord
+    //~^^ ERROR Ord
+    //~^^^ ERROR binary operation
     //~^^^^ ERROR binary operation
     //~^^^^^ ERROR binary operation
     //~^^^^^^ ERROR binary operation
@@ -62,11 +59,10 @@ struct AllTheRanges {
     //~^^^^^^^^ ERROR binary operation
     //~^^^^^^^^^ ERROR binary operation
     //~^^^^^^^^^^ ERROR binary operation
-    //~^^^^^^^^^^^ ERROR binary operation
     e: RangeInclusive<usize>,
     //~^ ERROR PartialOrd
-    //~^^ ERROR PartialOrd
-    //~^^^ ERROR Ord
+    //~^^ ERROR Ord
+    //~^^^ ERROR binary operation
     //~^^^^ ERROR binary operation
     //~^^^^^ ERROR binary operation
     //~^^^^^^ ERROR binary operation
@@ -74,11 +70,10 @@ struct AllTheRanges {
     //~^^^^^^^^ ERROR binary operation
     //~^^^^^^^^^ ERROR binary operation
     //~^^^^^^^^^^ ERROR binary operation
-    //~^^^^^^^^^^^ ERROR binary operation
     f: RangeToInclusive<usize>,
     //~^ ERROR PartialOrd
-    //~^^ ERROR PartialOrd
-    //~^^^ ERROR Ord
+    //~^^ ERROR Ord
+    //~^^^ ERROR binary operation
     //~^^^^ ERROR binary operation
     //~^^^^^ ERROR binary operation
     //~^^^^^^ ERROR binary operation
@@ -86,8 +81,6 @@ struct AllTheRanges {
     //~^^^^^^^^ ERROR binary operation
     //~^^^^^^^^^ ERROR binary operation
     //~^^^^^^^^^^ ERROR binary operation
-    //~^^^^^^^^^^^ ERROR binary operation
 }
 
 fn main() {}
-
diff --git a/src/test/compile-fail/str-mut-idx.rs b/src/test/compile-fail/str-mut-idx.rs
index 8851e5e0797..219fcdfd702 100644
--- a/src/test/compile-fail/str-mut-idx.rs
+++ b/src/test/compile-fail/str-mut-idx.rs
@@ -15,8 +15,7 @@ fn mutate(s: &mut str) {
     //~^ ERROR `str: std::marker::Sized` is not satisfied
     //~| ERROR `str: std::marker::Sized` is not satisfied
     s[1usize] = bot();
-    //~^ ERROR `str: std::ops::Index<usize>` is not satisfied
-    //~| ERROR `str: std::ops::IndexMut<usize>` is not satisfied
+    //~^ ERROR `str: std::ops::IndexMut<usize>` is not satisfied
 }
 
 pub fn main() {}
diff --git a/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs b/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs
index 2b0a8baf4f2..5ba93bf483f 100644
--- a/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs
+++ b/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs
@@ -21,13 +21,11 @@ fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
 fn a() {
     let x = call_it(&square, 22);
     //~^ ERROR E0277
-    //~| ERROR E0277
 }
 
 fn b() {
     let y = call_it_mut(&mut square, 22);
     //~^ ERROR E0277
-    //~| ERROR E0277
 }
 
 fn c() {
diff --git a/src/test/compile-fail/unboxed-closures-wrong-abi.rs b/src/test/compile-fail/unboxed-closures-wrong-abi.rs
index f6ba25f4368..ff06f7c559b 100644
--- a/src/test/compile-fail/unboxed-closures-wrong-abi.rs
+++ b/src/test/compile-fail/unboxed-closures-wrong-abi.rs
@@ -21,13 +21,11 @@ fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
 fn a() {
     let x = call_it(&square, 22);
     //~^ ERROR E0277
-    //~| ERROR E0277
 }
 
 fn b() {
     let y = call_it_mut(&mut square, 22);
     //~^ ERROR E0277
-    //~| ERROR E0277
 }
 
 fn c() {
diff --git a/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs b/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs
index 9d907ffc17f..d77750d2a04 100644
--- a/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs
+++ b/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs
@@ -22,13 +22,11 @@ fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
 fn a() {
     let x = call_it(&square, 22);
     //~^ ERROR E0277
-    //~| ERROR E0277
 }
 
 fn b() {
     let y = call_it_mut(&mut square, 22);
     //~^ ERROR E0277
-    //~| ERROR E0277
 }
 
 fn c() {
diff --git a/src/test/compile-fail/unsized6.rs b/src/test/compile-fail/unsized6.rs
index 462d760a60c..dec8699f46e 100644
--- a/src/test/compile-fail/unsized6.rs
+++ b/src/test/compile-fail/unsized6.rs
@@ -12,15 +12,15 @@
 
 trait T {}
 
-fn f1<X: ?Sized>(x: &X) {
-    let _: X; // <-- this is OK, no bindings created, no initializer.
+fn f1<W: ?Sized, X: ?Sized, Y: ?Sized, Z: ?Sized>(x: &X) {
+    let _: W; // <-- this is OK, no bindings created, no initializer.
     let _: (isize, (X, isize)); //~ERROR `X: std::marker::Sized` is not satisfie
-    let y: X; //~ERROR `X: std::marker::Sized` is not satisfied
-    let y: (isize, (X, usize));
+    let y: Y; //~ERROR `Y: std::marker::Sized` is not satisfied
+    let y: (isize, (Z, usize)); //~ERROR `Z: std::marker::Sized` is not satisfied
 }
-fn f2<X: ?Sized + T>(x: &X) {
+fn f2<X: ?Sized, Y: ?Sized>(x: &X) {
     let y: X; //~ERROR `X: std::marker::Sized` is not satisfied
-    let y: (isize, (X, isize)); //~ERROR `X: std::marker::Sized` is not satisfied
+    let y: (isize, (Y, isize)); //~ERROR `Y: std::marker::Sized` is not satisfied
 }
 
 fn f3<X: ?Sized>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
diff --git a/src/test/ui/mismatched_types/E0281.stderr b/src/test/ui/mismatched_types/E0281.stderr
index fab48e9a740..3eb5c125789 100644
--- a/src/test/ui/mismatched_types/E0281.stderr
+++ b/src/test/ui/mismatched_types/E0281.stderr
@@ -9,16 +9,5 @@ error[E0281]: type mismatch: `[closure@$DIR/E0281.rs:14:9: 14:24]` implements th
    |
    = note: required by `foo`
 
-error[E0281]: type mismatch: `[closure@$DIR/E0281.rs:14:9: 14:24]` implements the trait `std::ops::FnOnce<(std::string::String,)>`, but the trait `std::ops::FnOnce<(usize,)>` is required
-  --> $DIR/E0281.rs:14:5
-   |
-14 |     foo(|y: String| { });
-   |     ^^^ --------------- implements `std::ops::FnOnce<(std::string::String,)>`
-   |     |
-   |     requires `std::ops::FnOnce<(usize,)>`
-   |     expected usize, found struct `std::string::String`
-   |
-   = note: required by `foo`
-
 error: aborting due to previous error(s)
 
diff --git a/src/test/ui/mismatched_types/binops.stderr b/src/test/ui/mismatched_types/binops.stderr
index 1faf72cd760..cebdc12f568 100644
--- a/src/test/ui/mismatched_types/binops.stderr
+++ b/src/test/ui/mismatched_types/binops.stderr
@@ -30,14 +30,6 @@ error[E0277]: the trait bound `{integer}: std::ops::Div<&str>` is not satisfied
    |
    = help: the trait `std::ops::Div<&str>` is not implemented for `{integer}`
 
-error[E0277]: the trait bound `{integer}: std::cmp::PartialEq<std::string::String>` is not satisfied
-  --> $DIR/binops.rs:16:7
-   |
-16 |     5 < String::new();
-   |       ^ can't compare `{integer}` with `std::string::String`
-   |
-   = help: the trait `std::cmp::PartialEq<std::string::String>` is not implemented for `{integer}`
-
 error[E0277]: the trait bound `{integer}: std::cmp::PartialOrd<std::string::String>` is not satisfied
   --> $DIR/binops.rs:16:7
    |
diff --git a/src/test/ui/mismatched_types/closure-arg-count.stderr b/src/test/ui/mismatched_types/closure-arg-count.stderr
index cd16e5d70b6..85734dfac70 100644
--- a/src/test/ui/mismatched_types/closure-arg-count.stderr
+++ b/src/test/ui/mismatched_types/closure-arg-count.stderr
@@ -6,22 +6,6 @@ error[E0593]: closure takes 0 arguments but 2 arguments are required
    |               |
    |               expected closure that takes 2 arguments
 
-error[E0593]: closure takes 0 arguments but 2 arguments are required
-  --> $DIR/closure-arg-count.rs:12:15
-   |
-12 |     [1, 2, 3].sort_by(|| panic!());
-   |               ^^^^^^^ ----------- takes 0 arguments
-   |               |
-   |               expected closure that takes 2 arguments
-
-error[E0593]: closure takes 1 argument but 2 arguments are required
-  --> $DIR/closure-arg-count.rs:13:15
-   |
-13 |     [1, 2, 3].sort_by(|tuple| panic!());
-   |               ^^^^^^^ ---------------- takes 1 argument
-   |               |
-   |               expected closure that takes 2 arguments
-
 error[E0593]: closure takes 1 argument but 2 arguments are required
   --> $DIR/closure-arg-count.rs:13:15
    |
@@ -47,13 +31,5 @@ error[E0593]: closure takes 1 argument but 2 arguments are required
    |               |
    |               expected closure that takes 2 arguments
 
-error[E0593]: closure takes 1 argument but 2 arguments are required
-  --> $DIR/closure-arg-count.rs:14:15
-   |
-14 |     [1, 2, 3].sort_by(|(tuple, tuple2)| panic!());
-   |               ^^^^^^^ -------------------------- takes 1 argument
-   |               |
-   |               expected closure that takes 2 arguments
-
 error: aborting due to previous error(s)
 
diff --git a/src/test/ui/mismatched_types/issue-36053-2.stderr b/src/test/ui/mismatched_types/issue-36053-2.stderr
index 8b756814ced..f818bd8bcb1 100644
--- a/src/test/ui/mismatched_types/issue-36053-2.stderr
+++ b/src/test/ui/mismatched_types/issue-36053-2.stderr
@@ -17,14 +17,5 @@ error[E0281]: type mismatch: `[closure@$DIR/issue-36053-2.rs:17:39: 17:53]` impl
    |                                requires `for<'r> std::ops::FnMut<(&'r &str,)>`
    |                                expected &str, found str
 
-error[E0281]: type mismatch: `[closure@$DIR/issue-36053-2.rs:17:39: 17:53]` implements the trait `for<'r> std::ops::FnOnce<(&'r str,)>`, but the trait `for<'r> std::ops::FnOnce<(&'r &str,)>` is required
-  --> $DIR/issue-36053-2.rs:17:32
-   |
-17 |     once::<&str>("str").fuse().filter(|a: &str| true).count();
-   |                                ^^^^^^ -------------- implements `for<'r> std::ops::FnOnce<(&'r str,)>`
-   |                                |
-   |                                requires `for<'r> std::ops::FnOnce<(&'r &str,)>`
-   |                                expected &str, found str
-
 error: aborting due to previous error(s)
 
diff --git a/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.rs b/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.rs
index 7400a27fb6b..693a1585320 100644
--- a/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.rs
+++ b/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.rs
@@ -24,7 +24,6 @@ pub fn main() {
     //~| NOTE implements
     let z = call_it(3, f);
     //~^ ERROR type mismatch
-    //~| ERROR type mismatch
     //~| NOTE expected isize, found usize
     //~| NOTE expected isize, found usize
     //~| NOTE requires
diff --git a/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr b/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr
index c5bfb6e45e7..643c9b36dbd 100644
--- a/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr
+++ b/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr
@@ -12,19 +12,5 @@ error[E0281]: type mismatch: `[closure@$DIR/unboxed-closures-vtable-mismatch.rs:
    |
    = note: required by `call_it`
 
-error[E0281]: type mismatch: `[closure@$DIR/unboxed-closures-vtable-mismatch.rs:22:23: 22:73]` implements the trait `std::ops::FnOnce<(usize, isize)>`, but the trait `std::ops::FnOnce<(isize, isize)>` is required
-  --> $DIR/unboxed-closures-vtable-mismatch.rs:25:13
-   |
-22 |     let f = to_fn_mut(|x: usize, y: isize| -> isize { (x as isize) + y });
-   |                       -------------------------------------------------- implements `std::ops::FnOnce<(usize, isize)>`
-...
-25 |     let z = call_it(3, f);
-   |             ^^^^^^^
-   |             |
-   |             requires `std::ops::FnOnce<(isize, isize)>`
-   |             expected isize, found usize
-   |
-   = note: required by `call_it`
-
 error: aborting due to previous error(s)
 
diff --git a/src/test/ui/type-check/issue-40294.stderr b/src/test/ui/type-check/issue-40294.stderr
index bf03e52369f..cd474b14193 100644
--- a/src/test/ui/type-check/issue-40294.stderr
+++ b/src/test/ui/type-check/issue-40294.stderr
@@ -1,4 +1,4 @@
-error[E0282]: type annotations needed
+error[E0283]: type annotations required: cannot resolve `&'a T: Foo`
   --> $DIR/issue-40294.rs:15:1
    |
 15 | / fn foo<'a,'b,T>(x: &'a T, y: &'b T)
@@ -8,7 +8,9 @@ error[E0282]: type annotations needed
 19 | |     x.foo();
 20 | |     y.foo();
 21 | | }
-   | |_^ cannot infer type for `&'a T`
+   | |_^
+   |
+   = note: required by `Foo`
 
 error: aborting due to previous error(s)