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/prune.rs
Line
Count
Source
1
/// 1) Optimize generated SMT by pruning unreachable declarations and definitions.
2
///    This is strictly an optimization; it should not affect the SMT validity.
3
/// 2) Also compute names for abstract datatype sorts for the module,
4
///    since we're traversing the module-visible datatypes anyway.
5
use crate::ast::{
6
    ArrayKind, AssocTypeImpl, AssocTypeImplX, AutospecUsage, BinaryOp, BoundsCheck, CallTarget,
7
    CrateId, Datatype, Dt, Expr, ExprX, Fun, FunWithVis, Function, FunctionKind, Ident, Krate,
8
    KrateX, Mode, Module, ModuleX, OpaqueType, Path, Place, PlaceX, RevealGroup, Stmt, Trait,
9
    TraitId, TraitX, Typ, TypX, UnaryOp, UnaryOpr,
10
};
11
use crate::ast_util::{is_body_visible_to, is_visible_to, is_visible_to_or_true};
12
use crate::ast_visitor::{VisitorControlFlow, VisitorScopeMap};
13
use crate::datatype_to_air::is_datatype_transparent;
14
use crate::def::*;
15
use crate::poly::MonoTyp;
16
use crate::resolve_axioms::{ResolvableType, ResolvedTypeCollection};
17
use air::scope_map::ScopeMap;
18
use std::collections::{HashMap, HashSet};
19
use std::sync::Arc;
20
21
#[derive(Debug, Hash, Clone, PartialEq, Eq)]
22
// Overapproximation of TypX, used to overapproximate the reached types
23
// (it's ok if we fail to prune away some types)
24
// For example, if we reach Datatype("D"), and D is generic,
25
// we reach D applied to all possible type arguments.
26
enum ReachedType {
27
    None,
28
    Bool,
29
    Int(crate::ast::IntRange),
30
    Real,
31
    Float(u32),
32
    SpecFn(usize),
33
    Datatype(Dt),
34
    FnDef(Fun, Vec<ReachedType>),
35
    StrSlice,
36
    Array,
37
    Primitive,
38
    PointeeMetadata,
39
}
40
41
// Group all AssocTypeImpls with the same (ReachedType(self_typ), (trait_path, name)):
42
type AssocTypeGroup = (ReachedType, (Path, Ident));
43
44
type TraitName = Path;
45
type OpaqueTyName = Path;
46
type ImplName = Path;
47
48
#[derive(Debug)]
49
struct ReachTraitImpl {
50
    trait_impl: crate::ast::TraitImpl,
51
    // For an impl "...T'(...t'...)... ==> trait T(...t...)",
52
    // list all traits T' and types t' in the bounds:
53
    bound_traits: Vec<TraitName>,
54
    bound_types: Vec<ReachedType>,
55
    // list all t:
56
    trait_typ_args: Vec<ReachedType>,
57
}
58
59
#[derive(Debug)]
60
struct ReachBroadcastFunction {
61
    // For each trigger, keep a Vec<Fun> that contains every Fun that must be reached to
62
    // activate the trigger:
63
    reach_triggers: Vec<(Vec<Fun>, Vec<ReachedType>)>,
64
}
65
66
struct Ctxt {
67
    module: Option<Path>,
68
    function_map: HashMap<Fun, Function>,
69
    reveal_group_map: HashMap<Fun, RevealGroup>,
70
    datatype_map: HashMap<Dt, Datatype>,
71
    opaque_ty_map: HashMap<OpaqueTyName, OpaqueType>,
72
    trait_map: HashMap<Path, Trait>,
73
    // For an impl "bounds ==> trait T(...t...)", point T to impl:
74
    trait_to_trait_impls: HashMap<TraitName, Vec<ImplName>>,
75
    // For an impl "bounds ==> trait T(...t...)", point t to impl:
76
    typ_to_trait_impls: HashMap<ReachedType, Vec<ImplName>>,
77
    trait_impl_map: HashMap<ImplName, ReachTraitImpl>,
78
    assoc_type_impl_map: HashMap<AssocTypeGroup, Vec<AssocTypeImpl>>,
79
    // Map (D, T.f) -> D.f if D implements T.f:
80
    method_map: HashMap<(ReachedType, Fun), Vec<Fun>>,
81
    // For a broadcast function f with triggers containing functions f0..fn, point f0..fn to f:
82
    fun_to_trigger_broadcasts: HashMap<Fun, Vec<Fun>>,
83
    typ_to_trigger_broadcasts: HashMap<ReachedType, Vec<Fun>>,
84
    // Map each revealed broadcast function f to its ReachBroadcastFunction
85
    fun_revealed_broadcast_map: HashMap<Fun, ReachBroadcastFunction>,
86
    assert_by_compute: bool,
87
    assert_by_compute_seq_funs: Vec<Fun>,
88
}
89
90
#[derive(Default)]
91
struct State {
92
    reached_functions: HashSet<Fun>,
93
    reached_types: HashSet<ReachedType>,
94
    reached_bound_traits: HashSet<TraitName>,
95
    reached_trait_impls: HashSet<ImplName>,
96
    reached_assoc_type_decls: HashSet<(Path, Ident)>,
97
    reached_assoc_type_impls: HashSet<AssocTypeGroup>,
98
    reached_opaque_types: HashSet<OpaqueTyName>,
99
    worklist_functions: Vec<Fun>,
100
    worklist_reveal_groups: Vec<Fun>,
101
    worklist_types: Vec<ReachedType>,
102
    worklist_bound_traits: Vec<TraitName>,
103
    worklist_opaque_types: Vec<OpaqueTyName>,
104
    worklist_trait_impls: Vec<ImplName>,
105
    worklist_assoc_type_decls: Vec<(Path, Ident)>,
106
    worklist_assoc_type_impls: Vec<AssocTypeGroup>,
107
    mono_abstract_datatypes: Option<HashSet<MonoTyp>>,
108
    spec_fn_types: HashSet<usize>,
109
    dyn_traits: HashSet<Path>,
110
    uses_array: bool,
111
    uses_bytestr: bool,
112
    uses_pointee_metadata: bool,
113
    uses_ieee_float: bool,
114
    fndef_types: HashSet<Fun>,
115
    // broadcast functions that are also defined or called normally
116
    // (not just used for the broadcast)
117
    broadcast_functions_fully_reached: HashSet<Fun>,
118
    resolve_typs: Option<ResolvedTypeCollection>,
119
}
120
121
246M
fn typ_to_reached_type(typ: &Typ) -> ReachedType {
122
    use crate::ast::Primitive;
123
246M
    match &**typ {
124
5.39M
        TypX::Bool => ReachedType::Bool,
125
105M
        TypX::Int(range) => ReachedType::Int(*range),
126
77.5k
        TypX::Real => ReachedType::Real,
127
5.03M
        TypX::Float(n) => ReachedType::Float(*n),
128
352k
        TypX::SpecFn(ts, _) => ReachedType::SpecFn(ts.len()),
129
0
        TypX::AnonymousClosure(..) => ReachedType::None,
130
33.3M
        TypX::Datatype(dt, _, _) => ReachedType::Datatype(dt.clone()),
131
393
        TypX::Dyn(..) => ReachedType::None,
132
8.36M
        TypX::FnDef(fun, typs, _) => {
133
8.36M
            ReachedType::FnDef(fun.clone(), typs.iter().map(typ_to_reached_type).collect())
134
        }
135
34.0M
        TypX::Decorate(_, _, t) => typ_to_reached_type(t),
136
0
        TypX::Boxed(t) => typ_to_reached_type(t),
137
49.6M
        TypX::TypParam(_) => ReachedType::None,
138
39.8k
        TypX::Projection { trait_typ_args, .. } => typ_to_reached_type(&trait_typ_args[0]),
139
3.00k
        TypX::PointeeMetadata(_) => ReachedType::PointeeMetadata,
140
0
        TypX::TypeId => ReachedType::None,
141
4
        TypX::ConstInt(_) => ReachedType::None,
142
0
        TypX::ConstBool(_) => ReachedType::None,
143
0
        TypX::Air(_) => panic!("unexpected TypX::Air"),
144
864k
        TypX::Primitive(Primitive::StrSlice, _) => ReachedType::StrSlice,
145
1.13M
        TypX::Primitive(Primitive::Array, _) => ReachedType::Array,
146
        TypX::Primitive(Primitive::Slice | Primitive::Ptr | Primitive::Global, _) => {
147
2.68M
            ReachedType::Primitive
148
        }
149
537k
        TypX::MutRef(_) => ReachedType::None,
150
0
        TypX::Opaque { .. } => ReachedType::None,
151
    }
152
246M
}
153
154
9.88M
fn record_datatype(ctxt: &Ctxt, state: &mut State, typ: &Typ, dt: &Dt) {
155
9.88M
    let module = if let Some(module) = &ctxt.module {
156
6.04M
        module
157
    } else {
158
3.84M
        return;
159
    };
160
6.04M
    if let Some(mono_abstract_datatypes) = &mut state.mono_abstract_datatypes {
161
6.04M
        if let Some(d) = ctxt.datatype_map.get(dt) {
162
6.04M
            let is_vis = is_visible_to(&d.x.visibility, module);
163
6.04M
            let is_transparent = is_datatype_transparent(module, &d);
164
6.04M
            if is_vis && !is_transparent {
165
2.45M
                if let Some(monotyp) = crate::poly::typ_as_mono(typ) {
166
796k
                    mono_abstract_datatypes.insert(monotyp);
167
1.66M
                }
168
3.58M
            }
169
0
        }
170
0
    }
171
9.88M
}
172
173
30.5M
fn reach<A: std::hash::Hash + std::cmp::Eq + Clone>(
174
30.5M
    reached: &mut HashSet<A>,
175
30.5M
    worklist: &mut Vec<A>,
176
30.5M
    id: &A,
177
30.5M
) {
178
30.5M
    if !reached.contains(id) {
179
1.83M
        reached.insert(id.clone());
180
1.83M
        worklist.push(id.clone());
181
28.6M
    }
182
30.5M
}
_RINvNtCs6n9hmJXskGK_3vir5prune5reachINtNtCscdodAO9FK5_5alloc4sync3ArcNtNtB4_3ast4FunXEEB4_
Line
Count
Source
173
4.25M
fn reach<A: std::hash::Hash + std::cmp::Eq + Clone>(
174
4.25M
    reached: &mut HashSet<A>,
175
4.25M
    worklist: &mut Vec<A>,
176
4.25M
    id: &A,
177
4.25M
) {
178
4.25M
    if !reached.contains(id) {
179
970k
        reached.insert(id.clone());
180
970k
        worklist.push(id.clone());
181
3.28M
    }
182
4.25M
}
_RINvNtCs6n9hmJXskGK_3vir5prune5reachINtNtCscdodAO9FK5_5alloc4sync3ArcNtNtB4_3ast5PathXEEB4_
Line
Count
Source
173
3.15M
fn reach<A: std::hash::Hash + std::cmp::Eq + Clone>(
174
3.15M
    reached: &mut HashSet<A>,
175
3.15M
    worklist: &mut Vec<A>,
176
3.15M
    id: &A,
177
3.15M
) {
178
3.15M
    if !reached.contains(id) {
179
642k
        reached.insert(id.clone());
180
642k
        worklist.push(id.clone());
181
2.51M
    }
182
3.15M
}
_RINvNtCs6n9hmJXskGK_3vir5prune5reachNtB2_11ReachedTypeEB4_
Line
Count
Source
173
22.5M
fn reach<A: std::hash::Hash + std::cmp::Eq + Clone>(
174
22.5M
    reached: &mut HashSet<A>,
175
22.5M
    worklist: &mut Vec<A>,
176
22.5M
    id: &A,
177
22.5M
) {
178
22.5M
    if !reached.contains(id) {
179
140k
        reached.insert(id.clone());
180
140k
        worklist.push(id.clone());
181
22.4M
    }
182
22.5M
}
_RINvNtCs6n9hmJXskGK_3vir5prune5reachTINtNtCscdodAO9FK5_5alloc4sync3ArcNtNtB4_3ast5PathXEIBA_NtNtBE_6string6StringEEEB4_
Line
Count
Source
173
361k
fn reach<A: std::hash::Hash + std::cmp::Eq + Clone>(
174
361k
    reached: &mut HashSet<A>,
175
361k
    worklist: &mut Vec<A>,
176
361k
    id: &A,
177
361k
) {
178
361k
    if !reached.contains(id) {
179
13.3k
        reached.insert(id.clone());
180
13.3k
        worklist.push(id.clone());
181
347k
    }
182
361k
}
_RINvNtCs6n9hmJXskGK_3vir5prune5reachTNtB2_11ReachedTypeTINtNtCscdodAO9FK5_5alloc4sync3ArcNtNtB4_3ast5PathXEIBT_NtNtBX_6string6StringEEEEB4_
Line
Count
Source
173
194k
fn reach<A: std::hash::Hash + std::cmp::Eq + Clone>(
174
194k
    reached: &mut HashSet<A>,
175
194k
    worklist: &mut Vec<A>,
176
194k
    id: &A,
177
194k
) {
178
194k
    if !reached.contains(id) {
179
65.9k
        reached.insert(id.clone());
180
65.9k
        worklist.push(id.clone());
181
128k
    }
182
194k
}
183
184
4.34M
fn reach_function_inner(ctxt: &Ctxt, state: &mut State, name: &Fun, fully_reach: bool) {
185
4.34M
    if fully_reach {
186
3.97M
        state.broadcast_functions_fully_reached.insert(name.clone());
187
3.97M
    }
188
4.34M
    if ctxt.function_map.contains_key(name) {
189
3.38M
        reach(&mut state.reached_functions, &mut state.worklist_functions, name);
190
3.38M
    }
191
4.34M
    if ctxt.reveal_group_map.contains_key(name) {
192
239k
        reach(&mut state.reached_functions, &mut state.worklist_reveal_groups, name);
193
4.10M
    }
194
4.34M
}
195
196
3.97M
fn reach_function(ctxt: &Ctxt, state: &mut State, name: &Fun) {
197
3.97M
    reach_function_inner(ctxt, state, name, true);
198
3.97M
}
199
200
3.26M
fn reach_function_via_reveal(ctxt: &Ctxt, state: &mut State, name: &Fun) {
201
3.26M
    if let Some(broadcast) = ctxt.fun_revealed_broadcast_map.get(name) {
202
        // "name" is a revealed broadcast function
203
        // If any triggers are reachable, reach the function
204
2.33M
        if broadcast.reach_triggers.len() == 0 {
205
1
            // No triggers, so there's nothing to base pruning on, so we can't prune
206
1
            reach_function_inner(ctxt, state, name, false);
207
2.33M
        }
208
2.67M
        'try_next_trigger: for (trig_funs, trig_typs) in &broadcast.reach_triggers {
209
2.92M
            for f in trig_funs {
210
2.92M
                if !state.reached_functions.contains(f) {
211
2.16M
                    continue 'try_next_trigger;
212
764k
                }
213
            }
214
1.06M
            for t in trig_typs {
215
1.06M
                if !state.reached_types.contains(t) {
216
147k
                    continue 'try_next_trigger;
217
919k
                }
218
            }
219
            // We found a reachable trigger, so reach the whole broadcast function:
220
360k
            reach_function_inner(ctxt, state, name, false);
221
360k
            break;
222
        }
223
923k
    } else {
224
923k
        reach_function(ctxt, state, name);
225
923k
    }
226
3.26M
}
227
228
230k
fn reach_reveal_group(ctxt: &Ctxt, state: &mut State, name: &Fun) {
229
230k
    let group = &ctxt.reveal_group_map[name];
230
1.93M
    for member in group.x.members.iter() {
231
1.93M
        reach_function_via_reveal(ctxt, state, member);
232
1.93M
    }
233
230k
}
234
235
1.62M
fn reach_bound_trait(_ctxt: &Ctxt, state: &mut State, name: &TraitName) {
236
1.62M
    reach(&mut state.reached_bound_traits, &mut state.worklist_bound_traits, name);
237
1.62M
}
238
239
983
fn reach_opaque_type(_ctxt: &Ctxt, state: &mut State, name: &OpaqueTyName) {
240
983
    reach(&mut state.reached_opaque_types, &mut state.worklist_opaque_types, name);
241
983
}
242
243
14.2M
fn reach_trait_impl(ctxt: &Ctxt, state: &mut State, imp: &ImplName) {
244
14.2M
    if let Some(trait_impl) = ctxt.trait_impl_map.get(imp) {
245
        // We only reach the impl "bounds ==> trait T(...t...)" when all of T and t have been reached.
246
        // Otherwise, we consider the impl irrelevant.
247
21.4M
        for t in &trait_impl.trait_typ_args {
248
21.4M
            if *t != ReachedType::None && !state.reached_types.contains(t) {
249
6.26M
                return;
250
15.1M
            }
251
        }
252
7.97M
        if state.reached_bound_traits.contains(&trait_impl.trait_impl.x.trait_path) {
253
1.38M
            reach(&mut state.reached_trait_impls, &mut state.worklist_trait_impls, imp);
254
6.58M
        }
255
0
    }
256
14.2M
}
257
258
361k
fn reach_assoc_type_decl(_ctxt: &Ctxt, state: &mut State, name: &(Path, Ident)) {
259
361k
    reach(&mut state.reached_assoc_type_decls, &mut state.worklist_assoc_type_decls, name);
260
361k
}
261
262
1.55M
fn reach_assoc_type_impl(ctxt: &Ctxt, state: &mut State, name: &AssocTypeGroup) {
263
1.55M
    if ctxt.assoc_type_impl_map.contains_key(name) {
264
137k
        reach(&mut state.reached_assoc_type_impls, &mut state.worklist_assoc_type_impls, name);
265
1.42M
    }
266
1.55M
}
267
268
22.5M
fn reach_type(ctxt: &Ctxt, state: &mut State, typ: &ReachedType) {
269
22.5M
    match typ {
270
9.88M
        ReachedType::Datatype(dt) => {
271
9.88M
            if matches!(dt, Dt::Tuple(_)) || ctxt.datatype_map.contains_key(dt) {
272
9.88M
                reach(&mut state.reached_types, &mut state.worklist_types, typ);
273
9.88M
            }
274
        }
275
12.6M
        _ => {
276
12.6M
            reach(&mut state.reached_types, &mut state.worklist_types, typ);
277
12.6M
        }
278
    }
279
22.5M
}
280
281
// shallowly reach typ (the AST visitor takes care of recursing through typ)
282
42.9M
fn reach_typ(ctxt: &Ctxt, state: &mut State, typ: &Typ) {
283
42.9M
    match &**typ {
284
        TypX::Bool
285
        | TypX::Int(_)
286
        | TypX::Real
287
        | TypX::Float(_)
288
        | TypX::SpecFn(..)
289
        | TypX::Datatype(..)
290
        | TypX::Primitive(..)
291
21.3M
        | TypX::PointeeMetadata(_) => {
292
21.3M
            reach_type(ctxt, state, &typ_to_reached_type(typ));
293
21.3M
        }
294
393
        TypX::Dyn(trait_path, _, _) => {
295
393
            reach_type(ctxt, state, &typ_to_reached_type(typ));
296
393
            reach_bound_trait(ctxt, state, trait_path);
297
393
            state.dyn_traits.insert(trait_path.clone());
298
393
        }
299
983
        TypX::Opaque { def_path, .. } => {
300
983
            reach_opaque_type(ctxt, state, def_path);
301
983
        }
302
2.04k
        TypX::AnonymousClosure(..) => {}
303
        TypX::Air(_) => {
304
0
            panic!("unexpected TypX")
305
        }
306
3.34M
        TypX::Decorate(_, _, _t) | TypX::Boxed(_t) => {} // let visitor handle _t
307
16.8M
        TypX::TypParam(_) | TypX::TypeId | TypX::ConstInt(_) | TypX::ConstBool(_) => {}
308
346k
        TypX::Projection { trait_path, name, .. } => {
309
346k
            reach_assoc_type_decl(ctxt, state, &(trait_path.clone(), name.clone()));
310
346k
            // let visitor handle self_typ, trait_typ_args
311
346k
        }
312
87.1k
        TypX::FnDef(fun, typs, res_fun_opt) => {
313
87.1k
            state.fndef_types.insert(fun.clone());
314
87.1k
            reach_function(ctxt, state, fun);
315
87.1k
            let typ_args: Vec<ReachedType> = typs.iter().map(typ_to_reached_type).collect();
316
87.1k
            reach_type(ctxt, state, &ReachedType::FnDef(fun.clone(), typ_args));
317
318
87.1k
            if let Some(res_fun) = res_fun_opt {
319
298
                state.fndef_types.insert(res_fun.clone());
320
298
                reach_function(ctxt, state, res_fun);
321
86.8k
            }
322
        }
323
966k
        TypX::MutRef(_) => {}
324
    }
325
42.9M
}
326
327
880k
fn reached_methods<'a, 'b, I>(ctxt: &Ctxt, iter: I) -> Vec<Fun>
328
880k
where
329
880k
    I: Iterator<Item = (&'a ReachedType, &'b Fun)>,
330
{
331
    // If:
332
    // - we reach both D and T.f
333
    // - and D implements T.f with D.f
334
    // add D.f
335
880k
    let mut method_impls: Vec<Fun> = Vec::new();
336
135M
    for (self_typ, function) in iter {
337
135M
        if let Some(ms) = ctxt.method_map.get(&(self_typ.clone(), function.clone())) {
338
503k
            for method_impl in ms {
339
503k
                method_impls.push(method_impl.clone());
340
503k
            }
341
135M
        }
342
    }
343
880k
    method_impls
344
880k
}
_RINvNtCs6n9hmJXskGK_3vir5prune15reached_methodsINtNtNtNtCs4NRVxsYgnAr_4core4iter8adapters3map3MapINtNtBO_5chain5ChainINtNtNtNtCs2AWtUsOyxgP_3std11collections4hash3set4IterNtB2_11ReachedTypeEINtNtNtBS_5slice4iter4IterB2J_EENCNvB2_18traverse_reachables2_0EEB4_
Line
Count
Source
327
740k
fn reached_methods<'a, 'b, I>(ctxt: &Ctxt, iter: I) -> Vec<Fun>
328
740k
where
329
740k
    I: Iterator<Item = (&'a ReachedType, &'b Fun)>,
330
{
331
    // If:
332
    // - we reach both D and T.f
333
    // - and D implements T.f with D.f
334
    // add D.f
335
740k
    let mut method_impls: Vec<Fun> = Vec::new();
336
63.5M
    for (self_typ, function) in iter {
337
63.5M
        if let Some(ms) = ctxt.method_map.get(&(self_typ.clone(), function.clone())) {
338
240k
            for method_impl in ms {
339
240k
                method_impls.push(method_impl.clone());
340
240k
            }
341
63.3M
        }
342
    }
343
740k
    method_impls
344
740k
}
_RINvNtCs6n9hmJXskGK_3vir5prune15reached_methodsINtNtNtNtCs4NRVxsYgnAr_4core4iter8adapters3map3MapINtNtNtNtCs2AWtUsOyxgP_3std11collections4hash3set4IterINtNtCscdodAO9FK5_5alloc4sync3ArcNtNtB4_3ast4FunXEENCNvB2_18traverse_reachables3_0EEB4_
Line
Count
Source
327
140k
fn reached_methods<'a, 'b, I>(ctxt: &Ctxt, iter: I) -> Vec<Fun>
328
140k
where
329
140k
    I: Iterator<Item = (&'a ReachedType, &'b Fun)>,
330
{
331
    // If:
332
    // - we reach both D and T.f
333
    // - and D implements T.f with D.f
334
    // add D.f
335
140k
    let mut method_impls: Vec<Fun> = Vec::new();
336
72.1M
    for (self_typ, function) in iter {
337
72.1M
        if let Some(ms) = ctxt.method_map.get(&(self_typ.clone(), function.clone())) {
338
263k
            for method_impl in ms {
339
263k
                method_impls.push(method_impl.clone());
340
263k
            }
341
71.9M
        }
342
    }
343
140k
    method_impls
344
140k
}
345
346
880k
fn reach_methods(ctxt: &Ctxt, state: &mut State, method_impls: Vec<Fun>) {
347
880k
    for method_impl in &method_impls {
348
503k
        reach_function(ctxt, state, method_impl);
349
503k
    }
350
880k
}
351
352
895
fn reach_seq_funs(ctxt: &Ctxt, state: &mut State) {
353
895
    assert!(ctxt.assert_by_compute);
354
1.79k
    for f in ctxt.assert_by_compute_seq_funs.iter() {
355
1.79k
        reach_function(ctxt, state, f);
356
1.79k
    }
357
895
}
358
359
42.9M
fn traverse_typ(ctxt: &Ctxt, state: &mut State, t: &Typ) {
360
42.9M
    reach_typ(ctxt, state, t);
361
42.9M
    match &**t {
362
9.88M
        TypX::Datatype(path, _, _) => record_datatype(ctxt, state, t, path),
363
        TypX::Primitive(_, _) => {
364
403k
            if let Some(mono_abstract_datatypes) = &mut state.mono_abstract_datatypes {
365
247k
                if let Some(monotyp) = crate::poly::typ_as_mono(t) {
366
43.1k
                    mono_abstract_datatypes.insert(monotyp);
367
204k
                }
368
155k
            }
369
        }
370
947
        TypX::Opaque { .. } => {
371
947
            // Revisit.
372
947
            // For let x = foo<SomeType>(..);
373
947
            // Do we need to traverse typ args (SomeType)? Probably not?
374
947
            // All the type args should have been included in the function body through other means.
375
947
        }
376
32.6M
        _ => {}
377
    }
378
42.9M
}
379
380
1.67M
fn traverse_generic_bounds(
381
1.67M
    ctxt: &Ctxt,
382
1.67M
    state: &mut State,
383
1.67M
    bounds: &crate::ast::GenericBounds,
384
1.67M
    traverse_typs: bool,
385
1.67M
) {
386
2.48M
    for bound in bounds.iter() {
387
        // note: the types in the bounds are handled below in traverse_typs
388
2.48M
        let path = match &**bound {
389
1.11M
            crate::ast::GenericBoundX::Trait(TraitId::Path(path), _) => path,
390
            crate::ast::GenericBoundX::Trait(TraitId::Sizedness(_), _) => {
391
1.34M
                continue;
392
            }
393
15.0k
            crate::ast::GenericBoundX::TypEquality(path, _, name, _) => {
394
15.0k
                reach_assoc_type_decl(ctxt, state, &(path.clone(), name.clone()));
395
15.0k
                path
396
            }
397
            crate::ast::GenericBoundX::ConstTyp(_, _) => {
398
15.4k
                continue;
399
            }
400
        };
401
1.12M
        reach_bound_trait(ctxt, state, path);
402
    }
403
1.67M
    if traverse_typs {
404
203k
        let ft = |state: &mut State, t: &Typ| {
405
203k
            traverse_typ(ctxt, state, t);
406
203k
            Ok(t.clone())
407
203k
        };
408
126k
        let _ = crate::ast_visitor::map_generic_bounds_visitor(bounds, state, &ft)
409
126k
            .expect("traverse_typs");
410
1.54M
    }
411
1.67M
}
412
413
// set operations may be invoked for checking invariant masks,
414
// either when opening an invariant or invoking another function.
415
5.99k
fn reach_set_ops(state: &mut State, ctxt: &Ctxt) {
416
5.99k
    reach_function(ctxt, state, &fn_iset_contains_name());
417
5.99k
    reach_function(ctxt, state, &fn_iset_empty_name());
418
5.99k
    reach_function(ctxt, state, &fn_iset_full_name());
419
5.99k
    reach_function(ctxt, state, &fn_iset_insert_name());
420
5.99k
    reach_function(ctxt, state, &fn_iset_remove_name());
421
5.99k
    reach_function(ctxt, state, &fn_iset_subset_of_name());
422
5.99k
}
423
424
229
fn reach_atomic_update_ops(state: &mut State, ctxt: &Ctxt) {
425
229
    reach_function(ctxt, state, &fn_au_req());
426
229
    reach_function(ctxt, state, &fn_au_ens());
427
229
    reach_function(ctxt, state, &fn_au_pred());
428
229
    reach_function(ctxt, state, &fn_au_resolves());
429
229
    reach_function(ctxt, state, &fn_au_input());
430
229
    reach_function(ctxt, state, &fn_au_output());
431
229
    reach_function(ctxt, state, &fn_au_inner_mask());
432
229
    reach_function(ctxt, state, &fn_au_outer_mask());
433
229
    reach_function(ctxt, state, &fn_pred_args());
434
229
    reach_function(ctxt, state, &fn_branch_bool());
435
229
    reach_set_ops(state, &ctxt);
436
229
}
437
438
2.10M
fn maybe_reach_set_ops_for_call(
439
2.10M
    state: &mut State,
440
2.10M
    callee_name: &Fun,
441
2.10M
    ctxt: &Ctxt,
442
2.10M
    function: &Function,
443
2.10M
) {
444
2.10M
    let caller = crate::ast_util::get_non_trait_impl(&ctxt.function_map, &function.x.name);
445
2.10M
    let callee = crate::ast_util::get_non_trait_impl(&ctxt.function_map, callee_name);
446
2.10M
    if let (Some(caller), Some(callee)) = (caller, callee) {
447
2.09M
        let caller_mask = caller.x.mask_spec_or_default(&function.span);
448
2.09M
        let callee_mask = callee.x.mask_spec_or_default(&function.span);
449
        // If caller is `all`, we generate no set operations
450
        // If callee is `none`, we generate no set operations
451
2.09M
        if !caller_mask.is_all() && !callee_mask.is_none() {
452
4.13k
            reach_set_ops(state, ctxt);
453
2.09M
        }
454
13.1k
    }
455
2.10M
}
456
457
13.3k
fn traverse_reachable(ctxt: &Ctxt, state: &mut State) {
458
    loop {
459
42.7M
        let ft = |state: &mut State, t: &Typ| {
460
42.7M
            traverse_typ(ctxt, state, t);
461
42.7M
            Ok(t.clone())
462
42.7M
        };
463
1.84M
        if let Some(f) = state.worklist_functions.pop() {
464
740k
            let function = &ctxt.function_map[&f];
465
740k
            if ctxt.module.is_none() {
466
256k
                if let Some(autospec) = &function.x.attrs.autospec {
467
8.59k
                    reach_function(ctxt, state, autospec);
468
248k
                }
469
483k
            }
470
740k
            if let FunctionKind::TraitMethodImpl { method, .. } = &function.x.kind {
471
246k
                reach_function(ctxt, state, method);
472
493k
            }
473
740k
            if let Some(f_trigs) = ctxt.fun_to_trigger_broadcasts.get(&f) {
474
192k
                for f_trig in f_trigs {
475
192k
                    reach_function_via_reveal(ctxt, state, f_trig);
476
192k
                }
477
700k
            }
478
740k
            if ctxt.assert_by_compute && crate::interpreter::is_sequence_fn(&f).is_some() {
479
508
                reach_seq_funs(ctxt, state);
480
739k
            }
481
482
740k
            if function.x.atomic_update.is_some() {
483
75
                reach_atomic_update_ops(state, ctxt);
484
739k
            }
485
486
            // note: the types in typ_bounds are handled below by map_function_visitor_env
487
740k
            traverse_generic_bounds(ctxt, state, &function.x.typ_bounds, false);
488
11.1M
            let fe = |state: &mut State, _: &mut VisitorScopeMap, e: &Expr| {
489
                // note: the visitor automatically reaches e.typ
490
11.1M
                match &e.x {
491
560
                    ExprX::ConstVar(name, _) => {
492
560
                        assert!(ctxt.module.is_none());
493
560
                        reach_function(ctxt, state, name);
494
                    }
495
35
                    ExprX::StaticVar(name) => {
496
35
                        reach_function(ctxt, state, name);
497
35
                    }
498
                    ExprX::Call {
499
1.95M
                        target: CallTarget::Fun(kind, name, _, _impl_paths, attrs),
500
                        args: _,
501
                        post_args: _,
502
                        body: _,
503
                    } => {
504
                        // REVIEW: maybe we can be more precise if we use impl_paths here
505
1.95M
                        assert!(ctxt.module.is_none() || attrs.autospec == AutospecUsage::Final);
506
1.95M
                        reach_function(ctxt, state, name);
507
1.95M
                        if let crate::ast::CallTargetKind::DynamicResolved { resolved, .. } = kind {
508
155k
                            reach_function(ctxt, state, resolved);
509
155k
                            maybe_reach_set_ops_for_call(state, resolved, &ctxt, function);
510
1.79M
                        }
511
1.95M
                        maybe_reach_set_ops_for_call(state, name, &ctxt, function);
512
                    }
513
1.63k
                    ExprX::OpenInvariant(_, _, _, atomicity) => {
514
1.63k
                        // SST -> AIR conversion for OpenInvariant may introduce
515
1.63k
                        // references to these particular names.
516
1.63k
                        reach_function(ctxt, state, &fn_inv_name(*atomicity));
517
1.63k
                        reach_function(ctxt, state, &fn_namespace_name(*atomicity));
518
1.63k
                        reach_set_ops(state, ctxt);
519
1.63k
                    }
520
154
                    ExprX::TryOpenAtomicUpdate(..) | ExprX::Atomically(..) => {
521
154
                        reach_atomic_update_ops(state, &ctxt);
522
154
                    }
523
49.7k
                    ExprX::Fuel(fueled_f, _, is_broadcast_use) if *is_broadcast_use => {
524
33.5k
                        reach_function(ctxt, state, fueled_f);
525
33.5k
                    }
526
19.7k
                    ExprX::AssertAssumeUserDefinedTypeInvariant { is_assume: _, expr: _, fun } => {
527
19.7k
                        reach_function(ctxt, state, fun);
528
19.7k
                    }
529
387
                    ExprX::ArrayLiteral(..) if ctxt.assert_by_compute => {
530
387
                        reach_seq_funs(ctxt, state);
531
387
                    }
532
20.8k
                    ExprX::UnaryOpr(UnaryOpr::HasResolved(typ), _) => {
533
20.8k
                        if let Some(res) = &mut state.resolve_typs {
534
18.9k
                            res.visit_type(typ);
535
18.9k
                        }
536
                    }
537
16
                    ExprX::Unary(UnaryOp::Length(ArrayKind::Slice), _) => {
538
16
                        reach_function(ctxt, state, &fn_slice_len());
539
16
                    }
540
0
                    ExprX::Binary(BinaryOp::Index(ArrayKind::Slice, bounds_check), _, _) => {
541
0
                        reach_function(ctxt, state, &fn_slice_index());
542
0
                        if *bounds_check != BoundsCheck::Allow {
543
0
                            reach_function(ctxt, state, &fn_slice_len());
544
0
                        }
545
                    }
546
58
                    ExprX::Const(crate::ast::Constant::ByteStr(_)) => {
547
58
                        state.uses_bytestr = true;
548
58
                    }
549
31
                    ExprX::RevealByteString(_) => {
550
31
                        state.uses_bytestr = true;
551
31
                    }
552
                    ExprX::Unary(UnaryOp::IeeeFloat(_), _)
553
112
                    | ExprX::Binary(BinaryOp::IeeeFloat(_), _, _) => {
554
112
                        state.uses_ieee_float = true;
555
112
                    }
556
9.14M
                    _ => {}
557
                }
558
11.1M
                Ok(e.clone())
559
11.1M
            };
560
815k
            let fs = |_: &mut State, _: &mut VisitorScopeMap, s: &Stmt| Ok(vec![s.clone()]);
561
4.91M
            let fp = |state: &mut State, _: &mut VisitorScopeMap, p: &Place| {
562
4.91M
                match &p.x {
563
791
                    PlaceX::Index(_, _, ArrayKind::Array, _) => {
564
791
                        reach_function(ctxt, state, &fn_array_update());
565
791
                    }
566
343
                    PlaceX::Index(_, _, ArrayKind::Slice, bounds_check) => {
567
343
                        reach_function(ctxt, state, &fn_slice_index());
568
343
                        reach_function(ctxt, state, &fn_slice_update());
569
343
                        if *bounds_check != BoundsCheck::Allow {
570
311
                            reach_function(ctxt, state, &fn_slice_len());
571
311
                        }
572
                    }
573
4.91M
                    _ => {}
574
                }
575
4.91M
                Ok(p.clone())
576
4.91M
            };
577
740k
            let mut map: VisitorScopeMap = ScopeMap::new();
578
740k
            crate::ast_visitor::map_function_visitor_env(
579
740k
                &function, &mut map, state, &fe, &fs, &ft, &fp,
580
            )
581
740k
            .unwrap();
582
740k
            let methods = reached_methods(
583
740k
                ctxt,
584
63.5M
                state.reached_types.iter().chain([ReachedType::None].iter()).map(|t| (t, &f)),
585
            );
586
740k
            reach_methods(ctxt, state, methods);
587
740k
            if function.x.attrs.is_async {
588
36
                reach_typ(
589
36
                    ctxt,
590
36
                    state,
591
36
                    &function
592
36
                        .x
593
36
                        .async_ret
594
36
                        .as_ref()
595
36
                        .expect("Async function has no return type")
596
36
                        .x
597
36
                        .typ,
598
36
                );
599
739k
            }
600
740k
            continue;
601
1.10M
        }
602
1.10M
        if let Some(f) = state.worklist_reveal_groups.pop() {
603
230k
            reach_reveal_group(ctxt, state, &f);
604
230k
            continue;
605
875k
        }
606
875k
        if let Some(t) = state.worklist_types.pop() {
607
140k
            if let Some(f_trigs) = ctxt.typ_to_trigger_broadcasts.get(&t) {
608
1.13M
                for f_trig in f_trigs {
609
1.13M
                    reach_function_via_reveal(ctxt, state, f_trig);
610
1.13M
                }
611
105k
            }
612
65.4k
            match &t {
613
45.8k
                ReachedType::Datatype(dt @ Dt::Path(_path)) => {
614
45.8k
                    let datatype = &ctxt.datatype_map[dt];
615
45.8k
                    traverse_generic_bounds(ctxt, state, &datatype.x.typ_bounds, false);
616
45.8k
                    crate::ast_visitor::map_datatype_visitor_env(&datatype, state, &ft).unwrap();
617
2.66k
                    if let Some(FunWithVis { fun, visibility }) =
618
45.8k
                        &datatype.x.user_defined_invariant_fn
619
2.66k
                        && is_visible_to_or_true(visibility, &ctxt.module)
620
2.11k
                    {
621
2.11k
                        reach_function(ctxt, state, fun);
622
43.7k
                    }
623
                }
624
4.27k
                ReachedType::SpecFn(arity) => {
625
4.27k
                    state.spec_fn_types.insert(*arity);
626
4.27k
                }
627
819
                ReachedType::Array => {
628
819
                    state.uses_array = true;
629
819
                }
630
1.02k
                ReachedType::PointeeMetadata => {
631
1.02k
                    state.uses_pointee_metadata = true;
632
1.02k
                }
633
88.5k
                _ => {}
634
            }
635
140k
            if let Some(imps) = ctxt.typ_to_trait_impls.get(&t) {
636
12.0M
                for imp in imps {
637
12.0M
                    reach_trait_impl(ctxt, state, imp);
638
12.0M
                }
639
44.0k
            }
640
72.1M
            let methods = reached_methods(ctxt, state.reached_functions.iter().map(|f| (&t, f)));
641
140k
            reach_methods(ctxt, state, methods);
642
140k
            let assoc_decls: Vec<(Path, Ident)> =
643
140k
                state.reached_assoc_type_decls.iter().cloned().collect();
644
755k
            for a in assoc_decls {
645
755k
                reach_assoc_type_impl(ctxt, state, &(t.clone(), a.clone()));
646
755k
            }
647
140k
            continue;
648
735k
        }
649
735k
        if let Some(b) = state.worklist_bound_traits.pop() {
650
64.4k
            if let Some(impls) = ctxt.trait_to_trait_impls.get(&b) {
651
2.16M
                for imp in impls {
652
2.16M
                    reach_trait_impl(ctxt, state, imp);
653
2.16M
                }
654
3.99k
            }
655
64.4k
            if let Some(tr) = ctxt.trait_map.get(&b) {
656
63.2k
                // For assoc_type_trait_bounds_to_air, reach typ_bounds and assoc_typs_bounds
657
63.2k
                traverse_generic_bounds(ctxt, state, &tr.x.typ_bounds, true);
658
63.2k
                traverse_generic_bounds(ctxt, state, &tr.x.assoc_typs_bounds, true);
659
63.2k
            }
660
64.4k
            continue;
661
670k
        }
662
670k
        if let Some(i) = state.worklist_trait_impls.pop() {
663
578k
            if let Some(trait_impl) = ctxt.trait_impl_map.get(&i) {
664
578k
                for bound_trait in &trait_impl.bound_traits {
665
483k
                    reach_bound_trait(ctxt, state, bound_trait);
666
483k
                }
667
1.10M
                for bound_type in &trait_impl.bound_types {
668
1.10M
                    reach_type(ctxt, state, bound_type);
669
1.10M
                }
670
578k
                let ti = &trait_impl.trait_impl;
671
578k
                traverse_generic_bounds(ctxt, state, &ti.x.typ_bounds, false);
672
578k
                crate::ast_visitor::map_trait_impl_visitor_env(&ti, state, &ft).unwrap();
673
0
            }
674
578k
            continue;
675
92.8k
        }
676
92.8k
        if let Some(a) = state.worklist_assoc_type_decls.pop() {
677
13.3k
            let typs: Vec<ReachedType> =
678
13.3k
                state.reached_types.iter().chain([ReachedType::None].iter()).cloned().collect();
679
802k
            for t in typs {
680
802k
                reach_assoc_type_impl(ctxt, state, &(t.clone(), a.clone()));
681
802k
            }
682
            // assoc_type_trait_bounds_to_air needs typ_bounds and assoc_typs_bounds, so reach them.
683
            // We could be more precise and reach only the bounds relevant to a,
684
            // but this is probably not worth the complexity.
685
            // Instead, just have reach_bound_trait reach all of typ_bounds and assoc_typs_bounds.
686
13.3k
            reach_bound_trait(ctxt, state, &a.0);
687
13.3k
            continue;
688
79.4k
        }
689
79.4k
        if let Some(assoc_group) = state.worklist_assoc_type_impls.pop() {
690
65.9k
            if let Some(assoc_impls) = ctxt.assoc_type_impl_map.get(&assoc_group) {
691
181k
                for assoc_impl in assoc_impls {
692
181k
                    traverse_generic_bounds(ctxt, state, &assoc_impl.x.typ_bounds, false);
693
181k
                    crate::ast_visitor::map_assoc_type_impl_visitor_env(&assoc_impl, state, &ft)
694
181k
                        .unwrap();
695
181k
                }
696
0
            }
697
65.9k
            continue;
698
13.4k
        }
699
13.4k
        if let Some(opaque_ty_path) = state.worklist_opaque_types.pop() {
700
109
            if let Some(opaque_type) = ctxt.opaque_ty_map.get(&opaque_ty_path) {
701
                // Revist. this is probably needed, the opaque type can refer to some actual types, which, if pruned
702
                // can cause problems
703
109
                traverse_generic_bounds(ctxt, state, &opaque_type.x.typ_bounds, true);
704
109
                for t in opaque_type.x.typ_params.iter() {
705
7
                    // Revist. Not sure if this is needed. If I understand it correctly, these typs can only be
706
7
                    // type params like "T", not some types defined somewhere else.
707
7
                    traverse_typ(ctxt, state, t);
708
7
                }
709
0
            }
710
109
            continue;
711
13.3k
        }
712
13.3k
        break;
713
    }
714
13.3k
    assert!(state.worklist_functions.len() == 0);
715
13.3k
    assert!(state.worklist_reveal_groups.len() == 0);
716
13.3k
    assert!(state.worklist_types.len() == 0);
717
13.3k
    assert!(state.worklist_bound_traits.len() == 0);
718
13.3k
    assert!(state.worklist_trait_impls.len() == 0);
719
13.3k
    assert!(state.worklist_assoc_type_decls.len() == 0);
720
13.3k
    assert!(state.worklist_assoc_type_impls.len() == 0);
721
13.3k
    assert!(state.worklist_opaque_types.len() == 0);
722
13.3k
}
723
724
impl TraitX {
725
527k
    fn prune_name(&self, name: &Ident) -> (Path, Ident) {
726
527k
        (self.name.clone(), name.clone())
727
527k
    }
728
}
729
730
impl AssocTypeImplX {
731
34.6M
    fn prune_name(&self) -> AssocTypeGroup {
732
34.6M
        let self_typ = &self.trait_typ_args[0];
733
34.6M
        (typ_to_reached_type(self_typ), (self.trait_path.clone(), self.name.clone()))
734
34.6M
    }
735
}
736
737
13.3k
fn overapproximate_revealed_functions(
738
13.3k
    revealed_functions: &mut HashSet<Fun>,
739
13.3k
    reveal_groups: &Vec<RevealGroup>,
740
13.3k
) {
741
    // REVIEW: this is an unnecessary overapproximation;
742
    // we could be more precise in handling whether reveal_groups recursively reach and reveal
743
    // opaque functions,
744
    // but it would require refactoring the way we decide to keep or erase opaque function bodies,
745
    // which doesn't seem worth it now to optimize a feature that isn't really used yet.
746
    // So we just make an overapproximation.
747
    // (As a result, we might unnecessarily include the body of an opaque function even if
748
    // we only need the opaque function's signature.)
749
13.3k
    let mut reveal_group_map: HashMap<Fun, RevealGroup> = HashMap::new();
750
724k
    for f in reveal_groups {
751
724k
        reveal_group_map.insert(f.x.name.clone(), f.clone());
752
724k
    }
753
13.3k
    let mut worklist: Vec<Fun> =
754
23.1k
        revealed_functions.iter().filter(|f| reveal_group_map.contains_key(*f)).cloned().collect();
755
243k
    while let Some(f) = worklist.pop() {
756
229k
        let group = &reveal_group_map[&f];
757
1.93M
        for member in group.x.members.iter() {
758
1.93M
            if !revealed_functions.contains(member) {
759
1.92M
                revealed_functions.insert(member.clone());
760
1.92M
                if reveal_group_map.contains_key(member) {
761
221k
                    worklist.push(member.clone());
762
1.70M
                }
763
8.86k
            }
764
        }
765
    }
766
13.3k
}
767
768
1.01M
fn collect_broadcast_triggers(f: &Function) -> Vec<(Vec<Fun>, Vec<ReachedType>)> {
769
    use crate::ast::{Exprs, TriggerAnnotation, UnaryOp};
770
1.01M
    let mut unary_trigs: Vec<Expr> = Vec::new();
771
1.01M
    let mut with_triggers: Vec<Exprs> = Vec::new();
772
1.01M
    let mut map: VisitorScopeMap = ScopeMap::new();
773
10.7M
    let mut f_get_triggers = |_: &mut VisitorScopeMap, expr: &Expr| {
774
10.7M
        match &expr.x {
775
41.2k
            ExprX::WithTriggers { triggers, body: _ } => {
776
41.2k
                with_triggers.extend((**triggers).clone());
777
41.2k
                VisitorControlFlow::Recurse
778
            }
779
997k
            ExprX::Unary(UnaryOp::Trigger(TriggerAnnotation::Trigger(..)), e) => {
780
997k
                unary_trigs.push(e.clone());
781
997k
                VisitorControlFlow::Recurse
782
            }
783
            ExprX::Unary(UnaryOp::Trigger(..), _) => {
784
                // TODO: we should probably make this an error
785
4
                VisitorControlFlow::Stop(())
786
            }
787
88.4k
            ExprX::Quant(..) => VisitorControlFlow::Return,
788
9.59M
            _ => VisitorControlFlow::Recurse,
789
        }
790
10.7M
    };
791
792
    // Collect all triggers
793
2.49M
    for expr in f.x.require.iter().chain(f.x.ensure.0.iter()).chain(f.x.ensure.1.iter()) {
794
2.49M
        let control = crate::ast_visitor::expr_visitor_dfs(expr, &mut map, &mut f_get_triggers);
795
2.49M
        if control == VisitorControlFlow::Stop(()) {
796
4
            return vec![];
797
2.49M
        }
798
    }
799
1.01M
    if unary_trigs.len() > 0 {
800
971k
        with_triggers.push(Arc::new(unary_trigs));
801
971k
    }
802
803
    // Collect function calls and types in each trigger
804
    // (Note: it's ok to err on the side of missing some function calls and types)
805
1.01M
    let mut trigs: Vec<(Vec<Fun>, Vec<ReachedType>)> = Vec::new();
806
1.05M
    for trig in &with_triggers {
807
1.05M
        let mut call_set: HashSet<Fun> = HashSet::new();
808
1.05M
        let mut calls: Vec<Fun> = Vec::new();
809
1.05M
        let mut typ_set: HashSet<ReachedType> = HashSet::new();
810
1.05M
        let mut typs: Vec<ReachedType> = Vec::new();
811
1.05M
        typ_set.insert(ReachedType::None);
812
4.11M
        let mut ft = |typ: &Typ| {
813
4.11M
            let t = typ_to_reached_type(typ);
814
4.11M
            if !typ_set.contains(&t) {
815
2.19M
                typ_set.insert(t.clone());
816
2.19M
                typs.push(t.clone());
817
2.19M
            }
818
4.11M
        };
819
2.63M
        let mut f_get_calls = |_: &mut VisitorScopeMap, expr: &Expr| {
820
2.63M
            ft(&expr.typ);
821
2.63M
            match &expr.x {
822
                ExprX::Call {
823
1.29M
                    target: CallTarget::Fun(_, name, ts, _, _),
824
                    args: _,
825
                    post_args: _,
826
                    body: _,
827
                } => {
828
1.48M
                    for typ in ts.iter() {
829
1.48M
                        ft(typ);
830
1.48M
                    }
831
1.29M
                    if !call_set.contains(name) {
832
1.28M
                        call_set.insert(name.clone());
833
1.28M
                        calls.push(name.clone());
834
1.28M
                    }
835
1.29M
                    VisitorControlFlow::Recurse
836
                }
837
1.33M
                _ => VisitorControlFlow::Recurse,
838
            }
839
2.63M
        };
840
1.09M
        for term in trig.iter() {
841
1.09M
            let control =
842
1.09M
                crate::ast_visitor::expr_visitor_dfs(term, &mut ScopeMap::new(), &mut f_get_calls);
843
1.09M
            if control == VisitorControlFlow::Stop(()) {
844
0
                return vec![];
845
1.09M
            }
846
        }
847
1.05M
        if calls.len() == 0 && typs.len() == 0 {
848
            // For the case of a trigger with no function calls (e.g. a trigger on an
849
            // arithmetic op), we don't prune.
850
0
            return vec![];
851
1.05M
        }
852
1.05M
        trigs.push((calls, typs));
853
    }
854
1.01M
    trigs
855
1.01M
}
856
857
#[derive(Debug)]
858
pub struct UsedBuiltins {
859
    pub uses_array: bool,
860
    pub uses_bytestr: bool,
861
    pub uses_pointee_metadata: bool,
862
    pub uses_ieee_float: bool,
863
}
864
865
//  - module is none: prune to keep what's reachable from current_crate
866
//    module is some and fun is none: prune to keep what's reachable from module
867
//    module is some and fun is some: prune to keep what's reachable from fun
868
//  - collect_monotyps: if true, return a Vec<MonoTyp>; otherwise, return None
869
//    this should only be done post-simplification
870
871
pub struct PruneInfo {
872
    pub mono_abstract_datatypes: Option<Vec<MonoTyp>>,
873
    pub spec_fn_types: Vec<usize>,
874
    pub used_builtins: UsedBuiltins,
875
    pub fndef_types: Vec<Fun>,
876
    pub resolved_typs: Option<Vec<ResolvableType>>,
877
    pub dyn_traits: HashSet<Path>,
878
}
879
880
13.3k
pub fn prune_krate_for_module_or_krate(
881
13.3k
    krate: &Krate,
882
13.3k
    crate_name: &CrateId,
883
13.3k
    current_crate: Option<&Krate>,
884
13.3k
    module: Option<Path>,
885
13.3k
    fun: Option<&Fun>,
886
13.3k
    collect_monotyps: bool,
887
13.3k
    collect_resolve_typs: bool,
888
13.3k
) -> (Krate, PruneInfo) {
889
13.3k
    assert!(module.is_some() != current_crate.is_some());
890
891
13.3k
    let mut root_modules: HashSet<Path> = HashSet::new();
892
13.3k
    let mut root_functions: HashSet<Fun> = HashSet::new();
893
13.3k
    if let Some(module) = &module {
894
9.34k
        root_modules.insert(module.clone());
895
9.34k
        if let Some(fun) = fun {
896
366
            root_functions.insert(fun.clone());
897
366
        } else {
898
37.6M
            for f in &krate.functions {
899
37.6M
                match &f.x.owning_module {
900
37.6M
                    Some(m) if m == module => {
901
205k
                        root_functions.insert(f.x.name.clone());
902
205k
                    }
903
37.4M
                    _ => {}
904
                }
905
            }
906
        }
907
4.04k
    } else if let Some(current_crate) = current_crate {
908
10.1k
        for m in &current_crate.modules {
909
10.1k
            root_modules.insert(m.x.path.clone());
910
10.1k
        }
911
207k
        for f in &current_crate.functions {
912
207k
            root_functions.insert(f.x.name.clone());
913
207k
        }
914
    } else {
915
0
        unreachable!();
916
    }
917
5.58M
    let is_root_module = |module_path: &Path| root_modules.contains(module_path);
918
102M
    let is_root_function = |function: &Function| root_functions.contains(&function.x.name);
919
920
13.3k
    let mut state: State = Default::default();
921
13.3k
    if collect_monotyps {
922
9.34k
        state.mono_abstract_datatypes = Some(HashSet::new());
923
9.34k
    }
924
13.3k
    if collect_resolve_typs {
925
9.34k
        state.resolve_typs = Some(ResolvedTypeCollection::new(module.as_ref().unwrap(), &krate));
926
9.34k
    }
927
13.3k
    if let Some(current_crate) = current_crate {
928
        // Make sure we keep all of current_crate,
929
        // so that all of current_crate is sent to the well-formedness checks.
930
        let KrateX {
931
4.04k
            functions,
932
4.04k
            reveal_groups,
933
4.04k
            datatypes,
934
4.04k
            opaque_types,
935
4.04k
            assoc_type_impls,
936
4.04k
            traits,
937
4.04k
            trait_impls,
938
            modules: _,
939
4.04k
            external_fns: _no_pruning_of_external_fns,
940
4.04k
            external_types: _no_pruning_of_external_types,
941
4.04k
            path_as_rust_names: _no_pruning_of_past_as_rust_names,
942
4.04k
            arch: _no_pruning_of_arch,
943
4.04k
        } = &**current_crate;
944
207k
        for f in functions {
945
207k
            reach(&mut state.reached_functions, &mut state.worklist_functions, &f.x.name);
946
207k
        }
947
4.04k
        for f in reveal_groups {
948
2.32k
            reach(&mut state.reached_functions, &mut state.worklist_reveal_groups, &f.x.name);
949
2.32k
        }
950
9.55k
        for d in datatypes {
951
9.55k
            let t = ReachedType::Datatype(d.x.name.clone());
952
9.55k
            reach(&mut state.reached_types, &mut state.worklist_types, &t);
953
9.55k
        }
954
4.04k
        for o in opaque_types {
955
57
            reach(&mut state.reached_opaque_types, &mut state.worklist_opaque_types, &o.x.name);
956
57
        }
957
56.8k
        for a in assoc_type_impls {
958
56.8k
            reach(
959
56.8k
                &mut state.reached_assoc_type_impls,
960
56.8k
                &mut state.worklist_assoc_type_impls,
961
56.8k
                &a.x.prune_name(),
962
56.8k
            );
963
56.8k
        }
964
6.66k
        for tr in traits {
965
6.66k
            reach(&mut state.reached_bound_traits, &mut state.worklist_bound_traits, &tr.x.name);
966
6.66k
        }
967
135k
        for i in trait_impls {
968
135k
            reach(&mut state.reached_trait_impls, &mut state.worklist_trait_impls, &i.x.impl_path);
969
135k
        }
970
9.34k
    }
971
972
13.3k
    let mut root_modules_reveal: Vec<Fun> = Vec::new();
973
1.86M
    for m in &krate.modules {
974
1.86M
        if is_root_module(&m.x.path) {
975
19.5k
            if let Some(reveals) = &m.x.reveals {
976
1.73k
                root_modules_reveal.extend(reveals.x.clone());
977
17.7k
            }
978
1.84M
        }
979
    }
980
981
    // Collect all functions that our module reveals:
982
13.3k
    let mut revealed_functions: HashSet<Fun> = HashSet::new();
983
13.3k
    let mut assert_by_compute = false;
984
51.1M
    for f in &krate.functions {
985
51.1M
        if is_root_function(f) {
986
412k
            if let Some(body) = &f.x.body {
987
278k
                crate::ast_visitor::expr_visitor_check::<(), _>(
988
278k
                    body,
989
5.01M
                    &mut |_scope_map, e: &Expr| {
990
5.01M
                        match &e.x {
991
49.7k
                            ExprX::Fuel(path, fuel, _is_broadcast_use) if *fuel > 0 => {
992
49.7k
                                revealed_functions.insert(path.clone());
993
49.7k
                            }
994
4.20k
                            ExprX::AssertCompute(..) => {
995
4.20k
                                assert_by_compute = true;
996
4.20k
                            }
997
4.95M
                            _ => {}
998
                        }
999
5.01M
                        Ok(())
1000
5.01M
                    },
1001
                )
1002
278k
                .expect("expr_visitor_check failed unexpectedly");
1003
134k
            }
1004
50.7M
        }
1005
    }
1006
13.3k
    let reveal_group_set: HashSet<Fun> =
1007
730k
        krate.reveal_groups.iter().map(|g| g.x.name.clone()).collect();
1008
13.3k
    for f in &root_modules_reveal {
1009
3.12k
        revealed_functions.insert(f.clone());
1010
3.12k
        if reveal_group_set.contains(f) {
1011
3.00k
            reach(&mut state.reached_functions, &mut state.worklist_reveal_groups, f);
1012
3.00k
        } else {
1013
122
            reach(&mut state.reached_functions, &mut state.worklist_functions, f);
1014
122
        }
1015
    }
1016
730k
    for group in &krate.reveal_groups {
1017
730k
        if let Some(group_crate) = &group.x.broadcast_use_by_default_when_this_crate_is_imported {
1018
9.08k
            let is_imported = crate_name != group_crate;
1019
9.08k
            if is_imported {
1020
3.29k
                revealed_functions.insert(group.x.name.clone());
1021
5.78k
            }
1022
721k
        }
1023
    }
1024
1025
    // Collect functions and datatypes,
1026
    // pruning all bodies and variants that are not visible to our module
1027
13.3k
    let mut functions: Vec<Function> = Vec::new();
1028
13.3k
    let mut reveal_groups: Vec<RevealGroup> = Vec::new();
1029
13.3k
    let mut datatypes: Vec<Datatype> = Vec::new();
1030
13.3k
    let mut opaque_types: Vec<OpaqueType> = Vec::new();
1031
13.3k
    let mut traits: Vec<Trait> = Vec::new();
1032
730k
    for f in &krate.reveal_groups {
1033
730k
        if is_visible_to_or_true(&f.x.visibility, &module) {
1034
724k
            reveal_groups.push(f.clone());
1035
724k
            if revealed_functions.contains(&f.x.name) {
1036
8.67k
                reach(&mut state.reached_functions, &mut state.worklist_reveal_groups, &f.x.name);
1037
716k
            }
1038
5.72k
        }
1039
    }
1040
13.3k
    overapproximate_revealed_functions(&mut revealed_functions, &reveal_groups);
1041
51.1M
    for f in &krate.functions {
1042
51.1M
        if module.is_none() || is_root_function(f) {
1043
11.2M
            functions.push(f.clone());
1044
11.2M
            if is_root_function(f) {
1045
                // our function
1046
412k
                reach(&mut state.reached_functions, &mut state.worklist_functions, &f.x.name);
1047
1048
                // an async function, we need to include async related functions
1049
412k
                if f.x.attrs.is_async {
1050
36
                    reach(
1051
36
                        &mut state.reached_functions,
1052
36
                        &mut state.worklist_functions,
1053
36
                        &crate::fun!(CrateId::Vstd => "future", "FutureAdditionalSpecFns", "view"),
1054
36
                    );
1055
36
1056
36
                    reach(
1057
36
                        &mut state.reached_functions,
1058
36
                        &mut state.worklist_functions,
1059
36
                        &crate::fun!(CrateId::Vstd => "future", "FutureAdditionalSpecFns", "awaited"),
1060
36
                    );
1061
36
1062
36
                    reach(
1063
36
                        &mut state.reached_functions,
1064
36
                        &mut state.worklist_functions,
1065
36
                        &crate::fun!(CrateId::Vstd => "future", "exec_await"),
1066
36
                    );
1067
412k
                }
1068
10.8M
            }
1069
11.2M
            continue;
1070
39.8M
        }
1071
39.8M
        let module = module.as_ref().unwrap();
1072
1073
        // Remove body if any of the following are true:
1074
        // - function is not visible
1075
        // - function is abstract
1076
        // - function is opaque and not revealed
1077
        // - function is exec or proof
1078
        // (when optimizing for modules, after well-formedness checks)
1079
39.8M
        let is_vis = is_visible_to(&f.x.visibility, &module);
1080
39.8M
        let is_open = is_body_visible_to(&f.x.body_visibility, &module);
1081
39.8M
        let is_non_opaque = f.x.opaqueness.get_default_fuel_for_module_path(module) != 0;
1082
39.8M
        let is_revealed = is_non_opaque || revealed_functions.contains(&f.x.name);
1083
39.8M
        let is_spec = f.x.mode == Mode::Spec;
1084
39.8M
        if is_vis && is_open && is_revealed && is_spec {
1085
14.2M
            functions.push(f.clone());
1086
25.6M
        } else if f.x.body.is_none() {
1087
13.6M
            functions.push(f.clone());
1088
13.6M
        } else {
1089
11.9M
            let mut function = f.x.clone();
1090
11.9M
            function.body = None;
1091
11.9M
            functions.push(Spanned::new(f.span.clone(), function));
1092
11.9M
        }
1093
    }
1094
1.93M
    for d in &krate.datatypes {
1095
1.93M
        match &d.x.owning_module {
1096
1.85M
            Some(path) if is_root_module(path) && fun.is_none() => {
1097
18.5k
                // our datatype
1098
18.5k
                let t = ReachedType::Datatype(d.x.name.clone());
1099
18.5k
                reach(&mut state.reached_types, &mut state.worklist_types, &t);
1100
18.5k
            }
1101
1.91M
            _ => {}
1102
        }
1103
1.93M
        let is_vis = is_visible_to_or_true(&d.x.visibility, &module);
1104
1.93M
        let is_transparent =
1105
1.93M
            if let Some(module) = &module { is_datatype_transparent(module, &d) } else { true };
1106
1.93M
        if is_vis {
1107
1.86M
            if is_transparent {
1108
865k
                datatypes.push(d.clone());
1109
1.00M
            } else {
1110
1.00M
                let mut datatype = d.x.clone();
1111
1.00M
                datatype.variants = Arc::new(vec![]);
1112
1.00M
                datatypes.push(Spanned::new(d.span.clone(), datatype));
1113
1.00M
            }
1114
69.0k
        }
1115
    }
1116
1117
13.3k
    for op in &krate.opaque_types {
1118
109
        opaque_types.push(op.clone());
1119
109
    }
1120
1121
13.3k
    let mut function_map: HashMap<Fun, Function> = HashMap::new();
1122
13.3k
    let mut reveal_group_map: HashMap<Fun, RevealGroup> = HashMap::new();
1123
13.3k
    let mut datatype_map: HashMap<Dt, Datatype> = HashMap::new();
1124
13.3k
    let mut opaque_ty_map: HashMap<OpaqueTyName, OpaqueType> = HashMap::new();
1125
13.3k
    let mut trait_map: HashMap<Path, Trait> = HashMap::new();
1126
13.3k
    let mut assoc_type_impl_map: HashMap<AssocTypeGroup, Vec<AssocTypeImpl>> = HashMap::new();
1127
13.3k
    let mut trait_to_trait_impls: HashMap<TraitName, Vec<ImplName>> = HashMap::new();
1128
13.3k
    let mut typ_to_trait_impls: HashMap<ReachedType, Vec<ImplName>> = HashMap::new();
1129
13.3k
    let mut trait_impl_map: HashMap<ImplName, ReachTraitImpl> = HashMap::new();
1130
13.3k
    let mut method_map: HashMap<(ReachedType, Fun), Vec<Fun>> = HashMap::new();
1131
13.3k
    let mut fun_to_trigger_broadcasts: HashMap<Fun, Vec<Fun>> = HashMap::new();
1132
13.3k
    let mut typ_to_trigger_broadcasts: HashMap<ReachedType, Vec<Fun>> = HashMap::new();
1133
13.3k
    let mut fun_revealed_broadcast_map: HashMap<Fun, ReachBroadcastFunction> = HashMap::new();
1134
13.3k
    let mut assert_by_compute_seq_funs: Vec<Fun> = Vec::new();
1135
51.1M
    for f in &functions {
1136
51.1M
        function_map.insert(f.x.name.clone(), f.clone());
1137
17.7M
        if let FunctionKind::TraitMethodImpl { method, trait_typ_args, .. }
1138
51.1M
        | FunctionKind::ForeignTraitMethodImpl { method, trait_typ_args, .. } = &f.x.kind
1139
        {
1140
18.7M
            let self_typ = &trait_typ_args[0];
1141
18.7M
            let key = (typ_to_reached_type(self_typ), method.clone());
1142
18.7M
            if !method_map.contains_key(&key) {
1143
16.3M
                method_map.insert(key.clone(), Vec::new());
1144
16.3M
            }
1145
18.7M
            method_map.get_mut(&key).unwrap().push(f.x.name.clone());
1146
32.4M
        }
1147
51.1M
        if revealed_functions.contains(&f.x.name) {
1148
1.01M
            let reach_triggers = collect_broadcast_triggers(f);
1149
1.05M
            for (trig_funs, trig_typs) in &reach_triggers {
1150
1.28M
                for term in trig_funs {
1151
1.28M
                    fun_to_trigger_broadcasts
1152
1.28M
                        .entry(term.clone())
1153
1.28M
                        .or_insert_with(|| Vec::new())
1154
1.28M
                        .push(f.x.name.clone());
1155
                }
1156
2.19M
                for typ in trig_typs {
1157
2.19M
                    typ_to_trigger_broadcasts
1158
2.19M
                        .entry(typ.clone())
1159
2.19M
                        .or_insert_with(|| Vec::new())
1160
2.19M
                        .push(f.x.name.clone());
1161
                }
1162
            }
1163
1.01M
            let reach_broadcast = ReachBroadcastFunction { reach_triggers };
1164
1.01M
            fun_revealed_broadcast_map.insert(f.x.name.clone(), reach_broadcast);
1165
50.1M
        }
1166
51.1M
        if assert_by_compute && crate::interpreter::is_seq_to_sst_fun(&f.x.name) {
1167
302
            assert_by_compute_seq_funs.push(f.x.name.clone());
1168
51.1M
        }
1169
    }
1170
724k
    for f in &reveal_groups {
1171
724k
        reveal_group_map.insert(f.x.name.clone(), f.clone());
1172
724k
    }
1173
1.86M
    for d in &datatypes {
1174
1.86M
        datatype_map.insert(d.x.name.clone(), d.clone());
1175
1.86M
    }
1176
13.3k
    for op in &opaque_types {
1177
109
        opaque_ty_map.insert(op.x.name.clone(), op.clone());
1178
109
    }
1179
1.64M
    for tr in krate.traits.iter() {
1180
1.64M
        trait_map.insert(tr.x.name.clone(), tr.clone());
1181
1.64M
    }
1182
1183
41.9M
    for imp in krate.trait_impls.iter() {
1184
41.9M
        let mut bound_traits: Vec<TraitName> = Vec::new();
1185
41.9M
        let mut bound_types: Vec<ReachedType> = Vec::new();
1186
41.9M
        for bound in imp.x.typ_bounds.iter() {
1187
38.2M
            match &**bound {
1188
37.4M
                crate::ast::GenericBoundX::Trait(tid, typ_args) => {
1189
37.4M
                    match tid {
1190
18.9M
                        TraitId::Path(path) => {
1191
18.9M
                            bound_traits.push(path.clone());
1192
18.9M
                        }
1193
18.4M
                        TraitId::Sizedness(_) => {}
1194
                    }
1195
42.9M
                    for t in typ_args.iter() {
1196
42.9M
                        bound_types.push(typ_to_reached_type(t));
1197
42.9M
                    }
1198
                }
1199
212k
                crate::ast::GenericBoundX::TypEquality(path, typ_args, _name, typ) => {
1200
212k
                    bound_traits.push(path.clone());
1201
231k
                    for t in typ_args.iter() {
1202
231k
                        bound_types.push(typ_to_reached_type(t));
1203
231k
                    }
1204
212k
                    bound_types.push(typ_to_reached_type(typ));
1205
                }
1206
610k
                crate::ast::GenericBoundX::ConstTyp(t, s) => {
1207
610k
                    bound_types.push(typ_to_reached_type(t));
1208
610k
                    bound_types.push(typ_to_reached_type(s));
1209
610k
                }
1210
            }
1211
        }
1212
41.9M
        let trait_impl = ReachTraitImpl {
1213
41.9M
            trait_impl: imp.clone(),
1214
41.9M
            bound_traits,
1215
41.9M
            bound_types,
1216
41.9M
            trait_typ_args: imp.x.trait_typ_args.iter().map(typ_to_reached_type).collect(),
1217
41.9M
        };
1218
41.9M
        if !trait_to_trait_impls.contains_key(&imp.x.trait_path) {
1219
1.56M
            trait_to_trait_impls.insert(imp.x.trait_path.clone(), Vec::new());
1220
40.4M
        }
1221
41.9M
        trait_to_trait_impls.get_mut(&imp.x.trait_path).unwrap().push(imp.x.impl_path.clone());
1222
74.6M
        for t in &trait_impl.trait_typ_args {
1223
74.6M
            if !typ_to_trait_impls.contains_key(t) {
1224
2.70M
                typ_to_trait_impls.insert(t.clone(), Vec::new());
1225
71.9M
            }
1226
74.6M
            typ_to_trait_impls.get_mut(&t).unwrap().push(imp.x.impl_path.clone());
1227
        }
1228
41.9M
        assert!(module.is_none() || !trait_impl_map.contains_key(&imp.x.impl_path));
1229
41.9M
        trait_impl_map.insert(imp.x.impl_path.clone(), trait_impl);
1230
    }
1231
1232
17.3M
    for a in &krate.assoc_type_impls {
1233
17.3M
        let key = a.x.prune_name();
1234
17.3M
        if !assoc_type_impl_map.contains_key(&key) {
1235
4.82M
            assoc_type_impl_map.insert(key.clone(), Vec::new());
1236
12.4M
        }
1237
17.3M
        assoc_type_impl_map.get_mut(&key).unwrap().push(a.clone());
1238
    }
1239
13.3k
    let ctxt = Ctxt {
1240
13.3k
        module: module.clone(),
1241
13.3k
        function_map,
1242
13.3k
        reveal_group_map,
1243
13.3k
        datatype_map,
1244
13.3k
        opaque_ty_map,
1245
13.3k
        trait_map,
1246
13.3k
        trait_to_trait_impls,
1247
13.3k
        typ_to_trait_impls,
1248
13.3k
        trait_impl_map,
1249
13.3k
        assoc_type_impl_map,
1250
13.3k
        method_map,
1251
13.3k
        fun_to_trigger_broadcasts,
1252
13.3k
        typ_to_trigger_broadcasts,
1253
13.3k
        fun_revealed_broadcast_map,
1254
13.3k
        assert_by_compute,
1255
13.3k
        assert_by_compute_seq_funs,
1256
13.3k
    };
1257
13.3k
    traverse_reachable(&ctxt, &mut state);
1258
1259
1.64M
    for tr in krate.traits.iter() {
1260
1.64M
        let traitx = tr.x.clone();
1261
1.64M
        let assoc_typs = traitx
1262
1.64M
            .assoc_typs
1263
1.64M
            .iter()
1264
1.64M
            .filter(|a| state.reached_assoc_type_decls.contains(&traitx.prune_name(a)))
1265
1.64M
            .cloned()
1266
1.64M
            .collect();
1267
1.64M
        let assoc_typs = Arc::new(assoc_typs);
1268
1.64M
        let assoc_typs_bounds = if state.reached_bound_traits.contains(&tr.x.name) {
1269
63.2k
            traitx.assoc_typs_bounds
1270
        } else {
1271
1.58M
            Arc::new(vec![])
1272
        };
1273
1.64M
        traits.push(Spanned::new(
1274
1.64M
            tr.span.clone(),
1275
1.64M
            TraitX { assoc_typs, assoc_typs_bounds, ..traitx },
1276
        ));
1277
    }
1278
1279
13.3k
    let modules: Vec<Module> = krate
1280
13.3k
        .modules
1281
13.3k
        .iter()
1282
1.86M
        .map(|mm| {
1283
1.86M
            mm.map_x(|m| ModuleX {
1284
1.86M
                path: m.path.clone(),
1285
1.86M
                reveals: if is_root_module(&m.path) { m.reveals.clone() } else { None },
1286
1.86M
            })
1287
1.86M
        })
1288
13.3k
        .collect();
1289
1290
13.3k
    debug_assert!(
1291
0
        module.is_none() || modules.iter().filter(|m| m.x.reveals.is_some()).count() <= 1
1292
    );
1293
1294
740k
    let set_broadcast_only = |mut f: Function| {
1295
740k
        if f.x.attrs.broadcast_forall
1296
116k
            && !state.broadcast_functions_fully_reached.contains(&f.x.name)
1297
97.2k
        {
1298
97.2k
            Arc::make_mut(&mut Arc::make_mut(&mut f).x.attrs).broadcast_forall_only = true;
1299
642k
        }
1300
740k
        f
1301
740k
    };
1302
1303
13.3k
    let kratex = KrateX {
1304
13.3k
        functions: functions
1305
13.3k
            .into_iter()
1306
51.1M
            .filter(|f| state.reached_functions.contains(&f.x.name))
1307
13.3k
            .map(set_broadcast_only)
1308
13.3k
            .collect(),
1309
13.3k
        reveal_groups: reveal_groups
1310
13.3k
            .into_iter()
1311
724k
            .filter(|f| state.reached_functions.contains(&f.x.name))
1312
13.3k
            .collect(),
1313
13.3k
        datatypes: datatypes
1314
13.3k
            .into_iter()
1315
1.86M
            .filter(|d| state.reached_types.contains(&ReachedType::Datatype(d.x.name.clone())))
1316
13.3k
            .collect(),
1317
13.3k
        opaque_types: opaque_types
1318
13.3k
            .iter()
1319
13.3k
            .filter(|a| state.reached_opaque_types.contains(&a.x.name.clone()))
1320
13.3k
            .cloned()
1321
13.3k
            .collect(),
1322
13.3k
        assoc_type_impls: krate
1323
13.3k
            .assoc_type_impls
1324
13.3k
            .iter()
1325
17.3M
            .filter(|a| state.reached_assoc_type_impls.contains(&a.x.prune_name()))
1326
13.3k
            .cloned()
1327
13.3k
            .collect(),
1328
13.3k
        traits: traits
1329
13.3k
            .into_iter()
1330
1.64M
            .filter(|t| state.reached_bound_traits.contains(&t.x.name))
1331
13.3k
            .collect(),
1332
13.3k
        trait_impls: krate
1333
13.3k
            .trait_impls
1334
13.3k
            .iter()
1335
41.9M
            .filter(|i| state.reached_trait_impls.contains(&i.x.impl_path))
1336
13.3k
            .cloned()
1337
13.3k
            .collect(),
1338
13.3k
        modules,
1339
13.3k
        external_fns: krate.external_fns.clone(),
1340
13.3k
        external_types: krate.external_types.clone(),
1341
13.3k
        path_as_rust_names: krate.path_as_rust_names.clone(),
1342
13.3k
        arch: krate.arch.clone(),
1343
    };
1344
13.3k
    let mut spec_fn_types: Vec<usize> = state.spec_fn_types.into_iter().collect();
1345
13.3k
    spec_fn_types.sort();
1346
13.3k
    let mut fndef_types: Vec<Fun> = state.fndef_types.into_iter().collect();
1347
13.3k
    fndef_types.sort();
1348
13.3k
    let mono_abstract_datatypes = match state.mono_abstract_datatypes {
1349
9.34k
        Some(mono) => {
1350
9.34k
            let mut mono: Vec<MonoTyp> = mono.into_iter().collect();
1351
9.34k
            mono.sort();
1352
9.34k
            Some(mono)
1353
        }
1354
4.04k
        _ => None,
1355
    };
1356
13.3k
    let res_typs = match state.resolve_typs {
1357
9.34k
        Some(r) => Some(r.finish()),
1358
4.04k
        _ => None,
1359
    };
1360
13.3k
    let used_builtins = UsedBuiltins {
1361
13.3k
        uses_array: state.uses_array,
1362
13.3k
        uses_bytestr: state.uses_bytestr,
1363
13.3k
        uses_pointee_metadata: state.uses_pointee_metadata,
1364
13.3k
        uses_ieee_float: state.uses_ieee_float,
1365
13.3k
    };
1366
13.3k
    let prune_info = PruneInfo {
1367
13.3k
        mono_abstract_datatypes,
1368
13.3k
        spec_fn_types,
1369
13.3k
        used_builtins,
1370
13.3k
        fndef_types,
1371
13.3k
        resolved_typs: res_typs,
1372
13.3k
        dyn_traits: state.dyn_traits,
1373
13.3k
    };
1374
13.3k
    (Arc::new(kratex), prune_info)
1375
13.3k
}