Skip to content

Commit

Permalink
Support pattern match on mutably borrowed fields.
Browse files Browse the repository at this point in the history
  • Loading branch information
yannbolliger committed Jun 4, 2021
1 parent bc10454 commit 9272b04
Showing 1 changed file with 48 additions and 16 deletions.
64 changes: 48 additions & 16 deletions stainless_extraction/src/expr/pattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,14 @@ impl<'a, 'l, 'tcx> BodyExtractor<'a, 'l, 'tcx> {

PatKind::Binding {
mutability,
mode,
var: hir_id,
..
} if matches!(
mode,
BindingMode::ByValue | BindingMode::ByRef(BorrowKind::Shared)
) =>
{
} => {
let var = self.fetch_var(*hir_id);
if *mutability == Mutability::Not || var.is_mutable() {
Ok(self.factory().ValDef(var))
} else {
Err("Binding mode not allowed")
Err("Mutability not allowed")
}
}

Expand Down Expand Up @@ -151,7 +146,11 @@ impl<'a, 'l, 'tcx> BodyExtractor<'a, 'l, 'tcx> {
TyKind::Tuple(substs) => f
.TuplePattern(
binder,
self.extract_subpatterns(subpatterns.to_vec(), substs.len()),
self
.extract_subpatterns(subpatterns.to_vec(), substs.len())
.into_iter()
.map(|p| p.0)
.collect(),
)
.into(),

Expand All @@ -167,7 +166,23 @@ impl<'a, 'l, 'tcx> BodyExtractor<'a, 'l, 'tcx> {
},

// TODO: Confirm that rustc introduces this pattern only for primitive derefs
box PatKind::Deref { ref subpattern } => self.extract_pattern(subpattern, binder),
box PatKind::Deref { ref subpattern } => {
let sub = self.extract_pattern(subpattern, binder);

// If we pattern match on mutable vars, we want the MutCell not it's value
if ty::is_mut_ref(pattern.ty) {
if let st::Type::ADTType(st::ADTType { tps, .. }) =
self.base.extract_ty(pattern.ty, &self.txtcx, pattern.span)
{
f.ADTPattern(None, self.synth().mut_cell_id(), tps.clone(), vec![sub])
.into()
} else {
sub
}
} else {
sub
}
}

_ => self.unsupported_pattern(pattern.span, "Unsupported kind of pattern"),
}
Expand Down Expand Up @@ -197,9 +212,13 @@ impl<'a, 'l, 'tcx> BodyExtractor<'a, 'l, 'tcx> {
.base
.adt_field_types(adt_def, variant_index, &self.txtcx, substs),
)
.map(|(p, t)| {
f.ADTPattern(None, self.synth().mut_cell_id(), vec![t], vec![p])
.into()
.map(|((st_pat, thir_pat), t)| {
if is_mut_ref(thir_pat) {
st_pat
} else {
f.ADTPattern(None, self.synth().mut_cell_id(), vec![t], vec![st_pat])
.into()
}
})
.collect();

Expand All @@ -210,7 +229,7 @@ impl<'a, 'l, 'tcx> BodyExtractor<'a, 'l, 'tcx> {
&mut self,
mut field_pats: Vec<FieldPat<'tcx>>,
num_fields: usize,
) -> Vec<st::Pattern<'l>> {
) -> Vec<(st::Pattern<'l>, Option<Pat<'tcx>>)> {
let f = self.factory();
field_pats.sort_by_key(|field| field.field.index());
field_pats.reverse();
Expand All @@ -219,15 +238,28 @@ impl<'a, 'l, 'tcx> BodyExtractor<'a, 'l, 'tcx> {
let next = if let Some(FieldPat { field, .. }) = field_pats.last() {
if field.index() == i {
let FieldPat { pattern, .. } = field_pats.pop().unwrap();
self.extract_pattern(&pattern, None)
(self.extract_pattern(&pattern, None), Some(pattern))
} else {
f.WildcardPattern(None).into()
(f.WildcardPattern(None).into(), None)
}
} else {
f.WildcardPattern(None).into()
(f.WildcardPattern(None).into(), None)
};
subpatterns.push(next);
}
subpatterns
}
}

fn is_mut_ref<'tcx>(pat: Option<Pat<'tcx>>) -> bool {
matches!(
pat,
Some(Pat {
kind: box PatKind::Binding {
mode: BindingMode::ByRef(BorrowKind::Mut { .. }),
..
},
..
})
)
}

0 comments on commit 9272b04

Please sign in to comment.