@@ -65,6 +65,8 @@ enum IsRepeatExpr {
6565 Yes ,
6666}
6767
68+ struct IsNeverPattern ;
69+
6870/// Describes whether an `AnonConst` is a type level const arg or
6971/// some other form of anon const (i.e. inline consts or enum discriminants)
7072#[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
@@ -3246,12 +3248,31 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
32463248 self . resolve_pattern_top ( & local. pat , PatternSource :: Let ) ;
32473249 }
32483250
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 > {
32543274 let mut binding_map = FxIndexMap :: default ( ) ;
3275+ let mut is_never_pat = false ;
32553276
32563277 pat. walk ( & mut |pat| {
32573278 match pat. kind {
@@ -3263,18 +3284,27 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
32633284 PatKind :: Or ( ref ps) => {
32643285 // Check the consistency of this or-pattern and
32653286 // 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 ,
32683290 }
32693291 return false ;
32703292 }
3293+ PatKind :: Never => is_never_pat = true ,
32713294 _ => { }
32723295 }
32733296
32743297 true
32753298 } ) ;
32763299
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+ }
32783308 }
32793309
32803310 fn is_base_res_local ( & self , nid : NodeId ) -> bool {
@@ -3284,33 +3314,52 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
32843314 )
32853315 }
32863316
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 (
32903337 & mut self ,
32913338 pats : & [ P < Pat > ] ,
3292- ) -> Vec < FxIndexMap < Ident , BindingInfo > > {
3293- // pats is consistent.
3339+ ) -> Result < FxIndexMap < Ident , BindingInfo > , IsNeverPattern > {
32943340 let mut missing_vars = FxIndexMap :: default ( ) ;
32953341 let mut inconsistent_vars = FxIndexMap :: default ( ) ;
32963342
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 < _ > > ( ) ;
32993351
33003352 // 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 ( ) {
33023354 // Check against all arms except for the same pattern which is always self-consistent.
3303- let inners = maps
3355+ let inners = not_never_pats
33043356 . iter ( )
3305- . zip ( pats. iter ( ) )
33063357 . 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) ;
33113359
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) {
33143363 None => {
33153364 // The inner binding is missing in the outer.
33163365 let binding_error =
@@ -3351,19 +3400,32 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
33513400 self . report_error ( v. 0 , ResolutionError :: VariableBoundWithDifferentMode ( name, v. 1 ) ) ;
33523401 }
33533402
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+ }
33563414 }
33573415
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 ;
33603419 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 ;
33633422 false
33643423 }
33653424 _ => true ,
3366- } )
3425+ } ) ;
3426+ if is_or_or_never {
3427+ let _ = self . compute_and_check_binding_map ( pat) ;
3428+ }
33673429 }
33683430
33693431 fn resolve_arm ( & mut self , arm : & ' ast Arm ) {
@@ -3392,7 +3454,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
33923454 visit:: walk_pat ( self , pat) ;
33933455 self . resolve_pattern_inner ( pat, pat_src, bindings) ;
33943456 // 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) ;
33963458 }
33973459
33983460 /// Resolve bindings in a pattern. This is a helper to `resolve_pattern`.
0 commit comments