summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <arielb1@mail.tau.ac.il>2015-09-24 19:58:00 +0300
committerBrian Anderson <banderson@mozilla.com>2015-10-16 13:06:53 -0700
commiteb2aca307fc14dbcf0325f0dc06bb2f15faddc85 (patch)
treec9a45e2d71c66ec3cfbe32c64171e28ca20e1104 /src
parenta4cbd6a7fdb0bc01a593bab57207fd631c971764 (diff)
downloadrust-eb2aca307fc14dbcf0325f0dc06bb2f15faddc85.tar.gz
rust-eb2aca307fc14dbcf0325f0dc06bb2f15faddc85.zip
deduplicate trait errors before they are displayed
Because of type inference, duplicate obligations exist and cause duplicate
errors. To avoid this, only display the first error for each (predicate,span).

The inclusion of the span is somewhat bikesheddy, but *is* the more
conservative option (it does not remove some instability, as duplicate
obligations are ignored by `duplicate_set` under some inference conditions).

Fixes #28098
cc #21528 (is it a dupe?)
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/infer/mod.rs7
-rw-r--r--src/librustc/middle/traits/error_reporting.rs27
-rw-r--r--src/librustc/middle/traits/fulfill.rs6
-rw-r--r--src/librustc/middle/traits/mod.rs2
-rw-r--r--src/test/compile-fail/associated-types-ICE-when-projecting-out-of-err.rs1
-rw-r--r--src/test/compile-fail/associated-types-path-2.rs1
-rw-r--r--src/test/compile-fail/coerce-unsafe-to-closure.rs1
-rw-r--r--src/test/compile-fail/const-eval-overflow-4b.rs2
-rw-r--r--src/test/compile-fail/fn-variance-1.rs2
-rw-r--r--src/test/compile-fail/for-loop-bogosity.rs3
-rw-r--r--src/test/compile-fail/indexing-requires-a-uint.rs1
-rw-r--r--src/test/compile-fail/integral-indexing.rs8
-rw-r--r--src/test/compile-fail/issue-11771.rs2
-rw-r--r--src/test/compile-fail/issue-13352.rs1
-rw-r--r--src/test/compile-fail/issue-14084.rs1
-rw-r--r--src/test/compile-fail/issue-20605.rs3
-rw-r--r--src/test/compile-fail/issue-2149.rs1
-rw-r--r--src/test/compile-fail/issue-22645.rs4
-rw-r--r--src/test/compile-fail/issue-24352.rs1
-rw-r--r--src/test/compile-fail/issue-28098.rs35
-rw-r--r--src/test/compile-fail/shift-various-bad-types.rs3
-rw-r--r--src/test/compile-fail/str-idx.rs1
-rw-r--r--src/test/compile-fail/str-mut-idx.rs1
-rw-r--r--src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs1
-rw-r--r--src/test/compile-fail/unboxed-closures-wrong-abi.rs1
-rw-r--r--src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs1
26 files changed, 77 insertions, 40 deletions
diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs
index 917727907ba..3def56f94a1 100644
--- a/src/librustc/middle/infer/mod.rs
+++ b/src/librustc/middle/infer/mod.rs
@@ -43,7 +43,7 @@ use std::rc::Rc;
 use syntax::ast;
 use syntax::codemap;
 use syntax::codemap::{Span, DUMMY_SP};
-use util::nodemap::{FnvHashMap, NodeMap};
+use util::nodemap::{FnvHashMap, FnvHashSet, NodeMap};
 
 use self::combine::CombineFields;
 use self::region_inference::{RegionVarBindings, RegionSnapshot};
@@ -92,6 +92,10 @@ pub struct InferCtxt<'a, 'tcx: 'a> {
 
     pub fulfillment_cx: RefCell<traits::FulfillmentContext<'tcx>>,
 
+    // the set of predicates on which errors have been reported, to
+    // avoid reporting the same error twice.
+    pub reported_trait_errors: RefCell<FnvHashSet<traits::TraitErrorKey<'tcx>>>,
+
     // This is a temporary field used for toggling on normalization in the inference context,
     // as we move towards the approach described here:
     // https://internals.rust-lang.org/t/flattening-the-contexts-for-fun-and-profit/2293
@@ -374,6 +378,7 @@ pub fn new_infer_ctxt<'a, 'tcx>(tcx: &'a ty::ctxt<'tcx>,
         region_vars: RegionVarBindings::new(tcx),
         parameter_environment: param_env.unwrap_or(tcx.empty_parameter_environment()),
         fulfillment_cx: RefCell::new(traits::FulfillmentContext::new(errors_will_be_reported)),
+        reported_trait_errors: RefCell::new(FnvHashSet()),
         normalize: false,
         err_count_on_creation: tcx.sess.err_count()
     }
diff --git a/src/librustc/middle/traits/error_reporting.rs b/src/librustc/middle/traits/error_reporting.rs
index 2ed53f16afd..ce71ba2ff2e 100644
--- a/src/librustc/middle/traits/error_reporting.rs
+++ b/src/librustc/middle/traits/error_reporting.rs
@@ -33,6 +33,26 @@ use std::fmt;
 use syntax::codemap::Span;
 use rustc_front::attr::{AttributeMethods, AttrMetaMethods};
 
+#[derive(Debug, PartialEq, Eq, Hash)]
+pub struct TraitErrorKey<'tcx> {
+    is_warning: bool,
+    span: Span,
+    predicate: ty::Predicate<'tcx>
+}
+
+impl<'tcx> TraitErrorKey<'tcx> {
+    fn from_error<'a>(infcx: &InferCtxt<'a, 'tcx>,
+                      e: &FulfillmentError<'tcx>) -> Self {
+        let predicate =
+            infcx.resolve_type_vars_if_possible(&e.obligation.predicate);
+        TraitErrorKey {
+            is_warning: is_warning(&e.obligation),
+            span: e.obligation.cause.span,
+            predicate: infcx.tcx.erase_regions(&predicate)
+        }
+    }
+}
+
 pub fn report_fulfillment_errors<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
                                            errors: &Vec<FulfillmentError<'tcx>>) {
     for error in errors {
@@ -42,6 +62,13 @@ pub fn report_fulfillment_errors<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
 
 fn report_fulfillment_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
                                       error: &FulfillmentError<'tcx>) {
+    let error_key = TraitErrorKey::from_error(infcx, error);
+    debug!("report_fulfillment_errors({:?}) - key={:?}",
+           error, error_key);
+    if !infcx.reported_trait_errors.borrow_mut().insert(error_key) {
+        debug!("report_fulfillment_errors: skipping duplicate");
+        return;
+    }
     match error.code {
         FulfillmentErrorCode::CodeSelectionError(ref e) => {
             report_selection_error(infcx, &error.obligation, e);
diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs
index 29032f0c471..d4e6f693d96 100644
--- a/src/librustc/middle/traits/fulfill.rs
+++ b/src/librustc/middle/traits/fulfill.rs
@@ -49,6 +49,12 @@ pub struct FulfillmentContext<'tcx> {
     // than the `SelectionCache`: it avoids duplicate errors and
     // permits recursive obligations, which are often generated from
     // traits like `Send` et al.
+    //
+    // Note that because of type inference, a predicate can still
+    // occur twice in the predicates list, for example when 2
+    // initially-distinct type variables are unified after being
+    // inserted. Deduplicating the predicate set on selection had a
+    // significant performance cost the last time I checked.
     duplicate_set: FulfilledPredicates<'tcx>,
 
     // A list of all obligations that have been registered with this
diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs
index b0d4d92e8e1..7f76cfaee58 100644
--- a/src/librustc/middle/traits/mod.rs
+++ b/src/librustc/middle/traits/mod.rs
@@ -21,10 +21,12 @@ use middle::subst;
 use middle::ty::{self, HasTypeFlags, Ty};
 use middle::ty::fold::TypeFoldable;
 use middle::infer::{self, fixup_err_to_string, InferCtxt};
+
 use std::rc::Rc;
 use syntax::ast;
 use syntax::codemap::{Span, DUMMY_SP};
 
+pub use self::error_reporting::TraitErrorKey;
 pub use self::error_reporting::report_fulfillment_errors;
 pub use self::error_reporting::report_overflow_error;
 pub use self::error_reporting::report_selection_error;
diff --git a/src/test/compile-fail/associated-types-ICE-when-projecting-out-of-err.rs b/src/test/compile-fail/associated-types-ICE-when-projecting-out-of-err.rs
index 4aad828590a..c5a47f3e535 100644
--- a/src/test/compile-fail/associated-types-ICE-when-projecting-out-of-err.rs
+++ b/src/test/compile-fail/associated-types-ICE-when-projecting-out-of-err.rs
@@ -32,5 +32,4 @@ fn ice<A>(a: A) {
     let r = loop {};
     r = r + a;
     //~^ ERROR not implemented
-    //~| ERROR not implemented
 }
diff --git a/src/test/compile-fail/associated-types-path-2.rs b/src/test/compile-fail/associated-types-path-2.rs
index e603cca7f38..c9374d42938 100644
--- a/src/test/compile-fail/associated-types-path-2.rs
+++ b/src/test/compile-fail/associated-types-path-2.rs
@@ -39,7 +39,6 @@ pub fn f1_int_uint() {
 pub fn f1_uint_uint() {
     f1(2u32, 4u32);
     //~^ ERROR the trait `Foo` is not implemented
-    //~| ERROR the trait `Foo` is not implemented
 }
 
 pub fn f1_uint_int() {
diff --git a/src/test/compile-fail/coerce-unsafe-to-closure.rs b/src/test/compile-fail/coerce-unsafe-to-closure.rs
index 27b4a04054f..90cbbf242aa 100644
--- a/src/test/compile-fail/coerce-unsafe-to-closure.rs
+++ b/src/test/compile-fail/coerce-unsafe-to-closure.rs
@@ -11,5 +11,4 @@
 fn main() {
     let x: Option<&[u8]> = Some("foo").map(std::mem::transmute);
     //~^ ERROR E0277
-    //~| ERROR E0277
 }
diff --git a/src/test/compile-fail/const-eval-overflow-4b.rs b/src/test/compile-fail/const-eval-overflow-4b.rs
index 6322b56a82f..a8f47ab92e5 100644
--- a/src/test/compile-fail/const-eval-overflow-4b.rs
+++ b/src/test/compile-fail/const-eval-overflow-4b.rs
@@ -23,7 +23,6 @@ const A_I8_T
     : [u32; (i8::MAX as i8 + 1u8) as usize]
     //~^ ERROR mismatched types
     //~| the trait `core::ops::Add<u8>` is not implemented for the type `i8`
-    //~| the trait `core::ops::Add<u8>` is not implemented for the type `i8`
     = [0; (i8::MAX as usize) + 1];
 
 fn main() {
@@ -33,4 +32,3 @@ fn main() {
 fn foo<T:fmt::Debug>(x: T) {
     println!("{:?}", x);
 }
-
diff --git a/src/test/compile-fail/fn-variance-1.rs b/src/test/compile-fail/fn-variance-1.rs
index 8e1e88a92e4..e9dd1cb719d 100644
--- a/src/test/compile-fail/fn-variance-1.rs
+++ b/src/test/compile-fail/fn-variance-1.rs
@@ -20,10 +20,8 @@ fn main() {
     apply(&3, takes_imm);
     apply(&3, takes_mut);
     //~^ ERROR (values differ in mutability)
-    //~| ERROR (values differ in mutability)
 
     apply(&mut 3, takes_mut);
     apply(&mut 3, takes_imm);
     //~^ ERROR (values differ in mutability)
-    //~| ERROR (values differ in mutability)
 }
diff --git a/src/test/compile-fail/for-loop-bogosity.rs b/src/test/compile-fail/for-loop-bogosity.rs
index 6bc0e74a2eb..c7768304517 100644
--- a/src/test/compile-fail/for-loop-bogosity.rs
+++ b/src/test/compile-fail/for-loop-bogosity.rs
@@ -25,9 +25,6 @@ pub fn main() {
         y: 2,
     };
     for x in bogus { //~ ERROR `core::iter::Iterator` is not implemented for the type `MyStruct`
-    //~^ ERROR
-    //~^^ ERROR
-    // FIXME(#21528) not fulfilled obligation error should be reported once, not thrice
         drop(x);
     }
 }
diff --git a/src/test/compile-fail/indexing-requires-a-uint.rs b/src/test/compile-fail/indexing-requires-a-uint.rs
index 3ca00fcb66a..3d3b7bc1bcb 100644
--- a/src/test/compile-fail/indexing-requires-a-uint.rs
+++ b/src/test/compile-fail/indexing-requires-a-uint.rs
@@ -14,7 +14,6 @@
 fn main() {
     fn bar<T>(_: T) {}
     [0][0u8]; //~ ERROR: the trait `core::ops::Index<u8>` is not implemented
-    //~^ ERROR: the trait `core::ops::Index<u8>` is not implemented
 
     [0][0]; // should infer to be a usize
 
diff --git a/src/test/compile-fail/integral-indexing.rs b/src/test/compile-fail/integral-indexing.rs
index e2fb0fa4f2f..f78d677679b 100644
--- a/src/test/compile-fail/integral-indexing.rs
+++ b/src/test/compile-fail/integral-indexing.rs
@@ -14,21 +14,13 @@ pub fn main() {
     v[3_usize];
     v[3];
     v[3u8];  //~ERROR the trait `core::ops::Index<u8>` is not implemented
-    //~^ ERROR the trait `core::ops::Index<u8>` is not implemented
     v[3i8];  //~ERROR the trait `core::ops::Index<i8>` is not implemented
-    //~^ ERROR the trait `core::ops::Index<i8>` is not implemented
     v[3u32]; //~ERROR the trait `core::ops::Index<u32>` is not implemented
-    //~^ ERROR the trait `core::ops::Index<u32>` is not implemented
     v[3i32]; //~ERROR the trait `core::ops::Index<i32>` is not implemented
-    //~^ ERROR the trait `core::ops::Index<i32>` is not implemented
     s.as_bytes()[3_usize];
     s.as_bytes()[3];
     s.as_bytes()[3u8];  //~ERROR the trait `core::ops::Index<u8>` is not implemented
-    //~^ ERROR the trait `core::ops::Index<u8>` is not implemented
     s.as_bytes()[3i8];  //~ERROR the trait `core::ops::Index<i8>` is not implemented
-    //~^ ERROR the trait `core::ops::Index<i8>` is not implemented
     s.as_bytes()[3u32]; //~ERROR the trait `core::ops::Index<u32>` is not implemented
-    //~^ ERROR the trait `core::ops::Index<u32>` is not implemented
     s.as_bytes()[3i32]; //~ERROR the trait `core::ops::Index<i32>` is not implemented
-    //~^ ERROR the trait `core::ops::Index<i32>` is not implemented
 }
diff --git a/src/test/compile-fail/issue-11771.rs b/src/test/compile-fail/issue-11771.rs
index 40fc6b1ed6a..69899105bc3 100644
--- a/src/test/compile-fail/issue-11771.rs
+++ b/src/test/compile-fail/issue-11771.rs
@@ -12,12 +12,10 @@ fn main() {
     let x = ();
     1 +
     x //~^ ERROR E0277
-      //~| ERROR E0277
     ;
 
     let x: () = ();
     1 +
     x //~^ ERROR E0277
-      //~| ERROR E0277
     ;
 }
diff --git a/src/test/compile-fail/issue-13352.rs b/src/test/compile-fail/issue-13352.rs
index 14128a0e6f7..13e677d72bc 100644
--- a/src/test/compile-fail/issue-13352.rs
+++ b/src/test/compile-fail/issue-13352.rs
@@ -18,5 +18,4 @@ fn main() {
     });
     2_usize + (loop {});
     //~^ ERROR E0277
-    //~| ERROR E0277
 }
diff --git a/src/test/compile-fail/issue-14084.rs b/src/test/compile-fail/issue-14084.rs
index b33a6767274..26ed9d8c26a 100644
--- a/src/test/compile-fail/issue-14084.rs
+++ b/src/test/compile-fail/issue-14084.rs
@@ -14,6 +14,5 @@
 fn main() {
     box ( () ) 0;
     //~^ ERROR: the trait `core::ops::Placer<_>` is not implemented
-    //~| ERROR: the trait `core::ops::Placer<_>` is not implemented
     //~| WARN deprecated syntax
 }
diff --git a/src/test/compile-fail/issue-20605.rs b/src/test/compile-fail/issue-20605.rs
index 87b7616db8e..f2d65af9cdf 100644
--- a/src/test/compile-fail/issue-20605.rs
+++ b/src/test/compile-fail/issue-20605.rs
@@ -11,9 +11,6 @@
 fn changer<'a>(mut things: Box<Iterator<Item=&'a mut u8>>) {
     for item in *things { *item = 0 }
 //~^ ERROR the trait `core::marker::Sized` is not implemented for the type `core::iter::Iterator
-//~^^ ERROR
-//~^^^ ERROR
-// FIXME(#21528) error should be reported once, not thrice
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-2149.rs b/src/test/compile-fail/issue-2149.rs
index bb170ef7d00..256c5d8e6f7 100644
--- a/src/test/compile-fail/issue-2149.rs
+++ b/src/test/compile-fail/issue-2149.rs
@@ -17,7 +17,6 @@ impl<A> vec_monad<A> for Vec<A> {
         let mut r = panic!();
         for elt in self { r = r + f(*elt); }
         //~^ ERROR E0277
-        //~| ERROR E0277
    }
 }
 fn main() {
diff --git a/src/test/compile-fail/issue-22645.rs b/src/test/compile-fail/issue-22645.rs
index 8677934fd64..aa7fa82fa29 100644
--- a/src/test/compile-fail/issue-22645.rs
+++ b/src/test/compile-fail/issue-22645.rs
@@ -23,7 +23,5 @@ impl<RHS: Scalar> Add <RHS> for Bob {
 fn main() {
   let b = Bob + 3.5;
   b + 3 //~ ERROR: is not implemented
-  //~^ ERROR: is not implemented
-  //~^^ ERROR: is not implemented
-  //~^^^ ERROR: mismatched types
+  //~^ ERROR: mismatched types
 }
diff --git a/src/test/compile-fail/issue-24352.rs b/src/test/compile-fail/issue-24352.rs
index 0fbc634826b..9936f67b3af 100644
--- a/src/test/compile-fail/issue-24352.rs
+++ b/src/test/compile-fail/issue-24352.rs
@@ -11,5 +11,4 @@
 fn main() {
     1.0f64 - 1.0;
     1.0f64 - 1 //~ ERROR: is not implemented
-    //~^ ERROR: is not implemented
 }
diff --git a/src/test/compile-fail/issue-28098.rs b/src/test/compile-fail/issue-28098.rs
new file mode 100644
index 00000000000..f565d24e1fd
--- /dev/null
+++ b/src/test/compile-fail/issue-28098.rs
@@ -0,0 +1,35 @@
+// Copyright 2015 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.
+
+fn main() {
+    let _ = Iterator::next(&mut ());
+    //~^ ERROR the trait `core::iter::Iterator` is not implemented
+
+    for _ in false {}
+    //~^ ERROR the trait `core::iter::Iterator` is not implemented
+
+    let _ = Iterator::next(&mut ());
+    //~^ ERROR the trait `core::iter::Iterator` is not implemented
+
+    other()
+}
+
+pub fn other() {
+    // check errors are still reported globally
+
+    let _ = Iterator::next(&mut ());
+    //~^ ERROR the trait `core::iter::Iterator` is not implemented
+
+    let _ = Iterator::next(&mut ());
+    //~^ ERROR the trait `core::iter::Iterator` is not implemented
+
+    for _ in false {}
+    //~^ ERROR the trait `core::iter::Iterator` is not implemented
+}
diff --git a/src/test/compile-fail/shift-various-bad-types.rs b/src/test/compile-fail/shift-various-bad-types.rs
index 24b66213b39..c980572fa15 100644
--- a/src/test/compile-fail/shift-various-bad-types.rs
+++ b/src/test/compile-fail/shift-various-bad-types.rs
@@ -18,15 +18,12 @@ struct Panolpy {
 fn foo(p: &Panolpy) {
     22 >> p.char;
     //~^ ERROR E0277
-    //~| ERROR E0277
 
     22 >> p.str;
     //~^ ERROR E0277
-    //~| ERROR E0277
 
     22 >> p;
     //~^ ERROR E0277
-    //~| ERROR E0277
 
     let x;
     22 >> x; // ambiguity error winds up being suppressed
diff --git a/src/test/compile-fail/str-idx.rs b/src/test/compile-fail/str-idx.rs
index ddd2a4eeedf..6e48ae20d09 100644
--- a/src/test/compile-fail/str-idx.rs
+++ b/src/test/compile-fail/str-idx.rs
@@ -11,5 +11,4 @@
 pub fn main() {
     let s: &str = "hello";
     let c: u8 = s[4]; //~ ERROR the trait `core::ops::Index<_>` is not implemented
-    //~^ ERROR the trait `core::ops::Index<_>` is not implemented
 }
diff --git a/src/test/compile-fail/str-mut-idx.rs b/src/test/compile-fail/str-mut-idx.rs
index 73abe6cb59d..ec6a14778a4 100644
--- a/src/test/compile-fail/str-mut-idx.rs
+++ b/src/test/compile-fail/str-mut-idx.rs
@@ -17,7 +17,6 @@ fn mutate(s: &mut str) {
     s[1usize] = bot();
     //~^ ERROR `core::ops::Index<usize>` is not implemented for the type `str`
     //~| ERROR `core::ops::IndexMut<usize>` is not implemented for the type `str`
-    //~| ERROR `core::ops::Index<usize>` is not implemented for the type `str`
 }
 
 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 dc7c70ba649..361df93a716 100644
--- a/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs
+++ b/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs
@@ -35,7 +35,6 @@ fn b() {
 fn c() {
     let z = call_it_once(square, 22);
     //~^ ERROR not implemented
-    //~| ERROR not implemented
 }
 
 fn main() { }
diff --git a/src/test/compile-fail/unboxed-closures-wrong-abi.rs b/src/test/compile-fail/unboxed-closures-wrong-abi.rs
index cdcb435b65a..ca15d1bb5ee 100644
--- a/src/test/compile-fail/unboxed-closures-wrong-abi.rs
+++ b/src/test/compile-fail/unboxed-closures-wrong-abi.rs
@@ -35,7 +35,6 @@ fn b() {
 fn c() {
     let z = call_it_once(square, 22);
     //~^ ERROR not implemented
-    //~| ERROR not implemented
 }
 
 fn main() { }
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 150bf36dcc2..b960362aad7 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
@@ -36,7 +36,6 @@ fn b() {
 fn c() {
     let z = call_it_once(square, 22);
     //~^ ERROR not implemented
-    //~| ERROR not implemented
 }
 
 fn main() { }