@@ -65,6 +65,8 @@ enum IsRepeatExpr {
65
65
Yes ,
66
66
}
67
67
68
+ struct IsNeverPattern ;
69
+
68
70
/// Describes whether an `AnonConst` is a type level const arg or
69
71
/// some other form of anon const (i.e. inline consts or enum discriminants)
70
72
#[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
@@ -3246,12 +3248,31 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
3246
3248
self . resolve_pattern_top ( & local. pat , PatternSource :: Let ) ;
3247
3249
}
3248
3250
3249
- /// build a map from pattern identifiers to binding-info's.
3250
- /// this is done hygienically. This could arise for a macro
3251
- /// that expands into an or-pattern where one 'x' was from the
3252
- /// user and one 'x' came from the macro.
3253
- fn binding_mode_map ( & mut self , pat : & Pat ) -> FxIndexMap < Ident , BindingInfo > {
3251
+ /// Build a map from pattern identifiers to binding-info's, and check the bindings are
3252
+ /// consistent when encountering or-patterns and never patterns.
3253
+ /// This is done hygienically: this could arise for a macro that expands into an or-pattern
3254
+ /// where one 'x' was from the user and one 'x' came from the macro.
3255
+ ///
3256
+ /// A never pattern by definition indicates an unreachable case. For example, matching on
3257
+ /// `Result<T, &!>` could look like:
3258
+ /// ```rust
3259
+ /// # #![feature(never_type)]
3260
+ /// # #![feature(never_patterns)]
3261
+ /// # fn bar(_x: u32) {}
3262
+ /// let foo: Result<u32, &!> = Ok(0);
3263
+ /// match foo {
3264
+ /// Ok(x) => bar(x),
3265
+ /// Err(&!),
3266
+ /// }
3267
+ /// ```
3268
+ /// This extends to product types: `(x, !)` is likewise unreachable. So it doesn't make sense to
3269
+ /// have a binding here, and we tell the user to use `_` instead.
3270
+ fn compute_and_check_binding_map (
3271
+ & mut self ,
3272
+ pat : & Pat ,
3273
+ ) -> Result < FxIndexMap < Ident , BindingInfo > , IsNeverPattern > {
3254
3274
let mut binding_map = FxIndexMap :: default ( ) ;
3275
+ let mut is_never_pat = false ;
3255
3276
3256
3277
pat. walk ( & mut |pat| {
3257
3278
match pat. kind {
@@ -3263,18 +3284,27 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
3263
3284
PatKind :: Or ( ref ps) => {
3264
3285
// Check the consistency of this or-pattern and
3265
3286
// then add all bindings to the larger map.
3266
- for bm in self . check_consistent_bindings ( ps) {
3267
- binding_map. extend ( bm) ;
3287
+ match self . compute_and_check_or_pat_binding_map ( ps) {
3288
+ Ok ( bm) => binding_map. extend ( bm) ,
3289
+ Err ( IsNeverPattern ) => is_never_pat = true ,
3268
3290
}
3269
3291
return false ;
3270
3292
}
3293
+ PatKind :: Never => is_never_pat = true ,
3271
3294
_ => { }
3272
3295
}
3273
3296
3274
3297
true
3275
3298
} ) ;
3276
3299
3277
- binding_map
3300
+ if is_never_pat {
3301
+ for ( _, binding) in binding_map {
3302
+ self . report_error ( binding. span , ResolutionError :: BindingInNeverPattern ) ;
3303
+ }
3304
+ Err ( IsNeverPattern )
3305
+ } else {
3306
+ Ok ( binding_map)
3307
+ }
3278
3308
}
3279
3309
3280
3310
fn is_base_res_local ( & self , nid : NodeId ) -> bool {
@@ -3284,33 +3314,52 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
3284
3314
)
3285
3315
}
3286
3316
3287
- /// Checks that all of the arms in an or-pattern have exactly the
3288
- /// same set of bindings, with the same binding modes for each.
3289
- fn check_consistent_bindings (
3317
+ /// Compute the binding map for an or-pattern. Checks that all of the arms in the or-pattern
3318
+ /// have exactly the same set of bindings, with the same binding modes for each.
3319
+ /// Returns the computed binding map and a boolean indicating whether the pattern is a never
3320
+ /// pattern.
3321
+ ///
3322
+ /// A never pattern by definition indicates an unreachable case. For example, destructuring a
3323
+ /// `Result<T, &!>` could look like:
3324
+ /// ```rust
3325
+ /// # #![feature(never_type)]
3326
+ /// # #![feature(never_patterns)]
3327
+ /// # fn foo() -> Result<bool, &'static !> { Ok(true) }
3328
+ /// let (Ok(x) | Err(&!)) = foo();
3329
+ /// # let _ = x;
3330
+ /// ```
3331
+ /// Because the `Err(&!)` branch is never reached, it does not need to have the same bindings as
3332
+ /// the other branches of the or-pattern. So we must ignore never pattern when checking the
3333
+ /// bindings of an or-pattern.
3334
+ /// Moreover, if all the subpatterns are never patterns (e.g. `Ok(!) | Err(!)`), then the
3335
+ /// pattern as a whole counts as a never pattern (since it's definitionallly unreachable).
3336
+ fn compute_and_check_or_pat_binding_map (
3290
3337
& mut self ,
3291
3338
pats : & [ P < Pat > ] ,
3292
- ) -> Vec < FxIndexMap < Ident , BindingInfo > > {
3293
- // pats is consistent.
3339
+ ) -> Result < FxIndexMap < Ident , BindingInfo > , IsNeverPattern > {
3294
3340
let mut missing_vars = FxIndexMap :: default ( ) ;
3295
3341
let mut inconsistent_vars = FxIndexMap :: default ( ) ;
3296
3342
3297
- // 1) Compute the binding maps of all arms.
3298
- let maps = pats. iter ( ) . map ( |pat| self . binding_mode_map ( pat) ) . collect :: < Vec < _ > > ( ) ;
3343
+ // 1) Compute the binding maps of all arms; we must ignore never patterns here.
3344
+ let not_never_pats = pats
3345
+ . iter ( )
3346
+ . filter_map ( |pat| {
3347
+ let binding_map = self . compute_and_check_binding_map ( pat) . ok ( ) ?;
3348
+ Some ( ( binding_map, pat) )
3349
+ } )
3350
+ . collect :: < Vec < _ > > ( ) ;
3299
3351
3300
3352
// 2) Record any missing bindings or binding mode inconsistencies.
3301
- for ( map_outer, pat_outer) in maps . iter ( ) . zip ( pats . iter ( ) ) {
3353
+ for ( map_outer, pat_outer) in not_never_pats . iter ( ) {
3302
3354
// Check against all arms except for the same pattern which is always self-consistent.
3303
- let inners = maps
3355
+ let inners = not_never_pats
3304
3356
. iter ( )
3305
- . zip ( pats. iter ( ) )
3306
3357
. filter ( |( _, pat) | pat. id != pat_outer. id )
3307
- . flat_map ( |( map, _) | map)
3308
- . map ( |( key, binding) | ( key. name , map_outer. get ( key) , binding) ) ;
3309
-
3310
- let inners = inners. collect :: < Vec < _ > > ( ) ;
3358
+ . flat_map ( |( map, _) | map) ;
3311
3359
3312
- for ( name, info, & binding_inner) in inners {
3313
- match info {
3360
+ for ( key, binding_inner) in inners {
3361
+ let name = key. name ;
3362
+ match map_outer. get ( key) {
3314
3363
None => {
3315
3364
// The inner binding is missing in the outer.
3316
3365
let binding_error =
@@ -3351,19 +3400,32 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
3351
3400
self . report_error ( v. 0 , ResolutionError :: VariableBoundWithDifferentMode ( name, v. 1 ) ) ;
3352
3401
}
3353
3402
3354
- // 5) Finally bubble up all the binding maps.
3355
- maps
3403
+ // 5) Bubble up the final binding map.
3404
+ if not_never_pats. is_empty ( ) {
3405
+ // All the patterns are never patterns, so the whole or-pattern is one too.
3406
+ Err ( IsNeverPattern )
3407
+ } else {
3408
+ let mut binding_map = FxIndexMap :: default ( ) ;
3409
+ for ( bm, _) in not_never_pats {
3410
+ binding_map. extend ( bm) ;
3411
+ }
3412
+ Ok ( binding_map)
3413
+ }
3356
3414
}
3357
3415
3358
- /// Check the consistency of the outermost or-patterns.
3359
- fn check_consistent_bindings_top ( & mut self , pat : & ' ast Pat ) {
3416
+ /// Check the consistency of bindings wrt or-patterns and never patterns.
3417
+ fn check_consistent_bindings ( & mut self , pat : & ' ast Pat ) {
3418
+ let mut is_or_or_never = false ;
3360
3419
pat. walk ( & mut |pat| match pat. kind {
3361
- PatKind :: Or ( ref ps ) => {
3362
- self . check_consistent_bindings ( ps ) ;
3420
+ PatKind :: Or ( .. ) | PatKind :: Never => {
3421
+ is_or_or_never = true ;
3363
3422
false
3364
3423
}
3365
3424
_ => true ,
3366
- } )
3425
+ } ) ;
3426
+ if is_or_or_never {
3427
+ let _ = self . compute_and_check_binding_map ( pat) ;
3428
+ }
3367
3429
}
3368
3430
3369
3431
fn resolve_arm ( & mut self , arm : & ' ast Arm ) {
@@ -3392,7 +3454,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
3392
3454
visit:: walk_pat ( self , pat) ;
3393
3455
self . resolve_pattern_inner ( pat, pat_src, bindings) ;
3394
3456
// This has to happen *after* we determine which pat_idents are variants:
3395
- self . check_consistent_bindings_top ( pat) ;
3457
+ self . check_consistent_bindings ( pat) ;
3396
3458
}
3397
3459
3398
3460
/// Resolve bindings in a pattern. This is a helper to `resolve_pattern`.
0 commit comments