Skip to content

Commit fe6ad09

Browse files
Ariel Ben-Yehudaarielb1
Ariel Ben-Yehuda
authored andcommitted
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?)
1 parent 9169e6c commit fe6ad09

26 files changed

+77
-40
lines changed

Diff for: src/librustc/middle/infer/mod.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ use std::rc::Rc;
4343
use syntax::ast;
4444
use syntax::codemap;
4545
use syntax::codemap::{Span, DUMMY_SP};
46-
use util::nodemap::{FnvHashMap, NodeMap};
46+
use util::nodemap::{FnvHashMap, FnvHashSet, NodeMap};
4747

4848
use self::combine::CombineFields;
4949
use self::region_inference::{RegionVarBindings, RegionSnapshot};
@@ -92,6 +92,10 @@ pub struct InferCtxt<'a, 'tcx: 'a> {
9292

9393
pub fulfillment_cx: RefCell<traits::FulfillmentContext<'tcx>>,
9494

95+
// the set of predicates on which errors have been reported, to
96+
// avoid reporting the same error twice.
97+
pub reported_trait_errors: RefCell<FnvHashSet<traits::TraitErrorKey<'tcx>>>,
98+
9599
// This is a temporary field used for toggling on normalization in the inference context,
96100
// as we move towards the approach described here:
97101
// 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>,
374378
region_vars: RegionVarBindings::new(tcx),
375379
parameter_environment: param_env.unwrap_or(tcx.empty_parameter_environment()),
376380
fulfillment_cx: RefCell::new(traits::FulfillmentContext::new(errors_will_be_reported)),
381+
reported_trait_errors: RefCell::new(FnvHashSet()),
377382
normalize: false,
378383
err_count_on_creation: tcx.sess.err_count()
379384
}

Diff for: src/librustc/middle/traits/error_reporting.rs

+27
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,26 @@ use std::fmt;
3333
use syntax::codemap::Span;
3434
use syntax::attr::{AttributeMethods, AttrMetaMethods};
3535

36+
#[derive(Debug, PartialEq, Eq, Hash)]
37+
pub struct TraitErrorKey<'tcx> {
38+
is_warning: bool,
39+
span: Span,
40+
predicate: ty::Predicate<'tcx>
41+
}
42+
43+
impl<'tcx> TraitErrorKey<'tcx> {
44+
fn from_error<'a>(infcx: &InferCtxt<'a, 'tcx>,
45+
e: &FulfillmentError<'tcx>) -> Self {
46+
let predicate =
47+
infcx.resolve_type_vars_if_possible(&e.obligation.predicate);
48+
TraitErrorKey {
49+
is_warning: is_warning(&e.obligation),
50+
span: e.obligation.cause.span,
51+
predicate: infcx.tcx.erase_regions(&predicate)
52+
}
53+
}
54+
}
55+
3656
pub fn report_fulfillment_errors<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
3757
errors: &Vec<FulfillmentError<'tcx>>) {
3858
for error in errors {
@@ -42,6 +62,13 @@ pub fn report_fulfillment_errors<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
4262

4363
fn report_fulfillment_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
4464
error: &FulfillmentError<'tcx>) {
65+
let error_key = TraitErrorKey::from_error(infcx, error);
66+
debug!("report_fulfillment_errors({:?}) - key={:?}",
67+
error, error_key);
68+
if !infcx.reported_trait_errors.borrow_mut().insert(error_key) {
69+
debug!("report_fulfillment_errors: skipping duplicate");
70+
return;
71+
}
4572
match error.code {
4673
FulfillmentErrorCode::CodeSelectionError(ref e) => {
4774
report_selection_error(infcx, &error.obligation, e);

Diff for: src/librustc/middle/traits/fulfill.rs

+6
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ pub struct FulfillmentContext<'tcx> {
4949
// than the `SelectionCache`: it avoids duplicate errors and
5050
// permits recursive obligations, which are often generated from
5151
// traits like `Send` et al.
52+
//
53+
// Note that because of type inference, a predicate can still
54+
// occur twice in the predicates list, for example when 2
55+
// initially-distinct type variables are unified after being
56+
// inserted. Deduplicating the predicate set on selection had a
57+
// significant performance cost the last time I checked.
5258
duplicate_set: FulfilledPredicates<'tcx>,
5359

5460
// A list of all obligations that have been registered with this

Diff for: src/librustc/middle/traits/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@ use middle::subst;
2121
use middle::ty::{self, HasTypeFlags, Ty};
2222
use middle::ty::fold::TypeFoldable;
2323
use middle::infer::{self, fixup_err_to_string, InferCtxt};
24+
2425
use std::rc::Rc;
2526
use syntax::ast;
2627
use syntax::codemap::{Span, DUMMY_SP};
2728

29+
pub use self::error_reporting::TraitErrorKey;
2830
pub use self::error_reporting::report_fulfillment_errors;
2931
pub use self::error_reporting::report_overflow_error;
3032
pub use self::error_reporting::report_selection_error;

Diff for: src/test/compile-fail/associated-types-ICE-when-projecting-out-of-err.rs

-1
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,4 @@ fn ice<A>(a: A) {
3232
let r = loop {};
3333
r = r + a;
3434
//~^ ERROR not implemented
35-
//~| ERROR not implemented
3635
}

Diff for: src/test/compile-fail/associated-types-path-2.rs

-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ pub fn f1_int_uint() {
3939
pub fn f1_uint_uint() {
4040
f1(2u32, 4u32);
4141
//~^ ERROR the trait `Foo` is not implemented
42-
//~| ERROR the trait `Foo` is not implemented
4342
}
4443

4544
pub fn f1_uint_int() {

Diff for: src/test/compile-fail/coerce-unsafe-to-closure.rs

-1
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,4 @@
1111
fn main() {
1212
let x: Option<&[u8]> = Some("foo").map(std::mem::transmute);
1313
//~^ ERROR E0277
14-
//~| ERROR E0277
1514
}

Diff for: src/test/compile-fail/const-eval-overflow-4b.rs

-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ const A_I8_T
2323
: [u32; (i8::MAX as i8 + 1u8) as usize]
2424
//~^ ERROR mismatched types
2525
//~| the trait `core::ops::Add<u8>` is not implemented for the type `i8`
26-
//~| the trait `core::ops::Add<u8>` is not implemented for the type `i8`
2726
= [0; (i8::MAX as usize) + 1];
2827

2928
fn main() {
@@ -33,4 +32,3 @@ fn main() {
3332
fn foo<T:fmt::Debug>(x: T) {
3433
println!("{:?}", x);
3534
}
36-

Diff for: src/test/compile-fail/fn-variance-1.rs

-2
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,8 @@ fn main() {
2020
apply(&3, takes_imm);
2121
apply(&3, takes_mut);
2222
//~^ ERROR (values differ in mutability)
23-
//~| ERROR (values differ in mutability)
2423

2524
apply(&mut 3, takes_mut);
2625
apply(&mut 3, takes_imm);
2726
//~^ ERROR (values differ in mutability)
28-
//~| ERROR (values differ in mutability)
2927
}

Diff for: src/test/compile-fail/for-loop-bogosity.rs

-3
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,6 @@ pub fn main() {
2525
y: 2,
2626
};
2727
for x in bogus { //~ ERROR `core::iter::Iterator` is not implemented for the type `MyStruct`
28-
//~^ ERROR
29-
//~^^ ERROR
30-
// FIXME(#21528) not fulfilled obligation error should be reported once, not thrice
3128
drop(x);
3229
}
3330
}

Diff for: src/test/compile-fail/indexing-requires-a-uint.rs

-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
fn main() {
1515
fn bar<T>(_: T) {}
1616
[0][0u8]; //~ ERROR: the trait `core::ops::Index<u8>` is not implemented
17-
//~^ ERROR: the trait `core::ops::Index<u8>` is not implemented
1817

1918
[0][0]; // should infer to be a usize
2019

Diff for: src/test/compile-fail/integral-indexing.rs

-8
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,13 @@ pub fn main() {
1414
v[3_usize];
1515
v[3];
1616
v[3u8]; //~ERROR the trait `core::ops::Index<u8>` is not implemented
17-
//~^ ERROR the trait `core::ops::Index<u8>` is not implemented
1817
v[3i8]; //~ERROR the trait `core::ops::Index<i8>` is not implemented
19-
//~^ ERROR the trait `core::ops::Index<i8>` is not implemented
2018
v[3u32]; //~ERROR the trait `core::ops::Index<u32>` is not implemented
21-
//~^ ERROR the trait `core::ops::Index<u32>` is not implemented
2219
v[3i32]; //~ERROR the trait `core::ops::Index<i32>` is not implemented
23-
//~^ ERROR the trait `core::ops::Index<i32>` is not implemented
2420
s.as_bytes()[3_usize];
2521
s.as_bytes()[3];
2622
s.as_bytes()[3u8]; //~ERROR the trait `core::ops::Index<u8>` is not implemented
27-
//~^ ERROR the trait `core::ops::Index<u8>` is not implemented
2823
s.as_bytes()[3i8]; //~ERROR the trait `core::ops::Index<i8>` is not implemented
29-
//~^ ERROR the trait `core::ops::Index<i8>` is not implemented
3024
s.as_bytes()[3u32]; //~ERROR the trait `core::ops::Index<u32>` is not implemented
31-
//~^ ERROR the trait `core::ops::Index<u32>` is not implemented
3225
s.as_bytes()[3i32]; //~ERROR the trait `core::ops::Index<i32>` is not implemented
33-
//~^ ERROR the trait `core::ops::Index<i32>` is not implemented
3426
}

Diff for: src/test/compile-fail/issue-11771.rs

-2
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,10 @@ fn main() {
1212
let x = ();
1313
1 +
1414
x //~^ ERROR E0277
15-
//~| ERROR E0277
1615
;
1716

1817
let x: () = ();
1918
1 +
2019
x //~^ ERROR E0277
21-
//~| ERROR E0277
2220
;
2321
}

Diff for: src/test/compile-fail/issue-13352.rs

-1
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,4 @@ fn main() {
1818
});
1919
2_usize + (loop {});
2020
//~^ ERROR E0277
21-
//~| ERROR E0277
2221
}

Diff for: src/test/compile-fail/issue-14084.rs

-1
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,4 @@
1414
fn main() {
1515
in () { 0 };
1616
//~^ ERROR: the trait `core::ops::Placer<_>` is not implemented
17-
//~| ERROR: the trait `core::ops::Placer<_>` is not implemented
1817
}

Diff for: src/test/compile-fail/issue-20605.rs

-3
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@
1111
fn changer<'a>(mut things: Box<Iterator<Item=&'a mut u8>>) {
1212
for item in *things { *item = 0 }
1313
//~^ ERROR the trait `core::marker::Sized` is not implemented for the type `core::iter::Iterator
14-
//~^^ ERROR
15-
//~^^^ ERROR
16-
// FIXME(#21528) error should be reported once, not thrice
1714
}
1815

1916
fn main() {}

Diff for: src/test/compile-fail/issue-2149.rs

-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ impl<A> vec_monad<A> for Vec<A> {
1717
let mut r = panic!();
1818
for elt in self { r = r + f(*elt); }
1919
//~^ ERROR E0277
20-
//~| ERROR E0277
2120
}
2221
}
2322
fn main() {

Diff for: src/test/compile-fail/issue-22645.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,5 @@ impl<RHS: Scalar> Add <RHS> for Bob {
2323
fn main() {
2424
let b = Bob + 3.5;
2525
b + 3 //~ ERROR: is not implemented
26-
//~^ ERROR: is not implemented
27-
//~^^ ERROR: is not implemented
28-
//~^^^ ERROR: mismatched types
26+
//~^ ERROR: mismatched types
2927
}

Diff for: src/test/compile-fail/issue-24352.rs

-1
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,4 @@
1111
fn main() {
1212
1.0f64 - 1.0;
1313
1.0f64 - 1 //~ ERROR: is not implemented
14-
//~^ ERROR: is not implemented
1514
}

Diff for: src/test/compile-fail/issue-28098.rs

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn main() {
12+
let _ = Iterator::next(&mut ());
13+
//~^ ERROR the trait `core::iter::Iterator` is not implemented
14+
15+
for _ in false {}
16+
//~^ ERROR the trait `core::iter::Iterator` is not implemented
17+
18+
let _ = Iterator::next(&mut ());
19+
//~^ ERROR the trait `core::iter::Iterator` is not implemented
20+
21+
other()
22+
}
23+
24+
pub fn other() {
25+
// check errors are still reported globally
26+
27+
let _ = Iterator::next(&mut ());
28+
//~^ ERROR the trait `core::iter::Iterator` is not implemented
29+
30+
let _ = Iterator::next(&mut ());
31+
//~^ ERROR the trait `core::iter::Iterator` is not implemented
32+
33+
for _ in false {}
34+
//~^ ERROR the trait `core::iter::Iterator` is not implemented
35+
}

Diff for: src/test/compile-fail/shift-various-bad-types.rs

-3
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,12 @@ struct Panolpy {
1818
fn foo(p: &Panolpy) {
1919
22 >> p.char;
2020
//~^ ERROR E0277
21-
//~| ERROR E0277
2221

2322
22 >> p.str;
2423
//~^ ERROR E0277
25-
//~| ERROR E0277
2624

2725
22 >> p;
2826
//~^ ERROR E0277
29-
//~| ERROR E0277
3027

3128
let x;
3229
22 >> x; // ambiguity error winds up being suppressed

Diff for: src/test/compile-fail/str-idx.rs

-1
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,4 @@
1111
pub fn main() {
1212
let s: &str = "hello";
1313
let c: u8 = s[4]; //~ ERROR the trait `core::ops::Index<_>` is not implemented
14-
//~^ ERROR the trait `core::ops::Index<_>` is not implemented
1514
}

Diff for: src/test/compile-fail/str-mut-idx.rs

-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ fn mutate(s: &mut str) {
1717
s[1usize] = bot();
1818
//~^ ERROR `core::ops::Index<usize>` is not implemented for the type `str`
1919
//~| ERROR `core::ops::IndexMut<usize>` is not implemented for the type `str`
20-
//~| ERROR `core::ops::Index<usize>` is not implemented for the type `str`
2120
}
2221

2322
pub fn main() {}

Diff for: src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs

-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ fn b() {
3535
fn c() {
3636
let z = call_it_once(square, 22);
3737
//~^ ERROR not implemented
38-
//~| ERROR not implemented
3938
}
4039

4140
fn main() { }

Diff for: src/test/compile-fail/unboxed-closures-wrong-abi.rs

-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ fn b() {
3535
fn c() {
3636
let z = call_it_once(square, 22);
3737
//~^ ERROR not implemented
38-
//~| ERROR not implemented
3938
}
4039

4140
fn main() { }

Diff for: src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs

-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ fn b() {
3636
fn c() {
3737
let z = call_it_once(square, 22);
3838
//~^ ERROR not implemented
39-
//~| ERROR not implemented
4039
}
4140

4241
fn main() { }

0 commit comments

Comments
 (0)