Skip to content

Commit f11c868

Browse files
committed
new_mut_refs: distinguish copies from moves in pattern binders
1 parent e0b461a commit f11c868

11 files changed

Lines changed: 187 additions & 24 deletions

File tree

source/rust_verify/src/rust_to_vir_expr.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,7 @@ pub(crate) fn pattern_to_vir_unadjusted<'tcx>(
562562
mutable,
563563
by_ref: vir_by_ref,
564564
typ: var_typ.clone(),
565+
copy: bctx.is_copy(bctx.types.node_type(pat.hir_id)),
565566
};
566567
match subpat {
567568
None => PatternX::Var(binding),

source/rust_verify/src/rust_to_vir_func.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,6 +1202,7 @@ pub(crate) fn check_item_fn<'tcx>(
12021202
mutable: true,
12031203
by_ref: vir::ast::ByRef::No,
12041204
typ: typ.clone(),
1205+
copy: false,
12051206
}),
12061207
);
12071208
let new_init_expr =

source/rust_verify_test/tests/mut_refs_patterns.rs

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2035,3 +2035,139 @@ test_verify_one_file_with_options! {
20352035
}
20362036
} => Err(err) => assert_fails(err, 2)
20372037
}
2038+
2039+
test_verify_one_file_with_options! {
2040+
#[test] binders_in_pattern_copy_vs_no_copy ["new-mut-ref"] => verus_code! {
2041+
enum Option<A> {
2042+
Some(A),
2043+
None,
2044+
}
2045+
use crate::Option::Some;
2046+
use crate::Option::None;
2047+
2048+
fn consume<X>(x: X) { }
2049+
2050+
fn test_copy<X: Copy>(x: X, y: X) {
2051+
let t = (x, y);
2052+
2053+
match t {
2054+
(x, _) => { consume(x); }
2055+
}
2056+
2057+
assert(has_resolved(t));
2058+
}
2059+
2060+
fn test_no_copy<X>(x: X, y: X) {
2061+
let t = (x, y);
2062+
2063+
match t {
2064+
(x, _) => { consume(x); }
2065+
}
2066+
2067+
assert(has_resolved(t)); // FAILS
2068+
}
2069+
2070+
fn test_option_copy<X: Copy>(x: X, y: X) {
2071+
let t = Some((x, y));
2072+
2073+
match t {
2074+
Some((x, _)) => { consume(x); }
2075+
None => { }
2076+
}
2077+
2078+
assert(has_resolved(t));
2079+
}
2080+
2081+
fn test_option_no_copy<X>(x: X, y: X) {
2082+
let t = Some((x, y));
2083+
2084+
match t {
2085+
Some((x, _)) => { consume(x); }
2086+
None => { }
2087+
}
2088+
2089+
assert(has_resolved(t)); // FAILS
2090+
}
2091+
2092+
fn test_let_copy<X: Copy>(x: X, y: X) {
2093+
let t = (x, y);
2094+
2095+
let (x, _) = t;
2096+
consume(x);
2097+
2098+
assert(has_resolved(t));
2099+
}
2100+
2101+
fn test_let_no_copy<X>(x: X, y: X) {
2102+
let t = (x, y);
2103+
2104+
let (x, _) = t;
2105+
consume(x);
2106+
2107+
assert(has_resolved(t)); // FAILS
2108+
}
2109+
2110+
2111+
2112+
2113+
fn atbinder_test_copy<X: Copy>(x: X, y: X) {
2114+
let t = (x, y);
2115+
2116+
match t {
2117+
x @ (_, _) => { consume(x); }
2118+
}
2119+
2120+
assert(has_resolved(t));
2121+
}
2122+
2123+
fn atbinder_test_no_copy<X>(x: X, y: X) {
2124+
let t = (x, y);
2125+
2126+
match t {
2127+
x @ (_, _) => { consume(x); }
2128+
}
2129+
2130+
assert(has_resolved(t)); // FAILS
2131+
}
2132+
2133+
fn atbinder_test_option_copy<X: Copy>(x: X, y: X) {
2134+
let t = Some((x, y));
2135+
2136+
match t {
2137+
Some(x @ (_, _)) => { consume(x); }
2138+
None => { }
2139+
}
2140+
2141+
assert(has_resolved(t));
2142+
}
2143+
2144+
fn atbinder_test_option_no_copy<X>(x: X, y: X) {
2145+
let t = Some((x, y));
2146+
2147+
match t {
2148+
Some(x @ (_, _)) => { consume(x); }
2149+
None => { }
2150+
}
2151+
2152+
assert(has_resolved(t)); // FAILS
2153+
}
2154+
2155+
fn atbinder_test_let_copy<X: Copy>(x: X, y: X) {
2156+
let t = (x, y);
2157+
2158+
let x @ (_, _) = t;
2159+
consume(x);
2160+
2161+
assert(has_resolved(t));
2162+
}
2163+
2164+
fn atbinder_test_let_no_copy<X>(x: X, y: X) {
2165+
let t = (x, y);
2166+
2167+
let x @ (_, _) = t;
2168+
consume(x);
2169+
2170+
assert(has_resolved(t)); // FAILS
2171+
}
2172+
} => Err(err) => assert_fails(err, 6)
2173+
}

source/vir/src/ast.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,9 @@ pub struct PatternBinding {
641641
pub by_ref: ByRef,
642642
pub typ: Typ,
643643
pub mutable: bool,
644+
/// True if the type of this variable is copy.
645+
/// This is used by resolution analysis; it is meaningless post-simplification.
646+
pub copy: bool,
644647
}
645648

646649
/// Patterns for match expressions

source/vir/src/ast_simplify.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ fn pattern_to_decls_with_no_initializer(pattern: &Pattern, stmts: &mut Vec<Stmt>
264264
mutable: binding.mutable,
265265
by_ref: ByRef::No,
266266
typ: binding.typ.clone(),
267+
copy: false,
267268
});
268269
let v_pattern = SpannedTyped::new(&pattern.span, &binding.typ, v_patternx);
269270
stmts.push(Spanned::new(
@@ -711,9 +712,13 @@ fn tuple_get_field_expr(
711712
fn simplify_one_stmt(ctx: &GlobalCtx, state: &mut State, stmt: &Stmt) -> Result<Vec<Stmt>, VirErr> {
712713
match &stmt.x {
713714
StmtX::Decl { pattern, mode: _, init: None, els: None } => match &pattern.x {
714-
PatternX::Var(PatternBinding { by_ref: ByRef::No, name: _, mutable: _, typ: _ }) => {
715-
Ok(vec![stmt.clone()])
716-
}
715+
PatternX::Var(PatternBinding {
716+
by_ref: ByRef::No,
717+
name: _,
718+
mutable: _,
719+
typ: _,
720+
copy: _,
721+
}) => Ok(vec![stmt.clone()]),
717722
_ => {
718723
let mut stmts: Vec<Stmt> = Vec::new();
719724
pattern_to_decls_with_no_initializer(pattern, &mut stmts);
@@ -727,7 +732,13 @@ fn simplify_one_stmt(ctx: &GlobalCtx, state: &mut State, stmt: &Stmt) -> Result<
727732
StmtX::Decl { pattern, mode: _, init: Some(_init), els: None }
728733
if matches!(
729734
pattern.x,
730-
PatternX::Var(PatternBinding { by_ref: ByRef::No, name: _, mutable: _, typ: _ })
735+
PatternX::Var(PatternBinding {
736+
by_ref: ByRef::No,
737+
name: _,
738+
mutable: _,
739+
typ: _,
740+
copy: _
741+
})
731742
) =>
732743
{
733744
Ok(vec![stmt.clone()])

source/vir/src/ast_to_sst.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2728,9 +2728,13 @@ fn stmt_to_stm(
27282728
panic!("let-else should be simplified in ast_simpllify {:?}.", stmt)
27292729
}
27302730
let (name, mutable, typ) = match &pattern.x {
2731-
PatternX::Var(PatternBinding { name, mutable, by_ref: ByRef::No, typ }) => {
2732-
(name, mutable, typ)
2733-
}
2731+
PatternX::Var(PatternBinding {
2732+
name,
2733+
mutable,
2734+
by_ref: ByRef::No,
2735+
typ,
2736+
copy: _,
2737+
}) => (name, mutable, typ),
27342738
_ => panic!("internal error: Decl should have been simplified by ast_simplify"),
27352739
};
27362740

source/vir/src/ast_util.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1373,7 +1373,7 @@ fn place_to_expr_rec(place: &Place, loc: bool) -> Expr {
13731373

13741374
impl PatternX {
13751375
/// Returns a Pattern Var that is valid post-simplification.
1376-
pub fn simple_var(name: VarIdent, mutable: bool, span: &Span, typ: &Typ) -> Pattern {
1376+
pub(crate) fn simple_var(name: VarIdent, mutable: bool, span: &Span, typ: &Typ) -> Pattern {
13771377
SpannedTyped::new(
13781378
span,
13791379
typ,
@@ -1382,6 +1382,7 @@ impl PatternX {
13821382
mutable,
13831383
by_ref: ByRef::No,
13841384
typ: typ.clone(),
1385+
copy: false,
13851386
}),
13861387
)
13871388
}

source/vir/src/ast_visitor.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -704,13 +704,14 @@ pub(crate) trait AstVisitor<R: Returner, Err, Scope: Scoper> {
704704
&mut self,
705705
pb: &PatternBinding,
706706
) -> Result<R::Ret<PatternBinding>, Err> {
707-
let PatternBinding { name, by_ref, typ, mutable } = pb;
707+
let PatternBinding { name, by_ref, typ, mutable, copy } = pb;
708708
let typ = self.visit_typ(typ)?;
709709
R::ret(|| PatternBinding {
710710
name: name.clone(),
711711
by_ref: *by_ref,
712712
typ: R::get(typ),
713713
mutable: *mutable,
714+
copy: *copy,
714715
})
715716
}
716717

@@ -955,11 +956,11 @@ where
955956
fn insert_pattern_vars(map: &mut VisitorScopeMap, pattern: &Pattern, init: bool) {
956957
match &pattern.x {
957958
PatternX::Wildcard(_) => {}
958-
PatternX::Var(PatternBinding { name, mutable, by_ref: _, typ }) => {
959+
PatternX::Var(PatternBinding { name, mutable, by_ref: _, typ, copy: _ }) => {
959960
let _ = map.insert(name.clone(), ScopeEntry::new(typ, *mutable, init));
960961
}
961962
PatternX::Binding {
962-
binding: PatternBinding { name, mutable, by_ref: _, typ },
963+
binding: PatternBinding { name, mutable, by_ref: _, typ, copy: _ },
963964
sub_pat,
964965
} => {
965966
insert_pattern_vars(map, sub_pat, init);

source/vir/src/modes.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -481,13 +481,13 @@ fn add_pattern_rec(
481481

482482
match &pattern.x {
483483
PatternX::Wildcard(_dd) => Ok(()),
484-
PatternX::Var(PatternBinding { name: x, mutable: _, by_ref: _, typ: _ }) => {
484+
PatternX::Var(PatternBinding { name: x, mutable: _, by_ref: _, typ: _, copy: _ }) => {
485485
// TODO(new_mut_ref): disallow ByRef::Mut in spec code
486486
decls.push(PatternBoundDecl { span: pattern.span.clone(), name: x.clone(), mode });
487487
Ok(())
488488
}
489489
PatternX::Binding {
490-
binding: PatternBinding { name: x, mutable: _, by_ref: _, typ: _ },
490+
binding: PatternBinding { name: x, mutable: _, by_ref: _, typ: _, copy: _ },
491491
sub_pat,
492492
} => {
493493
add_pattern_rec(ctxt, record, typing, decls, mode, sub_pat, false)?;
@@ -1813,7 +1813,13 @@ fn check_stmt(
18131813
// in Rust as "let xl; ... { let pat ... xl = xr; }".
18141814
match (&pattern.x, init) {
18151815
(
1816-
PatternX::Var(PatternBinding { name: x, mutable: _, by_ref: _, typ: _ }),
1816+
PatternX::Var(PatternBinding {
1817+
name: x,
1818+
mutable: _,
1819+
by_ref: _,
1820+
typ: _,
1821+
copy: _,
1822+
}),
18171823
None,
18181824
) => {
18191825
typing.insert_var_mode(x, VarMode::Infer(pattern.span.clone()));

source/vir/src/patterns.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -198,13 +198,12 @@ fn pattern_to_exprs_rec(
198198
}
199199
}
200200

201-
// TODO(new_mut_ref): account for Copy types
202201
pub(crate) fn pattern_has_move(pattern: &Pattern) -> bool {
203202
match &pattern.x {
204203
PatternX::Wildcard(_) => false,
205-
PatternX::Var(binding) => matches!(binding.by_ref, ByRef::No),
204+
PatternX::Var(binding) => !binding.copy && matches!(binding.by_ref, ByRef::No),
206205
PatternX::Binding { binding, sub_pat } => {
207-
matches!(binding.by_ref, ByRef::No) || pattern_has_move(sub_pat)
206+
(!binding.copy && matches!(binding.by_ref, ByRef::No)) || pattern_has_move(sub_pat)
208207
}
209208
PatternX::Constructor(_path, _variant, patterns) => {
210209
for binder in patterns.iter() {

0 commit comments

Comments
 (0)