@@ -504,9 +504,27 @@ impl InferenceContext<'_> {
504504 self . consume_exprs ( args. iter ( ) . copied ( ) ) ;
505505 }
506506 Expr :: Match { expr, arms } => {
507- self . consume_expr ( * expr) ;
508507 for arm in arms. iter ( ) {
509508 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+ }
510528 }
511529 }
512530 Expr :: Break { expr, label : _ }
@@ -618,6 +636,57 @@ impl InferenceContext<'_> {
618636 }
619637 }
620638
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+
621690 fn expr_ty ( & self , expr : ExprId ) -> Ty {
622691 self . result [ expr] . clone ( )
623692 }
@@ -641,14 +710,14 @@ impl InferenceContext<'_> {
641710 false
642711 }
643712
644- fn is_ty_copy ( & self , ty : Ty ) -> bool {
713+ fn is_ty_copy ( & mut self , ty : Ty ) -> bool {
645714 if let TyKind :: Closure ( id, _) = ty. kind ( Interner ) {
646715 // FIXME: We handle closure as a special case, since chalk consider every closure as copy. We
647716 // should probably let chalk know which closures are copy, but I don't know how doing it
648717 // without creating query cycles.
649718 return self . result . closure_info . get ( id) . map ( |x| x. 1 == FnTrait :: Fn ) . unwrap_or ( true ) ;
650719 }
651- ty . is_copy ( self . db , self . owner )
720+ self . table . resolve_completely ( ty ) . is_copy ( self . db , self . owner )
652721 }
653722
654723 fn select_from_expr ( & mut self , expr : ExprId ) {
0 commit comments