@@ -1112,6 +1112,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
11121112 let mut bindings = smallvec ! [ ( false , <_>:: default ( ) ) ] ;
11131113 for Param { pat, ty, .. } in params {
11141114 self . resolve_pattern ( pat, PatternSource :: FnParam , & mut bindings) ;
1115+ self . check_consistent_bindings_top ( pat) ;
11151116 self . visit_ty ( ty) ;
11161117 debug ! ( "(resolving function / closure) recorded parameter" ) ;
11171118 }
@@ -1128,69 +1129,90 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
11281129 self . resolve_pattern_top ( & local. pat , PatternSource :: Let ) ;
11291130 }
11301131
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.
11351136 fn binding_mode_map ( & mut self , pat : & Pat ) -> BindingMap {
11361137 let mut binding_map = FxHashMap :: default ( ) ;
11371138
11381139 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 ;
11471153 }
1154+ _ => { }
11481155 }
1156+
11491157 true
11501158 } ) ;
11511159
11521160 binding_map
11531161 }
11541162
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 > {
11581173 let mut missing_vars = FxHashMap :: default ( ) ;
11591174 let mut inconsistent_vars = FxHashMap :: default ( ) ;
11601175
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 ) ) ;
11881209 }
11891210 }
11901211 }
11911212 }
11921213 }
11931214
1215+ // 3) Report all missing variables we found.
11941216 let mut missing_vars = missing_vars. iter_mut ( ) . collect :: < Vec < _ > > ( ) ;
11951217 missing_vars. sort ( ) ;
11961218 for ( name, mut v) in missing_vars {
@@ -1202,11 +1224,26 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
12021224 ResolutionError :: VariableNotBoundInPattern ( v) ) ;
12031225 }
12041226
1227+ // 4) Report all inconsistencies in binding modes we found.
12051228 let mut inconsistent_vars = inconsistent_vars. iter ( ) . collect :: < Vec < _ > > ( ) ;
12061229 inconsistent_vars. sort ( ) ;
12071230 for ( name, v) in inconsistent_vars {
12081231 self . r . report_error ( v. 0 , ResolutionError :: VariableBoundWithDifferentMode ( * name, v. 1 ) ) ;
12091232 }
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+ } )
12101247 }
12111248
12121249 fn resolve_arm ( & mut self , arm : & Arm ) {
@@ -1227,13 +1264,13 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
12271264 bindings. last_mut ( ) . unwrap ( ) . 1 . extend ( collected) ;
12281265 }
12291266 // 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) ;
12331268 }
12341269
12351270 fn resolve_pattern_top ( & mut self , pat : & Pat , pat_src : PatternSource ) {
12361271 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) ;
12371274 }
12381275
12391276 fn resolve_pattern (
0 commit comments