vir/src/resolution_types.rs
Line | Count | Source |
1 | | use crate::ast::{Datatype, DatatypeTransparency, Dt, Path, Primitive, Typ, TypDecoration, TypX}; |
2 | | use crate::ast_visitor::VisitorControlFlow; |
3 | | use std::collections::HashMap; |
4 | | |
5 | | /// Used to determine whether `has_resolved` for a given type is trivial or nontrivial. |
6 | | /// This allows us to avoid cluttering the AIR with useless `assume(has_resolved(...))` |
7 | | /// statements. |
8 | | /// |
9 | | /// There are no soundness consequences for this computation. Any type is safe to "resolve". |
10 | | /// However, if too many types are considered nontrivial, then we end up cluttering the AIR code, |
11 | | /// and if too few types are considered nontrivial, there may be completeness issues. |
12 | | /// Therefore, we err on the side of considering a type nontrivial if we don't know. |
13 | | pub(crate) struct ResolutionTypes { |
14 | | paths: HashMap<Path, bool>, |
15 | | } |
16 | | |
17 | | impl ResolutionTypes { |
18 | 3.68k | pub(crate) fn new(datatypes: &HashMap<Path, Datatype>) -> Self { |
19 | | // We graph dependencies of all datatypes to see which datatypes can "reach" |
20 | | // a `&mut T` type |
21 | 3.68k | let mut graph = crate::reachability::Graph::new(); |
22 | 14.2k | for (path, datatype) in datatypes.iter() { |
23 | 14.2k | graph.add_node(path.clone()); |
24 | 14.2k | match &datatype.x.transparency { |
25 | 4.69k | DatatypeTransparency::Never => { |
26 | 4.69k | // If a datatype is opaque, conservatively assume it might have mut refs |
27 | 4.69k | // (although this is rare) |
28 | 4.69k | graph.add_root(path.clone()); |
29 | 4.69k | } |
30 | | DatatypeTransparency::WhenVisible(_) => { |
31 | 12.6k | for variant in datatype.x.variants.iter() { |
32 | 15.0k | for field in variant.fields.iter() { |
33 | 15.0k | res_typ_visitor( |
34 | 15.0k | &field.a.0, |
35 | | true, |
36 | 10.0k | &mut |resolvedness| match resolvedness { |
37 | 75 | NodeResolve::Yes => { |
38 | 75 | graph.add_root(path.clone()); |
39 | 75 | } |
40 | 10.0k | NodeResolve::DatatypePath(p) => { |
41 | 10.0k | graph.add_edge(p.clone(), path.clone()); |
42 | 10.0k | } |
43 | 0 | NodeResolve::No | NodeResolve::TypArgDependent => {} |
44 | 10.0k | }, |
45 | | ); |
46 | | } |
47 | | } |
48 | | } |
49 | | } |
50 | | } |
51 | 3.68k | Self { paths: graph.into_reachable_set() } |
52 | 3.68k | } |
53 | | |
54 | 108k | pub(crate) fn has_nontrivial_resolve(&self, typ: &Typ) -> bool { |
55 | 108k | let mut res = false; |
56 | 110k | res_typ_visitor(typ, false, &mut |resolvedness| match resolvedness { |
57 | 50.2k | NodeResolve::Yes => { |
58 | 50.2k | res = true; |
59 | 50.2k | } |
60 | 60.2k | NodeResolve::DatatypePath(p) => { |
61 | 60.2k | if self.paths[p] { |
62 | 45.3k | res = true; |
63 | 45.3k | } |
64 | | } |
65 | 0 | NodeResolve::No | NodeResolve::TypArgDependent => {} |
66 | 110k | }); |
67 | 108k | res |
68 | 108k | } |
69 | | } |
70 | | |
71 | | /// Indicates whether a gived node of a Typ tree indicates resolvedness |
72 | | enum NodeResolve { |
73 | | /// Has resolvedness iff a type argument has resolvedness |
74 | | /// (i.e., we need to recurse into type arguments) |
75 | | TypArgDependent, |
76 | | /// Definitely has no resolvedness, no need to recurse (e.g., &T) |
77 | | No, |
78 | | /// Has resolvedness, e.g., &mut T |
79 | | /// Note: Type parameters and other opaque types are assumed to have resolvedness |
80 | | Yes, |
81 | | /// This is a datatype |
82 | | DatatypePath(Path), |
83 | | } |
84 | | |
85 | | /// Returns the NodeResolve for the root node of the Typ |
86 | 198k | fn typ_node_resolvability(t: &Typ) -> NodeResolve { |
87 | 198k | match &**t { |
88 | | TypX::Bool |
89 | | | TypX::Int(_) |
90 | | | TypX::Real |
91 | | | TypX::Float(_) |
92 | | | TypX::SpecFn(..) |
93 | | | TypX::FnDef(..) |
94 | | | TypX::PointeeMetadata(..) |
95 | | | TypX::TypeId |
96 | | | TypX::ConstInt(..) |
97 | | | TypX::ConstBool(..) |
98 | 30.5k | | TypX::Air(..) => NodeResolve::No, |
99 | | |
100 | | TypX::AnonymousClosure(..) | TypX::Datatype(Dt::Tuple(_), ..) | TypX::Boxed(..) => { |
101 | 12.2k | NodeResolve::TypArgDependent |
102 | | } |
103 | | |
104 | 1.67k | TypX::Primitive(primitive, _) => match primitive { |
105 | 1.03k | Primitive::Array | Primitive::Slice => NodeResolve::TypArgDependent, |
106 | 647 | Primitive::StrSlice | Primitive::Ptr | Primitive::Global => NodeResolve::No, |
107 | | }, |
108 | | |
109 | 33.7k | TypX::Decorate(dec, ..) => match dec { |
110 | | TypDecoration::Ref |
111 | | | TypDecoration::Rc |
112 | | | TypDecoration::Arc |
113 | | | TypDecoration::Ghost |
114 | | | TypDecoration::Never |
115 | 26.0k | | TypDecoration::ConstPtr => NodeResolve::No, |
116 | 7.72k | TypDecoration::Box | TypDecoration::Tracked => NodeResolve::TypArgDependent, |
117 | | }, |
118 | | |
119 | 70.2k | TypX::Datatype(Dt::Path(p), ..) => NodeResolve::DatatypePath(p.clone()), |
120 | | |
121 | | TypX::Opaque { .. } |
122 | | | TypX::TypParam(..) |
123 | | | TypX::MutRef(..) |
124 | | | TypX::Dyn(..) |
125 | 50.2k | | TypX::Projection { .. } => NodeResolve::Yes, |
126 | | } |
127 | 198k | } |
128 | | |
129 | 123k | fn res_typ_visitor(typ: &Typ, skip_typ_param: bool, mf: &mut impl FnMut(&NodeResolve)) { |
130 | 209k | crate::ast_visitor::typ_visitor_dfs(typ, &mut |typ| { |
131 | 209k | if skip_typ_param && matches!(&**typ, TypX::TypParam(_)) { |
132 | 10.6k | return VisitorControlFlow::Return; |
133 | 198k | } |
134 | 198k | let res = typ_node_resolvability(typ); |
135 | 198k | match res { |
136 | 57.1k | NodeResolve::No => VisitorControlFlow::Return, |
137 | 21.0k | NodeResolve::TypArgDependent => VisitorControlFlow::Recurse, |
138 | | NodeResolve::Yes => { |
139 | 50.2k | mf(&res); |
140 | 50.2k | VisitorControlFlow::Stop(()) |
141 | | } |
142 | | NodeResolve::DatatypePath(_) => { |
143 | 70.2k | mf(&res); |
144 | 70.2k | VisitorControlFlow::Recurse |
145 | | } |
146 | | } |
147 | 209k | }); _RNCINvNtCs3IMyNV1CYX4_3vir16resolution_types15res_typ_visitorNCNvMB4_NtB4_15ResolutionTypes22has_nontrivial_resolve0E0B6_ Line | Count | Source | 130 | 179k | crate::ast_visitor::typ_visitor_dfs(typ, &mut |typ| { | 131 | 179k | if skip_typ_param && matches!(&**typ, TypX::TypParam(_)) { | 132 | 0 | return VisitorControlFlow::Return; | 133 | 179k | } | 134 | 179k | let res = typ_node_resolvability(typ); | 135 | 179k | match res { | 136 | 51.1k | NodeResolve::No => VisitorControlFlow::Return, | 137 | 17.6k | NodeResolve::TypArgDependent => VisitorControlFlow::Recurse, | 138 | | NodeResolve::Yes => { | 139 | 50.2k | mf(&res); | 140 | 50.2k | VisitorControlFlow::Stop(()) | 141 | | } | 142 | | NodeResolve::DatatypePath(_) => { | 143 | 60.2k | mf(&res); | 144 | 60.2k | VisitorControlFlow::Recurse | 145 | | } | 146 | | } | 147 | 179k | }); |
_RNCINvNtCs3IMyNV1CYX4_3vir16resolution_types15res_typ_visitorNCNvMB4_NtB4_15ResolutionTypes3new0E0B6_ Line | Count | Source | 130 | 30.1k | crate::ast_visitor::typ_visitor_dfs(typ, &mut |typ| { | 131 | 30.1k | if skip_typ_param && matches!(&**typ, TypX::TypParam(_)) { | 132 | 10.6k | return VisitorControlFlow::Return; | 133 | 19.5k | } | 134 | 19.5k | let res = typ_node_resolvability(typ); | 135 | 19.5k | match res { | 136 | 6.06k | NodeResolve::No => VisitorControlFlow::Return, | 137 | 3.37k | NodeResolve::TypArgDependent => VisitorControlFlow::Recurse, | 138 | | NodeResolve::Yes => { | 139 | 75 | mf(&res); | 140 | 75 | VisitorControlFlow::Stop(()) | 141 | | } | 142 | | NodeResolve::DatatypePath(_) => { | 143 | 10.0k | mf(&res); | 144 | 10.0k | VisitorControlFlow::Recurse | 145 | | } | 146 | | } | 147 | 30.1k | }); |
|
148 | 123k | } _RINvNtCs3IMyNV1CYX4_3vir16resolution_types15res_typ_visitorNCNvMB2_NtB2_15ResolutionTypes22has_nontrivial_resolve0EB4_ Line | Count | Source | 129 | 108k | fn res_typ_visitor(typ: &Typ, skip_typ_param: bool, mf: &mut impl FnMut(&NodeResolve)) { | 130 | 108k | crate::ast_visitor::typ_visitor_dfs(typ, &mut |typ| { | 131 | | if skip_typ_param && matches!(&**typ, TypX::TypParam(_)) { | 132 | | return VisitorControlFlow::Return; | 133 | | } | 134 | | let res = typ_node_resolvability(typ); | 135 | | match res { | 136 | | NodeResolve::No => VisitorControlFlow::Return, | 137 | | NodeResolve::TypArgDependent => VisitorControlFlow::Recurse, | 138 | | NodeResolve::Yes => { | 139 | | mf(&res); | 140 | | VisitorControlFlow::Stop(()) | 141 | | } | 142 | | NodeResolve::DatatypePath(_) => { | 143 | | mf(&res); | 144 | | VisitorControlFlow::Recurse | 145 | | } | 146 | | } | 147 | | }); | 148 | 108k | } |
_RINvNtCs3IMyNV1CYX4_3vir16resolution_types15res_typ_visitorNCNvMB2_NtB2_15ResolutionTypes3new0EB4_ Line | Count | Source | 129 | 15.0k | fn res_typ_visitor(typ: &Typ, skip_typ_param: bool, mf: &mut impl FnMut(&NodeResolve)) { | 130 | 15.0k | crate::ast_visitor::typ_visitor_dfs(typ, &mut |typ| { | 131 | | if skip_typ_param && matches!(&**typ, TypX::TypParam(_)) { | 132 | | return VisitorControlFlow::Return; | 133 | | } | 134 | | let res = typ_node_resolvability(typ); | 135 | | match res { | 136 | | NodeResolve::No => VisitorControlFlow::Return, | 137 | | NodeResolve::TypArgDependent => VisitorControlFlow::Recurse, | 138 | | NodeResolve::Yes => { | 139 | | mf(&res); | 140 | | VisitorControlFlow::Stop(()) | 141 | | } | 142 | | NodeResolve::DatatypePath(_) => { | 143 | | mf(&res); | 144 | | VisitorControlFlow::Recurse | 145 | | } | 146 | | } | 147 | | }); | 148 | 15.0k | } |
|