1818#![ feature( range_contains) ]
1919#![ cfg_attr( unix, feature( libc) ) ]
2020#![ feature( conservative_impl_trait) ]
21+ #![ feature( i128_type) ]
2122
2223extern crate term;
2324#[ cfg( unix) ]
2425extern crate libc;
26+ extern crate rustc_data_structures;
2527extern crate serialize as rustc_serialize;
2628extern crate syntax_pos;
2729
@@ -31,6 +33,9 @@ use self::Level::*;
3133
3234use emitter:: { Emitter , EmitterWriter } ;
3335
36+ use rustc_data_structures:: fx:: FxHashSet ;
37+ use rustc_data_structures:: stable_hasher:: StableHasher ;
38+
3439use std:: borrow:: Cow ;
3540use std:: cell:: { RefCell , Cell } ;
3641use std:: mem;
@@ -47,7 +52,7 @@ mod lock;
4752
4853use syntax_pos:: { BytePos , Loc , FileLinesResult , FileMap , FileName , MultiSpan , Span , NO_EXPANSION } ;
4954
50- #[ derive( Clone , Debug , PartialEq , RustcEncodable , RustcDecodable ) ]
55+ #[ derive( Clone , Debug , PartialEq , Hash , RustcEncodable , RustcDecodable ) ]
5156pub enum RenderSpan {
5257 /// A FullSpan renders with both with an initial line for the
5358 /// message, prefixed by file:linenum, followed by a summary of
@@ -61,7 +66,7 @@ pub enum RenderSpan {
6166 Suggestion ( CodeSuggestion ) ,
6267}
6368
64- #[ derive( Clone , Debug , PartialEq , RustcEncodable , RustcDecodable ) ]
69+ #[ derive( Clone , Debug , PartialEq , Hash , RustcEncodable , RustcDecodable ) ]
6570pub struct CodeSuggestion {
6671 /// Each substitute can have multiple variants due to multiple
6772 /// applicable suggestions
@@ -86,7 +91,7 @@ pub struct CodeSuggestion {
8691 pub show_code_when_inline : bool ,
8792}
8893
89- #[ derive( Clone , Debug , PartialEq , RustcEncodable , RustcDecodable ) ]
94+ #[ derive( Clone , Debug , PartialEq , Hash , RustcEncodable , RustcDecodable ) ]
9095/// See the docs on `CodeSuggestion::substitutions`
9196pub struct Substitution {
9297 pub span : Span ,
@@ -271,6 +276,11 @@ pub struct Handler {
271276 continue_after_error : Cell < bool > ,
272277 delayed_span_bug : RefCell < Option < Diagnostic > > ,
273278 tracked_diagnostics : RefCell < Option < Vec < Diagnostic > > > ,
279+
280+ // This set contains a hash of every diagnostic that has been emitted by
281+ // this handler. These hashes is used to avoid emitting the same error
282+ // twice.
283+ emitted_diagnostics : RefCell < FxHashSet < u128 > > ,
274284}
275285
276286impl Handler {
@@ -295,6 +305,7 @@ impl Handler {
295305 continue_after_error : Cell :: new ( true ) ,
296306 delayed_span_bug : RefCell :: new ( None ) ,
297307 tracked_diagnostics : RefCell :: new ( None ) ,
308+ emitted_diagnostics : RefCell :: new ( FxHashSet ( ) ) ,
298309 }
299310 }
300311
@@ -559,15 +570,29 @@ impl Handler {
559570 }
560571
561572 fn emit_db ( & self , db : & DiagnosticBuilder ) {
573+ let diagnostic = & * * db;
574+
562575 if let Some ( ref mut list) = * self . tracked_diagnostics . borrow_mut ( ) {
563- list. push ( ( * * db) . clone ( ) ) ;
576+ list. push ( diagnostic. clone ( ) ) ;
577+ }
578+
579+ let diagnostic_hash = {
580+ use std:: hash:: Hash ;
581+ let mut hasher = StableHasher :: new ( ) ;
582+ diagnostic. hash ( & mut hasher) ;
583+ hasher. finish ( )
584+ } ;
585+
586+ // Only emit the diagnostic if we haven't already emitted an equivalent
587+ // one:
588+ if self . emitted_diagnostics . borrow_mut ( ) . insert ( diagnostic_hash) {
589+ self . emitter . borrow_mut ( ) . emit ( db) ;
564590 }
565- self . emitter . borrow_mut ( ) . emit ( db) ;
566591 }
567592}
568593
569594
570- #[ derive( Copy , PartialEq , Clone , Debug , RustcEncodable , RustcDecodable ) ]
595+ #[ derive( Copy , PartialEq , Clone , Hash , Debug , RustcEncodable , RustcDecodable ) ]
571596pub enum Level {
572597 Bug ,
573598 Fatal ,
0 commit comments