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