@@ -948,6 +948,21 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
948948    } 
949949
950950    /// The core driver for walking a pattern 
951+ /// 
952+ /// This should mirror how pattern-matching gets lowered to MIR, as 
953+ /// otherwise lowering will ICE when trying to resolve the upvars. 
954+ /// 
955+ /// However, it is okay to approximate it here by doing *more* accesses 
956+ /// than the actual MIR builder will, which is useful when some checks 
957+ /// are too cumbersome to perform here. For example, if only after type 
958+ /// inference it becomes clear that only one variant of an enum is 
959+ /// inhabited, and therefore a read of the discriminant is not necessary, 
960+ /// `walk_pat` will have over-approximated the necessary upvar capture 
961+ /// granularity. (Or, at least, that's what the code seems to be saying. 
962+ /// I didn't bother trying to craft an example where this actually happens). 
963+ /// 
964+ /// Do note that discrepancies like these do still create weird language 
965+ /// semantics, and should be avoided if possible. 
951966fn  walk_pat ( 
952967        & self , 
953968        discr_place :  & PlaceWithHirId < ' tcx > , 
@@ -958,6 +973,11 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
958973
959974        let  tcx = self . cx . tcx ( ) ; 
960975        self . cat_pattern ( discr_place. clone ( ) ,  pat,  & mut  |place,  pat| { 
976+             debug ! ( "walk_pat: pat.kind={:?}" ,  pat. kind) ; 
977+             let  read_discriminant = || { 
978+                 self . delegate . borrow_mut ( ) . borrow ( place,  discr_place. hir_id ,  BorrowKind :: Immutable ) ; 
979+             } ; 
980+ 
961981            match  pat. kind  { 
962982                PatKind :: Binding ( _,  canonical_id,  ..)  => { 
963983                    debug ! ( "walk_pat: binding place={:?} pat={:?}" ,  place,  pat) ; 
@@ -980,11 +1000,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
9801000                    // binding when lowering pattern guards to ensure that the guard does not 
9811001                    // modify the scrutinee. 
9821002                    if  has_guard { 
983-                         self . delegate . borrow_mut ( ) . borrow ( 
984-                             place, 
985-                             discr_place. hir_id , 
986-                             BorrowKind :: Immutable , 
987-                         ) ; 
1003+                         read_discriminant ( ) ; 
9881004                    } 
9891005
9901006                    // It is also a borrow or copy/move of the value being matched. 
@@ -1016,13 +1032,70 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
10161032                PatKind :: Never  => { 
10171033                    // A `!` pattern always counts as an immutable read of the discriminant, 
10181034                    // even in an irrefutable pattern. 
1019-                     self . delegate . borrow_mut ( ) . borrow ( 
1020-                         place, 
1021-                         discr_place. hir_id , 
1022-                         BorrowKind :: Immutable , 
1023-                     ) ; 
1035+                     read_discriminant ( ) ; 
1036+                 } 
1037+                 PatKind :: Expr ( PatExpr  {  kind :  PatExprKind :: Path ( qpath) ,  hir_id,  span } )  => { 
1038+                     // A `Path` pattern is just a name like `Foo`. This is either a 
1039+                     // named constant or else it refers to an ADT variant 
1040+ 
1041+                     let  res = self . cx . typeck_results ( ) . qpath_res ( qpath,  * hir_id) ; 
1042+                     match  res { 
1043+                         Res :: Def ( DefKind :: Const ,  _)  | Res :: Def ( DefKind :: AssocConst ,  _)  => { 
1044+                             // Named constants have to be equated with the value 
1045+                             // being matched, so that's a read of the value being matched. 
1046+                             // 
1047+                             // FIXME: Does the MIR code skip this read when matching on a ZST? 
1048+                             // If so, we can also skip it here. 
1049+                             read_discriminant ( ) ; 
1050+                         } 
1051+                         _ => { 
1052+                             // Otherwise, this is a struct/enum variant, and so it's 
1053+                             // only a read if we need to read the discriminant. 
1054+                             if  self . is_multivariant_adt ( place. place . ty ( ) ,  * span)  { 
1055+                                 read_discriminant ( ) ; 
1056+                             } 
1057+                         } 
1058+                     } 
1059+                 } 
1060+                 PatKind :: Expr ( _)  | PatKind :: Range ( ..)  => { 
1061+                     // When matching against a literal or range, we need to 
1062+                     // borrow the place to compare it against the pattern. 
1063+                     // 
1064+                     // FIXME: What if the type being matched only has one 
1065+                     // possible value? 
1066+                     // FIXME: What if the range is the full range of the type 
1067+                     // and doesn't actually require a discriminant read? 
1068+                     read_discriminant ( ) ; 
1069+                 } 
1070+                 PatKind :: Struct ( ..)  | PatKind :: TupleStruct ( ..)  => { 
1071+                     if  self . is_multivariant_adt ( place. place . ty ( ) ,  pat. span )  { 
1072+                         read_discriminant ( ) ; 
1073+                     } 
1074+                 } 
1075+                 PatKind :: Slice ( lhs,  wild,  rhs)  => { 
1076+                     // We don't need to test the length if the pattern is `[..]` 
1077+                     if  matches ! ( ( lhs,  wild,  rhs) ,  ( & [ ] ,  Some ( _) ,  & [ ] ) ) 
1078+                         // Arrays have a statically known size, so 
1079+                         // there is no need to read their length 
1080+                         || place. place . ty ( ) . peel_refs ( ) . is_array ( ) 
1081+                     { 
1082+                         // No read necessary 
1083+                     }  else  { 
1084+                         read_discriminant ( ) ; 
1085+                     } 
1086+                 } 
1087+                 PatKind :: Or ( _) 
1088+                 | PatKind :: Box ( _) 
1089+                 | PatKind :: Ref ( ..) 
1090+                 | PatKind :: Guard ( ..) 
1091+                 | PatKind :: Tuple ( ..) 
1092+                 | PatKind :: Wild 
1093+                 | PatKind :: Err ( _)  => { 
1094+                     // If the PatKind is Or, Box, Ref, Guard, or Tuple, the relevant accesses 
1095+                     // are made later as these patterns contains subpatterns. 
1096+                     // If the PatKind is Wild or Err, they are made when processing the other patterns 
1097+                     // being examined 
10241098                } 
1025-                 _ => { } 
10261099            } 
10271100
10281101            Ok ( ( ) ) 
@@ -1858,6 +1931,14 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
18581931        Ok ( ( ) ) 
18591932    } 
18601933
1934+     /// Checks whether a type has multiple variants, and therefore, whether a 
1935+ /// read of the discriminant might be necessary. Note that the actual MIR 
1936+ /// builder code does a more specific check, filtering out variants that 
1937+ /// happen to be uninhabited. 
1938+ /// 
1939+ /// Here, we cannot perform such an accurate checks, because querying 
1940+ /// whether a type is inhabited requires that it has been fully inferred, 
1941+ /// which cannot be guaranteed at this point. 
18611942fn  is_multivariant_adt ( & self ,  ty :  Ty < ' tcx > ,  span :  Span )  -> bool  { 
18621943        if  let  ty:: Adt ( def,  _)  = self . cx . try_structurally_resolve_type ( span,  ty) . kind ( )  { 
18631944            // Note that if a non-exhaustive SingleVariant is defined in another crate, we need 
0 commit comments