rust_verify_test coverage (7c1d655)

Coverage Report

Created: 2026-07-20 10:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
vir/src/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
}