rust_verify_test coverage (7c1d655)

Coverage Report

Created: 2026-07-20 10:58

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