rust_verify_test coverage (fbbbbcf)

Coverage Report

Created: 2026-08-23 08:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
vir/src/ast_simplify.rs
Line
Count
Source
1
//! VIR-AST -> VIR-AST transformation to simplify away some complicated features
2
3
use crate::ast::CrateId;
4
use crate::ast::Quant;
5
use crate::ast::Typs;
6
use crate::ast::VarBinder;
7
use crate::ast::VarBinderX;
8
use crate::ast::VarBinders;
9
use crate::ast::VarIdent;
10
use crate::ast::{
11
    AssocTypeImpl, AutospecUsage, BinaryOp, Binder, BoundsCheck, BuiltinSpecFun, ByRef, CallTarget,
12
    ChainedOp, ClosureKind, Constant, CtorPrintStyle, CtorUpdateTail, Datatype,
13
    DatatypeTransparency, DatatypeX, Dt, Expr, ExprX, Exprs, Field, FieldOpr, Fun, Function,
14
    FunctionKind, Ident, IntRange, ItemKind, Krate, KrateX, LogicalOp, Mode, MultiOp, Path,
15
    Pattern, PatternBinding, PatternX, Place, PlaceX, SpannedTyped, Stmt, StmtX, TraitImpl, Typ,
16
    TypX, UnaryOp, UnaryOpr, Variant, VariantCheck, VirErr, Visibility,
17
};
18
use crate::ast_util::{
19
    conjoin, mk_eq, mk_implies, place_to_spec_expr, typ_args_for_datatype_typ, undecorate_typ,
20
    unit_typ, wrap_in_trigger,
21
};
22
use crate::ast_visitor::VisitorScopeMap;
23
use crate::context::GlobalCtx;
24
use crate::def::dummy_param_name;
25
use crate::def::is_dummy_param_name;
26
use crate::def::{
27
    Spanned, impl_fndef_path, positional_field_ident, prefix_tuple_param, prefix_tuple_variant,
28
    user_local_name,
29
};
30
use crate::messages::Span;
31
use crate::messages::{error, internal_error};
32
use crate::sst_util::subst_typ_for_datatype;
33
use crate::util::vec_map_result;
34
use air::ast_util::ident_binder;
35
use air::scope_map::ScopeMap;
36
use std::collections::{HashMap, HashSet};
37
use std::sync::Arc;
38
39
struct ClosureDatatype {
40
    enclosing_fun: Fun,
41
    args: Typs,
42
    output: Typ,
43
    kind: ClosureKind,
44
    path: Path,
45
}
46
47
struct State {
48
    // Counter to generate temporary variables
49
    next_var: u64,
50
    // Rename parameters to simplify their names
51
    rename_vars: HashMap<VarIdent, VarIdent>,
52
    // Rename parameters to simplify their names
53
    rename_vars_reverse: HashMap<VarIdent, VarIdent>,
54
    // Name of a datatype to represent each tuple arity
55
    tuple_typs: HashSet<usize>,
56
    // Name of a datatype to represent each closure
57
    closure_typs: HashMap<usize, ClosureDatatype>,
58
    // Functions for which the corresponding FnDef type is used
59
    fndef_typs: HashSet<Fun>,
60
}
61
62
impl State {
63
3.16k
    fn new() -> Self {
64
3.16k
        State {
65
3.16k
            next_var: 0,
66
3.16k
            rename_vars: HashMap::new(),
67
3.16k
            rename_vars_reverse: HashMap::new(),
68
3.16k
            tuple_typs: HashSet::new(),
69
3.16k
            closure_typs: HashMap::new(),
70
3.16k
            fndef_typs: HashSet::new(),
71
3.16k
        }
72
3.16k
    }
73
74
262k
    fn reset_for_function(&mut self) {
75
262k
        self.next_var = 0;
76
262k
        self.rename_vars = HashMap::new();
77
262k
    }
78
79
91.7k
    fn next_temp(&mut self) -> VarIdent {
80
91.7k
        self.next_var += 1;
81
91.7k
        crate::def::simplify_temp_var(self.next_var)
82
91.7k
    }
83
84
799k
    fn tuple_type_name(&mut self, arity: usize) -> Dt {
85
799k
        self.tuple_typs.insert(arity);
86
799k
        Dt::Tuple(arity)
87
799k
    }
88
89
2.20k
    fn closure_type_name(
90
2.20k
        &mut self,
91
2.20k
        fun: Fun,
92
2.20k
        typs: Typs,
93
2.20k
        typ: Typ,
94
2.20k
        kind: ClosureKind,
95
2.20k
        id: usize,
96
2.20k
    ) -> Path {
97
2.20k
        let e = self.closure_typs.entry(id).or_insert(ClosureDatatype {
98
2.20k
            enclosing_fun: fun.clone(),
99
2.20k
            args: typs,
100
2.20k
            output: typ,
101
2.20k
            kind: kind,
102
2.20k
            path: crate::def::prefix_closure_type(id),
103
2.20k
        });
104
2.20k
        assert!(&e.enclosing_fun == &fun);
105
2.20k
        e.path.clone()
106
2.20k
    }
107
}
108
109
struct LocalCtxt {
110
    span: Span,
111
    typ_params: Vec<Ident>,
112
    fun: Option<Fun>,
113
}
114
115
/// Should only return true if this expression is guaranteed constant
116
/// (i.e., does not depend on evaluation order, i.e., does not depend on any mutable variable)
117
150
fn is_small_expr(expr: &Expr) -> bool {
118
150
    match &expr.x {
119
31
        ExprX::Const(_) => true,
120
2
        ExprX::Unary(UnaryOp::Not | UnaryOp::Clip { .. }, e) => is_small_expr(e),
121
0
        ExprX::UnaryOpr(UnaryOpr::Box(_) | UnaryOpr::Unbox(_), _) => panic!("unexpected box"),
122
117
        _ => false,
123
    }
124
150
}
125
126
/// Create a temporary and return:
127
///  - A Stmt that assigns the given `expr` to the temporary
128
///  - The name of the temporary
129
91.4k
fn temp_var(state: &mut State, expr: &Expr) -> (Stmt, VarIdent) {
130
91.4k
    let temp = state.next_temp();
131
91.4k
    let name = temp.clone();
132
91.4k
    let pattern = PatternX::simple_var(name, &expr.span, &expr.typ);
133
91.4k
    let decl = StmtX::Decl {
134
91.4k
        pattern,
135
91.4k
        mode: None,
136
91.4k
        init: Some(PlaceX::spec_temporary(expr.clone())),
137
91.4k
        els: None,
138
91.4k
        assert_irrefutable: false,
139
91.4k
    };
140
91.4k
    let temp_decl = Spanned::new(expr.span.clone(), decl);
141
91.4k
    (temp_decl, temp)
142
91.4k
}
143
144
82.3k
fn temp_expr(state: &mut State, expr: &Expr) -> (Stmt, Expr) {
145
82.3k
    let (temp_decl, var_ident) = temp_var(state, expr);
146
82.3k
    (temp_decl, SpannedTyped::new(&expr.span, &expr.typ, ExprX::Var(var_ident)))
147
82.3k
}
148
149
148
fn small_or_temp(state: &mut State, expr: &Expr) -> (Vec<Stmt>, Expr) {
150
148
    if is_small_expr(&expr) {
151
31
        (vec![], expr.clone())
152
    } else {
153
117
        let (ts, te) = temp_expr(state, expr);
154
117
        (vec![ts], te)
155
    }
156
148
}
157
158
45
fn pattern_to_decls_with_no_initializer(pattern: &Pattern, stmts: &mut Vec<Stmt>) {
159
45
    match &pattern.x {
160
15
        PatternX::Wildcard(_) => {}
161
10
        PatternX::Var(binding) | PatternX::Binding { binding, sub_pat: _ } => {
162
10
            let v_patternx = PatternX::Var(PatternBinding {
163
10
                name: binding.name.clone(),
164
10
                user_mut: None,
165
10
                by_ref: ByRef::No,
166
10
                typ: binding.typ.clone(),
167
10
                copy: false,
168
10
            });
169
10
            let v_pattern = SpannedTyped::new(&pattern.span, &binding.typ, v_patternx);
170
10
            stmts.push(Spanned::new(
171
10
                pattern.span.clone(),
172
10
                StmtX::Decl {
173
10
                    pattern: v_pattern,
174
10
                    mode: None, // mode doesn't matter anymore
175
10
                    init: None,
176
10
                    els: None,
177
10
                    assert_irrefutable: false,
178
10
                },
179
            ));
180
181
10
            match &pattern.x {
182
0
                PatternX::Binding { sub_pat, .. } => {
183
0
                    pattern_to_decls_with_no_initializer(sub_pat, stmts);
184
0
                }
185
10
                _ => {}
186
            }
187
        }
188
12
        PatternX::Constructor(_path, _variant, patterns) => {
189
20
            for binder in patterns.iter() {
190
20
                pattern_to_decls_with_no_initializer(&binder.a, stmts);
191
20
            }
192
        }
193
4
        PatternX::Or(pat1, _pat2) => {
194
4
            pattern_to_decls_with_no_initializer(&pat1, stmts);
195
4
        }
196
4
        PatternX::Expr(_) => {}
197
0
        PatternX::Range(_, _) => {}
198
0
        PatternX::ImmutRef(p) | PatternX::MutRef(p) => {
199
0
            pattern_to_decls_with_no_initializer(p, stmts);
200
0
        }
201
    }
202
45
}
203
204
1.41M
fn rename_var(state: &State, scope_map: &VisitorScopeMap, x: &VarIdent) -> VarIdent {
205
1.41M
    if let Some(rename) = state.rename_vars.get(x) {
206
1.10M
        if scope_map[x].is_outer_param_or_ret {
207
1.10M
            return rename.clone();
208
0
        }
209
311k
    }
210
311k
    x.clone()
211
1.41M
}
212
213
1.84M
fn simplify_one_place(
214
1.84M
    _ctx: &GlobalCtx,
215
1.84M
    state: &mut State,
216
1.84M
    scope_map: &VisitorScopeMap,
217
1.84M
    place: &Place,
218
1.84M
) -> Result<Place, VirErr> {
219
1.84M
    match &place.x {
220
1.40M
        PlaceX::Local(x) => Ok(place.new_x(PlaceX::Local(rename_var(state, scope_map, x)))),
221
448k
        _ => Ok(place.clone()),
222
    }
223
1.84M
}
224
225
/// Returns a "pure place", i.e., a Place with no-side effects, and which is rooted
226
/// at a Local (rather than a Temporary).
227
21.7k
fn place_to_pure_place(state: &mut State, place: &Place) -> (Vec<Stmt>, Place) {
228
21.7k
    let (mut stmts, place, wf) = place_to_pure_place_rec(state, place);
229
21.7k
    stmts.extend(wf);
230
21.7k
    (stmts, place)
231
21.7k
}
232
233
/// Returns (Stmts, place, wf)
234
/// wf are the remaining obligations to prove that accessing the place is safe
235
/// (i.e., those not already icnluded in Stmts)
236
23.8k
fn place_to_pure_place_rec(state: &mut State, place: &Place) -> (Vec<Stmt>, Place, Vec<Stmt>) {
237
23.8k
    match &place.x {
238
1.63k
        PlaceX::Field(field_opr, p) => {
239
1.63k
            let (stmts, p1, mut wf) = place_to_pure_place_rec(state, p);
240
1.63k
            match field_opr.check {
241
1.62k
                VariantCheck::None => {}
242
19
                VariantCheck::Union => {
243
19
                    let p1_expr = place_to_spec_expr(&p1);
244
19
                    let assert_stmt =
245
19
                        crate::place_preconditions::field_check(&place.span, &p1_expr, field_opr);
246
19
                    wf.push(assert_stmt);
247
19
                }
248
                // Handled later, at SST lowering - no AST-level encoding for this timing.
249
0
                VariantCheck::Recommends => {}
250
            }
251
            // Preserve Recommends for that later pass; Union is already discharged above.
252
1.63k
            let check = if field_opr.check == VariantCheck::Recommends {
253
0
                VariantCheck::Recommends
254
            } else {
255
1.63k
                VariantCheck::None
256
            };
257
1.63k
            let field_opr = FieldOpr { check, ..field_opr.clone() };
258
1.63k
            let p2 =
259
1.63k
                SpannedTyped::new(&place.span, &place.typ, PlaceX::Field(field_opr.clone(), p1));
260
1.63k
            (stmts, p2, wf)
261
        }
262
164
        PlaceX::DerefMut(p) => {
263
164
            let (stmts, p1, wf) = place_to_pure_place_rec(state, p);
264
164
            let p2 = SpannedTyped::new(&place.span, &place.typ, PlaceX::DerefMut(p1));
265
164
            (stmts, p2, wf)
266
        }
267
6
        PlaceX::ModeUnwrap(p, mwm) => {
268
6
            let (stmts, p1, wf) = place_to_pure_place_rec(state, p);
269
6
            let p2 = SpannedTyped::new(&place.span, &place.typ, PlaceX::ModeUnwrap(p1, *mwm));
270
6
            (stmts, p2, wf)
271
        }
272
12.6k
        PlaceX::Local(_l) => (vec![], place.clone(), vec![]),
273
9.12k
        PlaceX::Temporary(expr) => {
274
9.12k
            let (ts, var_ident) = temp_var(state, expr);
275
9.12k
            let p = SpannedTyped::new(&place.span, &place.typ, PlaceX::Local(var_ident));
276
9.12k
            (vec![ts], p, vec![])
277
        }
278
230
        PlaceX::WithExpr(expr, p) => {
279
230
            let (mut stmts, p1, wf) = place_to_pure_place_rec(state, p);
280
230
            stmts.insert(0, Spanned::new(place.span.clone(), StmtX::Expr(expr.clone())));
281
230
            (stmts, p1, wf)
282
        }
283
64
        PlaceX::Index(p, idx, kind, bounds_check) => {
284
64
            let (mut stmts, p1, mut wf) = place_to_pure_place_rec(state, p);
285
64
            let (idx_decl, idx_expr) = temp_expr(state, idx);
286
64
            stmts.push(idx_decl);
287
288
64
            match bounds_check {
289
0
                BoundsCheck::Allow => {}
290
                BoundsCheck::Error => {
291
64
                    if kind.getting_len_requires_read() {
292
16
                        stmts.extend(wf);
293
16
                        wf = vec![];
294
48
                    }
295
64
                    let p1_expr = place_to_spec_expr(&p1);
296
64
                    let assert_stmt = crate::place_preconditions::index_bound(
297
64
                        &place.span,
298
64
                        &p1_expr,
299
64
                        &idx_expr,
300
64
                        *kind,
301
                    );
302
64
                    stmts.push(assert_stmt);
303
                }
304
            }
305
306
64
            let p = SpannedTyped::new(
307
64
                &place.span,
308
64
                &place.typ,
309
64
                PlaceX::Index(p1, idx_expr, *kind, BoundsCheck::Allow),
310
            );
311
312
64
            (stmts, p, wf)
313
        }
314
        PlaceX::UserDefinedTypInvariantObligation(..) => {
315
0
            panic!("Verus internal error: unexpected UserDefinedTypInvariantObligation");
316
        }
317
    }
318
23.8k
}
319
320
// note that this gets called *bottom up*
321
// that is, if node A is the parent of children B and C,
322
// then simplify_one_expr is called first on B and C, and then on A
323
324
4.25M
fn simplify_one_expr(
325
4.25M
    ctx: &GlobalCtx,
326
4.25M
    state: &mut State,
327
4.25M
    scope_map: &VisitorScopeMap,
328
4.25M
    expr: &Expr,
329
4.25M
) -> Result<Expr, VirErr> {
330
    use crate::ast::CallTargetKind;
331
4.25M
    match &expr.x {
332
9.93k
        ExprX::Var(x) => Ok(expr.new_x(ExprX::Var(rename_var(state, scope_map, x)))),
333
1.76k
        ExprX::VarAt(x, at) => Ok(expr.new_x(ExprX::VarAt(rename_var(state, scope_map, x), *at))),
334
15.8k
        ExprX::Assign { place, .. }
335
3.36k
        | ExprX::BorrowMut(place)
336
11.1k
        | ExprX::TwoPhaseBorrowMut(place)
337
6
        | ExprX::BorrowMutTracked(place) => {
338
            // This check is no longer needed for soundness because ast_to_sst infers
339
            // mutability rather than relying on the user annotations.
340
            // Nonetheless, this check lets us pick up a few situations that wouldn't
341
            // get caught by borrowck (ghost variables).
342
            // However, much of the time it _does_ get caught by borrowck.
343
            // This check is in ast_simplify because it's after borrowck
344
            // (borrowck errors look nicer).
345
30.3k
            if !crate::ast_util::place_has_deref_mut(place)
346
20.2k
                && let Some(local) = crate::ast_util::place_get_local(place)
347
            {
348
20.1k
                let PlaceX::Local(x) = &local.x else { unreachable!() };
349
20.1k
                let x = match state.rename_vars_reverse.get(x) {
350
20.0k
                    None => x,
351
132
                    Some(y) => y,
352
                };
353
20.1k
                match scope_map.get(x) {
354
                    None => {
355
0
                        return Err(error(
356
0
                            &expr.span,
357
0
                            "Verus Internal Error: cannot find this variable",
358
0
                        ));
359
                    }
360
20.1k
                    Some(entry) if entry.user_mut == Some(false) && entry.init => {
361
2
                        let name = user_local_name(x);
362
2
                        return Err(error(
363
2
                            &expr.span,
364
2
                            format!("variable `{name:}` is not marked mutable"),
365
2
                        ));
366
                    }
367
20.1k
                    _ => {}
368
                }
369
10.1k
            }
370
30.3k
            Ok(expr.clone())
371
        }
372
540
        ExprX::ConstVar(x, autospec) => {
373
540
            let call_target_attrs = crate::ast::CallTargetAttrs {
374
540
                autospec: *autospec,
375
540
                const_var: true,
376
540
                assume_external_allowed: false,
377
540
            };
378
540
            let call = ExprX::Call {
379
540
                target: CallTarget::Fun(
380
540
                    CallTargetKind::Static,
381
540
                    x.clone(),
382
540
                    Arc::new(vec![]),
383
540
                    Arc::new(vec![]),
384
540
                    call_target_attrs,
385
540
                ),
386
540
                args: Arc::new(vec![]),
387
540
                post_args: None,
388
540
                body: None,
389
540
            };
390
540
            Ok(SpannedTyped::new(&expr.span, &expr.typ, call))
391
        }
392
        ExprX::Call {
393
776k
            target: CallTarget::Fun(kind, tgt, typs, impl_paths, attrs),
394
776k
            args,
395
776k
            post_args,
396
776k
            body,
397
        } => {
398
776k
            assert!(attrs.autospec == AutospecUsage::Final);
399
400
776k
            let is_trait_impl = match kind {
401
650k
                CallTargetKind::Static => false,
402
42
                CallTargetKind::ProofFn(..) => false,
403
62.8k
                CallTargetKind::Dynamic => true,
404
62.7k
                CallTargetKind::DynamicResolved { .. } => true,
405
16
                CallTargetKind::ExternalTraitDefault => true,
406
            };
407
776k
            let args = if typs.len() == 0 && args.len() == 0 && !is_trait_impl {
408
                // To simplify the AIR/SMT encoding, add a dummy argument to any function with 0 arguments
409
3.16k
                let typ = Arc::new(TypX::Int(IntRange::Int));
410
                use num_traits::Zero;
411
3.16k
                let argx = ExprX::Const(Constant::Int(num_bigint::BigInt::zero()));
412
3.16k
                let arg = SpannedTyped::new(&expr.span, &typ, argx);
413
3.16k
                Arc::new(vec![arg])
414
            } else {
415
772k
                args.clone()
416
            };
417
418
776k
            let call = ExprX::Call {
419
776k
                target: CallTarget::Fun(
420
776k
                    kind.clone(),
421
776k
                    tgt.clone(),
422
776k
                    typs.clone(),
423
776k
                    impl_paths.clone(),
424
776k
                    attrs.clone(),
425
776k
                ),
426
776k
                args,
427
776k
                post_args: post_args.clone(),
428
776k
                body: body.clone(),
429
776k
            };
430
776k
            Ok(SpannedTyped::new(&expr.span, &expr.typ, call))
431
        }
432
565
        ExprX::Ctor(name, variant, partial_binders, Some(update)) => {
433
565
            let CtorUpdateTail { place, taken_fields: _ } = update;
434
565
            let (stmts, update) = place_to_pure_place(state, place);
435
            // not really spec but that doesn't matter at this point
436
565
            let update = place_to_spec_expr(&update);
437
565
            let mut decls: Vec<Stmt> = Vec::new();
438
565
            let mut binders: Vec<Binder<Expr>> = Vec::new();
439
565
            if stmts.len() == 0 {
440
433
                for binder in partial_binders.iter() {
441
433
                    binders.push(binder.clone());
442
433
                }
443
            } else {
444
                // Because of Rust's order of evaluation here,
445
                // we have to put binders in temp vars, too.
446
148
                for binder in partial_binders.iter() {
447
148
                    let (temp_decl_inner, e) = small_or_temp(state, &binder.a);
448
148
                    decls.extend(temp_decl_inner.into_iter());
449
148
                    binders.push(binder.map_a(|_| e));
450
                }
451
138
                decls.extend(stmts.into_iter());
452
            }
453
454
565
            let path = match name {
455
565
                Dt::Path(p) => p,
456
                Dt::Tuple(_) => {
457
0
                    return Err(internal_error(
458
0
                        &expr.span,
459
0
                        "ExprX::Ctor with update and tuple type",
460
0
                    ));
461
                }
462
            };
463
464
565
            let (typ_positives, variants) = &ctx.datatypes[path];
465
565
            let fields = &crate::ast_util::get_variant(&variants, variant).fields;
466
565
            let typ_args = typ_args_for_datatype_typ(&expr.typ);
467
            // replace ..update
468
            // with f1: update.f1, f2: update.f2, ...
469
1.19k
            for field in fields.iter() {
470
1.30k
                if binders.iter().find(|b| b.name == field.name).is_none() {
471
611
                    let op = UnaryOpr::Field(FieldOpr {
472
611
                        datatype: name.clone(),
473
611
                        variant: variant.clone(),
474
611
                        field: field.name.clone(),
475
611
                        get_variant: false,
476
611
                        check: VariantCheck::None,
477
611
                    });
478
611
                    let exprx = ExprX::UnaryOpr(op, update.clone());
479
611
                    let ty = subst_typ_for_datatype(&typ_positives, typ_args, &field.a.0);
480
611
                    let field_exp = SpannedTyped::new(&expr.span, &ty, exprx);
481
611
                    binders.push(ident_binder(&field.name, &field_exp));
482
611
                }
483
            }
484
565
            let ctorx = ExprX::Ctor(name.clone(), variant.clone(), Arc::new(binders), None);
485
565
            let ctor = SpannedTyped::new(&expr.span, &expr.typ, ctorx);
486
565
            if decls.len() == 0 {
487
427
                Ok(ctor)
488
            } else {
489
138
                let block = ExprX::Block(Arc::new(decls), Some(ctor));
490
138
                Ok(SpannedTyped::new(&expr.span, &expr.typ, block))
491
            }
492
        }
493
32
        ExprX::ShrRefStructWrap(e1, e2, _t1, t2, variant, field) => {
494
            // Simplify as `Struct { field: e1, .. e2 }`
495
32
            let datatype_typ = undecorate_typ(&t2);
496
32
            let (dt, _typ_args) = match &*datatype_typ {
497
32
                TypX::Datatype(dt, typ_args, ..) => (dt, typ_args),
498
0
                _ => panic!("ShrRefStructWrap expects datatype"),
499
            };
500
32
            let Dt::Path(path) = dt else { panic!("ShrRefStructWrap expects Dt::Path") };
501
32
            let partial_binders =
502
32
                Arc::new(vec![Arc::new(air::ast::BinderX { name: field.clone(), a: e1.clone() })]);
503
32
            let place = SpannedTyped::new(&e2.span, &e2.typ, PlaceX::Temporary(e2.clone()));
504
            // taken_fields is ignored by this point
505
32
            let upd = CtorUpdateTail { place: place, taken_fields: Arc::new(vec![]) };
506
32
            let variant = if **variant == "" {
507
30
                let (_, variants) = &ctx.datatypes[path];
508
30
                assert!(variants.len() == 1);
509
30
                variants[0].name.clone()
510
            } else {
511
2
                variant.clone()
512
            };
513
32
            let ctor = ExprX::Ctor(dt.clone(), variant.clone(), partial_binders, Some(upd));
514
32
            let ctor = SpannedTyped::new(&expr.span, &expr.typ, ctor);
515
32
            simplify_one_expr(ctx, state, scope_map, &ctor)
516
        }
517
11.0k
        ExprX::Unary(UnaryOp::CoerceMode { .. }, expr0) => Ok(expr0.clone()),
518
26.5k
        ExprX::Multi(MultiOp::Chained(ops), args) => {
519
            use crate::ast::IeeeFloatBinaryOp;
520
26.5k
            assert!(args.len() == ops.len() + 1);
521
26.5k
            let mut stmts: Vec<Stmt> = Vec::new();
522
26.5k
            let mut es: Vec<Expr> = Vec::new();
523
26.5k
            let mut is_float = false;
524
            // Execute each argument in order; no short-circuiting
525
82.1k
            for i in 0..args.len() {
526
82.1k
                let t = crate::ast_util::undecorate_typ(&args[i].typ);
527
82.1k
                if matches!(*t, TypX::Float(_)) {
528
18
                    is_float = true;
529
82.1k
                }
530
82.1k
                let (decl, e) = temp_expr(state, &args[i]);
531
82.1k
                stmts.push(decl);
532
82.1k
                es.push(e);
533
            }
534
26.5k
            let mut conjunction: Expr = es[0].clone();
535
55.6k
            for i in 0..ops.len() {
536
55.6k
                let op = match (is_float, ops[i]) {
537
53.2k
                    (false, ChainedOp::Inequality(a)) => BinaryOp::Inequality(a),
538
12
                    (true, ChainedOp::Inequality(a)) => {
539
12
                        BinaryOp::IeeeFloat(IeeeFloatBinaryOp::InEq(a))
540
                    }
541
2.30k
                    (_, ChainedOp::MultiEq) => BinaryOp::Eq(Mode::Spec),
542
                };
543
55.6k
                let left = es[i].clone();
544
55.6k
                let right = es[i + 1].clone();
545
55.6k
                let span = left.span.clone();
546
55.6k
                let binary = SpannedTyped::new(&span, &expr.typ, ExprX::Binary(op, left, right));
547
55.6k
                if i == 0 {
548
26.5k
                    conjunction = binary;
549
29.0k
                } else {
550
29.0k
                    let exprx = ExprX::Logical(LogicalOp::And, conjunction, binary);
551
29.0k
                    conjunction = SpannedTyped::new(&span, &expr.typ, exprx);
552
29.0k
                }
553
            }
554
26.5k
            if stmts.len() == 0 {
555
0
                Ok(conjunction)
556
            } else {
557
26.5k
                let block = ExprX::Block(Arc::new(stmts), Some(conjunction));
558
26.5k
                Ok(SpannedTyped::new(&expr.span, &expr.typ, block))
559
            }
560
        }
561
13.9k
        ExprX::Match(place, arms1, assert_irrefutable) => {
562
13.9k
            let (temp_decl, place) = place_to_pure_place(state, place);
563
564
            // Translate into If expression
565
13.9k
            let t_bool = Arc::new(TypX::Bool);
566
13.9k
            let mut if_expr: Option<Expr> = None;
567
29.6k
            for arm in arms1.iter().rev() {
568
29.6k
                let mut decls: Vec<Stmt> = Vec::new();
569
29.6k
                let has_guard = arm.x.has_guard();
570
571
29.6k
                let test_pattern = crate::patterns::pattern_to_exprs(
572
29.6k
                    ctx,
573
29.6k
                    &place,
574
29.6k
                    &arm.x.pattern,
575
29.6k
                    has_guard,
576
29.6k
                    &mut decls,
577
1
                )?;
578
579
29.6k
                let test = if !has_guard {
580
29.5k
                    test_pattern
581
                } else {
582
62
                    assert!(!crate::patterns::pattern_has_or(&arm.x.pattern));
583
584
62
                    let mut guard = arm.x.guard.clone();
585
62
                    guard = SpannedTyped::new(
586
62
                        &guard.span,
587
62
                        &guard.typ,
588
62
                        ExprX::MatchGuardFreeze(place.clone(), guard.clone()),
589
                    );
590
62
                    let test_exp = ExprX::Logical(LogicalOp::And, test_pattern, guard);
591
62
                    let test = SpannedTyped::new(&arm.x.pattern.span, &t_bool, test_exp);
592
62
                    let block = ExprX::Block(Arc::new(decls.clone()), Some(test));
593
62
                    SpannedTyped::new(&arm.x.pattern.span, &t_bool, block)
594
                };
595
596
29.6k
                let block = ExprX::Block(Arc::new(decls), Some(arm.x.body.clone()));
597
29.6k
                let body = SpannedTyped::new(&arm.x.pattern.span, &expr.typ, block);
598
29.6k
                if let Some(prev) = if_expr {
599
15.6k
                    // if pattern && guard then body else prev
600
15.6k
                    let ifx = ExprX::If(test.clone(), body, Some(prev));
601
15.6k
                    if_expr = Some(SpannedTyped::new(&test.span, &expr.typ.clone(), ifx));
602
15.6k
                } else if *assert_irrefutable {
603
1.75k
                    if has_guard {
604
0
                        return Err(error(&arm.x.guard.span, "if-guard on final match arm"));
605
1.75k
                    }
606
1.75k
                    let assertion = SpannedTyped::new(
607
1.75k
                        &arm.x.pattern.span,
608
1.75k
                        &unit_typ(),
609
1.75k
                        ExprX::AssertAssume {
610
1.75k
                            is_assume: false,
611
1.75k
                            expr: test,
612
1.75k
                            msg: Some(irrefut_failure_msg(&arm.x.pattern.span)),
613
1.75k
                        },
614
                    );
615
1.75k
                    let block = SpannedTyped::new(
616
1.75k
                        &body.span,
617
1.75k
                        &body.typ,
618
1.75k
                        ExprX::Block(
619
1.75k
                            Arc::new(vec![Spanned::new(
620
1.75k
                                assertion.span.clone(),
621
1.75k
                                StmtX::Expr(assertion.clone()),
622
1.75k
                            )]),
623
1.75k
                            Some(body.clone()),
624
1.75k
                        ),
625
                    );
626
1.75k
                    if_expr = Some(block);
627
12.1k
                } else {
628
12.1k
                    // last arm is unconditional
629
12.1k
                    if_expr = Some(body);
630
12.1k
                }
631
            }
632
13.9k
            if let Some(if_expr) = if_expr {
633
13.9k
                let if_expr = if temp_decl.len() != 0 {
634
6.57k
                    let block = ExprX::Block(Arc::new(temp_decl), Some(if_expr));
635
6.57k
                    SpannedTyped::new(&expr.span, &expr.typ, block)
636
                } else {
637
7.37k
                    if_expr
638
                };
639
13.9k
                Ok(if_expr)
640
            } else {
641
1
                Err(error(&expr.span, "not yet implemented: zero-arm match expressions"))
642
            }
643
        }
644
29.6k
        ExprX::Ghost { alloc_wrapper: _, tracked: _, expr: expr1 } => Ok(expr1.clone()),
645
        ExprX::NonSpecClosure {
646
307
            params,
647
307
            proof_fn_modes,
648
307
            body,
649
307
            requires,
650
307
            ensures,
651
307
            ret,
652
307
            external_spec,
653
        } => {
654
307
            assert!(external_spec.is_none());
655
656
307
            let closure_var_ident = state.next_temp();
657
307
            let closure_var = SpannedTyped::new(
658
307
                &expr.span,
659
307
                &expr.typ.clone(),
660
307
                ExprX::Var(closure_var_ident.clone()),
661
            );
662
663
307
            let external_spec_expr =
664
307
                exec_closure_spec(state, &expr.span, &closure_var, params, ret, requires, ensures)?;
665
307
            let external_spec = Some((closure_var_ident, external_spec_expr));
666
667
307
            Ok(SpannedTyped::new(
668
307
                &expr.span,
669
307
                &expr.typ,
670
307
                ExprX::NonSpecClosure {
671
307
                    params: params.clone(),
672
307
                    proof_fn_modes: proof_fn_modes.clone(),
673
307
                    body: body.clone(),
674
307
                    requires: requires.clone(),
675
307
                    ensures: ensures.clone(),
676
307
                    ret: ret.clone(),
677
307
                    external_spec,
678
307
                },
679
307
            ))
680
        }
681
3.35M
        _ => Ok(expr.clone()),
682
    }
683
4.25M
}
684
685
5.39k
fn tuple_get_field_expr(
686
5.39k
    state: &mut State,
687
5.39k
    span: &Span,
688
5.39k
    typ: &Typ,
689
5.39k
    tuple_expr: &Expr,
690
5.39k
    tuple_arity: usize,
691
5.39k
    field: usize,
692
5.39k
) -> Expr {
693
5.39k
    let datatype = state.tuple_type_name(tuple_arity);
694
695
5.39k
    let variant = prefix_tuple_variant(tuple_arity);
696
5.39k
    let field = positional_field_ident(field);
697
5.39k
    let op = UnaryOpr::Field(FieldOpr {
698
5.39k
        datatype,
699
5.39k
        variant,
700
5.39k
        field,
701
5.39k
        get_variant: false,
702
5.39k
        check: VariantCheck::None,
703
5.39k
    });
704
5.39k
    let field_expr = SpannedTyped::new(span, typ, ExprX::UnaryOpr(op, tuple_expr.clone()));
705
5.39k
    field_expr
706
5.39k
}
707
708
1.75k
fn irrefut_failure_msg(pattern_span: &Span) -> crate::messages::Message {
709
1.75k
    error(pattern_span, "unable to prove this pattern will successfully match")
710
1.75k
}
711
712
300k
fn simplify_one_stmt(ctx: &GlobalCtx, state: &mut State, stmt: &Stmt) -> Result<Vec<Stmt>, VirErr> {
713
300k
    match &stmt.x {
714
11.5k
        StmtX::Decl { pattern, mode: _, init: None, els: None, assert_irrefutable } => {
715
11.5k
            assert!(!assert_irrefutable);
716
11.5k
            match &pattern.x {
717
                PatternX::Var(PatternBinding {
718
                    by_ref: ByRef::No,
719
                    name: _,
720
                    user_mut: _,
721
                    typ: _,
722
                    copy: _,
723
11.5k
                }) => Ok(vec![stmt.clone()]),
724
                _ => {
725
21
                    let mut stmts: Vec<Stmt> = Vec::new();
726
21
                    pattern_to_decls_with_no_initializer(pattern, &mut stmts);
727
21
                    Ok(stmts)
728
                }
729
            }
730
        }
731
0
        StmtX::Decl { pattern, mode: _, init: None, els: Some(_), .. } => Err(error(
732
0
            &pattern.span,
733
0
            "Verus Internal Error: Decl with else-block but no initializer",
734
0
        )),
735
63.5k
        StmtX::Decl { pattern, mode: _, init: Some(_init), els: None, assert_irrefutable: _ }
736
7.18k
            if matches!(
737
63.5k
                pattern.x,
738
                PatternX::Var(PatternBinding {
739
                    by_ref: ByRef::No,
740
                    name: _,
741
                    user_mut: _,
742
                    typ: _,
743
                    copy: _
744
                })
745
            ) =>
746
        {
747
56.3k
            Ok(vec![stmt.clone()])
748
        }
749
7.21k
        StmtX::Decl { pattern, mode: _, init: Some(init), els, assert_irrefutable } => {
750
7.21k
            let (mut stmts, place) = place_to_pure_place(state, init);
751
7.21k
            let mut stmts2: Vec<Stmt> = vec![];
752
7.21k
            let pattern_check =
753
7.21k
                crate::patterns::pattern_to_exprs(ctx, &place, pattern, false, &mut stmts2)?;
754
7.21k
            if let Some(els) = &els {
755
34
                assert!(!assert_irrefutable);
756
34
                let checkx = ExprX::Unary(UnaryOp::Not, pattern_check.clone());
757
34
                let check = SpannedTyped::new(&pattern_check.span, &pattern_check.typ, checkx);
758
34
                let neverx = ExprX::NeverToAny(els.clone());
759
34
                let never = SpannedTyped::new(&els.span, &unit_typ(), neverx);
760
34
                let ifx = ExprX::If(check.clone(), never, None);
761
34
                let ife = SpannedTyped::new(&stmt.span, &unit_typ(), ifx);
762
34
                let ifstmtx = StmtX::Expr(ife);
763
34
                let ifstmt = Spanned::new(stmt.span.clone(), ifstmtx);
764
34
                stmts.push(ifstmt);
765
7.18k
            } else if *assert_irrefutable {
766
1
                stmts.push(Spanned::new(
767
1
                    stmt.span.clone(),
768
1
                    StmtX::Expr(SpannedTyped::new(
769
1
                        &stmt.span,
770
1
                        &unit_typ(),
771
1
                        ExprX::AssertAssume {
772
1
                            is_assume: false,
773
1
                            expr: pattern_check,
774
1
                            msg: Some(irrefut_failure_msg(&pattern.span)),
775
1
                        },
776
1
                    )),
777
1
                ));
778
7.17k
            }
779
7.21k
            stmts.extend(stmts2);
780
7.21k
            Ok(stmts)
781
        }
782
225k
        StmtX::Expr(_) => Ok(vec![stmt.clone()]),
783
    }
784
300k
}
785
786
15.4M
fn simplify_one_typ(local: &LocalCtxt, state: &mut State, typ: &Typ) -> Result<Typ, VirErr> {
787
15.4M
    match &**typ {
788
770k
        TypX::Datatype(Dt::Tuple(i), ..) => {
789
770k
            state.tuple_type_name(*i);
790
770k
            Ok(typ.clone())
791
        }
792
2.20k
        TypX::AnonymousClosure(typs, typ, kind, id) => {
793
2.20k
            let Some(fun) = local.fun.clone() else {
794
0
                return Err(error(
795
0
                    &local.span,
796
0
                    format!("Verus Internal Error: found AnonymousClosure type outside function"),
797
0
                ));
798
            };
799
2.20k
            let path =
800
2.20k
                Dt::Path(state.closure_type_name(fun, typs.clone(), typ.clone(), *kind, *id));
801
2.20k
            let typ_args: Vec<Typ> = local
802
2.20k
                .typ_params
803
2.20k
                .iter()
804
2.20k
                .map(|name| Arc::new(TypX::TypParam(name.clone())))
805
2.20k
                .collect();
806
2.20k
            Ok(Arc::new(TypX::Datatype(path, Arc::new(typ_args), Arc::new(vec![]))))
807
        }
808
2.77k
        TypX::FnDef(fun, _typs, resolved) => {
809
2.77k
            state.fndef_typs.insert(fun.clone());
810
2.77k
            if let Some(resolved_fun) = resolved {
811
140
                state.fndef_typs.insert(resolved_fun.clone());
812
2.63k
            }
813
2.77k
            Ok(typ.clone())
814
        }
815
5.67M
        TypX::TypParam(x) => {
816
5.67M
            if !local.typ_params.contains(&x) {
817
0
                return Err(error(
818
0
                    &local.span,
819
0
                    format!("type parameter {} used before being declared", x),
820
0
                ));
821
5.67M
            }
822
5.67M
            Ok(typ.clone())
823
        }
824
8.98M
        _ => Ok(typ.clone()),
825
    }
826
15.4M
}
827
828
// TODO: a lot of this closure stuff could get its own file
829
// rename to apply to all fn types, not just closure types
830
831
5.31k
fn closure_trait_call_typ_args(state: &mut State, fn_val: &Expr, params: &VarBinders<Typ>) -> Typs {
832
5.31k
    let path = state.tuple_type_name(params.len());
833
834
5.41k
    let param_typs: Vec<Typ> = params.iter().map(|p| p.a.clone()).collect();
835
5.31k
    let tup_typ = Arc::new(TypX::Datatype(path, Arc::new(param_typs), Arc::new(vec![])));
836
837
5.31k
    Arc::new(vec![fn_val.typ.clone(), tup_typ])
838
5.31k
}
839
840
938
fn mk_closure_req_call(
841
938
    state: &mut State,
842
938
    span: &Span,
843
938
    params: &VarBinders<Typ>,
844
938
    fn_val: &Expr,
845
938
    arg_tuple: &Expr,
846
938
) -> Expr {
847
938
    let bool_typ = Arc::new(TypX::Bool);
848
938
    SpannedTyped::new(
849
938
        span,
850
938
        &bool_typ,
851
938
        ExprX::Call {
852
938
            target: CallTarget::BuiltinSpecFun(
853
938
                BuiltinSpecFun::ClosureReq,
854
938
                closure_trait_call_typ_args(state, fn_val, params),
855
938
                Arc::new(vec![]),
856
938
            ),
857
938
            args: Arc::new(vec![fn_val.clone(), arg_tuple.clone()]),
858
938
            post_args: None,
859
938
            body: None,
860
938
        },
861
    )
862
938
}
863
864
4.37k
fn mk_closure_ens_call(
865
4.37k
    state: &mut State,
866
4.37k
    span: &Span,
867
4.37k
    params: &VarBinders<Typ>,
868
4.37k
    fn_val: &Expr,
869
4.37k
    arg_tuple: &Expr,
870
4.37k
    ret_arg: &Expr,
871
4.37k
    builtin_spec_fun: BuiltinSpecFun,
872
4.37k
) -> Expr {
873
4.37k
    let bool_typ = Arc::new(TypX::Bool);
874
4.37k
    SpannedTyped::new(
875
4.37k
        span,
876
4.37k
        &bool_typ,
877
4.37k
        ExprX::Call {
878
4.37k
            target: CallTarget::BuiltinSpecFun(
879
4.37k
                builtin_spec_fun,
880
4.37k
                closure_trait_call_typ_args(state, fn_val, params),
881
4.37k
                Arc::new(vec![]),
882
4.37k
            ),
883
4.37k
            args: Arc::new(vec![fn_val.clone(), arg_tuple.clone(), ret_arg.clone()]),
884
4.37k
            post_args: None,
885
4.37k
            body: None,
886
4.37k
        },
887
    )
888
4.37k
}
889
890
5.31k
fn exec_closure_spec_param(
891
5.31k
    state: &mut State,
892
5.31k
    span: &Span,
893
5.31k
    params: &VarBinders<Typ>,
894
5.31k
) -> (VarIdent, Expr) {
895
5.41k
    let param_typs: Vec<Typ> = params.iter().map(|p| p.a.clone()).collect();
896
5.31k
    let tuple_path = state.tuple_type_name(params.len());
897
5.31k
    let tuple_typ = Arc::new(TypX::Datatype(tuple_path, Arc::new(param_typs), Arc::new(vec![])));
898
5.31k
    let tuple_ident = crate::def::closure_param_var();
899
5.31k
    let tuple_var = SpannedTyped::new(span, &tuple_typ, ExprX::Var(tuple_ident.clone()));
900
5.31k
    (tuple_ident, tuple_var)
901
5.31k
}
902
903
938
fn exec_closure_spec_requires(
904
938
    state: &mut State,
905
938
    span: &Span,
906
938
    closure_var: &Expr,
907
938
    params: &VarBinders<Typ>,
908
938
    requires: &Exprs,
909
938
) -> Result<Expr, VirErr> {
910
    // For requires:
911
912
    // If the closure has `|a0, a1, a2| requires f(a0, a1, a2)`
913
    // then we emit a spec of the form
914
    //
915
    //      forall x :: f(x.0, x.1, x.2) ==> closure.requires(x)
916
    //
917
    // with `closure.requires(x)` as the trigger
918
919
    // (Since the user doesn't have the option to specify a trigger here,
920
    // we need to use the most general one, and that means we need to
921
    // quantify over a tuple.)
922
923
938
    let (tuple_ident, tuple_var) = exec_closure_spec_param(state, span, params);
924
938
    let tuple_typ = tuple_var.typ.clone();
925
926
938
    let reqs = conjoin(span, requires);
927
928
    // Supply 'let' statements of the form 'let a0 = x.0; let a1 = x.1; ...' etc.
929
930
938
    let mut decls: Vec<Stmt> = Vec::new();
931
1.03k
    for (i, p) in params.iter().enumerate() {
932
1.03k
        let typ = &p.a;
933
1.03k
        let pattern = PatternX::simple_var(p.name.clone(), span, typ);
934
1.03k
        let tuple_field = tuple_get_field_expr(state, span, typ, &tuple_var, params.len(), i);
935
1.03k
        let decl = StmtX::Decl {
936
1.03k
            pattern,
937
1.03k
            mode: None,
938
1.03k
            init: Some(PlaceX::spec_temporary(tuple_field)),
939
1.03k
            els: None,
940
1.03k
            assert_irrefutable: false,
941
1.03k
        };
942
1.03k
        decls.push(Spanned::new(span.clone(), decl));
943
1.03k
    }
944
945
938
    let reqs_body =
946
938
        SpannedTyped::new(&reqs.span, &reqs.typ, ExprX::Block(Arc::new(decls), Some(reqs.clone())));
947
948
938
    let closure_req_call =
949
938
        wrap_in_trigger(&mk_closure_req_call(state, span, params, closure_var, &tuple_var));
950
951
938
    let bool_typ = Arc::new(TypX::Bool);
952
938
    let req_quant_body = mk_implies(span, &reqs_body, &closure_req_call);
953
954
938
    let forall = Quant { quant: air::ast::Quant::Forall };
955
938
    let binders = Arc::new(vec![Arc::new(VarBinderX { name: tuple_ident, a: tuple_typ })]);
956
938
    let req_forall =
957
938
        SpannedTyped::new(span, &bool_typ, ExprX::Quant(forall, binders, req_quant_body));
958
959
938
    Ok(req_forall)
960
938
}
961
962
4.36k
fn exec_closure_spec_ensures(
963
4.36k
    state: &mut State,
964
4.36k
    span: &Span,
965
4.36k
    closure_var: &Expr,
966
4.36k
    params: &VarBinders<Typ>,
967
4.36k
    ret: &VarBinder<Typ>,
968
4.36k
    ensures: &Vec<Expr>,
969
4.36k
    default_ens: bool,
970
4.36k
) -> Result<Expr, VirErr> {
971
    // For ensures:
972
973
    // If the closure has `|a0, a1, a2| ensures |b| f(a0, a1, a2, b)`
974
    // then we emit a spec of the form
975
    //
976
    //      forall x, y :: closure.ensures(x, y) ==> f(x.0, x.1, x.2, y)
977
    //
978
    // with `closure.ensures(x)` as the trigger
979
980
4.36k
    let (tuple_ident, tuple_var) = exec_closure_spec_param(state, span, params);
981
4.36k
    let tuple_typ = tuple_var.typ.clone();
982
983
4.36k
    let ret_ident = ret.clone();
984
4.36k
    let ret_var = SpannedTyped::new(span, &ret.a, ExprX::Var(ret_ident.name.clone()));
985
986
4.36k
    let enss = conjoin(span, ensures);
987
988
    // Supply 'let' statements of the form 'let a0 = x.0; let a1 = x.1; ...' etc.
989
990
4.36k
    let mut decls: Vec<Stmt> = Vec::new();
991
4.36k
    for (i, p) in params.iter().enumerate() {
992
4.36k
        let typ = &p.a;
993
4.36k
        let pattern = PatternX::simple_var(p.name.clone(), span, typ);
994
4.36k
        let tuple_field = tuple_get_field_expr(state, span, typ, &tuple_var, params.len(), i);
995
4.36k
        let decl = StmtX::Decl {
996
4.36k
            pattern,
997
4.36k
            mode: None,
998
4.36k
            init: Some(PlaceX::spec_temporary(tuple_field)),
999
4.36k
            els: None,
1000
4.36k
            assert_irrefutable: false,
1001
4.36k
        };
1002
4.36k
        decls.push(Spanned::new(span.clone(), decl));
1003
4.36k
    }
1004
1005
4.36k
    let enss_body =
1006
4.36k
        SpannedTyped::new(&enss.span, &enss.typ, ExprX::Block(Arc::new(decls), Some(enss.clone())));
1007
1008
4.36k
    let closure_ens_call = wrap_in_trigger(&mk_closure_ens_call(
1009
4.36k
        state,
1010
4.36k
        span,
1011
4.36k
        params,
1012
4.36k
        closure_var,
1013
4.36k
        &tuple_var,
1014
4.36k
        &ret_var,
1015
4.36k
        if default_ens { BuiltinSpecFun::DefaultEns } else { BuiltinSpecFun::ClosureEns },
1016
    ));
1017
1018
4.36k
    let bool_typ = Arc::new(TypX::Bool);
1019
4.36k
    let ens_quant_body = mk_implies(span, &closure_ens_call, &enss_body);
1020
1021
4.36k
    let forall = Quant { quant: air::ast::Quant::Forall };
1022
4.36k
    let binders =
1023
4.36k
        Arc::new(vec![Arc::new(VarBinderX { name: tuple_ident, a: tuple_typ }), ret.clone()]);
1024
4.36k
    let ens_forall =
1025
4.36k
        SpannedTyped::new(span, &bool_typ, ExprX::Quant(forall, binders, ens_quant_body));
1026
1027
4.36k
    Ok(ens_forall)
1028
4.36k
}
1029
1030
307
fn exec_closure_spec(
1031
307
    state: &mut State,
1032
307
    span: &Span,
1033
307
    closure_var: &Expr,
1034
307
    params: &VarBinders<Typ>,
1035
307
    ret: &VarBinder<Typ>,
1036
307
    requires: &Exprs,
1037
307
    ensures: &Exprs,
1038
307
) -> Result<Expr, VirErr> {
1039
307
    let req_forall = exec_closure_spec_requires(state, span, closure_var, params, requires)?;
1040
1041
307
    if ensures.len() > 0 {
1042
137
        let ens_forall =
1043
137
            exec_closure_spec_ensures(state, span, closure_var, params, ret, ensures, false)?;
1044
137
        Ok(conjoin(span, &vec![req_forall, ens_forall]))
1045
    } else {
1046
170
        Ok(req_forall)
1047
    }
1048
307
}
1049
1050
735k
pub(crate) fn need_fndef_axiom(fndef_typs: &HashSet<Fun>, f: &Function) -> bool {
1051
735k
    if fndef_typs.contains(&f.x.name) {
1052
3.99k
        return true;
1053
731k
    }
1054
731k
    match &f.x.kind {
1055
263k
        FunctionKind::TraitMethodImpl { method, .. } => fndef_typs.contains(method),
1056
468k
        _ => false,
1057
    }
1058
735k
}
1059
1060
9.34k
fn add_fndef_axioms_to_function(
1061
9.34k
    _ctx: &GlobalCtx,
1062
9.34k
    state: &mut State,
1063
9.34k
    function: &Function,
1064
9.34k
    fn_once_trait_in_scope: bool,
1065
9.34k
) -> Result<(Function, Vec<TraitImpl>, Option<AssocTypeImpl>), VirErr> {
1066
9.34k
    state.reset_for_function();
1067
1068
9.34k
    let params: Vec<_> = function
1069
9.34k
        .x
1070
9.34k
        .params
1071
9.34k
        .iter()
1072
10.9k
        .filter(|p| !is_dummy_param_name(&p.x.name))
1073
10.9k
        .map(|p| Arc::new(VarBinderX { name: p.x.name.clone(), a: p.x.typ.clone() }))
1074
9.34k
        .collect();
1075
9.34k
    let params = Arc::new(params);
1076
1077
9.34k
    let (fun, typ_args, is_trait_method_impl, inherit) = match &function.x.kind {
1078
8.71k
        FunctionKind::TraitMethodImpl { method, trait_typ_args, inherit_body_from, .. } => {
1079
8.71k
            (method, trait_typ_args.clone(), true, inherit_body_from.is_some())
1080
        }
1081
        _ => {
1082
631
            let typ_args: Vec<_> = function
1083
631
                .x
1084
631
                .typ_params
1085
631
                .iter()
1086
932
                .map(|tp| Arc::new(TypX::TypParam(tp.clone())))
1087
631
                .collect();
1088
631
            let typ_args = Arc::new(typ_args);
1089
631
            (&function.x.name, typ_args, false, false)
1090
        }
1091
    };
1092
1093
9.34k
    let fndef_singleton = SpannedTyped::new(
1094
9.34k
        &function.span,
1095
9.34k
        &Arc::new(TypX::FnDef(fun.clone(), typ_args.clone(), None)),
1096
9.34k
        ExprX::ExecFnByName(fun.clone()),
1097
    );
1098
1099
    // Emit `FnDef : {Fn, FnMut, FnOnce}<Args>` and `<FnDef as FnOnce<Args>>::Output = Ret`.
1100
    //
1101
    // We emit a TraitImpl for each of the three Fn-family traits (not just Fn), because
1102
    // code that mentions only one through an associated-type projection (e.g. `Map::Item = F::Output`)
1103
    // never creates a Fn term for the Fn-related axioms to trigger on.
1104
9.34k
    let (trait_impls_out, assoc_type_impl) = if fn_once_trait_in_scope {
1105
9.28k
        let self_typ = Arc::new(TypX::FnDef(fun.clone(), typ_args.clone(), None));
1106
10.8k
        let arg_typs: Vec<Typ> = params.iter().map(|p| p.a.clone()).collect();
1107
9.28k
        let tuple_dt = state.tuple_type_name(arg_typs.len());
1108
9.28k
        let args_tuple_typ =
1109
9.28k
            Arc::new(TypX::Datatype(tuple_dt, Arc::new(arg_typs), Arc::new(vec![])));
1110
9.28k
        let trait_typ_args = Arc::new(vec![self_typ, args_tuple_typ]);
1111
1112
9.28k
        let mut trait_impls_out: Vec<TraitImpl> = Vec::new();
1113
27.8k
        for kind in [ClosureKind::Fn, ClosureKind::FnMut, ClosureKind::FnOnce] {
1114
27.8k
            let trait_implx = crate::ast::TraitImplX {
1115
27.8k
                impl_path: impl_fndef_path(&function.x.name, kind),
1116
27.8k
                typ_params: function.x.typ_params.clone(),
1117
27.8k
                typ_bounds: function.x.typ_bounds.clone(),
1118
27.8k
                trait_path: kind.trait_path(),
1119
27.8k
                trait_typ_args: trait_typ_args.clone(),
1120
27.8k
                trait_typ_arg_impls: Spanned::new(function.span.clone(), Arc::new(vec![])),
1121
27.8k
                owning_module: None,
1122
27.8k
                auto_imported: true,
1123
27.8k
                external_trait_blanket: false,
1124
27.8k
            };
1125
27.8k
            trait_impls_out.push(Spanned::new(function.span.clone(), trait_implx));
1126
27.8k
        }
1127
1128
9.28k
        let assoc_typ_implx = crate::ast::AssocTypeImplX {
1129
9.28k
            name: Arc::new("Output".to_string()),
1130
9.28k
            impl_path: impl_fndef_path(&function.x.name, ClosureKind::FnOnce),
1131
9.28k
            typ_params: function.x.typ_params.clone(),
1132
9.28k
            typ_bounds: function.x.typ_bounds.clone(),
1133
9.28k
            trait_path: ClosureKind::FnOnce.trait_path(),
1134
9.28k
            trait_typ_args,
1135
9.28k
            typ: function.x.ret.x.typ.clone(),
1136
9.28k
            impl_paths: Arc::new(vec![]),
1137
9.28k
        };
1138
1139
9.28k
        (trait_impls_out, Some(Spanned::new(function.span.clone(), assoc_typ_implx)))
1140
    } else {
1141
61
        (Vec::new(), None)
1142
    };
1143
1144
9.34k
    let mut fndef_axioms = vec![];
1145
1146
    // Don't need to repeat the 'requires' for a trait impl fn because requires can't change
1147
9.34k
    if !is_trait_method_impl {
1148
631
        let req_forall = exec_closure_spec_requires(
1149
631
            state,
1150
631
            &function.span,
1151
631
            &fndef_singleton,
1152
631
            &params,
1153
631
            &function.x.require,
1154
0
        )?;
1155
631
        fndef_axioms.push(req_forall);
1156
8.71k
    }
1157
1158
9.34k
    let ret = Arc::new(VarBinderX {
1159
9.34k
        name: function.x.ret.x.name.clone(),
1160
9.34k
        a: function.x.ret.x.typ.clone(),
1161
9.34k
    });
1162
9.34k
    let (mut closure_enss, default_enss) = function.x.ensure.clone();
1163
9.34k
    if inherit {
1164
10
        assert!(closure_enss.len() + default_enss.len() == 0);
1165
10
        let (_, tuple_var) = exec_closure_spec_param(state, &function.span, &params);
1166
10
        let ret_var = SpannedTyped::new(&function.span, &ret.a, ExprX::Var(ret.name.clone()));
1167
10
        let default_expr = mk_closure_ens_call(
1168
10
            state,
1169
10
            &function.span,
1170
10
            &params,
1171
10
            &fndef_singleton,
1172
10
            &tuple_var,
1173
10
            &ret_var,
1174
10
            BuiltinSpecFun::DefaultEns,
1175
        );
1176
10
        closure_enss = Arc::new(vec![default_expr]);
1177
9.33k
    }
1178
18.6k
    for (default_ens, enss) in [(false, closure_enss), (true, default_enss)] {
1179
18.6k
        if enss.len() > 0 {
1180
4.23k
            let ens_forall = exec_closure_spec_ensures(
1181
4.23k
                state,
1182
4.23k
                &function.span,
1183
4.23k
                &fndef_singleton,
1184
4.23k
                &params,
1185
4.23k
                &ret,
1186
4.23k
                &*enss,
1187
4.23k
                default_ens,
1188
0
            )?;
1189
4.23k
            fndef_axioms.push(ens_forall);
1190
14.4k
        }
1191
    }
1192
1193
9.34k
    let mut functionx = function.x.clone();
1194
9.34k
    assert!(functionx.fndef_axioms.is_none());
1195
9.34k
    functionx.fndef_axioms = Some(Arc::new(fndef_axioms));
1196
9.34k
    Ok((Spanned::new(function.span.clone(), functionx), trait_impls_out, assoc_type_impl))
1197
9.34k
}
1198
1199
252k
fn simplify_function(
1200
252k
    ctx: &GlobalCtx,
1201
252k
    state: &mut State,
1202
252k
    function: &Function,
1203
252k
) -> Result<Function, VirErr> {
1204
252k
    state.reset_for_function();
1205
252k
    let mut functionx = function.x.clone();
1206
1207
252k
    if let Some(r) = functionx.returns.clone() {
1208
5.93k
        functionx.returns = None;
1209
1210
5.93k
        if functionx.ens_has_return {
1211
5.93k
            let var = SpannedTyped::new(
1212
5.93k
                &r.span,
1213
5.93k
                &functionx.ret.x.typ,
1214
5.93k
                ExprX::Var(functionx.ret.x.name.clone()),
1215
5.93k
            );
1216
5.93k
            let eq = mk_eq(&r.span, &var, &r);
1217
5.93k
            Arc::make_mut(&mut functionx.ensure.0).push(eq);
1218
5.93k
        } else {
1219
0
            // For a unit return type, any returns clause is tautological so we
1220
0
            // can just skip appending to the postconditions.
1221
0
        }
1222
246k
    }
1223
1224
252k
    let local = LocalCtxt {
1225
252k
        span: function.span.clone(),
1226
252k
        typ_params: (*functionx.typ_params).clone(),
1227
252k
        fun: Some(functionx.name.clone()),
1228
252k
    };
1229
1230
252k
    let is_trait_impl = matches!(functionx.kind, FunctionKind::TraitMethodImpl { .. });
1231
1232
    // If possible, rename parameters to drop the rustc id
1233
252k
    let mut param_ids: HashSet<Ident> = HashSet::new();
1234
252k
    let mut rename_ok = true;
1235
393k
    for p in functionx.params.iter() {
1236
393k
        let x = &p.x.name.0;
1237
393k
        if param_ids.contains(x) {
1238
0
            rename_ok = false;
1239
393k
        }
1240
393k
        param_ids.insert(x.clone());
1241
    }
1242
252k
    let mut param_names: Vec<VarIdent> = Vec::new();
1243
393k
    for param in functionx.params.iter() {
1244
393k
        let prev = param.x.name.clone();
1245
393k
        let name = if rename_ok {
1246
393k
            let name = VarIdent(prev.0.clone(), crate::ast::VarIdentDisambiguate::VirParam);
1247
393k
            state.rename_vars.insert(prev, name.clone()).map(|_| panic!("rename params"));
1248
393k
            name
1249
        } else {
1250
0
            prev
1251
        };
1252
393k
        param_names.push(name);
1253
    }
1254
252k
    let ret_name = if rename_ok && !param_ids.contains(&functionx.ret.x.name.0) {
1255
252k
        let prev = functionx.ret.x.name.clone();
1256
252k
        let name = VarIdent(prev.0.clone(), crate::ast::VarIdentDisambiguate::VirParam);
1257
252k
        state.rename_vars.insert(prev, name.clone()).map(|_| panic!("rename ret"));
1258
252k
        name
1259
    } else {
1260
0
        functionx.ret.x.name.clone()
1261
    };
1262
1263
645k
    for (a, b) in state.rename_vars.iter() {
1264
645k
        state.rename_vars_reverse.insert(b.clone(), a.clone());
1265
645k
    }
1266
1267
    // To simplify the AIR/SMT encoding, add a dummy argument to any function with 0 arguments
1268
252k
    if functionx.typ_params.len() == 0
1269
119k
        && functionx.params.len() == 0
1270
20.3k
        && !matches!(functionx.item_kind, ItemKind::Const)
1271
20.2k
        && !matches!(functionx.item_kind, ItemKind::Static)
1272
20.2k
        && !functionx.attrs.broadcast_forall
1273
17.1k
        && !is_trait_impl
1274
4.33k
    {
1275
4.33k
        let paramx = crate::ast::ParamX {
1276
4.33k
            name: dummy_param_name(),
1277
4.33k
            typ: Arc::new(TypX::Int(IntRange::Int)),
1278
4.33k
            mode: Mode::Spec,
1279
4.33k
            user_mut: false,
1280
4.33k
            unwrapped_info: None,
1281
4.33k
        };
1282
4.33k
        param_names.push(paramx.name.clone());
1283
4.33k
        let param = Spanned::new(function.span.clone(), paramx);
1284
4.33k
        functionx.params = Arc::new(vec![param]);
1285
248k
    }
1286
1287
252k
    let function = Spanned::new(function.span.clone(), functionx);
1288
252k
    let mut map: VisitorScopeMap = ScopeMap::new();
1289
252k
    let function = crate::ast_visitor::map_function_visitor_env(
1290
252k
        &function,
1291
252k
        &mut map,
1292
252k
        state,
1293
4.25M
        &|state, map, expr| simplify_one_expr(ctx, state, map, expr),
1294
300k
        &|state, _, stmt| simplify_one_stmt(ctx, state, stmt),
1295
14.2M
        &|state, typ| simplify_one_typ(&local, state, typ),
1296
1.84M
        &|state, map, place| simplify_one_place(ctx, state, map, place),
1297
5
    )?;
1298
252k
    let mut functionx = function.x.clone();
1299
252k
    assert!(functionx.params.len() == param_names.len());
1300
252k
    functionx.params = Arc::new(
1301
252k
        functionx
1302
252k
            .params
1303
252k
            .iter()
1304
252k
            .zip(param_names.iter())
1305
397k
            .map(|(p, x)| p.new_x(crate::ast::ParamX { name: x.clone(), ..p.x.clone() }))
1306
252k
            .collect(),
1307
    );
1308
252k
    functionx.ret =
1309
252k
        functionx.ret.new_x(crate::ast::ParamX { name: ret_name, ..functionx.ret.x.clone() });
1310
1311
252k
    Ok(Spanned::new(function.span.clone(), functionx))
1312
252k
}
1313
1314
14.1k
fn simplify_datatype(state: &mut State, datatype: &Datatype) -> Result<Datatype, VirErr> {
1315
14.1k
    let mut local = LocalCtxt { span: datatype.span.clone(), typ_params: Vec::new(), fun: None };
1316
14.1k
    for (x, _strict_pos) in datatype.x.typ_params.iter() {
1317
13.6k
        local.typ_params.push(x.clone());
1318
13.6k
    }
1319
49.8k
    crate::ast_visitor::map_datatype_visitor_env(datatype, state, &|state, typ| {
1320
49.8k
        simplify_one_typ(&local, state, typ)
1321
49.8k
    })
1322
14.1k
}
1323
1324
175k
fn simplify_trait_impl(state: &mut State, imp: &TraitImpl) -> Result<TraitImpl, VirErr> {
1325
175k
    let mut local = LocalCtxt { span: imp.span.clone(), typ_params: Vec::new(), fun: None };
1326
175k
    for x in imp.x.typ_params.iter() {
1327
119k
        local.typ_params.push(x.clone());
1328
119k
    }
1329
761k
    crate::ast_visitor::map_trait_impl_visitor_env(imp, state, &|state, typ| {
1330
761k
        simplify_one_typ(&local, state, typ)
1331
761k
    })
1332
175k
}
1333
1334
69.9k
fn simplify_assoc_type_impl(
1335
69.9k
    state: &mut State,
1336
69.9k
    assoc: &AssocTypeImpl,
1337
69.9k
) -> Result<AssocTypeImpl, VirErr> {
1338
69.9k
    let mut local = LocalCtxt { span: assoc.span.clone(), typ_params: Vec::new(), fun: None };
1339
69.9k
    for x in assoc.x.typ_params.iter() {
1340
25.4k
        local.typ_params.push(x.clone());
1341
25.4k
    }
1342
355k
    crate::ast_visitor::map_assoc_type_impl_visitor_env(assoc, state, &|state, typ| {
1343
355k
        simplify_one_typ(&local, state, typ)
1344
355k
    })
1345
69.9k
}
1346
1347
/*
1348
fn mk_fun_decl(
1349
    span: &Span,
1350
    path: &Path,
1351
    typ_params: &Idents,
1352
    params: &Params,
1353
    ret: &Param,
1354
) -> Function {
1355
    let mut attrs: crate::ast::FunctionAttrsX = Default::default();
1356
    attrs.no_auto_trigger = true;
1357
    Spanned::new(
1358
        span.clone(),
1359
        FunctionX {
1360
            name: Arc::new(FunX { path: path.clone() }),
1361
            visibility: Visibility { owning_module: None, restricted_to: None },
1362
            mode: Mode::Spec,
1363
            fuel: 0,
1364
            typ_params: typ_params.clone(),
1365
            typ_bounds: Arc::new(vec![]),
1366
            params: params.clone(),
1367
            ret: ret.clone(),
1368
            require: Arc::new(vec![]),
1369
            ensure: Arc::new(vec![]),
1370
            decrease: None,
1371
            is_const: false,
1372
            is_abstract: false,
1373
            attrs: Arc::new(attrs),
1374
            body: None,
1375
        },
1376
    )
1377
}
1378
*/
1379
1380
13.0k
fn add_tuple_auto_impl(
1381
13.0k
    ctx: &mut GlobalCtx,
1382
13.0k
    traits: &Vec<crate::ast::Trait>,
1383
13.0k
    trait_impls: &mut Vec<TraitImpl>,
1384
13.0k
    arity: usize,
1385
13.0k
    needs_bounds: bool,
1386
13.0k
    trait_path: Path,
1387
13.0k
) {
1388
    use crate::ast::{GenericBound, GenericBoundX};
1389
    use crate::def::impl_tuple;
1390
1391
139k
    if !traits.iter().any(|t| &t.x.name == &trait_path) {
1392
9.02k
        return;
1393
3.98k
    }
1394
    // Rust doesn't seem to give us the TraitImpl for tuples for the traits
1395
    // Tuple, Clone, Copy, Send, Sync, Unpin, so we make it ourselves:
1396
8.46k
    let typ_params: Vec<Ident> = (0..arity).map(|i| prefix_tuple_param(i)).collect();
1397
3.98k
    let typ_args: Vec<Typ> =
1398
8.46k
        typ_params.iter().map(|x| Arc::new(TypX::TypParam(x.clone()))).collect();
1399
3.98k
    let mut bounds: Vec<GenericBound> = Vec::new();
1400
3.98k
    if needs_bounds {
1401
5.27k
        for i in 0..arity {
1402
5.27k
            let id = crate::ast::TraitId::Path(trait_path.clone());
1403
5.27k
            let typs = Arc::new(vec![typ_args[i].clone()]);
1404
5.27k
            bounds.push(Arc::new(GenericBoundX::Trait(id, typs)));
1405
5.27k
        }
1406
2.25k
    }
1407
3.98k
    let self_ty = Arc::new(TypX::Datatype(Dt::Tuple(arity), Arc::new(typ_args), Arc::new(vec![])));
1408
3.98k
    let impl_path = Arc::new(crate::ast::PathX {
1409
3.98k
        krate: CrateId::Internal,
1410
3.98k
        segments: Arc::new(vec![impl_tuple(trait_path.segments.last().unwrap(), arity)]),
1411
3.98k
    });
1412
3.98k
    let trait_implx = crate::ast::TraitImplX {
1413
3.98k
        impl_path,
1414
3.98k
        typ_params: Arc::new(typ_params),
1415
3.98k
        typ_bounds: Arc::new(bounds),
1416
3.98k
        trait_path,
1417
3.98k
        trait_typ_args: Arc::new(vec![self_ty]),
1418
3.98k
        trait_typ_arg_impls: Spanned::new(ctx.no_span.clone(), Arc::new(vec![])),
1419
3.98k
        owning_module: None,
1420
3.98k
        auto_imported: true,
1421
3.98k
        external_trait_blanket: false,
1422
3.98k
    };
1423
3.98k
    trait_impls.push(Spanned::new(ctx.no_span.clone(), trait_implx));
1424
13.0k
}
1425
1426
3.16k
pub fn simplify_krate(ctx: &mut GlobalCtx, krate: &Krate) -> Result<Krate, VirErr> {
1427
    let KrateX {
1428
3.16k
        functions,
1429
3.16k
        reveal_groups,
1430
3.16k
        datatypes,
1431
3.16k
        opaque_types,
1432
3.16k
        traits,
1433
3.16k
        trait_impls,
1434
3.16k
        assoc_type_impls,
1435
3.16k
        modules: module_ids,
1436
3.16k
        external_fns,
1437
3.16k
        external_types,
1438
3.16k
        path_as_rust_names,
1439
3.16k
        arch,
1440
3.16k
    } = &**krate;
1441
3.16k
    let mut state = State::new();
1442
1443
    // Always add this because unit values might be added later, after ast_simplify.
1444
3.16k
    state.tuple_type_name(0);
1445
1446
14.1k
    let mut datatypes = vec_map_result(&datatypes, |d| simplify_datatype(&mut state, d))?;
1447
3.16k
    ctx.datatypes = Arc::new(
1448
3.16k
        datatypes
1449
3.16k
            .iter()
1450
14.1k
            .map(|d| (d.x.name.expect_path(), (d.x.typ_params.clone(), d.x.variants.clone())))
1451
3.16k
            .collect(),
1452
    );
1453
252k
    let functions = vec_map_result(functions, |f| simplify_function(ctx, &mut state, f))?;
1454
175k
    let mut trait_impls = vec_map_result(&trait_impls, |t| simplify_trait_impl(&mut state, t))?;
1455
3.15k
    let mut assoc_type_impls =
1456
69.9k
        vec_map_result(&assoc_type_impls, |a| simplify_assoc_type_impl(&mut state, a))?;
1457
1458
3.15k
    let fn_once_trait_path = ClosureKind::FnOnce.trait_path();
1459
8.78k
    let fn_once_trait_in_scope = traits.iter().any(|t| t.x.name == fn_once_trait_path);
1460
1461
3.15k
    let mut new_functions: Vec<Function> = Vec::with_capacity(functions.len());
1462
252k
    for f in functions.iter() {
1463
252k
        if need_fndef_axiom(&state.fndef_typs, f) {
1464
9.34k
            let (f2, tis, ai) =
1465
9.34k
                add_fndef_axioms_to_function(ctx, &mut state, f, fn_once_trait_in_scope)?;
1466
9.34k
            trait_impls.extend(tis);
1467
9.34k
            if let Some(ai) = ai {
1468
9.28k
                assoc_type_impls.push(ai);
1469
9.28k
            }
1470
9.34k
            new_functions.push(f2);
1471
243k
        } else {
1472
243k
            new_functions.push(f.clone());
1473
243k
        }
1474
    }
1475
3.15k
    let functions = new_functions;
1476
1477
    // Add a generic datatype to represent each tuple arity
1478
    // Iterate in sorted order to get consistent output
1479
3.15k
    let mut tuples: Vec<usize> = state.tuple_typs.into_iter().collect();
1480
3.15k
    tuples.sort();
1481
4.33k
    for arity in tuples {
1482
4.33k
        let visibility = Visibility { restricted_to: None };
1483
4.33k
        let transparency = DatatypeTransparency::WhenVisible(visibility.clone());
1484
4.33k
        let acc = crate::ast::AcceptRecursiveType::RejectInGround;
1485
4.33k
        let typ_params = Arc::new((0..arity).map(|i| (prefix_tuple_param(i), acc)).collect());
1486
4.33k
        let mut fields: Vec<Field> = Vec::new();
1487
4.33k
        for i in 0..arity {
1488
3.73k
            let typ = Arc::new(TypX::TypParam(prefix_tuple_param(i)));
1489
3.73k
            let vis = Visibility { restricted_to: None };
1490
3.73k
            // Note: the mode is irrelevant at this stage, so we arbitrarily use Mode::Exec
1491
3.73k
            fields.push(ident_binder(&positional_field_ident(i), &(typ, Mode::Exec, vis)));
1492
3.73k
        }
1493
4.33k
        let variant = Variant {
1494
4.33k
            name: prefix_tuple_variant(arity),
1495
4.33k
            fields: Arc::new(fields),
1496
4.33k
            ctor_style: CtorPrintStyle::Tuple,
1497
4.33k
        };
1498
4.33k
        let variants = Arc::new(vec![variant]);
1499
4.33k
        let datatypex = DatatypeX {
1500
4.33k
            name: Dt::Tuple(arity),
1501
4.33k
            proxy: None,
1502
4.33k
            visibility,
1503
4.33k
            owning_module: None,
1504
4.33k
            transparency,
1505
4.33k
            typ_params,
1506
4.33k
            typ_bounds: Arc::new(vec![]),
1507
4.33k
            variants,
1508
4.33k
            mode: Mode::Exec,
1509
4.33k
            ext_equal: arity > 0,
1510
4.33k
            user_defined_invariant_fn: None,
1511
4.33k
            sized_constraint: if arity == 0 {
1512
3.15k
                None
1513
            } else {
1514
1.17k
                Some(Arc::new(TypX::TypParam(prefix_tuple_param(arity - 1))))
1515
            },
1516
            destructor: false,
1517
        };
1518
4.33k
        datatypes.push(Spanned::new(ctx.no_span.clone(), datatypex));
1519
1520
4.33k
        let tuple_path = crate::path![CrateId::Core => "marker", "Tuple"];
1521
4.33k
        let clone_path = crate::path![CrateId::Core => "clone", "Clone"];
1522
4.33k
        let copy_path = crate::path![CrateId::Core => "marker", "Copy"];
1523
        //let send_path = crate::path![CrateId::Core => "marker", "Send"];
1524
        //let sync_path = crate::path![CrateId::Core => "marker", "Sync"];
1525
        //let unpin_path = crate::path![CrateId::Core => "marker", "Unpin"];
1526
4.33k
        add_tuple_auto_impl(ctx, &traits, &mut trait_impls, arity, false, tuple_path);
1527
4.33k
        add_tuple_auto_impl(ctx, &traits, &mut trait_impls, arity, true, clone_path);
1528
4.33k
        add_tuple_auto_impl(ctx, &traits, &mut trait_impls, arity, true, copy_path);
1529
        // TODO when when we have full support for auto traits:
1530
        //add_tuple_auto_impl(ctx, &traits, &mut trait_impls, arity, true, send_path);
1531
        //add_tuple_auto_impl(ctx, &traits, &mut trait_impls, arity, true, sync_path);
1532
        //add_tuple_auto_impl(ctx, &traits, &mut trait_impls, arity, true, unpin_path);
1533
    }
1534
1535
3.15k
    let mut closures: Vec<_> = state.closure_typs.into_iter().collect();
1536
3.15k
    closures.sort_by_key(|kv| kv.0);
1537
3.15k
    for (id, closure) in closures {
1538
        // Right now, we translate the closure type into an a global datatype.
1539
        //
1540
        // However, I'm pretty sure an anonymous closure can't actually be referenced
1541
        // from outside the item that defines it (Rust seems to represent it as an
1542
        // "opaque type" if it escapes through an existential type, which Verus currently
1543
        // doesn't support anyway.)
1544
        // So in principle, we could make the type private to the item and not emit any
1545
        // global declarations for it.
1546
1547
        // Also, note that Rust already prohibits a closure type from depending on itself
1548
        // (not even via reference types, which would be allowed for other types).
1549
        // As such, we don't have to worry about any kind of recursion-checking:
1550
        // a closure type cannot possibly be involved in any type cycle.
1551
        // (In principle, the closure should depend negatively on its param and return types,
1552
        // since they are arguments to the 'requires' and 'ensures' predicates, but thanks
1553
        // to Rust's restrictions, we don't have to do any additional checks.)
1554
1555
227
        let visibility = Visibility { restricted_to: None };
1556
227
        let transparency = DatatypeTransparency::Never;
1557
1558
227
        let variants = Arc::new(vec![]);
1559
1560
3.62k
        let function = functions.iter().find(|f| f.x.name == closure.enclosing_fun).unwrap();
1561
1562
227
        let typ_params: crate::ast::TypPositives = Arc::new(
1563
227
            function
1564
227
                .x
1565
227
                .typ_params
1566
227
                .iter()
1567
227
                .map(|tb| (tb.clone(), crate::ast::AcceptRecursiveType::Accept))
1568
227
                .collect(),
1569
        );
1570
227
        let datatypex = DatatypeX {
1571
227
            name: Dt::Path(closure.path.clone()),
1572
227
            proxy: None,
1573
227
            visibility,
1574
227
            owning_module: None,
1575
227
            transparency,
1576
227
            typ_params: typ_params.clone(),
1577
227
            typ_bounds: function.x.typ_bounds.clone(),
1578
227
            variants,
1579
227
            mode: Mode::Exec,
1580
227
            ext_equal: false,
1581
227
            user_defined_invariant_fn: None,
1582
227
            sized_constraint: None,
1583
227
            destructor: false,
1584
227
        };
1585
227
        datatypes.push(Spanned::new(ctx.no_span.clone(), datatypex));
1586
1587
        // Add a trait bound, `ClosureType: {Fn, FnMut, FnOnce}`, and the corresponding
1588
        // `<ClosureType as FnOnce<Args>>::Output = ReturnType` associated-type impl.
1589
1590
227
        let typ_args: Typs = Arc::new(
1591
227
            function.x.typ_params.iter().map(|tb| Arc::new(TypX::TypParam(tb.clone()))).collect(),
1592
        );
1593
227
        let self_typ =
1594
227
            Arc::new(TypX::Datatype(Dt::Path(closure.path.clone()), typ_args, Arc::new(vec![])));
1595
227
        let args_tuple_typ = Arc::new(TypX::Datatype(
1596
227
            Dt::Tuple(closure.args.len()),
1597
227
            closure.args.clone(),
1598
227
            Arc::new(vec![]),
1599
227
        ));
1600
227
        let impl_path = Arc::new(crate::ast::PathX {
1601
227
            krate: CrateId::Internal,
1602
227
            segments: Arc::new(vec![crate::def::impl_closure(closure.kind, id)]),
1603
227
        });
1604
227
        let trait_typ_args = Arc::new(vec![self_typ.clone(), args_tuple_typ.clone()]);
1605
227
        let trait_implx = crate::ast::TraitImplX {
1606
227
            impl_path: impl_path.clone(),
1607
227
            typ_params: function.x.typ_params.clone(),
1608
227
            typ_bounds: function.x.typ_bounds.clone(),
1609
227
            trait_path: closure.kind.trait_path(),
1610
227
            trait_typ_args: trait_typ_args.clone(),
1611
227
            trait_typ_arg_impls: Spanned::new(ctx.no_span.clone(), Arc::new(vec![])),
1612
227
            owning_module: None,
1613
227
            auto_imported: true,
1614
227
            external_trait_blanket: false,
1615
227
        };
1616
227
        trait_impls.push(Spanned::new(ctx.no_span.clone(), trait_implx));
1617
1618
        // The `Output` associated type is defined on the `FnOnce` trait (and
1619
        // inherited by `Fn` and `FnMut`), so we always use the `FnOnce` trait
1620
        // path for the associated-type impl, regardless of the closure's kind.
1621
227
        let fn_once_trait_path = crate::ast::ClosureKind::FnOnce.trait_path();
1622
419
        if traits.iter().any(|t| &t.x.name == &fn_once_trait_path) {
1623
136
            let assoc_typ_implx = crate::ast::AssocTypeImplX {
1624
136
                name: Arc::new("Output".to_string()),
1625
136
                impl_path,
1626
136
                typ_params: function.x.typ_params.clone(),
1627
136
                typ_bounds: function.x.typ_bounds.clone(),
1628
136
                trait_path: fn_once_trait_path,
1629
136
                trait_typ_args,
1630
136
                typ: closure.output.clone(),
1631
136
                impl_paths: Arc::new(vec![]),
1632
136
            };
1633
136
            assoc_type_impls.push(Spanned::new(ctx.no_span.clone(), assoc_typ_implx));
1634
136
        }
1635
    }
1636
1637
3.15k
    let traits = traits.clone();
1638
3.15k
    let module_ids = module_ids.clone();
1639
3.15k
    let external_fns = external_fns.clone();
1640
3.15k
    let external_types = external_types.clone();
1641
3.15k
    let krate = Arc::new(KrateX {
1642
3.15k
        functions,
1643
3.15k
        reveal_groups: reveal_groups.clone(),
1644
3.15k
        datatypes,
1645
3.15k
        opaque_types: opaque_types.clone(),
1646
3.15k
        traits,
1647
3.15k
        trait_impls,
1648
3.15k
        assoc_type_impls,
1649
3.15k
        modules: module_ids,
1650
3.15k
        external_fns,
1651
3.15k
        external_types,
1652
3.15k
        path_as_rust_names: path_as_rust_names.clone(),
1653
3.15k
        arch: arch.clone(),
1654
3.15k
    });
1655
3.15k
    *ctx = crate::context::GlobalCtx::new(
1656
3.15k
        &krate,
1657
3.15k
        ctx.crate_name.clone(),
1658
3.15k
        ctx.no_span.clone(),
1659
3.15k
        ctx.rlimit,
1660
3.15k
        ctx.interpreter_log.clone(),
1661
3.15k
        ctx.func_call_graph_log.clone(),
1662
3.15k
        ctx.warning_ctx.clone(),
1663
3.15k
        ctx.solver.clone(),
1664
        true,
1665
3.15k
        ctx.check_api_safety,
1666
3.15k
        ctx.axiom_usage_info,
1667
3.15k
        ctx.no_bv_simplify,
1668
3.15k
        ctx.report_long_running,
1669
0
    )?;
1670
3.15k
    Ok(krate)
1671
3.16k
}
1672
1673
4.04k
pub fn merge_krates(krates: Vec<Krate>) -> Result<Krate, VirErr> {
1674
4.04k
    let mut krates = krates.into_iter();
1675
4.04k
    let mut kratex: KrateX = (*krates.next().expect("at least one crate")).clone();
1676
4.04k
    for k in krates {
1677
        let KrateX {
1678
1.62k
            functions,
1679
1.62k
            reveal_groups,
1680
1.62k
            datatypes,
1681
1.62k
            opaque_types,
1682
1.62k
            traits,
1683
1.62k
            trait_impls,
1684
1.62k
            assoc_type_impls,
1685
1.62k
            modules,
1686
1.62k
            external_fns,
1687
1.62k
            external_types,
1688
1.62k
            path_as_rust_names,
1689
1.62k
            arch,
1690
1.62k
        } = &*k;
1691
1.62k
        kratex.functions.extend(functions.clone());
1692
1.62k
        kratex.reveal_groups.extend(reveal_groups.clone());
1693
1.62k
        kratex.datatypes.extend(datatypes.clone());
1694
1.62k
        kratex.opaque_types.extend(opaque_types.clone());
1695
1.62k
        kratex.traits.extend(traits.clone());
1696
1.62k
        kratex.trait_impls.extend(trait_impls.clone());
1697
1.62k
        kratex.assoc_type_impls.extend(assoc_type_impls.clone());
1698
1.62k
        kratex.modules.extend(modules.clone());
1699
1.62k
        kratex.external_fns.extend(external_fns.clone());
1700
1.62k
        kratex.external_types.extend(external_types.clone());
1701
1.62k
        kratex.path_as_rust_names.extend(path_as_rust_names.clone());
1702
        kratex.arch.word_bits = {
1703
1.62k
            let word_bits = match (arch.word_bits, kratex.arch.word_bits) {
1704
0
                (crate::ast::ArchWordBits::Exactly(l), crate::ast::ArchWordBits::Exactly(r)) => {
1705
0
                    if l != r {
1706
0
                        return Err(crate::messages::error_bare(
1707
0
                            "all crates must have compatible arch_word_bits (set via `global size_of usize`",
1708
0
                        ));
1709
                    } else {
1710
0
                        crate::ast::ArchWordBits::Exactly(l)
1711
                    }
1712
                }
1713
1.59k
                (crate::ast::ArchWordBits::Either32Or64, other)
1714
1.62k
                | (other, crate::ast::ArchWordBits::Either32Or64) => other,
1715
            };
1716
1.62k
            if let crate::ast::ArchWordBits::Exactly(e) = &word_bits {
1717
28
                assert!(*e == 32 || *e == 64);
1718
1.59k
            }
1719
1.62k
            word_bits
1720
        };
1721
    }
1722
4.04k
    Ok(Arc::new(kratex))
1723
4.04k
}