@@ -69,6 +69,7 @@ use errors::DiagnosticBuilder;
69
69
70
70
use std:: cell:: { Cell , RefCell } ;
71
71
use std:: cmp;
72
+ use std:: collections:: BTreeSet ;
72
73
use std:: fmt;
73
74
use std:: mem:: replace;
74
75
use std:: rc:: Rc ;
@@ -97,6 +98,31 @@ enum AssocSuggestion {
97
98
AssocItem ,
98
99
}
99
100
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
+
100
126
enum ResolutionError < ' a > {
101
127
/// error E0401: can't use type parameters from outer function
102
128
TypeParametersFromOuterFunction ,
@@ -110,10 +136,10 @@ enum ResolutionError<'a> {
110
136
TypeNotMemberOfTrait ( Name , & ' a str ) ,
111
137
/// error E0438: const is not a member of trait
112
138
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 ) ,
117
143
/// error E0415: identifier is bound more than once in this parameter list
118
144
IdentifierBoundMoreThanOnceInParameterList ( & ' a str ) ,
119
145
/// 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,
207
233
err. span_label ( span, & format ! ( "not a member of trait `{}`" , trait_) ) ;
208
234
err
209
235
}
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
+ }
219
248
err
220
249
}
221
250
ResolutionError :: VariableBoundWithDifferentMode ( variable_name,
222
- pattern_number,
223
251
first_binding_span) => {
224
252
let mut err = struct_span_err ! ( resolver. session,
225
253
span,
226
254
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) ;
231
258
err. span_label ( span, & format ! ( "bound in different ways" ) ) ;
232
259
err. span_label ( first_binding_span, & format ! ( "first binding" ) ) ;
233
260
err
@@ -335,7 +362,7 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
335
362
}
336
363
}
337
364
338
- #[ derive( Copy , Clone ) ]
365
+ #[ derive( Copy , Clone , Debug ) ]
339
366
struct BindingInfo {
340
367
span : Span ,
341
368
binding_mode : BindingMode ,
@@ -1904,36 +1931,66 @@ impl<'a> Resolver<'a> {
1904
1931
if arm. pats . is_empty ( ) {
1905
1932
return ;
1906
1933
}
1907
- let map_0 = self . binding_mode_map ( & arm. pats [ 0 ] ) ;
1934
+
1935
+ let mut missing_vars = FxHashMap ( ) ;
1936
+ let mut inconsistent_vars = FxHashMap ( ) ;
1908
1937
for ( i, p) in arm. pats . iter ( ) . enumerate ( ) {
1909
1938
let map_i = self . binding_mode_map ( & p) ;
1910
1939
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 ) ;
1916
1957
}
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
+ }
1925
1978
}
1926
1979
}
1927
1980
}
1928
1981
}
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 ) ) ;
1937
1994
}
1938
1995
}
1939
1996
0 commit comments