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 ¤t_crate.modules { |
905 | 10.0k | root_modules.insert(m.x.path.clone()); |
906 | 10.0k | } |
907 | 189k | for f in ¤t_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 | } |