@@ -19,6 +19,7 @@ use rustc::hir::def::Namespace::{self, *};
19
19
use rustc:: hir:: def_id:: { DefId , CRATE_DEF_INDEX } ;
20
20
use rustc:: hir:: TraitCandidate ;
21
21
use rustc:: util:: nodemap:: FxHashMap ;
22
+ use rustc_data_structures:: fx:: FxIndexMap ;
22
23
use smallvec:: { smallvec, SmallVec } ;
23
24
use syntax:: { unwrap_or, walk_list} ;
24
25
use syntax:: ast:: * ;
@@ -408,7 +409,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
408
409
visit:: walk_foreign_item ( this, foreign_item) ;
409
410
} ) ;
410
411
}
411
- fn visit_fn ( & mut self , fn_kind : FnKind < ' tcx > , declaration : & ' tcx FnDecl , _: Span , _ : NodeId ) {
412
+ fn visit_fn ( & mut self , fn_kind : FnKind < ' tcx > , declaration : & ' tcx FnDecl , _: Span , id : NodeId ) {
412
413
debug ! ( "(resolving function) entering function" ) ;
413
414
let rib_kind = match fn_kind {
414
415
FnKind :: ItemFn ( ..) => FnItemRibKind ,
@@ -420,7 +421,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
420
421
// Create a label rib for the function.
421
422
this. with_label_rib ( rib_kind, |this| {
422
423
// Add each argument to the rib.
423
- this. resolve_params ( & declaration. inputs ) ;
424
+ this. resolve_params ( & declaration. inputs , id ) ;
424
425
425
426
visit:: walk_fn_ret_ty ( this, & declaration. output ) ;
426
427
@@ -1108,11 +1109,11 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
1108
1109
}
1109
1110
}
1110
1111
1111
- fn resolve_params ( & mut self , params : & [ Arg ] ) {
1112
- let mut bindings_list = FxHashMap :: default ( ) ;
1113
- for param in params {
1114
- self . resolve_pattern ( & param . pat , PatternSource :: FnParam , & mut bindings_list ) ;
1115
- self . visit_ty ( & param . ty ) ;
1112
+ fn resolve_params ( & mut self , params : & [ Param ] , id : NodeId ) {
1113
+ let mut bindings = FxIndexMap :: default ( ) ;
1114
+ for Param { pat , ty , .. } in params {
1115
+ self . resolve_pattern ( pat, PatternSource :: FnParam , & mut smallvec ! [ id ] , & mut bindings ) ;
1116
+ self . visit_ty ( ty) ;
1116
1117
debug ! ( "(resolving function / closure) recorded parameter" ) ;
1117
1118
}
1118
1119
}
@@ -1125,7 +1126,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
1125
1126
walk_list ! ( self , visit_expr, & local. init) ;
1126
1127
1127
1128
// Resolve the pattern.
1128
- self . resolve_pattern ( & local. pat , PatternSource :: Let , & mut FxHashMap :: default ( ) ) ;
1129
+ self . resolve_pattern_top ( & local. pat , PatternSource :: Let ) ;
1129
1130
}
1130
1131
1131
1132
// build a map from pattern identifiers to binding-info's.
@@ -1219,25 +1220,39 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
1219
1220
1220
1221
/// Arising from `source`, resolve a sequence of patterns (top level or-patterns).
1221
1222
fn resolve_pats ( & mut self , pats : & [ P < Pat > ] , source : PatternSource ) {
1222
- let mut bindings_list = FxHashMap :: default ( ) ;
1223
+ let mut bindings_list = FxIndexMap :: default ( ) ;
1223
1224
for pat in pats {
1224
- self . resolve_pattern ( pat, source, & mut bindings_list) ;
1225
+ self . resolve_pattern ( pat, source, & mut smallvec ! [ pat . id ] , & mut bindings_list) ;
1225
1226
}
1226
1227
// This has to happen *after* we determine which pat_idents are variants
1227
1228
if pats. len ( ) > 1 {
1228
1229
self . check_consistent_bindings ( pats) ;
1229
1230
}
1230
1231
}
1231
1232
1233
+ fn resolve_pattern_top ( & mut self , pat : & Pat , pat_src : PatternSource ) {
1234
+ self . resolve_pattern ( pat, pat_src, & mut smallvec ! [ pat. id] , & mut FxIndexMap :: default ( ) ) ;
1235
+ }
1236
+
1232
1237
fn resolve_pattern (
1233
1238
& mut self ,
1234
1239
pat : & Pat ,
1235
1240
pat_src : PatternSource ,
1236
- // Maps idents to the node ID for the outermost pattern that binds them.
1237
- bindings : & mut IdentMap < NodeId > ,
1241
+ prod_ids : & mut SmallVec < [ NodeId ; 1 ] > ,
1242
+ bindings : & mut FxIndexMap < Ident , NodeId > ,
1243
+ ) {
1244
+ self . resolve_pattern_inner ( pat, pat_src, prod_ids, bindings) ;
1245
+ visit:: walk_pat ( self , pat) ;
1246
+ }
1247
+
1248
+ fn resolve_pattern_inner (
1249
+ & mut self ,
1250
+ pat : & Pat ,
1251
+ pat_src : PatternSource ,
1252
+ prod_ids : & mut SmallVec < [ NodeId ; 1 ] > ,
1253
+ bindings : & mut FxIndexMap < Ident , NodeId > ,
1238
1254
) {
1239
1255
// Visit all direct subpatterns of this pattern.
1240
- let outer_pat_id = pat. id ;
1241
1256
pat. walk ( & mut |pat| {
1242
1257
debug ! ( "resolve_pattern pat={:?} node={:?}" , pat, pat. node) ;
1243
1258
match pat. node {
@@ -1247,7 +1262,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
1247
1262
let has_sub = sub. is_some ( ) ;
1248
1263
let res = self . try_resolve_as_non_binding ( pat_src, pat, bmode, ident, has_sub)
1249
1264
. unwrap_or_else ( || {
1250
- self . fresh_binding ( ident, pat. id , outer_pat_id , pat_src , bindings)
1265
+ self . fresh_binding ( ident, pat. id , pat_src , prod_ids , bindings)
1251
1266
} ) ;
1252
1267
self . r . record_partial_res ( pat. id , PartialRes :: new ( res) ) ;
1253
1268
}
@@ -1260,59 +1275,70 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
1260
1275
PatKind :: Struct ( ref path, ..) => {
1261
1276
self . smart_resolve_path ( pat. id , None , path, PathSource :: Struct ) ;
1262
1277
}
1278
+ PatKind :: Or ( ref ps) => {
1279
+ let len_before = bindings. len ( ) ;
1280
+ for p in ps {
1281
+ // We need to change `prod_ids.last()` at this point so that overlapping
1282
+ // bindings across the summands in the or-pattern do not result in an error.
1283
+ // The idea is that in `V1(a) | V2(a)`, the `a` in `V1` will be inserted
1284
+ // with a different id than the one in `V2`. As a result, `V1(a) | V2(a)`
1285
+ // compiles as it should. We will later check or-patterns for consistency.
1286
+ prod_ids. push ( p. id ) ;
1287
+ self . resolve_pattern_inner ( p, pat_src, prod_ids, bindings) ;
1288
+ prod_ids. pop ( ) ;
1289
+ }
1290
+
1291
+ // We've rejected overlap in each product in the sum.
1292
+ // Now we must account for the possibility that the or-pattern is a factor
1293
+ // in a product. A basic case to reject here is `(V1(a) | V2(a), a)`.
1294
+ let last_id = * prod_ids. last ( ) . unwrap ( ) ;
1295
+ bindings. values_mut ( ) . skip ( len_before) . for_each ( |val| * val = last_id) ;
1296
+
1297
+ // Prevent visiting `ps` as we've already done so above.
1298
+ return false ;
1299
+ }
1263
1300
_ => { }
1264
1301
}
1265
1302
true
1266
1303
} ) ;
1267
-
1268
- visit:: walk_pat ( self , pat) ;
1269
1304
}
1270
1305
1271
1306
fn fresh_binding (
1272
1307
& mut self ,
1273
1308
ident : Ident ,
1274
1309
pat_id : NodeId ,
1275
- outer_pat_id : NodeId ,
1276
1310
pat_src : PatternSource ,
1277
- bindings : & mut IdentMap < NodeId > ,
1311
+ prod_ids : & [ NodeId ] ,
1312
+ bindings : & mut FxIndexMap < Ident , NodeId > ,
1278
1313
) -> Res {
1279
1314
// Add the binding to the local ribs, if it doesn't already exist in the bindings map.
1280
1315
// (We must not add it if it's in the bindings map because that breaks the assumptions
1281
1316
// later passes make about or-patterns.)
1282
1317
let ident = ident. modern_and_legacy ( ) ;
1283
- let mut res = Res :: Local ( pat_id) ;
1318
+ let res = Res :: Local ( pat_id) ;
1284
1319
match bindings. get ( & ident) . cloned ( ) {
1285
- Some ( id) if id == outer_pat_id => {
1286
- // `Variant(a, a)`, error
1287
- self . r . report_error (
1288
- ident. span ,
1289
- ResolutionError :: IdentifierBoundMoreThanOnceInSamePattern ( & ident. as_str ( ) ) ,
1290
- ) ;
1291
- }
1292
- Some ( ..) if pat_src == PatternSource :: FnParam => {
1293
- // `fn f(a: u8, a: u8)`, error
1294
- self . r . report_error (
1295
- ident. span ,
1296
- ResolutionError :: IdentifierBoundMoreThanOnceInParameterList ( & ident. as_str ( ) ) ,
1297
- ) ;
1320
+ Some ( id) if prod_ids. contains ( & id) => {
1321
+ // We have some overlap in a product pattern, e.g. `(a, a)` which is not allowed.
1322
+ use ResolutionError :: * ;
1323
+ let error = match pat_src {
1324
+ // `fn f(a: u8, a: u8)`:
1325
+ PatternSource :: FnParam => IdentifierBoundMoreThanOnceInParameterList ,
1326
+ // `Variant(a, a)`:
1327
+ _ => IdentifierBoundMoreThanOnceInSamePattern ,
1328
+ } ;
1329
+ self . r . report_error ( ident. span , error ( & ident. as_str ( ) ) ) ;
1298
1330
}
1299
- Some ( ..) if pat_src == PatternSource :: Match ||
1300
- pat_src == PatternSource :: Let => {
1331
+ Some ( ..) => {
1301
1332
// `Variant1(a) | Variant2(a)`, ok
1302
1333
// Reuse definition from the first `a`.
1303
- res = self . innermost_rib_bindings ( ValueNS ) [ & ident] ;
1334
+ return self . innermost_rib_bindings ( ValueNS ) [ & ident] ;
1304
1335
}
1305
- Some ( ..) => {
1306
- span_bug ! ( ident. span, "two bindings with the same name from \
1307
- unexpected pattern source {:?}", pat_src) ;
1308
- }
1309
- None => {
1310
- // A completely fresh binding, add to the lists if it's valid.
1311
- if ident. name != kw:: Invalid {
1312
- bindings. insert ( ident, outer_pat_id) ;
1313
- self . innermost_rib_bindings ( ValueNS ) . insert ( ident, res) ;
1314
- }
1336
+ // A completely fresh binding, add to the lists if it's valid.
1337
+ None if ident. name != kw:: Invalid => {
1338
+ bindings. insert ( ident, * prod_ids. last ( ) . unwrap ( ) ) ;
1339
+ self . innermost_rib_bindings ( ValueNS ) . insert ( ident, res) ;
1315
1340
}
1341
+ None => { }
1316
1342
}
1317
1343
1318
1344
res
@@ -1810,7 +1836,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
1810
1836
ExprKind :: ForLoop ( ref pat, ref iter_expr, ref block, label) => {
1811
1837
self . visit_expr ( iter_expr) ;
1812
1838
self . with_rib ( ValueNS , NormalRibKind , |this| {
1813
- this. resolve_pattern ( pat, PatternSource :: For , & mut FxHashMap :: default ( ) ) ;
1839
+ this. resolve_pattern_top ( pat, PatternSource :: For ) ;
1814
1840
this. resolve_labeled_block ( label, expr. id , block) ;
1815
1841
} ) ;
1816
1842
}
@@ -1847,7 +1873,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
1847
1873
ExprKind :: Closure ( _, IsAsync :: Async { .. } , _, ref fn_decl, ref body, _span) => {
1848
1874
self . with_rib ( ValueNS , NormalRibKind , |this| {
1849
1875
// Resolve arguments:
1850
- this. resolve_params ( & fn_decl. inputs ) ;
1876
+ this. resolve_params ( & fn_decl. inputs , expr . id ) ;
1851
1877
// No need to resolve return type --
1852
1878
// the outer closure return type is `FunctionRetTy::Default`.
1853
1879
0 commit comments