7
7
8
8
use std:: cell:: { Ref , RefCell } ;
9
9
use std:: ops:: Deref ;
10
- use std:: slice:: from_ref;
11
10
12
- use hir:: Expr ;
13
11
use hir:: def:: DefKind ;
14
12
use hir:: pat_util:: EnumerateAndAdjustIterator as _;
15
13
use rustc_abi:: { FIRST_VARIANT , FieldIdx , VariantIdx } ;
@@ -312,7 +310,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
312
310
313
311
let param_place = self . cat_rvalue ( param. hir_id , param_ty) ;
314
312
315
- self . walk_irrefutable_pat ( & param_place, param. pat ) ?;
313
+ self . fake_read_scrutinee ( & param_place, false ) ?;
314
+ self . walk_pat ( & param_place, param. pat , false ) ?;
316
315
}
317
316
318
317
self . consume_expr ( body. value ) ?;
@@ -454,13 +453,9 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
454
453
455
454
hir:: ExprKind :: Match ( discr, arms, _) => {
456
455
let discr_place = self . cat_expr ( discr) ?;
457
- self . maybe_read_scrutinee (
458
- discr,
459
- discr_place. clone ( ) ,
460
- arms. iter ( ) . map ( |arm| arm. pat ) ,
461
- ) ?;
456
+ self . fake_read_scrutinee ( & discr_place, true ) ?;
457
+ self . walk_expr ( discr) ?;
462
458
463
- // treatment of the discriminant is handled while walking the arms.
464
459
for arm in arms {
465
460
self . walk_arm ( & discr_place, arm) ?;
466
461
}
@@ -597,116 +592,25 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
597
592
Ok ( ( ) )
598
593
}
599
594
600
- fn maybe_read_scrutinee < ' t > (
595
+ #[ instrument( skip( self ) , level = "debug" ) ]
596
+ fn fake_read_scrutinee (
601
597
& self ,
602
- discr : & Expr < ' _ > ,
603
- discr_place : PlaceWithHirId < ' tcx > ,
604
- pats : impl Iterator < Item = & ' t hir:: Pat < ' t > > ,
598
+ discr_place : & PlaceWithHirId < ' tcx > ,
599
+ refutable : bool ,
605
600
) -> Result < ( ) , Cx :: Error > {
606
- // Matching should not always be considered a use of the place, hence
607
- // discr does not necessarily need to be borrowed.
608
- // We only want to borrow discr if the pattern contain something other
609
- // than wildcards.
610
- let mut needs_to_be_read = false ;
611
- for pat in pats {
612
- self . cat_pattern ( discr_place. clone ( ) , pat, & mut |place, pat| {
613
- match & pat. kind {
614
- PatKind :: Missing => unreachable ! ( ) ,
615
- PatKind :: Binding ( .., opt_sub_pat) => {
616
- // If the opt_sub_pat is None, then the binding does not count as
617
- // a wildcard for the purpose of borrowing discr.
618
- if opt_sub_pat. is_none ( ) {
619
- needs_to_be_read = true ;
620
- }
621
- }
622
- PatKind :: Never => {
623
- // A never pattern reads the value.
624
- // FIXME(never_patterns): does this do what I expect?
625
- needs_to_be_read = true ;
626
- }
627
- PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( qpath) , hir_id, span } ) => {
628
- // A `Path` pattern is just a name like `Foo`. This is either a
629
- // named constant or else it refers to an ADT variant
630
-
631
- let res = self . cx . typeck_results ( ) . qpath_res ( qpath, * hir_id) ;
632
- match res {
633
- Res :: Def ( DefKind :: Const , _) | Res :: Def ( DefKind :: AssocConst , _) => {
634
- // Named constants have to be equated with the value
635
- // being matched, so that's a read of the value being matched.
636
- //
637
- // FIXME: We don't actually reads for ZSTs.
638
- needs_to_be_read = true ;
639
- }
640
- _ => {
641
- // Otherwise, this is a struct/enum variant, and so it's
642
- // only a read if we need to read the discriminant.
643
- needs_to_be_read |=
644
- self . is_multivariant_adt ( place. place . ty ( ) , * span) ;
645
- }
646
- }
647
- }
648
- PatKind :: TupleStruct ( ..) | PatKind :: Struct ( ..) | PatKind :: Tuple ( ..) => {
649
- // For `Foo(..)`, `Foo { ... }` and `(...)` patterns, check if we are matching
650
- // against a multivariant enum or struct. In that case, we have to read
651
- // the discriminant. Otherwise this kind of pattern doesn't actually
652
- // read anything (we'll get invoked for the `...`, which may indeed
653
- // perform some reads).
654
-
655
- let place_ty = place. place . ty ( ) ;
656
- needs_to_be_read |= self . is_multivariant_adt ( place_ty, pat. span ) ;
657
- }
658
- PatKind :: Expr ( _) | PatKind :: Range ( ..) => {
659
- // If the PatKind is a Lit or a Range then we want
660
- // to borrow discr.
661
- needs_to_be_read = true ;
662
- }
663
- PatKind :: Slice ( lhs, wild, rhs) => {
664
- // We don't need to test the length if the pattern is `[..]`
665
- if matches ! ( ( lhs, wild, rhs) , ( & [ ] , Some ( _) , & [ ] ) )
666
- // Arrays have a statically known size, so
667
- // there is no need to read their length
668
- || place. place . ty ( ) . peel_refs ( ) . is_array ( )
669
- {
670
- } else {
671
- needs_to_be_read = true ;
672
- }
673
- }
674
- PatKind :: Or ( _)
675
- | PatKind :: Box ( _)
676
- | PatKind :: Deref ( _)
677
- | PatKind :: Ref ( ..)
678
- | PatKind :: Guard ( ..)
679
- | PatKind :: Wild
680
- | PatKind :: Err ( _) => {
681
- // If the PatKind is Or, Box, or Ref, the decision is made later
682
- // as these patterns contains subpatterns
683
- // If the PatKind is Wild or Err, the decision is made based on the other patterns
684
- // being examined
685
- }
686
- }
687
-
688
- Ok ( ( ) )
689
- } ) ?
690
- }
601
+ let closure_def_id = match discr_place. place . base {
602
+ PlaceBase :: Upvar ( upvar_id) => Some ( upvar_id. closure_expr_id ) ,
603
+ _ => None ,
604
+ } ;
691
605
692
- if needs_to_be_read {
693
- self . borrow_expr ( discr , BorrowKind :: Immutable ) ? ;
606
+ let cause = if refutable {
607
+ FakeReadCause :: ForMatchedPlace ( closure_def_id )
694
608
} else {
695
- let closure_def_id = match discr_place. place . base {
696
- PlaceBase :: Upvar ( upvar_id) => Some ( upvar_id. closure_expr_id ) ,
697
- _ => None ,
698
- } ;
609
+ FakeReadCause :: ForLet ( closure_def_id)
610
+ } ;
699
611
700
- self . delegate . borrow_mut ( ) . fake_read (
701
- & discr_place,
702
- FakeReadCause :: ForMatchedPlace ( closure_def_id) ,
703
- discr_place. hir_id ,
704
- ) ;
612
+ self . delegate . borrow_mut ( ) . fake_read ( discr_place, cause, discr_place. hir_id ) ;
705
613
706
- // We always want to walk the discriminant. We want to make sure, for instance,
707
- // that the discriminant has been initialized.
708
- self . walk_expr ( discr) ?;
709
- }
710
614
Ok ( ( ) )
711
615
}
712
616
@@ -723,12 +627,11 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
723
627
self . walk_expr ( expr) ?;
724
628
let expr_place = self . cat_expr ( expr) ?;
725
629
f ( ) ?;
630
+ self . fake_read_scrutinee ( & expr_place, els. is_some ( ) ) ?;
631
+ self . walk_pat ( & expr_place, pat, false ) ?;
726
632
if let Some ( els) = els {
727
- // borrowing because we need to test the discriminant
728
- self . maybe_read_scrutinee ( expr, expr_place. clone ( ) , from_ref ( pat) . iter ( ) ) ?;
729
633
self . walk_block ( els) ?;
730
634
}
731
- self . walk_irrefutable_pat ( & expr_place, pat) ?;
732
635
Ok ( ( ) )
733
636
}
734
637
@@ -900,16 +803,6 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
900
803
discr_place : & PlaceWithHirId < ' tcx > ,
901
804
arm : & hir:: Arm < ' _ > ,
902
805
) -> Result < ( ) , Cx :: Error > {
903
- let closure_def_id = match discr_place. place . base {
904
- PlaceBase :: Upvar ( upvar_id) => Some ( upvar_id. closure_expr_id ) ,
905
- _ => None ,
906
- } ;
907
-
908
- self . delegate . borrow_mut ( ) . fake_read (
909
- discr_place,
910
- FakeReadCause :: ForMatchedPlace ( closure_def_id) ,
911
- discr_place. hir_id ,
912
- ) ;
913
806
self . walk_pat ( discr_place, arm. pat , arm. guard . is_some ( ) ) ?;
914
807
915
808
if let Some ( ref e) = arm. guard {
@@ -920,27 +813,6 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
920
813
Ok ( ( ) )
921
814
}
922
815
923
- /// Walks a pat that occurs in isolation (i.e., top-level of fn argument or
924
- /// let binding, and *not* a match arm or nested pat.)
925
- fn walk_irrefutable_pat (
926
- & self ,
927
- discr_place : & PlaceWithHirId < ' tcx > ,
928
- pat : & hir:: Pat < ' _ > ,
929
- ) -> Result < ( ) , Cx :: Error > {
930
- let closure_def_id = match discr_place. place . base {
931
- PlaceBase :: Upvar ( upvar_id) => Some ( upvar_id. closure_expr_id ) ,
932
- _ => None ,
933
- } ;
934
-
935
- self . delegate . borrow_mut ( ) . fake_read (
936
- discr_place,
937
- FakeReadCause :: ForLet ( closure_def_id) ,
938
- discr_place. hir_id ,
939
- ) ;
940
- self . walk_pat ( discr_place, pat, false ) ?;
941
- Ok ( ( ) )
942
- }
943
-
944
816
/// The core driver for walking a pattern
945
817
///
946
818
/// This should mirror how pattern-matching gets lowered to MIR, as
@@ -1960,8 +1832,11 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
1960
1832
/// Here, we cannot perform such an accurate checks, because querying
1961
1833
/// whether a type is inhabited requires that it has been fully inferred,
1962
1834
/// which cannot be guaranteed at this point.
1835
+ #[ instrument( skip( self , span) , level = "debug" ) ]
1963
1836
fn is_multivariant_adt ( & self , ty : Ty < ' tcx > , span : Span ) -> bool {
1964
- if let ty:: Adt ( def, _) = self . cx . try_structurally_resolve_type ( span, ty) . kind ( ) {
1837
+ let ty = self . cx . try_structurally_resolve_type ( span, ty) ;
1838
+ debug ! ( ?ty, "is_multivariant_adt: resolved" ) ;
1839
+ if let ty:: Adt ( def, _) = ty. kind ( ) {
1965
1840
// Note that if a non-exhaustive SingleVariant is defined in another crate, we need
1966
1841
// to assume that more cases will be added to the variant in the future. This mean
1967
1842
// that we should handle non-exhaustive SingleVariant the same way we would handle
0 commit comments