@@ -18,8 +18,7 @@ use rustc::hir::def::{self, PartialRes, DefKind, CtorKind, PerNS};
18
18
use rustc:: hir:: def:: Namespace :: { self , * } ;
19
19
use rustc:: hir:: def_id:: { DefId , CRATE_DEF_INDEX } ;
20
20
use rustc:: hir:: TraitCandidate ;
21
- use rustc:: util:: nodemap:: FxHashMap ;
22
- use rustc_data_structures:: fx:: FxIndexMap ;
21
+ use rustc:: util:: nodemap:: { FxHashMap , FxHashSet } ;
23
22
use smallvec:: { smallvec, SmallVec } ;
24
23
use syntax:: { unwrap_or, walk_list} ;
25
24
use syntax:: ast:: * ;
@@ -409,7 +408,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
409
408
visit:: walk_foreign_item ( this, foreign_item) ;
410
409
} ) ;
411
410
}
412
- fn visit_fn ( & mut self , fn_kind : FnKind < ' tcx > , declaration : & ' tcx FnDecl , _: Span , id : NodeId ) {
411
+ fn visit_fn ( & mut self , fn_kind : FnKind < ' tcx > , declaration : & ' tcx FnDecl , _: Span , _ : NodeId ) {
413
412
debug ! ( "(resolving function) entering function" ) ;
414
413
let rib_kind = match fn_kind {
415
414
FnKind :: ItemFn ( ..) => FnItemRibKind ,
@@ -421,7 +420,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
421
420
// Create a label rib for the function.
422
421
this. with_label_rib ( rib_kind, |this| {
423
422
// Add each argument to the rib.
424
- this. resolve_params ( & declaration. inputs , id ) ;
423
+ this. resolve_params ( & declaration. inputs ) ;
425
424
426
425
visit:: walk_fn_ret_ty ( this, & declaration. output ) ;
427
426
@@ -1109,10 +1108,10 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
1109
1108
}
1110
1109
}
1111
1110
1112
- fn resolve_params ( & mut self , params : & [ Param ] , id : NodeId ) {
1113
- let mut bindings = FxIndexMap :: default ( ) ;
1111
+ fn resolve_params ( & mut self , params : & [ Param ] ) {
1112
+ let mut bindings = smallvec ! [ ( false , <_> :: default ( ) ) ] ;
1114
1113
for Param { pat, ty, .. } in params {
1115
- self . resolve_pattern ( pat, PatternSource :: FnParam , & mut smallvec ! [ id ] , & mut bindings) ;
1114
+ self . resolve_pattern ( pat, PatternSource :: FnParam , & mut bindings) ;
1116
1115
self . visit_ty ( ty) ;
1117
1116
debug ! ( "(resolving function / closure) recorded parameter" ) ;
1118
1117
}
@@ -1220,9 +1219,12 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
1220
1219
1221
1220
/// Arising from `source`, resolve a sequence of patterns (top level or-patterns).
1222
1221
fn resolve_pats ( & mut self , pats : & [ P < Pat > ] , source : PatternSource ) {
1223
- let mut bindings_list = FxIndexMap :: default ( ) ;
1222
+ let mut bindings = smallvec ! [ ( true , <_> :: default ( ) ) ] ;
1224
1223
for pat in pats {
1225
- self . resolve_pattern ( pat, source, & mut smallvec ! [ pat. id] , & mut bindings_list) ;
1224
+ bindings. push ( ( false , <_ >:: default ( ) ) ) ;
1225
+ self . resolve_pattern ( pat, source, & mut bindings) ;
1226
+ let collected = bindings. pop ( ) . unwrap ( ) . 1 ;
1227
+ bindings. last_mut ( ) . unwrap ( ) . 1 . extend ( collected) ;
1226
1228
}
1227
1229
// This has to happen *after* we determine which pat_idents are variants
1228
1230
if pats. len ( ) > 1 {
@@ -1231,26 +1233,24 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
1231
1233
}
1232
1234
1233
1235
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 ( ) ) ;
1236
+ self . resolve_pattern ( pat, pat_src, & mut smallvec ! [ ( false , <_> :: default ( ) ) ] ) ;
1235
1237
}
1236
1238
1237
1239
fn resolve_pattern (
1238
1240
& mut self ,
1239
1241
pat : & Pat ,
1240
1242
pat_src : PatternSource ,
1241
- prod_ids : & mut SmallVec < [ NodeId ; 1 ] > ,
1242
- bindings : & mut FxIndexMap < Ident , NodeId > ,
1243
+ bindings : & mut SmallVec < [ ( bool , FxHashSet < Ident > ) ; 1 ] > ,
1243
1244
) {
1244
- self . resolve_pattern_inner ( pat, pat_src, prod_ids , bindings) ;
1245
+ self . resolve_pattern_inner ( pat, pat_src, bindings) ;
1245
1246
visit:: walk_pat ( self , pat) ;
1246
1247
}
1247
1248
1248
1249
fn resolve_pattern_inner (
1249
1250
& mut self ,
1250
1251
pat : & Pat ,
1251
1252
pat_src : PatternSource ,
1252
- prod_ids : & mut SmallVec < [ NodeId ; 1 ] > ,
1253
- bindings : & mut FxIndexMap < Ident , NodeId > ,
1253
+ bindings : & mut SmallVec < [ ( bool , FxHashSet < Ident > ) ; 1 ] > ,
1254
1254
) {
1255
1255
// Visit all direct subpatterns of this pattern.
1256
1256
pat. walk ( & mut |pat| {
@@ -1261,9 +1261,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
1261
1261
// then fall back to a fresh binding.
1262
1262
let has_sub = sub. is_some ( ) ;
1263
1263
let res = self . try_resolve_as_non_binding ( pat_src, pat, bmode, ident, has_sub)
1264
- . unwrap_or_else ( || {
1265
- self . fresh_binding ( ident, pat. id , pat_src, prod_ids, bindings)
1266
- } ) ;
1264
+ . unwrap_or_else ( || self . fresh_binding ( ident, pat. id , pat_src, bindings) ) ;
1267
1265
self . r . record_partial_res ( pat. id , PartialRes :: new ( res) ) ;
1268
1266
}
1269
1267
PatKind :: TupleStruct ( ref path, ..) => {
@@ -1276,23 +1274,26 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
1276
1274
self . smart_resolve_path ( pat. id , None , path, PathSource :: Struct ) ;
1277
1275
}
1278
1276
PatKind :: Or ( ref ps) => {
1279
- let len_before = bindings. len ( ) ;
1277
+ // Add a new set of bindings to the stack. `true` here records that when a
1278
+ // binding already exists in this set, it should not result in an error because
1279
+ // `V1(a) | V2(a)` must be allowed and are checked for consistency later.
1280
+ bindings. push ( ( true , <_ >:: default ( ) ) ) ;
1280
1281
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 ( ) ;
1282
+ // Now we need to switch back to a product context so that each
1283
+ // part of the or-pattern internally rejects already bound names.
1284
+ // For example, `V1(a) | V2(a, a)` and `V1(a, a) | V2(a)` are bad.
1285
+ bindings. push ( ( false , <_ >:: default ( ) ) ) ;
1286
+ self . resolve_pattern_inner ( p, pat_src, bindings) ;
1287
+ // Move up the non-overlapping bindings to the or-pattern.
1288
+ // Existing bindings just get "merged".
1289
+ let collected = bindings. pop ( ) . unwrap ( ) . 1 ;
1290
+ bindings. last_mut ( ) . unwrap ( ) . 1 . extend ( collected) ;
1289
1291
}
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) ;
1292
+ // This or-pattern itself can itself be part of a product,
1293
+ // e.g. `(V1(a) | V2(a), a)` or `(a, V1(a) | V2(a))`.
1294
+ // Both cases bind `a` again in a product pattern and must be rejected.
1295
+ let collected = bindings. pop ( ) . unwrap ( ) . 1 ;
1296
+ bindings. last_mut ( ) . unwrap ( ) . 1 . extend ( collected) ;
1296
1297
1297
1298
// Prevent visiting `ps` as we've already done so above.
1298
1299
return false ;
@@ -1308,40 +1309,59 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
1308
1309
ident : Ident ,
1309
1310
pat_id : NodeId ,
1310
1311
pat_src : PatternSource ,
1311
- prod_ids : & [ NodeId ] ,
1312
- bindings : & mut FxIndexMap < Ident , NodeId > ,
1312
+ bindings : & mut SmallVec < [ ( bool , FxHashSet < Ident > ) ; 1 ] > ,
1313
1313
) -> Res {
1314
1314
// Add the binding to the local ribs, if it doesn't already exist in the bindings map.
1315
1315
// (We must not add it if it's in the bindings map because that breaks the assumptions
1316
1316
// later passes make about or-patterns.)
1317
1317
let ident = ident. modern_and_legacy ( ) ;
1318
- let res = Res :: Local ( pat_id) ;
1319
- match bindings. get ( & ident) . cloned ( ) {
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 ( ) ) ) ;
1330
- }
1331
- Some ( ..) => {
1332
- // `Variant1(a) | Variant2(a)`, ok
1333
- // Reuse definition from the first `a`.
1334
- return self . innermost_rib_bindings ( ValueNS ) [ & ident] ;
1318
+
1319
+ // Walk outwards the stack of products / or-patterns and
1320
+ // find out if the identifier has been bound in any of these.
1321
+ let mut already_bound_and = false ;
1322
+ let mut already_bound_or = false ;
1323
+ for ( is_sum, set) in bindings. iter_mut ( ) . rev ( ) {
1324
+ match ( is_sum, set. get ( & ident) . cloned ( ) ) {
1325
+ // Already bound in a product pattern, e.g. `(a, a)` which is not allowed.
1326
+ ( false , Some ( ..) ) => already_bound_and = true ,
1327
+ // Already bound in an or-pattern, e.g. `V1(a) | V2(a)`.
1328
+ // This is *required* for consistency which is checked later.
1329
+ ( true , Some ( ..) ) => already_bound_or = true ,
1330
+ // Not already bound here.
1331
+ _ => { }
1335
1332
}
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 ( ) ) ;
1333
+ }
1334
+
1335
+ if already_bound_and {
1336
+ // Overlap in a product pattern somewhere; report an error.
1337
+ use ResolutionError :: * ;
1338
+ let error = match pat_src {
1339
+ // `fn f(a: u8, a: u8)`:
1340
+ PatternSource :: FnParam => IdentifierBoundMoreThanOnceInParameterList ,
1341
+ // `Variant(a, a)`:
1342
+ _ => IdentifierBoundMoreThanOnceInSamePattern ,
1343
+ } ;
1344
+ self . r . report_error ( ident. span , error ( & ident. as_str ( ) ) ) ;
1345
+ }
1346
+
1347
+ // Record as bound if it's valid:
1348
+ let ident_valid = ident. name != kw:: Invalid ;
1349
+ if ident_valid {
1350
+ bindings. last_mut ( ) . unwrap ( ) . 1 . insert ( ident) ;
1351
+ }
1352
+
1353
+ if already_bound_or {
1354
+ // `Variant1(a) | Variant2(a)`, ok
1355
+ // Reuse definition from the first `a`.
1356
+ self . innermost_rib_bindings ( ValueNS ) [ & ident]
1357
+ } else {
1358
+ let res = Res :: Local ( pat_id) ;
1359
+ if ident_valid {
1360
+ // A completely fresh binding add to the set if it's valid.
1339
1361
self . innermost_rib_bindings ( ValueNS ) . insert ( ident, res) ;
1340
1362
}
1341
- None => { }
1363
+ res
1342
1364
}
1343
-
1344
- res
1345
1365
}
1346
1366
1347
1367
fn innermost_rib_bindings ( & mut self , ns : Namespace ) -> & mut IdentMap < Res > {
@@ -1873,7 +1893,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
1873
1893
ExprKind :: Closure ( _, IsAsync :: Async { .. } , _, ref fn_decl, ref body, _span) => {
1874
1894
self . with_rib ( ValueNS , NormalRibKind , |this| {
1875
1895
// Resolve arguments:
1876
- this. resolve_params ( & fn_decl. inputs , expr . id ) ;
1896
+ this. resolve_params ( & fn_decl. inputs ) ;
1877
1897
// No need to resolve return type --
1878
1898
// the outer closure return type is `FunctionRetTy::Default`.
1879
1899
0 commit comments