1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use crate::{
cfgir::absint::*,
parser::ast::Var,
shared::{unique_map::UniqueMap, *},
};
use move_ir_types::location::*;
#[derive(Debug, Clone, Copy)]
pub enum UnavailableReason {
Unassigned,
Moved,
}
#[derive(Clone, Debug)]
pub enum LocalState {
Unavailable(Loc, UnavailableReason),
Available(Loc),
MaybeUnavailable {
available: Loc,
unavailable: Loc,
unavailable_reason: UnavailableReason,
},
}
impl LocalState {
pub fn is_available(&self) -> bool {
match self {
LocalState::Available(_) => true,
LocalState::Unavailable(_, _) | LocalState::MaybeUnavailable { .. } => false,
}
}
}
#[derive(Clone, Debug)]
pub struct LocalStates {
local_states: UniqueMap<Var, LocalState>,
}
impl LocalStates {
pub fn initial<T>(function_arguments: &[(Var, T)], local_types: &UniqueMap<Var, T>) -> Self {
let mut states = LocalStates {
local_states: UniqueMap::new(),
};
for (var, _) in local_types.key_cloned_iter() {
let local_state = LocalState::Unavailable(var.loc(), UnavailableReason::Unassigned);
states.set_state(var, local_state)
}
for (var, _) in function_arguments {
let local_state = LocalState::Available(var.loc());
states.set_state(*var, local_state)
}
states
}
pub fn get_state(&self, local: &Var) -> &LocalState {
self.local_states
.get(local)
.unwrap_or_else(|| panic!("ICE: Unable to get state for local {:#?}", local))
}
pub fn set_state(&mut self, local: Var, state: LocalState) {
self.local_states.remove(&local);
self.local_states.add(local, state).unwrap();
}
pub fn iter(&self) -> impl Iterator<Item = (Var, &LocalState)> {
self.local_states.key_cloned_iter()
}
#[allow(dead_code)]
pub fn debug(&self) {
use LocalState as L;
for (var, state) in self.iter() {
print!("{}: ", var);
match state {
L::Unavailable(_, _) => println!("Unavailable"),
L::Available(_) => println!("Available"),
L::MaybeUnavailable { .. } => println!("MaybeUnavailable"),
}
}
}
}
impl AbstractDomain for LocalStates {
fn join(&mut self, other: &Self) -> JoinResult {
use LocalState as L;
let mut result = JoinResult::Unchanged;
for (local, other_state) in other.local_states.key_cloned_iter() {
match (self.get_state(&local), other_state) {
(L::Unavailable(_, _), L::Unavailable(_, _))
| (L::Available(_), L::Available(_))
| (L::MaybeUnavailable { .. }, L::MaybeUnavailable { .. }) => (),
(L::MaybeUnavailable { .. }, _) => (),
(_, L::MaybeUnavailable { .. }) => {
result = JoinResult::Changed;
let state = other_state.clone();
self.set_state(local, state)
}
(L::Available(available), L::Unavailable(unavailable, reason))
| (L::Unavailable(unavailable, reason), L::Available(available)) => {
result = JoinResult::Changed;
let available = *available;
let unavailable = *unavailable;
let state = L::MaybeUnavailable {
available,
unavailable,
unavailable_reason: *reason,
};
self.set_state(local, state)
}
}
}
result
}
}