1#![cfg_attr(feature = "nightly", feature(rustc_private))]
5
6#[cfg(feature = "nightly")]
7extern crate rustc_macros;
8#[cfg(feature = "nightly")]
9extern crate rustc_serialize;
10#[cfg(feature = "nightly")]
11extern crate rustc_span;
12
13mod constraint;
14#[cfg(feature = "rust-fixpoint")]
15mod constraint_fragments;
16#[cfg(feature = "rust-fixpoint")]
17mod constraint_solving;
18mod constraint_with_env;
19#[cfg(feature = "rust-fixpoint")]
20mod cstr2smt2;
21mod format;
22#[cfg(feature = "rust-fixpoint")]
23mod graph;
24pub mod parser;
25pub mod sexp;
26
27use std::{
28 collections::{HashMap, hash_map::DefaultHasher},
29 fmt::{self, Debug},
30 hash::{Hash, Hasher},
31 io,
32 str::FromStr,
33};
34#[cfg(not(feature = "rust-fixpoint"))]
35use std::{
36 io::{BufWriter, Write as IOWrite},
37 process::{Command, Stdio},
38};
39
40pub use constraint::{
41 BinOp, BinRel, Bind, BoundVar, Constant, Constraint, DataCtor, DataDecl, DataField, Expr,
42 FunSort, Pred, Qualifier, Sort, SortCtor, SortDecl,
43};
44use derive_where::derive_where;
45#[cfg(feature = "nightly")]
46use rustc_macros::{Decodable, Encodable};
47use serde::{Deserialize, Serialize, de};
48
49pub type Assignments<'a, T> = HashMap<<T as Types>::KVar, Vec<(&'a Qualifier<T>, Vec<usize>)>>;
51
52#[cfg(feature = "rust-fixpoint")]
53use crate::constraint_with_env::ConstraintWithEnv;
54
55pub trait Types {
56 type Sort: Identifier + Hash + Clone + Debug + Eq;
57 type KVar: Identifier + Hash + Clone + Debug + Eq;
58 type Var: Identifier + Hash + Clone + Debug + Eq;
59 type String: FixpointFmt + Hash + Clone + Debug;
60 type Tag: fmt::Display + FromStr + Hash + Clone + Debug;
61}
62
63pub trait FixpointFmt: Sized {
64 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
65
66 fn display(&self) -> impl fmt::Display {
68 struct DisplayAdapter<T>(T);
69 impl<T: FixpointFmt> std::fmt::Display for DisplayAdapter<&T> {
70 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71 FixpointFmt::fmt(self.0, f)
72 }
73 }
74 DisplayAdapter(self)
75 }
76}
77
78pub trait Identifier: Sized {
79 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
80
81 fn display(&self) -> impl fmt::Display {
83 struct DisplayAdapter<T>(T);
84 impl<T: Identifier> fmt::Display for DisplayAdapter<&T> {
85 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86 Identifier::fmt(self.0, f)
87 }
88 }
89 DisplayAdapter(self)
90 }
91}
92
93impl Identifier for &str {
94 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95 write!(f, "{self}")
96 }
97}
98
99impl FixpointFmt for u32 {
100 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101 write!(f, "{self}")
102 }
103}
104
105impl FixpointFmt for String {
106 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107 write!(f, "\"{self}\"")
108 }
109}
110
111#[macro_export]
112macro_rules! declare_types {
113 ( type Sort = $sort:ty;
114 type KVar = $kvar:ty;
115 type Var = $var:ty;
116 type String = $str:ty;
117 type Tag = $tag:ty;
118 ) => {
119 pub mod fixpoint_generated {
120 pub struct FixpointTypes;
121 pub type Expr = $crate::Expr<FixpointTypes>;
122 pub type Pred = $crate::Pred<FixpointTypes>;
123 pub type Constraint = $crate::Constraint<FixpointTypes>;
124 pub type KVarDecl = $crate::KVarDecl<FixpointTypes>;
125 pub type ConstDecl = $crate::ConstDecl<FixpointTypes>;
126 pub type FunDef = $crate::FunDef<FixpointTypes>;
127 pub type FunSort = $crate::FunSort<FixpointTypes>;
128 pub type FunBody = $crate::FunBody<FixpointTypes>;
129 pub type Task = $crate::Task<FixpointTypes>;
130 pub type Qualifier = $crate::Qualifier<FixpointTypes>;
131 pub type Sort = $crate::Sort<FixpointTypes>;
132 pub type SortCtor = $crate::SortCtor<FixpointTypes>;
133 pub type SortDecl = $crate::SortDecl<FixpointTypes>;
134 pub type DataDecl = $crate::DataDecl<FixpointTypes>;
135 pub type DataCtor = $crate::DataCtor<FixpointTypes>;
136 pub type DataField = $crate::DataField<FixpointTypes>;
137 pub type Bind = $crate::Bind<FixpointTypes>;
138 pub type Constant = $crate::Constant<FixpointTypes>;
139 pub use $crate::{BinOp, BinRel, BoundVar, ThyFunc};
140 }
141
142 impl $crate::Types for fixpoint_generated::FixpointTypes {
143 type Sort = $sort;
144 type KVar = $kvar;
145 type Var = $var;
146 type String = $str;
147 type Tag = $tag;
148 }
149 };
150}
151
152#[derive_where(Hash, Clone, Debug)]
153pub struct ConstDecl<T: Types> {
154 pub name: T::Var,
155 pub sort: Sort<T>,
156 #[derive_where(skip)]
157 pub comment: Option<String>,
158}
159
160#[derive_where(Hash, Debug)]
161pub struct FunDef<T: Types> {
162 pub name: T::Var,
163 pub sort: FunSort<T>,
164 pub body: Option<FunBody<T>>,
165 #[derive_where(skip)]
166 pub comment: Option<String>,
167}
168
169#[derive_where(Hash, Debug)]
170pub struct FunBody<T: Types> {
171 pub args: Vec<T::Var>,
172 pub expr: Expr<T>,
173}
174
175#[derive_where(Hash)]
176pub struct Task<T: Types> {
177 #[derive_where(skip)]
178 pub comments: Vec<String>,
179 pub constants: Vec<ConstDecl<T>>,
180 pub data_decls: Vec<DataDecl<T>>,
181 pub define_funs: Vec<FunDef<T>>,
182 pub kvars: Vec<KVarDecl<T>>,
183 pub constraint: Constraint<T>,
184 pub qualifiers: Vec<Qualifier<T>>,
185 pub scrape_quals: bool,
186 pub solver: SmtSolver,
187}
188
189#[derive(Clone, Copy, Hash)]
190pub enum SmtSolver {
191 Z3,
192 CVC5,
193}
194
195impl fmt::Display for SmtSolver {
196 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197 match self {
198 SmtSolver::Z3 => write!(f, "z3"),
199 SmtSolver::CVC5 => write!(f, "cvc5"),
200 }
201 }
202}
203
204#[derive(Serialize, Deserialize, Debug, Clone)]
205#[serde(
206 tag = "tag",
207 content = "contents",
208 bound(deserialize = "Tag: FromStr", serialize = "Tag: ToString")
209)]
210pub enum FixpointStatus<Tag> {
211 Safe(Stats),
212 Unsafe(Stats, Vec<Error<Tag>>),
213 Crash(CrashInfo),
214}
215
216#[derive(Serialize, Deserialize, Debug, Clone)]
217#[serde(bound(deserialize = "Tag: FromStr", serialize = "Tag: ToString"))]
218pub struct FixpointResult<Tag> {
219 pub status: FixpointStatus<Tag>,
220 pub solution: Vec<KVarBind>,
221 #[serde(rename = "nonCutsSolution")]
222 pub non_cuts_solution: Vec<KVarBind>,
223}
224
225#[derive(Serialize, Deserialize, Debug, Clone)]
226pub struct KVarBind {
227 pub kvar: String,
228 pub val: String,
229}
230
231impl KVarBind {
232 pub fn dump(&self) -> String {
233 format!("{} := {}", self.kvar, self.val)
234 }
235}
236
237impl<Tag> FixpointStatus<Tag> {
238 pub fn is_safe(&self) -> bool {
239 matches!(self, FixpointStatus::Safe(_))
240 }
241
242 pub fn merge(self, other: FixpointStatus<Tag>) -> Self {
243 use FixpointStatus as FR;
244 match (self, other) {
245 (FR::Safe(stats1), FR::Safe(stats2)) => FR::Safe(stats1.merge(&stats2)),
246 (FR::Safe(stats1), FR::Unsafe(stats2, errors)) => {
247 FR::Unsafe(stats1.merge(&stats2), errors)
248 }
249 (FR::Unsafe(stats1, mut errors1), FR::Unsafe(stats2, errors2)) => {
250 errors1.extend(errors2);
251 FR::Unsafe(stats1.merge(&stats2), errors1)
252 }
253 (FR::Unsafe(stats1, errors), FR::Safe(stats2)) => {
254 FR::Unsafe(stats1.merge(&stats2), errors)
255 }
256 (FR::Crash(info1), FR::Crash(info2)) => FR::Crash(info1.merge(info2)),
257 (FR::Crash(info), _) => FR::Crash(info),
258 (_, FR::Crash(info)) => FR::Crash(info),
259 }
260 }
261}
262
263#[derive(Debug, Clone)]
264pub struct Error<Tag> {
265 pub id: i32,
266 pub tag: Tag,
267}
268
269#[derive(Debug, Serialize, Deserialize, Default, Clone)]
270#[serde(rename_all = "camelCase")]
271pub struct Stats {
272 pub num_cstr: i32,
273 pub num_iter: i32,
274 pub num_chck: i32,
275 pub num_vald: i32,
276}
277
278impl Stats {
279 pub fn merge(&self, other: &Stats) -> Self {
280 Stats {
281 num_cstr: self.num_cstr + other.num_cstr,
282 num_iter: self.num_iter + other.num_iter,
283 num_chck: self.num_chck + other.num_chck,
284 num_vald: self.num_vald + other.num_vald,
285 }
286 }
287}
288
289#[derive(Serialize, Deserialize, Debug, Clone)]
290pub struct CrashInfo(Vec<serde_json::Value>);
291
292impl CrashInfo {
293 pub fn merge(self, other: CrashInfo) -> Self {
294 let mut v = self.0;
295 v.extend(other.0);
296 CrashInfo(v)
297 }
298}
299
300#[derive_where(Debug, Clone, Hash)]
301pub struct KVarDecl<T: Types> {
302 pub kvid: T::KVar,
303 pub sorts: Vec<Sort<T>>,
304 #[derive_where(skip)]
305 pub comment: String,
306}
307
308impl<T: Types> Task<T> {
309 pub fn hash_with_default(&self) -> u64 {
310 let mut hasher = DefaultHasher::new();
311 self.hash(&mut hasher);
312 hasher.finish()
313 }
314
315 #[cfg(feature = "rust-fixpoint")]
316 pub fn run(&self) -> io::Result<FixpointResult<T::Tag>> {
317 let mut cstr_with_env = ConstraintWithEnv::new(
318 self.data_decls.clone(),
319 self.kvars.clone(),
320 self.qualifiers.clone(),
321 self.constants.clone(),
322 self.constraint.clone(),
323 );
324 Ok(FixpointResult {
325 status: cstr_with_env.is_satisfiable(),
326 solution: vec![],
327 non_cuts_solution: vec![],
328 })
329 }
330
331 #[cfg(not(feature = "rust-fixpoint"))]
332 pub fn run(&self) -> io::Result<FixpointResult<T::Tag>> {
333 let mut child = Command::new("fixpoint")
334 .arg("-q")
335 .arg("--stdin")
336 .arg("--sortedsolution")
337 .arg("--json")
338 .arg("--allowho")
339 .arg("--allowhoqs")
340 .arg(format!("--solver={}", self.solver))
341 .stdin(Stdio::piped())
342 .stdout(Stdio::piped())
343 .stderr(Stdio::piped())
344 .spawn()?;
345 let mut stdin = None;
346 std::mem::swap(&mut stdin, &mut child.stdin);
347 {
348 let mut w = BufWriter::new(stdin.unwrap());
349 writeln!(w, "{self}")?;
350 }
351 let out = child.wait_with_output()?;
352
353 serde_json::from_slice(&out.stdout).map_err(|err| {
354 if !out.stderr.is_empty() {
357 let stderr = std::str::from_utf8(&out.stderr)
358 .unwrap_or("fixpoint exited with a non-zero return code");
359 io::Error::other(stderr)
360 } else {
361 err.into()
362 }
363 })
364 }
365}
366
367impl<T: Types> KVarDecl<T> {
368 pub fn new(kvid: T::KVar, sorts: Vec<Sort<T>>, comment: String) -> Self {
369 Self { kvid, sorts, comment }
370 }
371}
372
373#[derive(Serialize, Deserialize)]
374struct ErrorInner(i32, String);
375
376impl<Tag: ToString> Serialize for Error<Tag> {
377 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
378 where
379 S: serde::Serializer,
380 {
381 ErrorInner(self.id, self.tag.to_string()).serialize(serializer)
382 }
383}
384
385impl<'de, Tag: FromStr> Deserialize<'de> for Error<Tag> {
386 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
387 where
388 D: serde::Deserializer<'de>,
389 {
390 let ErrorInner(id, tag) = Deserialize::deserialize(deserializer)?;
391 let tag = tag
392 .parse()
393 .map_err(|_| de::Error::invalid_value(de::Unexpected::Str(&tag), &"valid tag"))?;
394 Ok(Error { id, tag })
395 }
396}
397
398#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
399#[cfg_attr(feature = "nightly", derive(Encodable, Decodable))]
400pub enum ThyFunc {
401 StrLen,
403 StrConcat,
404 StrPrefixOf,
405 StrSuffixOf,
406 StrContains,
407
408 BvZeroExtend(u8),
410 BvSignExtend(u8),
411 IntToBv8,
412 Bv8ToInt,
413 IntToBv32,
414 Bv32ToInt,
415 IntToBv64,
416 Bv64ToInt,
417 BvUle,
418 BvSle,
419 BvUge,
420 BvSge,
421 BvUdiv,
422 BvSdiv,
423 BvSrem,
424 BvUrem,
425 BvLshr,
426 BvAshr,
427 BvAnd,
428 BvOr,
429 BvXor,
430 BvNot,
431 BvAdd,
432 BvNeg,
433 BvSub,
434 BvMul,
435 BvShl,
436 BvUgt,
437 BvSgt,
438 BvUlt,
439 BvSlt,
440
441 SetEmpty,
444 SetSng,
446 SetCup,
448 SetCap,
450 SetDif,
452 SetSub,
454 SetMem,
456
457 MapDefault,
460 MapSelect,
462 MapStore,
464}
465
466impl ThyFunc {
467 pub const ALL: [ThyFunc; 44] = [
468 ThyFunc::StrLen,
469 ThyFunc::StrConcat,
470 ThyFunc::StrPrefixOf,
471 ThyFunc::StrSuffixOf,
472 ThyFunc::StrContains,
473 ThyFunc::IntToBv8,
474 ThyFunc::Bv8ToInt,
475 ThyFunc::IntToBv32,
476 ThyFunc::Bv32ToInt,
477 ThyFunc::IntToBv64,
478 ThyFunc::Bv64ToInt,
479 ThyFunc::BvAdd,
480 ThyFunc::BvNeg,
481 ThyFunc::BvSub,
482 ThyFunc::BvShl,
483 ThyFunc::BvLshr,
484 ThyFunc::BvAshr,
485 ThyFunc::BvMul,
486 ThyFunc::BvUdiv,
487 ThyFunc::BvSdiv,
488 ThyFunc::BvUrem,
489 ThyFunc::BvSrem,
490 ThyFunc::BvAnd,
491 ThyFunc::BvOr,
492 ThyFunc::BvXor,
493 ThyFunc::BvNot,
494 ThyFunc::BvUle,
495 ThyFunc::BvSle,
496 ThyFunc::BvUge,
497 ThyFunc::BvSge,
498 ThyFunc::BvUgt,
499 ThyFunc::BvSgt,
500 ThyFunc::BvUlt,
501 ThyFunc::BvSlt,
502 ThyFunc::SetEmpty,
503 ThyFunc::SetSng,
504 ThyFunc::SetCup,
505 ThyFunc::SetMem,
506 ThyFunc::SetCap,
507 ThyFunc::SetDif,
508 ThyFunc::SetSub,
509 ThyFunc::MapDefault,
510 ThyFunc::MapSelect,
511 ThyFunc::MapStore,
512 ];
513}
514
515impl fmt::Display for ThyFunc {
516 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
517 match self {
518 ThyFunc::StrLen => write!(f, "strLen"),
519 ThyFunc::StrConcat => write!(f, "strConcat"),
520 ThyFunc::StrPrefixOf => write!(f, "strPrefixOf"),
521 ThyFunc::StrSuffixOf => write!(f, "strSuffixOf"),
522 ThyFunc::StrContains => write!(f, "strContains"),
523 ThyFunc::BvZeroExtend(size) => {
524 write!(f, "app (_ zero_extend {size})")
526 }
527 ThyFunc::BvSignExtend(size) => write!(f, "app (_ sign_extend {size})"),
528 ThyFunc::IntToBv32 => write!(f, "int_to_bv32"),
529 ThyFunc::Bv32ToInt => write!(f, "bv32_to_int"),
530 ThyFunc::IntToBv8 => write!(f, "int_to_bv8"),
531 ThyFunc::Bv8ToInt => write!(f, "bv8_to_int"),
532 ThyFunc::IntToBv64 => write!(f, "int_to_bv64"),
533 ThyFunc::Bv64ToInt => write!(f, "bv64_to_int"),
534 ThyFunc::BvUle => write!(f, "bvule"),
535 ThyFunc::BvSle => write!(f, "bvsle"),
536 ThyFunc::BvUge => write!(f, "bvuge"),
537 ThyFunc::BvSge => write!(f, "bvsge"),
538 ThyFunc::BvUdiv => write!(f, "bvudiv"),
539 ThyFunc::BvSdiv => write!(f, "bvsdiv"),
540 ThyFunc::BvUrem => write!(f, "bvurem"),
541 ThyFunc::BvSrem => write!(f, "bvsrem"),
542 ThyFunc::BvLshr => write!(f, "bvlshr"),
543 ThyFunc::BvAshr => write!(f, "bvashr"),
544 ThyFunc::BvAnd => write!(f, "bvand"),
545 ThyFunc::BvOr => write!(f, "bvor"),
546 ThyFunc::BvXor => write!(f, "bvxor"),
547 ThyFunc::BvNot => write!(f, "bvnot"),
548 ThyFunc::BvAdd => write!(f, "bvadd"),
549 ThyFunc::BvNeg => write!(f, "bvneg"),
550 ThyFunc::BvSub => write!(f, "bvsub"),
551 ThyFunc::BvMul => write!(f, "bvmul"),
552 ThyFunc::BvShl => write!(f, "bvshl"),
553 ThyFunc::BvUgt => write!(f, "bvugt"),
554 ThyFunc::BvSgt => write!(f, "bvsgt"),
555 ThyFunc::BvUlt => write!(f, "bvult"),
556 ThyFunc::BvSlt => write!(f, "bvslt"),
557 ThyFunc::SetEmpty => write!(f, "Set_empty"),
558 ThyFunc::SetSng => write!(f, "Set_sng"),
559 ThyFunc::SetCup => write!(f, "Set_cup"),
560 ThyFunc::SetCap => write!(f, "Set_cap"),
561 ThyFunc::SetDif => write!(f, "Set_dif"),
562 ThyFunc::SetMem => write!(f, "Set_mem"),
563 ThyFunc::SetSub => write!(f, "Set_sub"),
564 ThyFunc::MapDefault => write!(f, "Map_default"),
565 ThyFunc::MapSelect => write!(f, "Map_select"),
566 ThyFunc::MapStore => write!(f, "Map_store"),
567 }
568 }
569}