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;
14mod constraint_fragments;
15mod constraint_solving;
16mod constraint_with_env;
17mod cstr2smt2;
18mod format;
19mod graph;
20mod parser;
21mod sexp;
22
23use std::{
24 collections::hash_map::DefaultHasher,
25 fmt::{self, Debug},
26 hash::{Hash, Hasher},
27 io::{self, BufWriter, Write as IOWrite},
28 process::{Command, Stdio},
29 str::FromStr,
30};
31
32pub use constraint::{
33 BinOp, BinRel, Bind, Constant, Constraint, DataCtor, DataDecl, DataField, Expr, Pred,
34 Qualifier, Sort, SortCtor,
35};
36pub use cstr2smt2::is_constraint_satisfiable;
37use derive_where::derive_where;
38pub use parser::parse_constraint_with_kvars;
39#[cfg(feature = "nightly")]
40use rustc_macros::{Decodable, Encodable};
41use serde::{Deserialize, Serialize, de};
42
43pub trait Types {
44 type Sort: Identifier + Hash + Clone + Debug;
45 type KVar: Identifier + Hash + Clone + Debug + Eq;
46 type Var: Identifier + Hash + Clone + Debug + PartialEq;
47 type Decimal: FixpointFmt + Hash + Clone + Debug;
48 type String: FixpointFmt + Hash + Clone + Debug;
49 type Tag: fmt::Display + FromStr + Hash + Clone + Debug;
50}
51
52pub trait FixpointFmt: Sized {
53 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
54
55 fn display(&self) -> impl fmt::Display {
57 struct DisplayAdapter<T>(T);
58 impl<T: FixpointFmt> std::fmt::Display for DisplayAdapter<&T> {
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 FixpointFmt::fmt(self.0, f)
61 }
62 }
63 DisplayAdapter(self)
64 }
65}
66
67pub trait Identifier: Sized {
68 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
69
70 fn display(&self) -> impl fmt::Display {
72 struct DisplayAdapter<T>(T);
73 impl<T: Identifier> fmt::Display for DisplayAdapter<&T> {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75 Identifier::fmt(self.0, f)
76 }
77 }
78 DisplayAdapter(self)
79 }
80}
81
82struct DefaultTypes;
83
84impl Types for DefaultTypes {
85 type Sort = &'static str;
86 type KVar = &'static str;
87 type Var = &'static str;
88 type Tag = String;
89 type Decimal = u32;
90 type String = String;
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 Decimal = $real:ty;
117 type String = $str:ty;
118
119 type Tag = $tag:ty;
120 ) => {
121 pub mod fixpoint_generated {
122 pub struct FixpointTypes;
123 pub type Expr = $crate::Expr<FixpointTypes>;
124 pub type Pred = $crate::Pred<FixpointTypes>;
125 pub type Constraint = $crate::Constraint<FixpointTypes>;
126 pub type KVarDecl = $crate::KVarDecl<FixpointTypes>;
127 pub type ConstDecl = $crate::ConstDecl<FixpointTypes>;
128 pub type FunDef = $crate::FunDef<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 DataDecl = $crate::DataDecl<FixpointTypes>;
134 pub type DataCtor = $crate::DataCtor<FixpointTypes>;
135 pub type DataField = $crate::DataField<FixpointTypes>;
136 pub type Bind = $crate::Bind<FixpointTypes>;
137 pub type Constant = $crate::Constant<FixpointTypes>;
138 pub use $crate::{BinOp, BinRel, ThyFunc};
139 }
140
141 impl $crate::Types for fixpoint_generated::FixpointTypes {
142 type Sort = $sort;
143 type KVar = $kvar;
144 type Var = $var;
145
146 type Decimal = $real;
147 type String = $str;
148
149 type Tag = $tag;
150 }
151 };
152}
153
154#[derive_where(Hash)]
155pub struct ConstDecl<T: Types> {
156 pub name: T::Var,
157 pub sort: Sort<T>,
158 #[derive_where(skip)]
159 pub comment: Option<String>,
160}
161
162#[derive_where(Hash)]
163pub struct FunDef<T: Types> {
164 pub name: T::Var,
165 pub args: Vec<(T::Var, Sort<T>)>,
166 pub out: Sort<T>,
167 pub body: Expr<T>,
168 #[derive_where(skip)]
169 pub comment: Option<String>,
170}
171
172#[derive_where(Hash)]
173pub struct Task<T: Types> {
174 #[derive_where(skip)]
175 pub comments: Vec<String>,
176 pub constants: Vec<ConstDecl<T>>,
177 pub data_decls: Vec<DataDecl<T>>,
178 pub define_funs: Vec<FunDef<T>>,
179 pub kvars: Vec<KVarDecl<T>>,
180 pub constraint: Constraint<T>,
181 pub qualifiers: Vec<Qualifier<T>>,
182 pub scrape_quals: bool,
183 pub solver: SmtSolver,
184}
185
186#[derive(Clone, Copy, Hash)]
187pub enum SmtSolver {
188 Z3,
189 CVC5,
190}
191
192impl fmt::Display for SmtSolver {
193 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
194 match self {
195 SmtSolver::Z3 => write!(f, "z3"),
196 SmtSolver::CVC5 => write!(f, "cvc5"),
197 }
198 }
199}
200
201#[derive(Serialize, Deserialize, Debug, Clone)]
202#[serde(
203 tag = "tag",
204 content = "contents",
205 bound(deserialize = "Tag: FromStr", serialize = "Tag: ToString")
206)]
207pub enum FixpointResult<Tag> {
208 Safe(Stats),
209 Unsafe(Stats, Vec<Error<Tag>>),
210 Crash(CrashInfo),
211}
212
213#[derive(Debug, Clone)]
214pub struct Error<Tag> {
215 pub id: i32,
216 pub tag: Tag,
217}
218
219#[derive(Debug, Serialize, Deserialize, Default, Clone)]
220#[serde(rename_all = "camelCase")]
221pub struct Stats {
222 pub num_cstr: i32,
223 pub num_iter: i32,
224 pub num_chck: i32,
225 pub num_vald: i32,
226}
227
228#[derive(Serialize, Deserialize, Debug, Clone)]
229pub struct CrashInfo(Vec<serde_json::Value>);
230
231#[derive_where(Debug, Clone, Hash)]
232pub struct KVarDecl<T: Types> {
233 pub kvid: T::KVar,
234 pub sorts: Vec<Sort<T>>,
235 #[derive_where(skip)]
236 pub comment: String,
237}
238
239impl<T: Types> Task<T> {
240 pub fn hash_with_default(&self) -> u64 {
241 let mut hasher = DefaultHasher::new();
242 self.hash(&mut hasher);
243 hasher.finish()
244 }
245
246 pub fn run(&self) -> io::Result<FixpointResult<T::Tag>> {
247 let mut child = Command::new("fixpoint")
248 .arg("-q")
249 .arg("--stdin")
250 .arg("--json")
251 .arg("--allowho")
252 .arg("--allowhoqs")
253 .arg(format!("--solver={}", self.solver))
254 .stdin(Stdio::piped())
255 .stdout(Stdio::piped())
256 .stderr(Stdio::piped())
257 .spawn()?;
258 let mut stdin = None;
259 std::mem::swap(&mut stdin, &mut child.stdin);
260 {
261 let mut w = BufWriter::new(stdin.unwrap());
262 writeln!(w, "{self}")?;
263 }
264 let out = child.wait_with_output()?;
265
266 serde_json::from_slice(&out.stdout).map_err(|err| {
267 if !out.stderr.is_empty() {
270 let stderr = std::str::from_utf8(&out.stderr)
271 .unwrap_or("fixpoint exited with a non-zero return code");
272 io::Error::other(stderr)
273 } else {
274 err.into()
275 }
276 })
277 }
278}
279
280impl<T: Types> KVarDecl<T> {
281 pub fn new(kvid: T::KVar, sorts: Vec<Sort<T>>, comment: String) -> Self {
282 Self { kvid, sorts, comment }
283 }
284}
285
286#[derive(Serialize, Deserialize)]
287struct ErrorInner(i32, String);
288
289impl<Tag: ToString> Serialize for Error<Tag> {
290 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
291 where
292 S: serde::Serializer,
293 {
294 ErrorInner(self.id, self.tag.to_string()).serialize(serializer)
295 }
296}
297
298impl<'de, Tag: FromStr> Deserialize<'de> for Error<Tag> {
299 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
300 where
301 D: serde::Deserializer<'de>,
302 {
303 let ErrorInner(id, tag) = Deserialize::deserialize(deserializer)?;
304 let tag = tag
305 .parse()
306 .map_err(|_| de::Error::invalid_value(de::Unexpected::Str(&tag), &"valid tag"))?;
307 Ok(Error { id, tag })
308 }
309}
310
311#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
312#[cfg_attr(feature = "nightly", derive(Encodable, Decodable))]
313pub enum ThyFunc {
314 StrLen,
316
317 BvZeroExtend(u8),
319 BvSignExtend(u8),
320 IntToBv8,
321 Bv8ToInt,
322 IntToBv32,
323 Bv32ToInt,
324 IntToBv64,
325 Bv64ToInt,
326 BvUle,
327 BvSle,
328 BvUge,
329 BvSge,
330 BvUdiv,
331 BvSdiv,
332 BvSrem,
333 BvUrem,
334 BvLshr,
335 BvAshr,
336 BvAnd,
337 BvOr,
338 BvXor,
339 BvNot,
340 BvAdd,
341 BvNeg,
342 BvSub,
343 BvMul,
344 BvShl,
345 BvUgt,
346 BvSgt,
347 BvUlt,
348 BvSlt,
349
350 SetEmpty,
353 SetSng,
355 SetCup,
357 SetMem,
359
360 MapDefault,
363 MapSelect,
365 MapStore,
367}
368
369impl ThyFunc {
370 pub const ALL: [ThyFunc; 37] = [
371 ThyFunc::StrLen,
372 ThyFunc::IntToBv8,
373 ThyFunc::Bv8ToInt,
374 ThyFunc::IntToBv32,
375 ThyFunc::Bv32ToInt,
376 ThyFunc::IntToBv64,
377 ThyFunc::Bv64ToInt,
378 ThyFunc::BvAdd,
379 ThyFunc::BvNeg,
380 ThyFunc::BvSub,
381 ThyFunc::BvShl,
382 ThyFunc::BvLshr,
383 ThyFunc::BvAshr,
384 ThyFunc::BvMul,
385 ThyFunc::BvUdiv,
386 ThyFunc::BvSdiv,
387 ThyFunc::BvUrem,
388 ThyFunc::BvSrem,
389 ThyFunc::BvAnd,
390 ThyFunc::BvOr,
391 ThyFunc::BvXor,
392 ThyFunc::BvNot,
393 ThyFunc::BvUle,
394 ThyFunc::BvSle,
395 ThyFunc::BvUge,
396 ThyFunc::BvSge,
397 ThyFunc::BvUgt,
398 ThyFunc::BvSgt,
399 ThyFunc::BvUlt,
400 ThyFunc::BvSlt,
401 ThyFunc::SetEmpty,
402 ThyFunc::SetSng,
403 ThyFunc::SetCup,
404 ThyFunc::SetMem,
405 ThyFunc::MapDefault,
406 ThyFunc::MapSelect,
407 ThyFunc::MapStore,
408 ];
409}
410
411impl fmt::Display for ThyFunc {
412 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
413 match self {
414 ThyFunc::StrLen => write!(f, "strLen"),
415 ThyFunc::BvZeroExtend(size) => {
416 write!(f, "app (_ zero_extend {size})")
418 }
419 ThyFunc::BvSignExtend(size) => write!(f, "app (_ sign_extend {size})"),
420 ThyFunc::IntToBv32 => write!(f, "int_to_bv32"),
421 ThyFunc::Bv32ToInt => write!(f, "bv32_to_int"),
422 ThyFunc::IntToBv8 => write!(f, "int_to_bv8"),
423 ThyFunc::Bv8ToInt => write!(f, "bv8_to_int"),
424 ThyFunc::IntToBv64 => write!(f, "int_to_bv64"),
425 ThyFunc::Bv64ToInt => write!(f, "bv64_to_int"),
426 ThyFunc::BvUle => write!(f, "bvule"),
427 ThyFunc::BvSle => write!(f, "bvsle"),
428 ThyFunc::BvUge => write!(f, "bvuge"),
429 ThyFunc::BvSge => write!(f, "bvsge"),
430 ThyFunc::BvUdiv => write!(f, "bvudiv"),
431 ThyFunc::BvSdiv => write!(f, "bvsdiv"),
432 ThyFunc::BvUrem => write!(f, "bvurem"),
433 ThyFunc::BvSrem => write!(f, "bvsrem"),
434 ThyFunc::BvLshr => write!(f, "bvlshr"),
435 ThyFunc::BvAshr => write!(f, "bvashr"),
436 ThyFunc::BvAnd => write!(f, "bvand"),
437 ThyFunc::BvOr => write!(f, "bvor"),
438 ThyFunc::BvXor => write!(f, "bvxor"),
439 ThyFunc::BvNot => write!(f, "bvnot"),
440 ThyFunc::BvAdd => write!(f, "bvadd"),
441 ThyFunc::BvNeg => write!(f, "bvneg"),
442 ThyFunc::BvSub => write!(f, "bvsub"),
443 ThyFunc::BvMul => write!(f, "bvmul"),
444 ThyFunc::BvShl => write!(f, "bvshl"),
445 ThyFunc::BvUgt => write!(f, "bvugt"),
446 ThyFunc::BvSgt => write!(f, "bvsgt"),
447 ThyFunc::BvUlt => write!(f, "bvult"),
448 ThyFunc::BvSlt => write!(f, "bvslt"),
449 ThyFunc::SetEmpty => write!(f, "Set_empty"),
450 ThyFunc::SetSng => write!(f, "Set_sng"),
451 ThyFunc::SetCup => write!(f, "Set_cup"),
452 ThyFunc::SetMem => write!(f, "Set_mem"),
453 ThyFunc::MapDefault => write!(f, "Map_default"),
454 ThyFunc::MapSelect => write!(f, "Map_select"),
455 ThyFunc::MapStore => write!(f, "Map_store"),
456 }
457 }
458}