]> git.lizzy.rs Git - rust.git/commitdiff
deduplicate trait errors before they are displayed
authorAriel Ben-Yehuda <arielb1@mail.tau.ac.il>
Thu, 24 Sep 2015 16:58:00 +0000 (19:58 +0300)
committerAriel Ben-Yehuda <ariel.byd@gmail.com>
Sat, 26 Sep 2015 18:13:31 +0000 (21:13 +0300)
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?)

26 files changed:
src/librustc/middle/infer/mod.rs
src/librustc/middle/traits/error_reporting.rs
src/librustc/middle/traits/fulfill.rs
src/librustc/middle/traits/mod.rs
src/test/compile-fail/associated-types-ICE-when-projecting-out-of-err.rs
src/test/compile-fail/associated-types-path-2.rs
src/test/compile-fail/coerce-unsafe-to-closure.rs
src/test/compile-fail/const-eval-overflow-4b.rs
src/test/compile-fail/fn-variance-1.rs
src/test/compile-fail/for-loop-bogosity.rs
src/test/compile-fail/indexing-requires-a-uint.rs
src/test/compile-fail/integral-indexing.rs
src/test/compile-fail/issue-11771.rs
src/test/compile-fail/issue-13352.rs
src/test/compile-fail/issue-14084.rs
src/test/compile-fail/issue-20605.rs
src/test/compile-fail/issue-2149.rs
src/test/compile-fail/issue-22645.rs
src/test/compile-fail/issue-24352.rs
src/test/compile-fail/issue-28098.rs [new file with mode: 0644]
src/test/compile-fail/shift-various-bad-types.rs
src/test/compile-fail/str-idx.rs
src/test/compile-fail/str-mut-idx.rs
src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs
src/test/compile-fail/unboxed-closures-wrong-abi.rs
src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs

index 917727907ba885651b4dd28b6b60ba55b4f5173d..3def56f94a1818b62cc631f80782500b21e4a4ec 100644 (file)
@@ -43,7 +43,7 @@
 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()
     }
index 25e6036e85ab47496685aa24c07d617ce99d3132..c6c438f1d83c479a01487616535f260c9301d96f 100644 (file)
 use syntax::codemap::Span;
 use syntax::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);
index 29032f0c4719a3df4afdd0fe9c2891825926fe2c..d4e6f693d965d79c7e008948975e912924bdaca1 100644 (file)
@@ -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
index 5dc6f9454a881505ffcf541822237f084ed02891..a037621f5c02545265b5fc7ae4a87845083dbe9a 100644 (file)
 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;
index 4aad828590a309e5f775f350706743635c9d88a7..c5a47f3e5358f1440330edbfc7427c32d4bf7f10 100644 (file)
@@ -32,5 +32,4 @@ fn ice<A>(a: A) {
     let r = loop {};
     r = r + a;
     //~^ ERROR not implemented
-    //~| ERROR not implemented
 }
index e603cca7f384b838f6ff6313de42723bdf088025..c9374d42938002979a871480b1e1b94987ea567b 100644 (file)
@@ -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() {
index 27b4a04054f073f203503b5ef9a01298e864a622..90cbbf242aad4b2b07ac0cb751444cb1cda22943 100644 (file)
@@ -11,5 +11,4 @@
 fn main() {
     let x: Option<&[u8]> = Some("foo").map(std::mem::transmute);
     //~^ ERROR E0277
-    //~| ERROR E0277
 }
index 6322b56a82f000b1931e24ae96ce653534c9068d..a8f47ab92e52950040606ebc5174b7e47d8373c0 100644 (file)
@@ -23,7 +23,6 @@
     : [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);
 }
-
index 8e1e88a92e452c09d0200806c4bfe2cdc7386394..e9dd1cb719dbcc88455cab8a61d517fa6e37e77d 100644 (file)
@@ -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)
 }
index 6bc0e74a2eb58f16b8f0d4e970069a0e65a695db..c77683045170e11675cf029c64b20f169c16f346 100644 (file)
@@ -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);
     }
 }
index 3ca00fcb66ac16e1a51dbc48fa99feb96fa6a21d..3d3b7bc1bcb430b30416e4f77ac0a2c656a220c8 100644 (file)
@@ -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
 
index e2fb0fa4f2fa518f7fe9280c959b417d052e0c4b..f78d677679bc88ed9d4cd75b31b91901c704c98d 100644 (file)
@@ -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
 }
index 40fc6b1ed6aaacebf6a682e43b67d369b5dff5ab..69899105bc3178720a9c880b5f7efc61c1b0724f 100644 (file)
@@ -12,12 +12,10 @@ fn main() {
     let x = ();
     1 +
     x //~^ ERROR E0277
-      //~| ERROR E0277
     ;
 
     let x: () = ();
     1 +
     x //~^ ERROR E0277
-      //~| ERROR E0277
     ;
 }
index 14128a0e6f7ec94591e42b3a247167bf318512f3..13e677d72bc1e35c0cef924ac7ba63c0dd789a61 100644 (file)
@@ -18,5 +18,4 @@ fn main() {
     });
     2_usize + (loop {});
     //~^ ERROR E0277
-    //~| ERROR E0277
 }
index b2863202ef0cf1624a8f7b662269b25d182f5cdd..6b19cb0b68f10e6c294d9fe30d4c226df3b37b3b 100644 (file)
@@ -14,5 +14,4 @@
 fn main() {
     in () { 0 };
     //~^ ERROR: the trait `core::ops::Placer<_>` is not implemented
-    //~| ERROR: the trait `core::ops::Placer<_>` is not implemented
 }
index 87b7616db8ed23b35619a2f6603e55a5f48e95a7..f2d65af9cdfc80276be064f05092f903f8be64d3 100644 (file)
@@ -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() {}
index bb170ef7d003662d004fc358fb86d9ea0ed9778a..256c5d8e6f72cc08d375e1e45caba593528c0e77 100644 (file)
@@ -17,7 +17,6 @@ fn bind<B, F>(&self, mut f: F) where F: FnMut(A) -> Vec<B> {
         let mut r = panic!();
         for elt in self { r = r + f(*elt); }
         //~^ ERROR E0277
-        //~| ERROR E0277
    }
 }
 fn main() {
index 8677934fd646cb66269215b86c69d3c6a0ebc5ab..aa7fa82fa29ba843654586c2f5ad14681770ddfd 100644 (file)
@@ -23,7 +23,5 @@ fn add(self, rhs : RHS) -> 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
 }
index 0fbc634826bc5b2931beef5389b333c8beb429bd..9936f67b3af3c8e0908bfff2d03376c0d7725c77 100644 (file)
@@ -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 (file)
index 0000000..f565d24
--- /dev/null
@@ -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
+}
index 24b66213b39bd410cdffb9d011bd6b38caa63ab4..c980572fa152f595693a2e5132be769fb85f23c6 100644 (file)
@@ -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
index ddd2a4eeedf76f4f6b5107bcd8ed5f27a2737e2e..6e48ae20d09f3ab1ebe47f1f91fa81b89bd1db5b 100644 (file)
@@ -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
 }
index 73abe6cb59db2669d006314aaa7686e18a384497..ec6a14778a463f22f266b9f6aa66654b52935d5f 100644 (file)
@@ -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() {}
index dc7c70ba649d8b0524766893a060679a1714c511..361df93a71669ed3ccdb7a22e27415efb587a9dd 100644 (file)
@@ -35,7 +35,6 @@ fn b() {
 fn c() {
     let z = call_it_once(square, 22);
     //~^ ERROR not implemented
-    //~| ERROR not implemented
 }
 
 fn main() { }
index cdcb435b65a6acfcc8cdc3700d420022234385bb..ca15d1bb5eefc83f11278776d3d9ba9bbab47784 100644 (file)
@@ -35,7 +35,6 @@ fn b() {
 fn c() {
     let z = call_it_once(square, 22);
     //~^ ERROR not implemented
-    //~| ERROR not implemented
 }
 
 fn main() { }
index 150bf36dcc286db2befd582b8dd6fa055495e1b8..b960362aad7cd36c3f0d97bafa4507b9087ad2cd 100644 (file)
@@ -36,7 +36,6 @@ fn b() {
 fn c() {
     let z = call_it_once(square, 22);
     //~^ ERROR not implemented
-    //~| ERROR not implemented
 }
 
 fn main() { }