upvar inference for implicit deref patterns
This commit is contained in:
parent
977c9ab7a2
commit
ff0d4bc743
2 changed files with 70 additions and 11 deletions
|
@ -1000,6 +1000,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
// determines whether to borrow *at the level of the deref pattern* rather than
|
||||
// borrowing the bound place (since that inner place is inside the temporary that
|
||||
// stores the result of calling `deref()`/`deref_mut()` so can't be captured).
|
||||
// HACK: this could be a fake pattern corresponding to a deref inserted by match
|
||||
// ergonomics, in which case `pat.hir_id` will be the id of the subpattern.
|
||||
let mutable = self.cx.typeck_results().pat_has_ref_mut_binding(subpattern);
|
||||
let mutability =
|
||||
if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
|
||||
|
@ -1675,12 +1677,31 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
// Then we see that to get the same result, we must start with
|
||||
// `deref { deref { place_foo }}` instead of `place_foo` since the pattern is now `Some(x,)`
|
||||
// and not `&&Some(x,)`, even though its assigned type is that of `&&Some(x,)`.
|
||||
for _ in
|
||||
0..self.cx.typeck_results().pat_adjustments().get(pat.hir_id).map_or(0, |v| v.len())
|
||||
{
|
||||
let typeck_results = self.cx.typeck_results();
|
||||
let adjustments: &[adjustment::PatAdjustment<'tcx>] =
|
||||
typeck_results.pat_adjustments().get(pat.hir_id).map_or(&[], |v| &**v);
|
||||
let mut adjusts = adjustments.iter().peekable();
|
||||
while let Some(adjust) = adjusts.next() {
|
||||
debug!("applying adjustment to place_with_id={:?}", place_with_id);
|
||||
place_with_id = self.cat_deref(pat.hir_id, place_with_id)?;
|
||||
place_with_id = match adjust.kind {
|
||||
adjustment::PatAdjust::BuiltinDeref => self.cat_deref(pat.hir_id, place_with_id)?,
|
||||
adjustment::PatAdjust::OverloadedDeref => {
|
||||
// This adjustment corresponds to an overloaded deref; it borrows the scrutinee to
|
||||
// call `Deref::deref` or `DerefMut::deref_mut`. Invoke the callback before setting
|
||||
// `place_with_id` to the temporary storing the result of the deref.
|
||||
// HACK(dianne): giving the callback a fake deref pattern makes sure it behaves the
|
||||
// same as it would if this were an explicit deref pattern.
|
||||
op(&place_with_id, &hir::Pat { kind: PatKind::Deref(pat), ..*pat })?;
|
||||
let target_ty = match adjusts.peek() {
|
||||
Some(&&next_adjust) => next_adjust.source,
|
||||
// At the end of the deref chain, we get `pat`'s scrutinee.
|
||||
None => self.pat_ty_unadjusted(pat)?,
|
||||
};
|
||||
self.pat_deref_temp(pat.hir_id, pat, target_ty)?
|
||||
}
|
||||
};
|
||||
}
|
||||
drop(typeck_results); // explicitly release borrow of typeck results, just in case.
|
||||
let place_with_id = place_with_id; // lose mutability
|
||||
debug!("applied adjustment derefs to get place_with_id={:?}", place_with_id);
|
||||
|
||||
|
@ -1783,14 +1804,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
self.cat_pattern(subplace, subpat, op)?;
|
||||
}
|
||||
PatKind::Deref(subpat) => {
|
||||
let mutable = self.cx.typeck_results().pat_has_ref_mut_binding(subpat);
|
||||
let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
|
||||
let re_erased = self.cx.tcx().lifetimes.re_erased;
|
||||
let ty = self.pat_ty_adjusted(subpat)?;
|
||||
let ty = Ty::new_ref(self.cx.tcx(), re_erased, ty, mutability);
|
||||
// A deref pattern generates a temporary.
|
||||
let base = self.cat_rvalue(pat.hir_id, ty);
|
||||
let place = self.cat_deref(pat.hir_id, base)?;
|
||||
let place = self.pat_deref_temp(pat.hir_id, subpat, ty)?;
|
||||
self.cat_pattern(place, subpat, op)?;
|
||||
}
|
||||
|
||||
|
@ -1843,6 +1858,23 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Represents the place of the temp that stores the scrutinee of a deref pattern's interior.
|
||||
fn pat_deref_temp(
|
||||
&self,
|
||||
hir_id: HirId,
|
||||
inner: &hir::Pat<'_>,
|
||||
target_ty: Ty<'tcx>,
|
||||
) -> Result<PlaceWithHirId<'tcx>, Cx::Error> {
|
||||
let mutable = self.cx.typeck_results().pat_has_ref_mut_binding(inner);
|
||||
let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
|
||||
let re_erased = self.cx.tcx().lifetimes.re_erased;
|
||||
let ty = Ty::new_ref(self.cx.tcx(), re_erased, target_ty, mutability);
|
||||
// A deref pattern stores the result of `Deref::deref` or `DerefMut::deref_mut` ...
|
||||
let base = self.cat_rvalue(hir_id, ty);
|
||||
// ... and the inner pattern matches on the place behind that reference.
|
||||
self.cat_deref(hir_id, base)
|
||||
}
|
||||
|
||||
fn is_multivariant_adt(&self, ty: Ty<'tcx>, span: Span) -> bool {
|
||||
if let ty::Adt(def, _) = self.cx.try_structurally_resolve_type(span, ty).kind() {
|
||||
// Note that if a non-exhaustive SingleVariant is defined in another crate, we need
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue