@@ -1112,6 +1112,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
1112
1112
let mut bindings = smallvec ! [ ( false , <_>:: default ( ) ) ] ;
1113
1113
for Param { pat, ty, .. } in params {
1114
1114
self . resolve_pattern ( pat, PatternSource :: FnParam , & mut bindings) ;
1115
+ self . check_consistent_bindings_top ( pat) ;
1115
1116
self . visit_ty ( ty) ;
1116
1117
debug ! ( "(resolving function / closure) recorded parameter" ) ;
1117
1118
}
@@ -1128,69 +1129,90 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
1128
1129
self . resolve_pattern_top ( & local. pat , PatternSource :: Let ) ;
1129
1130
}
1130
1131
1131
- // build a map from pattern identifiers to binding-info's.
1132
- // this is done hygienically. This could arise for a macro
1133
- // that expands into an or-pattern where one 'x' was from the
1134
- // user and one 'x' came from the macro.
1132
+ /// build a map from pattern identifiers to binding-info's.
1133
+ /// this is done hygienically. This could arise for a macro
1134
+ /// that expands into an or-pattern where one 'x' was from the
1135
+ /// user and one 'x' came from the macro.
1135
1136
fn binding_mode_map ( & mut self , pat : & Pat ) -> BindingMap {
1136
1137
let mut binding_map = FxHashMap :: default ( ) ;
1137
1138
1138
1139
pat. walk ( & mut |pat| {
1139
- if let PatKind :: Ident ( binding_mode, ident, ref sub_pat) = pat. node {
1140
- if sub_pat. is_some ( ) || match self . r . partial_res_map . get ( & pat. id )
1141
- . map ( |res| res. base_res ( ) ) {
1142
- Some ( Res :: Local ( ..) ) => true ,
1143
- _ => false ,
1144
- } {
1145
- let binding_info = BindingInfo { span : ident. span , binding_mode : binding_mode } ;
1146
- binding_map. insert ( ident, binding_info) ;
1140
+ match pat. node {
1141
+ PatKind :: Ident ( binding_mode, ident, ref sub_pat)
1142
+ if sub_pat. is_some ( ) || self . is_base_res_local ( pat. id ) =>
1143
+ {
1144
+ binding_map. insert ( ident, BindingInfo { span : ident. span , binding_mode } ) ;
1145
+ }
1146
+ PatKind :: Or ( ref ps) => {
1147
+ // Check the consistency of this or-pattern and
1148
+ // then add all bindings to the larger map.
1149
+ for bm in self . check_consistent_bindings ( ps) {
1150
+ binding_map. extend ( bm) ;
1151
+ }
1152
+ return false ;
1147
1153
}
1154
+ _ => { }
1148
1155
}
1156
+
1149
1157
true
1150
1158
} ) ;
1151
1159
1152
1160
binding_map
1153
1161
}
1154
1162
1155
- // Checks that all of the arms in an or-pattern have exactly the
1156
- // same set of bindings, with the same binding modes for each.
1157
- fn check_consistent_bindings ( & mut self , pats : & [ P < Pat > ] ) {
1163
+ fn is_base_res_local ( & self , nid : NodeId ) -> bool {
1164
+ match self . r . partial_res_map . get ( & nid) . map ( |res| res. base_res ( ) ) {
1165
+ Some ( Res :: Local ( ..) ) => true ,
1166
+ _ => false ,
1167
+ }
1168
+ }
1169
+
1170
+ /// Checks that all of the arms in an or-pattern have exactly the
1171
+ /// same set of bindings, with the same binding modes for each.
1172
+ fn check_consistent_bindings ( & mut self , pats : & [ P < Pat > ] ) -> Vec < BindingMap > {
1158
1173
let mut missing_vars = FxHashMap :: default ( ) ;
1159
1174
let mut inconsistent_vars = FxHashMap :: default ( ) ;
1160
1175
1161
- for pat_outer in pats. iter ( ) {
1162
- let map_outer = self . binding_mode_map ( & pat_outer) ;
1163
-
1164
- for pat_inner in pats. iter ( ) . filter ( |pat| pat. id != pat_outer. id ) {
1165
- let map_inner = self . binding_mode_map ( & pat_inner) ;
1166
-
1167
- for ( & key_inner, & binding_inner) in map_inner. iter ( ) {
1168
- match map_outer. get ( & key_inner) {
1169
- None => { // missing binding
1170
- let binding_error = missing_vars
1171
- . entry ( key_inner. name )
1172
- . or_insert ( BindingError {
1173
- name : key_inner. name ,
1174
- origin : BTreeSet :: new ( ) ,
1175
- target : BTreeSet :: new ( ) ,
1176
- could_be_path :
1177
- key_inner. name . as_str ( ) . starts_with ( char:: is_uppercase)
1178
- } ) ;
1179
- binding_error. origin . insert ( binding_inner. span ) ;
1180
- binding_error. target . insert ( pat_outer. span ) ;
1181
- }
1182
- Some ( binding_outer) => { // check consistent binding
1183
- if binding_outer. binding_mode != binding_inner. binding_mode {
1184
- inconsistent_vars
1185
- . entry ( key_inner. name )
1186
- . or_insert ( ( binding_inner. span , binding_outer. span ) ) ;
1187
- }
1176
+ // 1) Compute the binding maps of all arms.
1177
+ let maps = pats. iter ( )
1178
+ . map ( |pat| self . binding_mode_map ( pat) )
1179
+ . collect :: < Vec < _ > > ( ) ;
1180
+
1181
+ // 2) Record any missing bindings or binding mode inconsistencies.
1182
+ for ( map_outer, pat_outer) in pats. iter ( ) . enumerate ( ) . map ( |( idx, pat) | ( & maps[ idx] , pat) ) {
1183
+ // Check against all arms except for the same pattern which is always self-consistent.
1184
+ let inners = pats. iter ( ) . enumerate ( )
1185
+ . filter ( |( _, pat) | pat. id != pat_outer. id )
1186
+ . flat_map ( |( idx, _) | maps[ idx] . iter ( ) )
1187
+ . map ( |( key, binding) | ( key. name , map_outer. get ( & key) , binding) ) ;
1188
+
1189
+ for ( name, info, & binding_inner) in inners {
1190
+ match info {
1191
+ None => { // The inner binding is missing in the outer.
1192
+ let binding_error = missing_vars
1193
+ . entry ( name)
1194
+ . or_insert_with ( || BindingError {
1195
+ name,
1196
+ origin : BTreeSet :: new ( ) ,
1197
+ target : BTreeSet :: new ( ) ,
1198
+ could_be_path : name. as_str ( ) . starts_with ( char:: is_uppercase) ,
1199
+ } ) ;
1200
+ binding_error. origin . insert ( binding_inner. span ) ;
1201
+ binding_error. target . insert ( pat_outer. span ) ;
1202
+ }
1203
+ Some ( binding_outer) => {
1204
+ if binding_outer. binding_mode != binding_inner. binding_mode {
1205
+ // The binding modes in the outer and inner bindings differ.
1206
+ inconsistent_vars
1207
+ . entry ( name)
1208
+ . or_insert ( ( binding_inner. span , binding_outer. span ) ) ;
1188
1209
}
1189
1210
}
1190
1211
}
1191
1212
}
1192
1213
}
1193
1214
1215
+ // 3) Report all missing variables we found.
1194
1216
let mut missing_vars = missing_vars. iter_mut ( ) . collect :: < Vec < _ > > ( ) ;
1195
1217
missing_vars. sort ( ) ;
1196
1218
for ( name, mut v) in missing_vars {
@@ -1202,11 +1224,26 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
1202
1224
ResolutionError :: VariableNotBoundInPattern ( v) ) ;
1203
1225
}
1204
1226
1227
+ // 4) Report all inconsistencies in binding modes we found.
1205
1228
let mut inconsistent_vars = inconsistent_vars. iter ( ) . collect :: < Vec < _ > > ( ) ;
1206
1229
inconsistent_vars. sort ( ) ;
1207
1230
for ( name, v) in inconsistent_vars {
1208
1231
self . r . report_error ( v. 0 , ResolutionError :: VariableBoundWithDifferentMode ( * name, v. 1 ) ) ;
1209
1232
}
1233
+
1234
+ // 5) Finally bubble up all the binding maps.
1235
+ maps
1236
+ }
1237
+
1238
+ /// Check the consistency of the outermost or-patterns.
1239
+ fn check_consistent_bindings_top ( & mut self , pat : & Pat ) {
1240
+ pat. walk ( & mut |pat| match pat. node {
1241
+ PatKind :: Or ( ref ps) => {
1242
+ self . check_consistent_bindings ( ps) ;
1243
+ false
1244
+ } ,
1245
+ _ => true ,
1246
+ } )
1210
1247
}
1211
1248
1212
1249
fn resolve_arm ( & mut self , arm : & Arm ) {
@@ -1227,13 +1264,13 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
1227
1264
bindings. last_mut ( ) . unwrap ( ) . 1 . extend ( collected) ;
1228
1265
}
1229
1266
// This has to happen *after* we determine which pat_idents are variants
1230
- if pats. len ( ) > 1 {
1231
- self . check_consistent_bindings ( pats) ;
1232
- }
1267
+ self . check_consistent_bindings ( pats) ;
1233
1268
}
1234
1269
1235
1270
fn resolve_pattern_top ( & mut self , pat : & Pat , pat_src : PatternSource ) {
1236
1271
self . resolve_pattern ( pat, pat_src, & mut smallvec ! [ ( false , <_>:: default ( ) ) ] ) ;
1272
+ // This has to happen *after* we determine which pat_idents are variants:
1273
+ self . check_consistent_bindings_top ( pat) ;
1237
1274
}
1238
1275
1239
1276
fn resolve_pattern (
0 commit comments