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,115 +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 :: Binding ( .., opt_sub_pat) => {
615
- // If the opt_sub_pat is None, then the binding does not count as
616
- // a wildcard for the purpose of borrowing discr.
617
- if opt_sub_pat. is_none ( ) {
618
- needs_to_be_read = true ;
619
- }
620
- }
621
- PatKind :: Never => {
622
- // A never pattern reads the value.
623
- // FIXME(never_patterns): does this do what I expect?
624
- needs_to_be_read = true ;
625
- }
626
- PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( qpath) , hir_id, span } ) => {
627
- // A `Path` pattern is just a name like `Foo`. This is either a
628
- // named constant or else it refers to an ADT variant
629
-
630
- let res = self . cx . typeck_results ( ) . qpath_res ( qpath, * hir_id) ;
631
- match res {
632
- Res :: Def ( DefKind :: Const , _) | Res :: Def ( DefKind :: AssocConst , _) => {
633
- // Named constants have to be equated with the value
634
- // being matched, so that's a read of the value being matched.
635
- //
636
- // FIXME: We don't actually reads for ZSTs.
637
- needs_to_be_read = true ;
638
- }
639
- _ => {
640
- // Otherwise, this is a struct/enum variant, and so it's
641
- // only a read if we need to read the discriminant.
642
- needs_to_be_read |=
643
- self . is_multivariant_adt ( place. place . ty ( ) , * span) ;
644
- }
645
- }
646
- }
647
- PatKind :: TupleStruct ( ..) | PatKind :: Struct ( ..) | PatKind :: Tuple ( ..) => {
648
- // For `Foo(..)`, `Foo { ... }` and `(...)` patterns, check if we are matching
649
- // against a multivariant enum or struct. In that case, we have to read
650
- // the discriminant. Otherwise this kind of pattern doesn't actually
651
- // read anything (we'll get invoked for the `...`, which may indeed
652
- // perform some reads).
653
-
654
- let place_ty = place. place . ty ( ) ;
655
- needs_to_be_read |= self . is_multivariant_adt ( place_ty, pat. span ) ;
656
- }
657
- PatKind :: Expr ( _) | PatKind :: Range ( ..) => {
658
- // If the PatKind is a Lit or a Range then we want
659
- // to borrow discr.
660
- needs_to_be_read = true ;
661
- }
662
- PatKind :: Slice ( lhs, wild, rhs) => {
663
- // We don't need to test the length if the pattern is `[..]`
664
- if matches ! ( ( lhs, wild, rhs) , ( & [ ] , Some ( _) , & [ ] ) )
665
- // Arrays have a statically known size, so
666
- // there is no need to read their length
667
- || place. place . ty ( ) . peel_refs ( ) . is_array ( )
668
- {
669
- } else {
670
- needs_to_be_read = true ;
671
- }
672
- }
673
- PatKind :: Or ( _)
674
- | PatKind :: Box ( _)
675
- | PatKind :: Deref ( _)
676
- | PatKind :: Ref ( ..)
677
- | PatKind :: Guard ( ..)
678
- | PatKind :: Wild
679
- | PatKind :: Err ( _) => {
680
- // If the PatKind is Or, Box, or Ref, the decision is made later
681
- // as these patterns contains subpatterns
682
- // If the PatKind is Wild or Err, the decision is made based on the other patterns
683
- // being examined
684
- }
685
- }
686
-
687
- Ok ( ( ) )
688
- } ) ?
689
- }
601
+ let closure_def_id = match discr_place. place . base {
602
+ PlaceBase :: Upvar ( upvar_id) => Some ( upvar_id. closure_expr_id ) ,
603
+ _ => None ,
604
+ } ;
690
605
691
- if needs_to_be_read {
692
- self . borrow_expr ( discr , BorrowKind :: Immutable ) ? ;
606
+ let cause = if refutable {
607
+ FakeReadCause :: ForMatchedPlace ( closure_def_id )
693
608
} else {
694
- let closure_def_id = match discr_place. place . base {
695
- PlaceBase :: Upvar ( upvar_id) => Some ( upvar_id. closure_expr_id ) ,
696
- _ => None ,
697
- } ;
609
+ FakeReadCause :: ForLet ( closure_def_id)
610
+ } ;
698
611
699
- self . delegate . borrow_mut ( ) . fake_read (
700
- & discr_place,
701
- FakeReadCause :: ForMatchedPlace ( closure_def_id) ,
702
- discr_place. hir_id ,
703
- ) ;
612
+ self . delegate . borrow_mut ( ) . fake_read ( discr_place, cause, discr_place. hir_id ) ;
704
613
705
- // We always want to walk the discriminant. We want to make sure, for instance,
706
- // that the discriminant has been initialized.
707
- self . walk_expr ( discr) ?;
708
- }
709
614
Ok ( ( ) )
710
615
}
711
616
@@ -722,12 +627,11 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
722
627
self . walk_expr ( expr) ?;
723
628
let expr_place = self . cat_expr ( expr) ?;
724
629
f ( ) ?;
630
+ self . fake_read_scrutinee ( & expr_place, els. is_some ( ) ) ?;
631
+ self . walk_pat ( & expr_place, pat, false ) ?;
725
632
if let Some ( els) = els {
726
- // borrowing because we need to test the discriminant
727
- self . maybe_read_scrutinee ( expr, expr_place. clone ( ) , from_ref ( pat) . iter ( ) ) ?;
728
633
self . walk_block ( els) ?;
729
634
}
730
- self . walk_irrefutable_pat ( & expr_place, pat) ?;
731
635
Ok ( ( ) )
732
636
}
733
637
@@ -899,16 +803,6 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
899
803
discr_place : & PlaceWithHirId < ' tcx > ,
900
804
arm : & hir:: Arm < ' _ > ,
901
805
) -> Result < ( ) , Cx :: Error > {
902
- let closure_def_id = match discr_place. place . base {
903
- PlaceBase :: Upvar ( upvar_id) => Some ( upvar_id. closure_expr_id ) ,
904
- _ => None ,
905
- } ;
906
-
907
- self . delegate . borrow_mut ( ) . fake_read (
908
- discr_place,
909
- FakeReadCause :: ForMatchedPlace ( closure_def_id) ,
910
- discr_place. hir_id ,
911
- ) ;
912
806
self . walk_pat ( discr_place, arm. pat , arm. guard . is_some ( ) ) ?;
913
807
914
808
if let Some ( ref e) = arm. guard {
@@ -919,27 +813,6 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
919
813
Ok ( ( ) )
920
814
}
921
815
922
- /// Walks a pat that occurs in isolation (i.e., top-level of fn argument or
923
- /// let binding, and *not* a match arm or nested pat.)
924
- fn walk_irrefutable_pat (
925
- & self ,
926
- discr_place : & PlaceWithHirId < ' tcx > ,
927
- pat : & hir:: Pat < ' _ > ,
928
- ) -> Result < ( ) , Cx :: Error > {
929
- let closure_def_id = match discr_place. place . base {
930
- PlaceBase :: Upvar ( upvar_id) => Some ( upvar_id. closure_expr_id ) ,
931
- _ => None ,
932
- } ;
933
-
934
- self . delegate . borrow_mut ( ) . fake_read (
935
- discr_place,
936
- FakeReadCause :: ForLet ( closure_def_id) ,
937
- discr_place. hir_id ,
938
- ) ;
939
- self . walk_pat ( discr_place, pat, false ) ?;
940
- Ok ( ( ) )
941
- }
942
-
943
816
/// The core driver for walking a pattern
944
817
///
945
818
/// This should mirror how pattern-matching gets lowered to MIR, as
@@ -1928,8 +1801,11 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
1928
1801
/// Here, we cannot perform such an accurate checks, because querying
1929
1802
/// whether a type is inhabited requires that it has been fully inferred,
1930
1803
/// which cannot be guaranteed at this point.
1804
+ #[ instrument( skip( self , span) , level = "debug" ) ]
1931
1805
fn is_multivariant_adt ( & self , ty : Ty < ' tcx > , span : Span ) -> bool {
1932
- if let ty:: Adt ( def, _) = self . cx . try_structurally_resolve_type ( span, ty) . kind ( ) {
1806
+ let ty = self . cx . try_structurally_resolve_type ( span, ty) ;
1807
+ debug ! ( ?ty, "is_multivariant_adt: resolved" ) ;
1808
+ if let ty:: Adt ( def, _) = ty. kind ( ) {
1933
1809
// Note that if a non-exhaustive SingleVariant is defined in another crate, we need
1934
1810
// to assume that more cases will be added to the variant in the future. This mean
1935
1811
// that we should handle non-exhaustive SingleVariant the same way we would handle
0 commit comments