From fe6ad097c654d2655ad11610b2c96d577a3fcc2b Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 24 Sep 2015 19:58:00 +0300 Subject: [PATCH] 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?) --- src/librustc/middle/infer/mod.rs | 7 +++- src/librustc/middle/traits/error_reporting.rs | 27 ++++++++++++++ src/librustc/middle/traits/fulfill.rs | 6 ++++ src/librustc/middle/traits/mod.rs | 2 ++ ...ed-types-ICE-when-projecting-out-of-err.rs | 1 - .../compile-fail/associated-types-path-2.rs | 1 - .../compile-fail/coerce-unsafe-to-closure.rs | 1 - .../compile-fail/const-eval-overflow-4b.rs | 2 -- src/test/compile-fail/fn-variance-1.rs | 2 -- src/test/compile-fail/for-loop-bogosity.rs | 3 -- .../compile-fail/indexing-requires-a-uint.rs | 1 - src/test/compile-fail/integral-indexing.rs | 8 ----- src/test/compile-fail/issue-11771.rs | 2 -- src/test/compile-fail/issue-13352.rs | 1 - src/test/compile-fail/issue-14084.rs | 1 - src/test/compile-fail/issue-20605.rs | 3 -- src/test/compile-fail/issue-2149.rs | 1 - src/test/compile-fail/issue-22645.rs | 4 +-- src/test/compile-fail/issue-24352.rs | 1 - src/test/compile-fail/issue-28098.rs | 35 +++++++++++++++++++ .../compile-fail/shift-various-bad-types.rs | 3 -- src/test/compile-fail/str-idx.rs | 1 - src/test/compile-fail/str-mut-idx.rs | 1 - .../unboxed-closures-unsafe-extern-fn.rs | 1 - .../unboxed-closures-wrong-abi.rs | 1 - ...boxed-closures-wrong-arg-type-extern-fn.rs | 1 - 26 files changed, 77 insertions(+), 40 deletions(-) create mode 100644 src/test/compile-fail/issue-28098.rs 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 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>, + // the set of predicates on which errors have been reported, to + // avoid reporting the same error twice. + pub reported_trait_errors: RefCell>>, + // 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 25e6036e85a..c6c438f1d83 100644 --- a/src/librustc/middle/traits/error_reporting.rs +++ b/src/librustc/middle/traits/error_reporting.rs @@ -33,6 +33,26 @@ 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>) { 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 5dc6f9454a8..a037621f5c0 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -21,10 +21,12 @@ 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) { 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 @@ : [u32; (i8::MAX as i8 + 1u8) as usize] //~^ ERROR mismatched types //~| the trait `core::ops::Add` is not implemented for the type `i8` - //~| the trait `core::ops::Add` is not implemented for the type `i8` = [0; (i8::MAX as usize) + 1]; fn main() { @@ -33,4 +32,3 @@ fn main() { fn foo(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) {} [0][0u8]; //~ ERROR: the trait `core::ops::Index` is not implemented - //~^ ERROR: the trait `core::ops::Index` 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` is not implemented - //~^ ERROR the trait `core::ops::Index` is not implemented v[3i8]; //~ERROR the trait `core::ops::Index` is not implemented - //~^ ERROR the trait `core::ops::Index` is not implemented v[3u32]; //~ERROR the trait `core::ops::Index` is not implemented - //~^ ERROR the trait `core::ops::Index` is not implemented v[3i32]; //~ERROR the trait `core::ops::Index` is not implemented - //~^ ERROR the trait `core::ops::Index` is not implemented s.as_bytes()[3_usize]; s.as_bytes()[3]; s.as_bytes()[3u8]; //~ERROR the trait `core::ops::Index` is not implemented - //~^ ERROR the trait `core::ops::Index` is not implemented s.as_bytes()[3i8]; //~ERROR the trait `core::ops::Index` is not implemented - //~^ ERROR the trait `core::ops::Index` is not implemented s.as_bytes()[3u32]; //~ERROR the trait `core::ops::Index` is not implemented - //~^ ERROR the trait `core::ops::Index` is not implemented s.as_bytes()[3i32]; //~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/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 b2863202ef0..6b19cb0b68f 100644 --- a/src/test/compile-fail/issue-14084.rs +++ b/src/test/compile-fail/issue-14084.rs @@ -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 } 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>) { 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 @@ fn bind(&self, mut f: F) where F: FnMut(A) -> Vec { 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 @@ 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 } 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 or the MIT license +// , 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` is not implemented for the type `str` //~| ERROR `core::ops::IndexMut` is not implemented for the type `str` - //~| ERROR `core::ops::Index` 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() { } -- 2.44.0