-
Notifications
You must be signed in to change notification settings - Fork 52
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add add option for running why3 though cargo creusot
CLI
#925
Conversation
I like this, we've also discussed a project a while ago to have an engineer link why3 directly into cargo creusot, but this gets us 80% there. |
I improved the spans reported by making sure each mlcfg assignment has an associated span, and each mlcfg The couterexamples are also somewhat buggy but I think has more to do with Why3 than my changes. Why3 doesn't seem to include values of polymorphic types in its counter examples. It also seems to have z3 run Do you think this is still useful enough to merge into Creusot in this state? Should I try to fix the issue with relative spans when not using |
creusot/src/translation/fmir.rs
Outdated
@@ -54,7 +54,7 @@ pub enum Statement<'tcx> { | |||
#[derive(Clone, Debug)] | |||
pub enum RValue<'tcx> { | |||
Ghost(Term<'tcx>), | |||
Borrow(Place<'tcx>), | |||
Borrow(Place<'tcx>, Span), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain the purpose of these specific spans? I can be sold on special casing these, but if possible it would be nice to recover the span from a surrounding Expr
, Statement
or Terminator
.
Oh, with
I noticed. I'm fine with starting with this, but I'd like to push the spans into proper fields in a follow up, copying the structure of MIR (more generally
I'm getting close, all tests compile to MLCFG, and ~30% are still failing during Why3 typechecking. I'm co-chairing at POPL this week but I expect it to be merged sometime the week after.
I'm not sure what these issues are and how crippling they are. I'm generally a fan of smaller PRs anyways, so I'd lean to merge and fix afterwards. |
Overall, I'm positive about this work, but ideally, I'd like the spans in |
It seems like in MIR spans are attached to |
Yes this is reasonable. In general our expressions can correspond to multiple rust statements (due to simplifications or optimizations) so it will probably still make sense to have spans on them. |
# Conflicts: # creusot/src/backend.rs # creusot/tests/should_fail/bug/01_resolve_unsoundness.mlcfg # creusot/tests/should_fail/bug/222.mlcfg # creusot/tests/should_fail/bug/492.mlcfg # creusot/tests/should_fail/bug/692.mlcfg # creusot/tests/should_fail/bug/695.mlcfg # creusot/tests/should_fail/bug/specialize.mlcfg # creusot/tests/should_fail/opaque_unproveable.mlcfg # creusot/tests/should_succeed/100doors.mlcfg # creusot/tests/should_succeed/all_zero.mlcfg # creusot/tests/should_succeed/bdd.mlcfg # creusot/tests/should_succeed/binary_search.mlcfg # creusot/tests/should_succeed/bug/387.mlcfg # creusot/tests/should_succeed/bug/463.mlcfg # creusot/tests/should_succeed/bug/552.mlcfg # creusot/tests/should_succeed/bug/594.mlcfg # creusot/tests/should_succeed/bug/682.mlcfg # creusot/tests/should_succeed/bug/691.mlcfg # creusot/tests/should_succeed/bug/693.mlcfg # creusot/tests/should_succeed/bug/766.mlcfg # creusot/tests/should_succeed/bug/874.mlcfg # creusot/tests/should_succeed/bug/box_borrow_resolve.mlcfg # creusot/tests/should_succeed/bug/eq_panic.mlcfg # creusot/tests/should_succeed/bug/two_phase.mlcfg # creusot/tests/should_succeed/cell/01.mlcfg # creusot/tests/should_succeed/cell/02.mlcfg # creusot/tests/should_succeed/checked_ops.mlcfg # creusot/tests/should_succeed/clones/01.mlcfg # creusot/tests/should_succeed/clones/03.mlcfg # creusot/tests/should_succeed/closures/01_basic.mlcfg # creusot/tests/should_succeed/closures/02_nested.mlcfg # creusot/tests/should_succeed/closures/03_generic_bound.mlcfg # creusot/tests/should_succeed/closures/04_generic_closure.mlcfg # creusot/tests/should_succeed/closures/05_map.mlcfg # creusot/tests/should_succeed/closures/06_fn_specs.mlcfg # creusot/tests/should_succeed/closures/07_mutable_capture.mlcfg # creusot/tests/should_succeed/closures/08_multiple_calls.mlcfg # creusot/tests/should_succeed/constrained_types.mlcfg # creusot/tests/should_succeed/drop_pair.mlcfg # creusot/tests/should_succeed/duration.mlcfg # creusot/tests/should_succeed/filter_positive.mlcfg # creusot/tests/should_succeed/hashmap.mlcfg # creusot/tests/should_succeed/heapsort_generic.mlcfg # creusot/tests/should_succeed/hillel.mlcfg # creusot/tests/should_succeed/immut.mlcfg # creusot/tests/should_succeed/index_range.mlcfg # creusot/tests/should_succeed/inplace_list_reversal.mlcfg # creusot/tests/should_succeed/instant.mlcfg # creusot/tests/should_succeed/invariant_moves.mlcfg # creusot/tests/should_succeed/ite_normalize.mlcfg # creusot/tests/should_succeed/iterators/01_range.mlcfg # creusot/tests/should_succeed/iterators/02_iter_mut.mlcfg # creusot/tests/should_succeed/iterators/03_std_iterators.mlcfg # creusot/tests/should_succeed/iterators/04_skip.mlcfg # creusot/tests/should_succeed/iterators/05_map.mlcfg # creusot/tests/should_succeed/iterators/06_map_precond.mlcfg # creusot/tests/should_succeed/iterators/07_fuse.mlcfg # creusot/tests/should_succeed/iterators/08_collect_extend.mlcfg # creusot/tests/should_succeed/iterators/09_empty.mlcfg # creusot/tests/should_succeed/iterators/10_once.mlcfg # creusot/tests/should_succeed/iterators/11_repeat.mlcfg # creusot/tests/should_succeed/iterators/12_zip.mlcfg # creusot/tests/should_succeed/iterators/13_cloned.mlcfg # creusot/tests/should_succeed/iterators/14_copied.mlcfg # creusot/tests/should_succeed/iterators/15_enumerate.mlcfg # creusot/tests/should_succeed/iterators/16_take.mlcfg # creusot/tests/should_succeed/knapsack.mlcfg # creusot/tests/should_succeed/knapsack_full.mlcfg # creusot/tests/should_succeed/lang/assoc_type.mlcfg # creusot/tests/should_succeed/lang/branch_borrow_2.mlcfg # creusot/tests/should_succeed/lang/modules.mlcfg # creusot/tests/should_succeed/lang/move_path.mlcfg # creusot/tests/should_succeed/lang/while_let.mlcfg # creusot/tests/should_succeed/list_index_mut.mlcfg # creusot/tests/should_succeed/list_reversal_lasso.mlcfg # creusot/tests/should_succeed/loop.mlcfg # creusot/tests/should_succeed/mapping_test.mlcfg # creusot/tests/should_succeed/mutex.mlcfg # creusot/tests/should_succeed/one_side_update.mlcfg # creusot/tests/should_succeed/option.mlcfg # creusot/tests/should_succeed/ord_trait.mlcfg # creusot/tests/should_succeed/projection_toggle.mlcfg # creusot/tests/should_succeed/projections.mlcfg # creusot/tests/should_succeed/prophecy.mlcfg # creusot/tests/should_succeed/red_black_tree.mlcfg # creusot/tests/should_succeed/resolve_uninit.mlcfg # creusot/tests/should_succeed/result/own.mlcfg # creusot/tests/should_succeed/result/result.mlcfg # creusot/tests/should_succeed/rusthorn/inc_max.mlcfg # creusot/tests/should_succeed/rusthorn/inc_max_3.mlcfg # creusot/tests/should_succeed/rusthorn/inc_max_many.mlcfg # creusot/tests/should_succeed/rusthorn/inc_max_repeat.mlcfg # creusot/tests/should_succeed/rusthorn/inc_some_2_list.mlcfg # creusot/tests/should_succeed/rusthorn/inc_some_2_tree.mlcfg # creusot/tests/should_succeed/rusthorn/inc_some_list.mlcfg # creusot/tests/should_succeed/rusthorn/inc_some_tree.mlcfg # creusot/tests/should_succeed/selection_sort_generic.mlcfg # creusot/tests/should_succeed/slices/01.mlcfg # creusot/tests/should_succeed/slices/02_std.mlcfg # creusot/tests/should_succeed/sparse_array.mlcfg # creusot/tests/should_succeed/specification/opaque.mlcfg # creusot/tests/should_succeed/specification/trusted.mlcfg # creusot/tests/should_succeed/split_borrow.mlcfg # creusot/tests/should_succeed/sum.mlcfg # creusot/tests/should_succeed/sum_of_odds.mlcfg # creusot/tests/should_succeed/swap_borrows.mlcfg # creusot/tests/should_succeed/switch.mlcfg # creusot/tests/should_succeed/syntax/04_assoc_prec.mlcfg # creusot/tests/should_succeed/syntax/05_pearlite.mlcfg # creusot/tests/should_succeed/syntax/09_maintains.mlcfg # creusot/tests/should_succeed/syntax/10_mutual_rec_types.mlcfg # creusot/tests/should_succeed/syntax/11_array_types.mlcfg # creusot/tests/should_succeed/syntax/12_ghost_code.mlcfg # creusot/tests/should_succeed/syntax/13_vec_macro.mlcfg # creusot/tests/should_succeed/syntax/derive_macros.mlcfg # creusot/tests/should_succeed/take_first_mut.mlcfg # creusot/tests/should_succeed/trait.mlcfg # creusot/tests/should_succeed/trait_impl.mlcfg # creusot/tests/should_succeed/traits/01.mlcfg # creusot/tests/should_succeed/traits/02.mlcfg # creusot/tests/should_succeed/traits/03.mlcfg # creusot/tests/should_succeed/traits/04.mlcfg # creusot/tests/should_succeed/traits/06.mlcfg # creusot/tests/should_succeed/traits/07.mlcfg # creusot/tests/should_succeed/traits/08.mlcfg # creusot/tests/should_succeed/traits/09.mlcfg # creusot/tests/should_succeed/traits/11.mlcfg # creusot/tests/should_succeed/traits/12_default_method.mlcfg # creusot/tests/should_succeed/traits/13_assoc_types.mlcfg # creusot/tests/should_succeed/traits/16_impl_cloning.mlcfg # creusot/tests/should_succeed/two_modules.mlcfg # creusot/tests/should_succeed/type_invariants/borrows.mlcfg # creusot/tests/should_succeed/type_invariants/generated.mlcfg # creusot/tests/should_succeed/unnest.mlcfg # creusot/tests/should_succeed/vecdeque.mlcfg # creusot/tests/should_succeed/vector/01.mlcfg # creusot/tests/should_succeed/vector/02_gnome.mlcfg # creusot/tests/should_succeed/vector/03_knuth_shuffle.mlcfg # creusot/tests/should_succeed/vector/04_binary_search.mlcfg # creusot/tests/should_succeed/vector/05_binary_search_generic.mlcfg # creusot/tests/should_succeed/vector/06_knights_tour.mlcfg # creusot/tests/should_succeed/vector/07_read_write.mlcfg # creusot/tests/should_succeed/vector/08_haystack.mlcfg # creusot/tests/should_succeed/vector/09_capacity.mlcfg
I modified |
Yes, st the very least this gives us indication of where we can improve things. |
@@ -345,6 +351,60 @@ impl<'tcx> Why3Generator<'tcx> { | |||
_ => false, | |||
} | |||
} | |||
|
|||
pub(crate) fn span_attr(&mut self, span: Span) -> Option<why3::declaration::Attribute> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks
creusot/src/run_why3.rs
Outdated
if false { | ||
// This is necessary for type checking since ThinVec is not nameable | ||
return exp(ExprKind::Call(P(name_to_path(f)), v)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
? I don't understand this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I didn't add this, Rust wasn't able to infer the type for
let mut v = args.into_iter().map(|x| P(x)).collect();
The type is supposed to be ThinVec
but it isn't pub use
d in rustc
so I couldn't just do let mut v: ThinVec<_> = ...
Can we upgrade the
|
Maybe somewhat, but I think it is good to be able to send arbitrary options to Why3. |
I do, but we can also do that in a follow up. |
Many thanks, David, for all the hard work! All in all, I am quite happy with these changes. There is one thing with which I am not very comfortable in this PR. "why3 prove" is usually not the recommended work flow for using Why3 : the generated VCs often require a few transformations (a series of split_vc / use_th are quite common). While I think it is fine to offer a cargo command for "why3 prove", I think that we should also offer one for "why3 ide" (which you already did), and "why3 replay", the two commands mainly used in the session-based work flow. |
Would you like me to add "why3 replay" to this PR, or wait for the follow up where I'll switch |
I think we can wait for the follow up, and in case you aren't aware, there is a plan to add |
Is there anything I should still do before you merge this PR? (aside from merging and blessing) |
I think we can do other work in follow ups |
# Conflicts: # creusot/tests/should_fail/bug/222.mlcfg # creusot/tests/should_fail/bug/492.mlcfg # creusot/tests/should_fail/bug/692.mlcfg # creusot/tests/should_fail/bug/695.mlcfg # creusot/tests/should_succeed/100doors.mlcfg # creusot/tests/should_succeed/all_zero.mlcfg # creusot/tests/should_succeed/bdd.mlcfg # creusot/tests/should_succeed/bug/463.mlcfg # creusot/tests/should_succeed/bug/486.mlcfg # creusot/tests/should_succeed/bug/570.mlcfg # creusot/tests/should_succeed/bug/594.mlcfg # creusot/tests/should_succeed/bug/682.mlcfg # creusot/tests/should_succeed/bug/766.mlcfg # creusot/tests/should_succeed/bug/box_borrow_resolve.mlcfg # creusot/tests/should_succeed/bug/two_phase.mlcfg # creusot/tests/should_succeed/closures/01_basic.mlcfg # creusot/tests/should_succeed/closures/03_generic_bound.mlcfg # creusot/tests/should_succeed/closures/05_map.mlcfg # creusot/tests/should_succeed/closures/06_fn_specs.mlcfg # creusot/tests/should_succeed/closures/07_mutable_capture.mlcfg # creusot/tests/should_succeed/drop_pair.mlcfg # creusot/tests/should_succeed/hashmap.mlcfg # creusot/tests/should_succeed/heapsort_generic.mlcfg # creusot/tests/should_succeed/hillel.mlcfg # creusot/tests/should_succeed/index_range.mlcfg # creusot/tests/should_succeed/inplace_list_reversal.mlcfg # creusot/tests/should_succeed/invariant_moves.mlcfg # creusot/tests/should_succeed/ite_normalize.mlcfg # creusot/tests/should_succeed/iterators/01_range.mlcfg # creusot/tests/should_succeed/iterators/02_iter_mut.mlcfg # creusot/tests/should_succeed/iterators/03_std_iterators.mlcfg # creusot/tests/should_succeed/iterators/04_skip.mlcfg # creusot/tests/should_succeed/iterators/05_map.mlcfg # creusot/tests/should_succeed/iterators/06_map_precond.mlcfg # creusot/tests/should_succeed/iterators/07_fuse.mlcfg # creusot/tests/should_succeed/iterators/08_collect_extend.mlcfg # creusot/tests/should_succeed/iterators/10_once.mlcfg # creusot/tests/should_succeed/iterators/12_zip.mlcfg # creusot/tests/should_succeed/iterators/13_cloned.mlcfg # creusot/tests/should_succeed/iterators/14_copied.mlcfg # creusot/tests/should_succeed/iterators/15_enumerate.mlcfg # creusot/tests/should_succeed/iterators/16_take.mlcfg # creusot/tests/should_succeed/knapsack.mlcfg # creusot/tests/should_succeed/knapsack_full.mlcfg # creusot/tests/should_succeed/lang/branch_borrow_2.mlcfg # creusot/tests/should_succeed/lang/promoted_constants.mlcfg # creusot/tests/should_succeed/list_index_mut.mlcfg # creusot/tests/should_succeed/list_reversal_lasso.mlcfg # creusot/tests/should_succeed/mapping_test.mlcfg # creusot/tests/should_succeed/projection_toggle.mlcfg # creusot/tests/should_succeed/projections.mlcfg # creusot/tests/should_succeed/red_black_tree.mlcfg # creusot/tests/should_succeed/resolve_uninit.mlcfg # creusot/tests/should_succeed/result/own.mlcfg # creusot/tests/should_succeed/rusthorn/inc_max.mlcfg # creusot/tests/should_succeed/rusthorn/inc_max_3.mlcfg # creusot/tests/should_succeed/rusthorn/inc_max_many.mlcfg # creusot/tests/should_succeed/rusthorn/inc_max_repeat.mlcfg # creusot/tests/should_succeed/rusthorn/inc_some_2_list.mlcfg # creusot/tests/should_succeed/rusthorn/inc_some_2_tree.mlcfg # creusot/tests/should_succeed/rusthorn/inc_some_list.mlcfg # creusot/tests/should_succeed/rusthorn/inc_some_tree.mlcfg # creusot/tests/should_succeed/selection_sort_generic.mlcfg # creusot/tests/should_succeed/sparse_array.mlcfg # creusot/tests/should_succeed/split_borrow.mlcfg # creusot/tests/should_succeed/sum.mlcfg # creusot/tests/should_succeed/sum_of_odds.mlcfg # creusot/tests/should_succeed/swap_borrows.mlcfg # creusot/tests/should_succeed/syntax/11_array_types.mlcfg # creusot/tests/should_succeed/syntax/12_ghost_code.mlcfg # creusot/tests/should_succeed/take_first_mut.mlcfg # creusot/tests/should_succeed/type_invariants/borrows.mlcfg # creusot/tests/should_succeed/type_invariants/generated.mlcfg # creusot/tests/should_succeed/type_invariants/non_zero.mlcfg # creusot/tests/should_succeed/type_invariants/quant.mlcfg # creusot/tests/should_succeed/type_invariants/type_invariants.mlcfg # creusot/tests/should_succeed/type_invariants/vec_inv.mlcfg # creusot/tests/should_succeed/unnest.mlcfg # creusot/tests/should_succeed/vector/01.mlcfg # creusot/tests/should_succeed/vector/02_gnome.mlcfg # creusot/tests/should_succeed/vector/03_knuth_shuffle.mlcfg # creusot/tests/should_succeed/vector/06_knights_tour.mlcfg # creusot/tests/should_succeed/vector/07_read_write.mlcfg # creusot/tests/should_succeed/vector/08_haystack.mlcfg # creusot/tests/should_succeed/vector/09_capacity.mlcfg
I merged and blessed the latest changes. Would you be ok to fix the Why3 sessions and merge this? |
sure, but note that 99% of these can be fixed via |
I'm going to merge this. In a follow up PR it would be good to see Once we've figured out the correct workflow and options, I'd like to eventually just have |
I added an experimental
--why3 <CMD>
flag to tocargo creusot
which cause Creusot to run Why3 on the generated mlcfg (automatically including the mlcfg file).Example usages:
cargo creusot --why3 "prove"
TODO, should give a nice error requiring a prover/driver but currently gives a parse errorcargo creusot --why3 "prove -P z3 -a split-vc"
: Runs Creusot and Why3 prove and reports verifications failures as Rust errors usually pointing to appropriate spans, (TODO issue with spans from inside macros)cargo creusot --why3 "prove -P z3-ce -a split-vc"
: Like above but also prints counter examples in a pseudo-Rust syntax (TODO this could be improved by mapping why3 paths to Rust paths).TODO I'm currently using a hack in
printer.rs
to get some spans for assignments but this should also be improvedcargo creusot --why3 "ide"
: Runs creusot and then opens the Why3 ide, (TODO spans don't work because of how I'm using them for "prove" and I need to handle them differently).