@@ -69,6 +69,7 @@ use errors::DiagnosticBuilder;
6969
7070use std:: cell:: { Cell , RefCell } ;
7171use std:: cmp;
72+ use std:: collections:: BTreeSet ;
7273use std:: fmt;
7374use std:: mem:: replace;
7475use std:: rc:: Rc ;
@@ -97,6 +98,31 @@ enum AssocSuggestion {
9798 AssocItem ,
9899}
99100
101+ #[ derive( Eq ) ]
102+ struct BindingError {
103+ name : Name ,
104+ origin : BTreeSet < Span > ,
105+ target : BTreeSet < Span > ,
106+ }
107+
108+ impl PartialOrd for BindingError {
109+ fn partial_cmp ( & self , other : & BindingError ) -> Option < cmp:: Ordering > {
110+ Some ( self . cmp ( other) )
111+ }
112+ }
113+
114+ impl PartialEq for BindingError {
115+ fn eq ( & self , other : & BindingError ) -> bool {
116+ self . name == other. name
117+ }
118+ }
119+
120+ impl Ord for BindingError {
121+ fn cmp ( & self , other : & BindingError ) -> cmp:: Ordering {
122+ self . name . cmp ( & other. name )
123+ }
124+ }
125+
100126enum ResolutionError < ' a > {
101127 /// error E0401: can't use type parameters from outer function
102128 TypeParametersFromOuterFunction ,
@@ -110,10 +136,10 @@ enum ResolutionError<'a> {
110136 TypeNotMemberOfTrait ( Name , & ' a str ) ,
111137 /// error E0438: const is not a member of trait
112138 ConstNotMemberOfTrait ( Name , & ' a str ) ,
113- /// error E0408: variable `{}` from pattern #{} is not bound in pattern #{}
114- VariableNotBoundInPattern ( Name , usize , usize ) ,
115- /// error E0409: variable is bound with different mode in pattern #{} than in pattern #1
116- VariableBoundWithDifferentMode ( Name , usize , Span ) ,
139+ /// error E0408: variable `{}` is not bound in all patterns
140+ VariableNotBoundInPattern ( & ' a BindingError ) ,
141+ /// error E0409: variable `{}` is bound in inconsistent ways within the same match arm
142+ VariableBoundWithDifferentMode ( Name , Span ) ,
117143 /// error E0415: identifier is bound more than once in this parameter list
118144 IdentifierBoundMoreThanOnceInParameterList ( & ' a str ) ,
119145 /// error E0416: identifier is bound more than once in the same pattern
@@ -207,27 +233,28 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
207233 err. span_label ( span, & format ! ( "not a member of trait `{}`" , trait_) ) ;
208234 err
209235 }
210- ResolutionError :: VariableNotBoundInPattern ( variable_name, from, to) => {
211- let mut err = struct_span_err ! ( resolver. session,
212- span,
213- E0408 ,
214- "variable `{}` from pattern #{} is not bound in pattern #{}" ,
215- variable_name,
216- from,
217- to) ;
218- err. span_label ( span, & format ! ( "pattern doesn't bind `{}`" , variable_name) ) ;
236+ ResolutionError :: VariableNotBoundInPattern ( binding_error) => {
237+ let target_sp = binding_error. target . iter ( ) . map ( |x| * x) . collect :: < Vec < _ > > ( ) ;
238+ let msp = MultiSpan :: from_spans ( target_sp. clone ( ) ) ;
239+ let msg = format ! ( "variable `{}` is not bound in all patterns" , binding_error. name) ;
240+ let mut err = resolver. session . struct_span_err_with_code ( msp, & msg, "E0408" ) ;
241+ for sp in target_sp {
242+ err. span_label ( sp, & format ! ( "pattern doesn't bind `{}`" , binding_error. name) ) ;
243+ }
244+ let origin_sp = binding_error. origin . iter ( ) . map ( |x| * x) . collect :: < Vec < _ > > ( ) ;
245+ for sp in origin_sp {
246+ err. span_label ( sp, & "variable not in all patterns" ) ;
247+ }
219248 err
220249 }
221250 ResolutionError :: VariableBoundWithDifferentMode ( variable_name,
222- pattern_number,
223251 first_binding_span) => {
224252 let mut err = struct_span_err ! ( resolver. session,
225253 span,
226254 E0409 ,
227- "variable `{}` is bound with different mode in pattern #{} than in \
228- pattern #1",
229- variable_name,
230- pattern_number) ;
255+ "variable `{}` is bound in inconsistent \
256+ ways within the same match arm",
257+ variable_name) ;
231258 err. span_label ( span, & format ! ( "bound in different ways" ) ) ;
232259 err. span_label ( first_binding_span, & format ! ( "first binding" ) ) ;
233260 err
@@ -335,7 +362,7 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
335362 }
336363}
337364
338- #[ derive( Copy , Clone ) ]
365+ #[ derive( Copy , Clone , Debug ) ]
339366struct BindingInfo {
340367 span : Span ,
341368 binding_mode : BindingMode ,
@@ -1904,36 +1931,66 @@ impl<'a> Resolver<'a> {
19041931 if arm. pats . is_empty ( ) {
19051932 return ;
19061933 }
1907- let map_0 = self . binding_mode_map ( & arm. pats [ 0 ] ) ;
1934+
1935+ let mut missing_vars = FxHashMap ( ) ;
1936+ let mut inconsistent_vars = FxHashMap ( ) ;
19081937 for ( i, p) in arm. pats . iter ( ) . enumerate ( ) {
19091938 let map_i = self . binding_mode_map ( & p) ;
19101939
1911- for ( & key, & binding_0) in & map_0 {
1912- match map_i. get ( & key) {
1913- None => {
1914- let error = ResolutionError :: VariableNotBoundInPattern ( key. name , 1 , i + 1 ) ;
1915- resolve_error ( self , p. span , error) ;
1940+ for ( j, q) in arm. pats . iter ( ) . enumerate ( ) {
1941+ if i == j {
1942+ continue ;
1943+ }
1944+
1945+ let map_j = self . binding_mode_map ( & q) ;
1946+ for ( & key, & binding_i) in & map_i {
1947+ if map_j. len ( ) == 0 { // Account for missing bindings when
1948+ let binding_error = missing_vars // map_j has none.
1949+ . entry ( key. name )
1950+ . or_insert ( BindingError {
1951+ name : key. name ,
1952+ origin : BTreeSet :: new ( ) ,
1953+ target : BTreeSet :: new ( ) ,
1954+ } ) ;
1955+ binding_error. origin . insert ( binding_i. span ) ;
1956+ binding_error. target . insert ( q. span ) ;
19161957 }
1917- Some ( binding_i) => {
1918- if binding_0. binding_mode != binding_i. binding_mode {
1919- resolve_error ( self ,
1920- binding_i. span ,
1921- ResolutionError :: VariableBoundWithDifferentMode (
1922- key. name ,
1923- i + 1 ,
1924- binding_0. span ) ) ;
1958+ for ( & key_j, & binding_j) in & map_j {
1959+ match map_i. get ( & key_j) {
1960+ None => { // missing binding
1961+ let binding_error = missing_vars
1962+ . entry ( key_j. name )
1963+ . or_insert ( BindingError {
1964+ name : key_j. name ,
1965+ origin : BTreeSet :: new ( ) ,
1966+ target : BTreeSet :: new ( ) ,
1967+ } ) ;
1968+ binding_error. origin . insert ( binding_j. span ) ;
1969+ binding_error. target . insert ( p. span ) ;
1970+ }
1971+ Some ( binding_i) => { // check consistent binding
1972+ if binding_i. binding_mode != binding_j. binding_mode {
1973+ inconsistent_vars
1974+ . entry ( key. name )
1975+ . or_insert ( ( binding_j. span , binding_i. span ) ) ;
1976+ }
1977+ }
19251978 }
19261979 }
19271980 }
19281981 }
1929-
1930- for ( & key, & binding) in & map_i {
1931- if !map_0. contains_key ( & key) {
1932- resolve_error ( self ,
1933- binding. span ,
1934- ResolutionError :: VariableNotBoundInPattern ( key. name , i + 1 , 1 ) ) ;
1935- }
1936- }
1982+ }
1983+ let mut missing_vars = missing_vars. iter ( ) . collect :: < Vec < _ > > ( ) ;
1984+ missing_vars. sort ( ) ;
1985+ for ( _, v) in missing_vars {
1986+ resolve_error ( self ,
1987+ * v. origin . iter ( ) . next ( ) . unwrap ( ) ,
1988+ ResolutionError :: VariableNotBoundInPattern ( v) ) ;
1989+ }
1990+ let mut inconsistent_vars = inconsistent_vars. iter ( ) . collect :: < Vec < _ > > ( ) ;
1991+ inconsistent_vars. sort ( ) ;
1992+ for ( name, v) in inconsistent_vars {
1993+ resolve_error ( self , v. 0 , ResolutionError :: VariableBoundWithDifferentMode ( * name, v. 1 ) ) ;
19371994 }
19381995 }
19391996
0 commit comments