dedicated visitor for arm patterns
This commit is contained in:
parent
df127b86cb
commit
4a8ba7b031
1 changed files with 41 additions and 18 deletions
|
@ -28,9 +28,8 @@ struct InteriorVisitor<'a, 'tcx> {
|
||||||
/// such borrows can span across this yield point.
|
/// such borrows can span across this yield point.
|
||||||
/// As such, we need to track these borrows and record them despite of the fact
|
/// As such, we need to track these borrows and record them despite of the fact
|
||||||
/// that they may succeed the said yield point in the post-order.
|
/// that they may succeed the said yield point in the post-order.
|
||||||
nested_scope_of_guards: SmallVec<[SmallVec<[HirId; 4]>; 4]>,
|
guard_bindings: SmallVec<[SmallVec<[HirId; 4]>; 1]>,
|
||||||
current_scope_of_guards: HirIdSet,
|
guard_bindings_set: HirIdSet,
|
||||||
arm_has_guard: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
|
impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
|
||||||
|
@ -147,9 +146,8 @@ pub fn resolve_interior<'a, 'tcx>(
|
||||||
expr_count: 0,
|
expr_count: 0,
|
||||||
kind,
|
kind,
|
||||||
prev_unresolved_span: None,
|
prev_unresolved_span: None,
|
||||||
nested_scope_of_guards: <_>::default(),
|
guard_bindings: <_>::default(),
|
||||||
current_scope_of_guards: <_>::default(),
|
guard_bindings_set: <_>::default(),
|
||||||
arm_has_guard: false,
|
|
||||||
};
|
};
|
||||||
intravisit::walk_body(&mut visitor, body);
|
intravisit::walk_body(&mut visitor, body);
|
||||||
|
|
||||||
|
@ -228,25 +226,34 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
|
||||||
|
|
||||||
fn visit_arm(&mut self, arm: &'tcx Arm<'tcx>) {
|
fn visit_arm(&mut self, arm: &'tcx Arm<'tcx>) {
|
||||||
if arm.guard.is_some() {
|
if arm.guard.is_some() {
|
||||||
self.nested_scope_of_guards.push(<_>::default());
|
self.guard_bindings.push(<_>::default());
|
||||||
self.arm_has_guard = true;
|
|
||||||
}
|
}
|
||||||
self.visit_pat(&arm.pat);
|
self.visit_pat(&arm.pat);
|
||||||
if let Some(ref g) = arm.guard {
|
if let Some(ref g) = arm.guard {
|
||||||
|
self.guard_bindings.push(<_>::default());
|
||||||
|
ArmPatCollector {
|
||||||
|
guard_bindings_set: &mut self.guard_bindings_set,
|
||||||
|
guard_bindings: self
|
||||||
|
.guard_bindings
|
||||||
|
.last_mut()
|
||||||
|
.expect("should have pushed at least one earlier"),
|
||||||
|
}
|
||||||
|
.visit_pat(&arm.pat);
|
||||||
|
|
||||||
match g {
|
match g {
|
||||||
Guard::If(ref e) => {
|
Guard::If(ref e) => {
|
||||||
self.visit_expr(e);
|
self.visit_expr(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut scope_var_ids =
|
let mut scope_var_ids =
|
||||||
self.nested_scope_of_guards.pop().expect("should have pushed at least one earlier");
|
self.guard_bindings.pop().expect("should have pushed at least one earlier");
|
||||||
for var_id in scope_var_ids.drain(..) {
|
for var_id in scope_var_ids.drain(..) {
|
||||||
assert!(
|
assert!(
|
||||||
self.current_scope_of_guards.remove(&var_id),
|
self.guard_bindings_set.remove(&var_id),
|
||||||
"variable should be placed in scope earlier"
|
"variable should be placed in scope earlier"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
self.arm_has_guard = false;
|
|
||||||
}
|
}
|
||||||
self.visit_expr(&arm.body);
|
self.visit_expr(&arm.body);
|
||||||
}
|
}
|
||||||
|
@ -256,14 +263,10 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
|
||||||
|
|
||||||
self.expr_count += 1;
|
self.expr_count += 1;
|
||||||
|
|
||||||
if let PatKind::Binding(_, id, ..) = pat.kind {
|
if let PatKind::Binding(..) = pat.kind {
|
||||||
let scope = self.region_scope_tree.var_scope(pat.hir_id.local_id);
|
let scope = self.region_scope_tree.var_scope(pat.hir_id.local_id);
|
||||||
let ty = self.fcx.typeck_results.borrow().pat_ty(pat);
|
let ty = self.fcx.typeck_results.borrow().pat_ty(pat);
|
||||||
self.record(ty, Some(scope), None, pat.span, false);
|
self.record(ty, Some(scope), None, pat.span, false);
|
||||||
if self.arm_has_guard {
|
|
||||||
self.nested_scope_of_guards.as_mut_slice().last_mut().unwrap().push(id);
|
|
||||||
self.current_scope_of_guards.insert(id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,8 +302,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
|
||||||
intravisit::walk_expr(self, expr);
|
intravisit::walk_expr(self, expr);
|
||||||
let res = self.fcx.typeck_results.borrow().qpath_res(qpath, expr.hir_id);
|
let res = self.fcx.typeck_results.borrow().qpath_res(qpath, expr.hir_id);
|
||||||
match res {
|
match res {
|
||||||
Res::Local(id) if self.current_scope_of_guards.contains(&id) => {
|
Res::Local(id) if self.guard_bindings_set.contains(&id) => {
|
||||||
debug!("a borrow in guard from pattern local is detected");
|
|
||||||
guard_borrowing_from_pattern = true;
|
guard_borrowing_from_pattern = true;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -350,3 +352,24 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ArmPatCollector<'a> {
|
||||||
|
guard_bindings_set: &'a mut HirIdSet,
|
||||||
|
guard_bindings: &'a mut SmallVec<[HirId; 4]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'tcx> Visitor<'tcx> for ArmPatCollector<'a> {
|
||||||
|
type Map = intravisit::ErasedMap<'tcx>;
|
||||||
|
|
||||||
|
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
|
||||||
|
NestedVisitorMap::None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) {
|
||||||
|
intravisit::walk_pat(self, pat);
|
||||||
|
if let PatKind::Binding(_, id, ..) = pat.kind {
|
||||||
|
self.guard_bindings.push(id);
|
||||||
|
self.guard_bindings_set.insert(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue