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 ¤t_crate.modules { |
909 | 10.1k | root_modules.insert(m.x.path.clone()); |
910 | 10.1k | } |
911 | 207k | for f in ¤t_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 | } |