@@ -504,9 +504,27 @@ impl InferenceContext<'_> {
504
504
self . consume_exprs ( args. iter ( ) . copied ( ) ) ;
505
505
}
506
506
Expr :: Match { expr, arms } => {
507
- self . consume_expr ( * expr) ;
508
507
for arm in arms. iter ( ) {
509
508
self . consume_expr ( arm. expr ) ;
509
+ if let Some ( guard) = arm. guard {
510
+ self . consume_expr ( guard) ;
511
+ }
512
+ }
513
+ self . walk_expr ( * expr) ;
514
+ if let Some ( discr_place) = self . place_of_expr ( * expr) {
515
+ if self . is_upvar ( & discr_place) {
516
+ let mut capture_mode = None ;
517
+ for arm in arms. iter ( ) {
518
+ self . walk_pat ( & mut capture_mode, arm. pat ) ;
519
+ }
520
+ if let Some ( c) = capture_mode {
521
+ self . push_capture ( CapturedItemWithoutTy {
522
+ place : discr_place,
523
+ kind : c,
524
+ span : ( * expr) . into ( ) ,
525
+ } )
526
+ }
527
+ }
510
528
}
511
529
}
512
530
Expr :: Break { expr, label : _ }
@@ -618,6 +636,57 @@ impl InferenceContext<'_> {
618
636
}
619
637
}
620
638
639
+ fn walk_pat ( & mut self , result : & mut Option < CaptureKind > , pat : PatId ) {
640
+ let mut update_result = |ck : CaptureKind | match result {
641
+ Some ( r) => {
642
+ * r = cmp:: max ( * r, ck) ;
643
+ }
644
+ None => * result = Some ( ck) ,
645
+ } ;
646
+ self . body . walk_pats ( pat, & mut |p| match & self . body [ p] {
647
+ Pat :: Ref { .. }
648
+ | Pat :: Box { .. }
649
+ | Pat :: Missing
650
+ | Pat :: Wild
651
+ | Pat :: Tuple { .. }
652
+ | Pat :: Or ( _) => ( ) ,
653
+ Pat :: TupleStruct { .. } | Pat :: Record { .. } => {
654
+ if let Some ( variant) = self . result . variant_resolution_for_pat ( p) {
655
+ let adt = variant. adt_id ( ) ;
656
+ let is_multivariant = match adt {
657
+ hir_def:: AdtId :: EnumId ( e) => self . db . enum_data ( e) . variants . len ( ) != 1 ,
658
+ _ => false ,
659
+ } ;
660
+ if is_multivariant {
661
+ update_result ( CaptureKind :: ByRef ( BorrowKind :: Shared ) ) ;
662
+ }
663
+ }
664
+ }
665
+ Pat :: Slice { .. }
666
+ | Pat :: ConstBlock ( _)
667
+ | Pat :: Path ( _)
668
+ | Pat :: Lit ( _)
669
+ | Pat :: Range { .. } => {
670
+ update_result ( CaptureKind :: ByRef ( BorrowKind :: Shared ) ) ;
671
+ }
672
+ Pat :: Bind { id, .. } => match self . result . binding_modes [ * id] {
673
+ crate :: BindingMode :: Move => {
674
+ if self . is_ty_copy ( self . result . type_of_binding [ * id] . clone ( ) ) {
675
+ update_result ( CaptureKind :: ByRef ( BorrowKind :: Shared ) ) ;
676
+ } else {
677
+ update_result ( CaptureKind :: ByValue ) ;
678
+ }
679
+ }
680
+ crate :: BindingMode :: Ref ( r) => match r {
681
+ Mutability :: Mut => update_result ( CaptureKind :: ByRef ( BorrowKind :: Mut {
682
+ allow_two_phase_borrow : false ,
683
+ } ) ) ,
684
+ Mutability :: Not => update_result ( CaptureKind :: ByRef ( BorrowKind :: Shared ) ) ,
685
+ } ,
686
+ } ,
687
+ } ) ;
688
+ }
689
+
621
690
fn expr_ty ( & self , expr : ExprId ) -> Ty {
622
691
self . result [ expr] . clone ( )
623
692
}
@@ -641,14 +710,14 @@ impl InferenceContext<'_> {
641
710
false
642
711
}
643
712
644
- fn is_ty_copy ( & self , ty : Ty ) -> bool {
713
+ fn is_ty_copy ( & mut self , ty : Ty ) -> bool {
645
714
if let TyKind :: Closure ( id, _) = ty. kind ( Interner ) {
646
715
// FIXME: We handle closure as a special case, since chalk consider every closure as copy. We
647
716
// should probably let chalk know which closures are copy, but I don't know how doing it
648
717
// without creating query cycles.
649
718
return self . result . closure_info . get ( id) . map ( |x| x. 1 == FnTrait :: Fn ) . unwrap_or ( true ) ;
650
719
}
651
- ty . is_copy ( self . db , self . owner )
720
+ self . table . resolve_completely ( ty ) . is_copy ( self . db , self . owner )
652
721
}
653
722
654
723
fn select_from_expr ( & mut self , expr : ExprId ) {
0 commit comments