Skip to content

Commit 8d04c64

Browse files
committed
merge
2 parents b4d0b9a + 4d1c5a5 commit 8d04c64

File tree

19 files changed

+648
-194
lines changed

19 files changed

+648
-194
lines changed
Lines changed: 351 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,351 @@
1+
use crate::ir_visitor::{Action, Visitor, VisitorData};
2+
use fil_ir::{self as ir, AddCtx, Ctx, DisplayCtx, Foldable};
3+
use fil_utils::GPosIdx;
4+
use itertools::Itertools;
5+
6+
/// Generates default assumptions associated with
7+
/// well-formed programs.
8+
#[derive(Default)]
9+
pub struct Assumptions;
10+
11+
impl Assumptions {
12+
fn transfer_prop(
13+
prop: ir::Foreign<ir::Prop, ir::Component>,
14+
data: &mut VisitorData,
15+
param_bind: &ir::Bind<
16+
ir::Foreign<ir::Param, ir::Component>,
17+
ir::ExprIdx,
18+
>,
19+
event_bind: &ir::Bind<
20+
ir::Foreign<ir::Event, ir::Component>,
21+
ir::TimeIdx,
22+
>,
23+
) -> ir::PropIdx {
24+
if prop.owner() == data.idx {
25+
// The proposition is in the current component,
26+
// use ir::Subst instead of transfer
27+
let prop = prop.key();
28+
prop.fold_with(&mut data.comp, &mut |param| {
29+
param_bind.get(&ir::Foreign::new(param, data.idx)).copied()
30+
})
31+
.fold_with(&mut data.comp, &mut |event| {
32+
event_bind.get(&ir::Foreign::new(event, data.idx)).copied()
33+
})
34+
} else {
35+
// The proposition is in a different component
36+
// Thus, we can use data.mut_ctx.get directly to get the component
37+
prop.transfer_with(
38+
&mut data.comp,
39+
data.mut_ctx.get(prop.owner()),
40+
param_bind,
41+
event_bind,
42+
)
43+
}
44+
}
45+
46+
/// Adds assumptions about the ports in the component
47+
fn port_assumptions(&mut self, data: &mut VisitorData) -> Vec<ir::Command> {
48+
let comp = &mut data.comp;
49+
let mut cmds = Vec::with_capacity(comp.ports().len() * 2);
50+
let ports = comp
51+
.ports()
52+
.iter()
53+
.flat_map(|(_, p)| {
54+
p.live.idxs.iter().copied().zip(p.live.lens.iter().copied())
55+
})
56+
.collect_vec();
57+
58+
// Add assumptions for range of bundle-bound indices
59+
for (idx, len) in ports {
60+
let ir::Param { info, .. } = comp.get(idx);
61+
let bind_loc = if let Some(&ir::info::Param { bind_loc, .. }) =
62+
comp.get(*info).into()
63+
{
64+
bind_loc
65+
} else {
66+
GPosIdx::UNKNOWN
67+
};
68+
69+
let idx = idx.expr(comp);
70+
let start = idx.gte(comp.num(0), comp);
71+
let end = idx.lt(len, comp);
72+
let in_range = start.and(end, comp);
73+
74+
let reason = comp.add(
75+
ir::info::Reason::misc(
76+
"bundle index is within range",
77+
bind_loc,
78+
)
79+
.into(),
80+
);
81+
82+
cmds.extend(comp.assume(in_range, reason))
83+
}
84+
cmds
85+
}
86+
87+
/// Get the parameter binding for an instance
88+
fn param_binding(
89+
&self,
90+
inst: ir::InstIdx,
91+
data: &mut VisitorData,
92+
) -> ir::Bind<ir::Foreign<ir::Param, ir::Component>, ir::ExprIdx> {
93+
let ir::Instance {
94+
comp: idx,
95+
args,
96+
params,
97+
..
98+
} = data.comp.get(inst).clone();
99+
100+
let comp = data.get(idx);
101+
let param_bind = comp
102+
.param_args()
103+
.iter()
104+
.copied()
105+
.chain(comp.exist_params())
106+
.map(|param| ir::Foreign::new(param, idx))
107+
.collect_vec();
108+
109+
let param_args = args
110+
.iter()
111+
.copied()
112+
.chain(params.into_iter().map(|param| param.expr(&mut data.comp)))
113+
.collect_vec();
114+
115+
ir::Bind::new(
116+
param_bind.into_iter().zip(param_args).collect::<Vec<_>>(),
117+
)
118+
}
119+
}
120+
121+
impl Visitor for Assumptions {
122+
fn name() -> &'static str {
123+
"assumptions"
124+
}
125+
126+
fn start(&mut self, data: &mut VisitorData) -> Action {
127+
// Intern all signature-level parameter assumptions
128+
let mut assumptions = Vec::new();
129+
130+
for (prop, loc) in data
131+
.comp
132+
.get_event_asserts()
133+
.iter()
134+
.chain(data.comp.get_param_asserts())
135+
.copied()
136+
.collect_vec()
137+
{
138+
let info = data.comp.add(ir::Info::assert(ir::info::Reason::misc(
139+
"Signature assumption",
140+
loc,
141+
)));
142+
assumptions.extend(data.comp.assume(prop, info))
143+
}
144+
145+
// Add assumptions about the ports in the component
146+
assumptions.extend(self.port_assumptions(data));
147+
148+
Action::AddBefore(assumptions)
149+
}
150+
151+
fn instance(
152+
&mut self,
153+
inst: fil_ir::InstIdx,
154+
data: &mut VisitorData,
155+
) -> Action {
156+
let ir::Instance {
157+
comp: foreign_idx,
158+
info,
159+
..
160+
} = data.comp.get(inst).clone();
161+
162+
let info = data.comp.get(info);
163+
let comp_loc =
164+
if let Some(&ir::info::Instance { comp_loc, .. }) = info.into() {
165+
comp_loc
166+
} else {
167+
GPosIdx::UNKNOWN
168+
};
169+
let mut assumptions = Vec::new();
170+
171+
log::trace!(
172+
"Transferring assumptions for instance {} from comp {} to {}",
173+
data.comp.display(inst),
174+
foreign_idx,
175+
data.idx
176+
);
177+
178+
let param_bind = self.param_binding(inst, data);
179+
180+
let param_asserts = data
181+
.get(foreign_idx)
182+
.get_param_asserts()
183+
.iter()
184+
.copied()
185+
.collect_vec();
186+
187+
// Intern all instance-level param assertions in the foreign component
188+
// as assertions that need to be proved for the current component.
189+
for (prop, loc) in param_asserts {
190+
log::trace!(
191+
"Transferring parameter assumption {} from {} to {}",
192+
data.get(foreign_idx).display(prop),
193+
foreign_idx,
194+
data.idx
195+
);
196+
197+
let prop = ir::Foreign::new(prop, foreign_idx);
198+
199+
let new_prop = Assumptions::transfer_prop(
200+
prop,
201+
data,
202+
&param_bind,
203+
&ir::Bind::new(None),
204+
);
205+
206+
let info = data.comp.add(ir::Info::assert(
207+
ir::info::Reason::param_cons(comp_loc, loc),
208+
));
209+
210+
assumptions.extend(data.comp.assert(new_prop, info))
211+
}
212+
213+
let exist_assumes = data.get(foreign_idx).all_exist_assumes();
214+
215+
// Existential assumptions in the foreign component become
216+
// assumptions in the current component.
217+
for (prop, loc) in exist_assumes {
218+
log::trace!(
219+
"Transferring existential assumption {} from {} to {}",
220+
data.get(foreign_idx).display(prop),
221+
foreign_idx,
222+
data.idx
223+
);
224+
225+
let prop = ir::Foreign::new(prop, foreign_idx);
226+
227+
let new_prop = Assumptions::transfer_prop(
228+
prop,
229+
data,
230+
&param_bind,
231+
&ir::Bind::new(None),
232+
);
233+
234+
let info = data.comp.add(ir::Info::assert(
235+
ir::info::Reason::exist_cons(comp_loc, Some(loc)),
236+
));
237+
238+
assumptions.extend(data.comp.assume(new_prop, info))
239+
}
240+
241+
Action::AddBefore(assumptions)
242+
}
243+
244+
fn invoke(
245+
&mut self,
246+
inv: fil_ir::InvIdx,
247+
data: &mut VisitorData,
248+
) -> Action {
249+
let ir::Invoke {
250+
inst, events, info, ..
251+
} = data.comp.get(inv).clone();
252+
253+
let foreign_idx = inv.comp(&data.comp);
254+
255+
let info: &fil_ir::Info = data.comp.get(info);
256+
let inst_loc =
257+
if let Some(&ir::info::Invoke { inst_loc, .. }) = info.into() {
258+
inst_loc
259+
} else {
260+
GPosIdx::UNKNOWN
261+
};
262+
let mut assumptions = Vec::new();
263+
264+
log::trace!(
265+
"Transferring assumptions for invoke {} from comp {} to {}",
266+
data.comp.display(inv),
267+
foreign_idx,
268+
data.idx
269+
);
270+
271+
let param_bind = self.param_binding(inst, data);
272+
273+
let event_bind = ir::Bind::new(
274+
events
275+
.into_iter()
276+
.map(|ir::EventBind { arg, base, .. }| (base, arg)),
277+
);
278+
// We need to do this separately to avoid borrowing data.comp mutably while it is immutably borrowed.
279+
let event_asserts = data
280+
.get(foreign_idx)
281+
.get_event_asserts()
282+
.iter()
283+
.copied()
284+
.collect_vec();
285+
286+
// Intern all instance-level param assertions in the foreign component
287+
// as assertions that need to be proved for the current component.
288+
for (prop, loc) in event_asserts {
289+
log::trace!(
290+
"Transferring event assertion {} from {} to {}",
291+
data.get(foreign_idx).display(prop),
292+
foreign_idx,
293+
data.idx
294+
);
295+
296+
let prop = ir::Foreign::new(prop, foreign_idx);
297+
298+
let new_prop = Assumptions::transfer_prop(
299+
prop,
300+
data,
301+
&param_bind,
302+
&event_bind,
303+
);
304+
305+
let info = data.comp.add(ir::Info::assert(
306+
ir::info::Reason::event_cons(inst_loc, loc),
307+
));
308+
309+
assumptions.extend(data.comp.assert(new_prop, info))
310+
}
311+
312+
Action::AddBefore(assumptions)
313+
}
314+
315+
fn start_loop(
316+
&mut self,
317+
l: &mut fil_ir::Loop,
318+
data: &mut VisitorData,
319+
) -> Action {
320+
let comp = &mut data.comp;
321+
322+
let ir::Loop {
323+
index, start, end, ..
324+
} = l;
325+
326+
let start = *start;
327+
let end = *end;
328+
let index = *index;
329+
let ir::Param { info, .. } = comp.get(index);
330+
let bind_loc = if let Some(&ir::info::Param { bind_loc, .. }) =
331+
comp.get(*info).into()
332+
{
333+
bind_loc
334+
} else {
335+
GPosIdx::UNKNOWN
336+
};
337+
let index = index.expr(comp);
338+
339+
// Add the assumption that the index is within bounds
340+
let idx_start = index.gte(start, comp);
341+
let idx_end = index.lt(end, comp);
342+
let in_range = idx_start.and(idx_end, comp);
343+
344+
let info = comp.add(
345+
ir::info::Reason::misc("loop index is within range", bind_loc)
346+
.into(),
347+
);
348+
349+
Action::AddBefore(vec![comp.assume(in_range, info).unwrap()])
350+
}
351+
}

0 commit comments

Comments
 (0)