@@ -1000,6 +1000,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
1000
1000
// determines whether to borrow *at the level of the deref pattern* rather than
1001
1001
// borrowing the bound place (since that inner place is inside the temporary that
1002
1002
// stores the result of calling `deref()`/`deref_mut()` so can't be captured).
1003
+ // HACK: this could be a fake pattern corresponding to a deref inserted by match
1004
+ // ergonomics, in which case `pat.hir_id` will be the id of the subpattern.
1003
1005
let mutable = self . cx . typeck_results ( ) . pat_has_ref_mut_binding ( subpattern) ;
1004
1006
let mutability =
1005
1007
if mutable { hir:: Mutability :: Mut } else { hir:: Mutability :: Not } ;
@@ -1227,9 +1229,9 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
1227
1229
// actually this is somewhat "disjoint" from the code below
1228
1230
// that aims to account for `ref x`.
1229
1231
if let Some ( vec) = self . cx . typeck_results ( ) . pat_adjustments ( ) . get ( pat. hir_id ) {
1230
- if let Some ( first_ty ) = vec. first ( ) {
1231
- debug ! ( "pat_ty(pat={:?}) found adjusted ty `{:?}`" , pat, first_ty ) ;
1232
- return Ok ( * first_ty ) ;
1232
+ if let Some ( first_adjust ) = vec. first ( ) {
1233
+ debug ! ( "pat_ty(pat={:?}) found adjustment `{:?}`" , pat, first_adjust ) ;
1234
+ return Ok ( first_adjust . source ) ;
1233
1235
}
1234
1236
} else if let PatKind :: Ref ( subpat, _) = pat. kind
1235
1237
&& self . cx . typeck_results ( ) . skipped_ref_pats ( ) . contains ( pat. hir_id )
@@ -1680,12 +1682,31 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
1680
1682
// Then we see that to get the same result, we must start with
1681
1683
// `deref { deref { place_foo }}` instead of `place_foo` since the pattern is now `Some(x,)`
1682
1684
// and not `&&Some(x,)`, even though its assigned type is that of `&&Some(x,)`.
1683
- for _ in
1684
- 0 ..self . cx . typeck_results ( ) . pat_adjustments ( ) . get ( pat. hir_id ) . map_or ( 0 , |v| v. len ( ) )
1685
- {
1685
+ let typeck_results = self . cx . typeck_results ( ) ;
1686
+ let adjustments: & [ adjustment:: PatAdjustment < ' tcx > ] =
1687
+ typeck_results. pat_adjustments ( ) . get ( pat. hir_id ) . map_or ( & [ ] , |v| & * * v) ;
1688
+ let mut adjusts = adjustments. iter ( ) . peekable ( ) ;
1689
+ while let Some ( adjust) = adjusts. next ( ) {
1686
1690
debug ! ( "applying adjustment to place_with_id={:?}" , place_with_id) ;
1687
- place_with_id = self . cat_deref ( pat. hir_id , place_with_id) ?;
1691
+ place_with_id = match adjust. kind {
1692
+ adjustment:: PatAdjust :: BuiltinDeref => self . cat_deref ( pat. hir_id , place_with_id) ?,
1693
+ adjustment:: PatAdjust :: OverloadedDeref => {
1694
+ // This adjustment corresponds to an overloaded deref; it borrows the scrutinee to
1695
+ // call `Deref::deref` or `DerefMut::deref_mut`. Invoke the callback before setting
1696
+ // `place_with_id` to the temporary storing the result of the deref.
1697
+ // HACK(dianne): giving the callback a fake deref pattern makes sure it behaves the
1698
+ // same as it would if this were an explicit deref pattern.
1699
+ op ( & place_with_id, & hir:: Pat { kind : PatKind :: Deref ( pat) , ..* pat } ) ?;
1700
+ let target_ty = match adjusts. peek ( ) {
1701
+ Some ( & & next_adjust) => next_adjust. source ,
1702
+ // At the end of the deref chain, we get `pat`'s scrutinee.
1703
+ None => self . pat_ty_unadjusted ( pat) ?,
1704
+ } ;
1705
+ self . pat_deref_temp ( pat. hir_id , pat, target_ty) ?
1706
+ }
1707
+ } ;
1688
1708
}
1709
+ drop ( typeck_results) ; // explicitly release borrow of typeck results, just in case.
1689
1710
let place_with_id = place_with_id; // lose mutability
1690
1711
debug ! ( "applied adjustment derefs to get place_with_id={:?}" , place_with_id) ;
1691
1712
@@ -1788,14 +1809,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
1788
1809
self . cat_pattern ( subplace, subpat, op) ?;
1789
1810
}
1790
1811
PatKind :: Deref ( subpat) => {
1791
- let mutable = self . cx . typeck_results ( ) . pat_has_ref_mut_binding ( subpat) ;
1792
- let mutability = if mutable { hir:: Mutability :: Mut } else { hir:: Mutability :: Not } ;
1793
- let re_erased = self . cx . tcx ( ) . lifetimes . re_erased ;
1794
1812
let ty = self . pat_ty_adjusted ( subpat) ?;
1795
- let ty = Ty :: new_ref ( self . cx . tcx ( ) , re_erased, ty, mutability) ;
1796
- // A deref pattern generates a temporary.
1797
- let base = self . cat_rvalue ( pat. hir_id , ty) ;
1798
- let place = self . cat_deref ( pat. hir_id , base) ?;
1813
+ let place = self . pat_deref_temp ( pat. hir_id , subpat, ty) ?;
1799
1814
self . cat_pattern ( place, subpat, op) ?;
1800
1815
}
1801
1816
@@ -1848,6 +1863,23 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
1848
1863
Ok ( ( ) )
1849
1864
}
1850
1865
1866
+ /// Represents the place of the temp that stores the scrutinee of a deref pattern's interior.
1867
+ fn pat_deref_temp (
1868
+ & self ,
1869
+ hir_id : HirId ,
1870
+ inner : & hir:: Pat < ' _ > ,
1871
+ target_ty : Ty < ' tcx > ,
1872
+ ) -> Result < PlaceWithHirId < ' tcx > , Cx :: Error > {
1873
+ let mutable = self . cx . typeck_results ( ) . pat_has_ref_mut_binding ( inner) ;
1874
+ let mutability = if mutable { hir:: Mutability :: Mut } else { hir:: Mutability :: Not } ;
1875
+ let re_erased = self . cx . tcx ( ) . lifetimes . re_erased ;
1876
+ let ty = Ty :: new_ref ( self . cx . tcx ( ) , re_erased, target_ty, mutability) ;
1877
+ // A deref pattern stores the result of `Deref::deref` or `DerefMut::deref_mut` ...
1878
+ let base = self . cat_rvalue ( hir_id, ty) ;
1879
+ // ... and the inner pattern matches on the place behind that reference.
1880
+ self . cat_deref ( hir_id, base)
1881
+ }
1882
+
1851
1883
fn is_multivariant_adt ( & self , ty : Ty < ' tcx > , span : Span ) -> bool {
1852
1884
if let ty:: Adt ( def, _) = self . cx . try_structurally_resolve_type ( span, ty) . kind ( ) {
1853
1885
// Note that if a non-exhaustive SingleVariant is defined in another crate, we need
0 commit comments