Skip to content

Commit 0f6f9a2

Browse files
feat: Add Datatype::update_field, FuncDecl::domain, FuncDecl::range (#455)
Co-authored-by: Mark DenHoed <mark.denhoed@cs.ox.ac.uk>
1 parent d89fdb6 commit 0f6f9a2

File tree

3 files changed

+73
-2
lines changed

3 files changed

+73
-2
lines changed

z3/src/ast/datatype.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::ast::Ast;
2-
use crate::{Context, Sort, Symbol};
2+
use crate::{Context, FuncDecl, Sort, Symbol};
33
use std::ffi::CString;
44
use z3_sys::*;
55

@@ -35,4 +35,30 @@ impl Datatype {
3535
})
3636
}
3737
}
38+
39+
/// Update the field of the given datatype.
40+
///
41+
/// The accessor should be taken from the datatype definition.
42+
pub fn update_field(&self, accessor: &FuncDecl, value: &impl Ast) -> Self {
43+
let c = self.ctx.get_z3_context();
44+
let field_access = accessor.z3_func_decl;
45+
let t = self.z3_ast;
46+
let v = value.get_z3_ast();
47+
48+
// The Z3 docs say that the 1-indexed param should be a datatype,
49+
// but that seems like a typo.
50+
let domain = accessor.domain(0).expect("accessor lacks domain");
51+
assert_eq!(domain, SortKind::Datatype);
52+
53+
let range = accessor.range();
54+
assert_eq!(value.get_sort().kind(), range);
55+
56+
unsafe {
57+
Self::wrap(
58+
&self.ctx,
59+
Z3_datatype_update_field(c, field_access, t, v)
60+
.expect("failed to update field of struct"),
61+
)
62+
}
63+
}
3864
}

z3/src/func_decl.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
use std::borrow::Borrow;
21
use std::convert::TryInto;
32
use std::ffi::CStr;
43
use std::fmt;
4+
use std::{borrow::Borrow, ffi::c_uint};
55
use z3_sys::*;
66

77
use crate::{Context, FuncDecl, Sort, Symbol, Translate, ast, ast::Ast};
@@ -247,6 +247,37 @@ impl FuncDecl {
247247
}
248248
}
249249
}
250+
251+
/// Returns the kind of the `i`-th domain (parameter) of this `FuncDecl`.
252+
///
253+
/// Returns `None` if `i >= |domain|`.
254+
pub fn domain(&self, i: usize) -> Option<SortKind> {
255+
let z3_ctx = self.ctx.z3_ctx.0;
256+
let i = c_uint::try_from(i).unwrap();
257+
258+
let domain_size = unsafe { Z3_get_domain_size(z3_ctx, self.z3_func_decl) };
259+
if i >= domain_size {
260+
return None;
261+
}
262+
263+
Some(unsafe {
264+
Z3_get_sort_kind(
265+
z3_ctx,
266+
Z3_get_domain(z3_ctx, self.z3_func_decl, i).expect("cannot get domain of FuncDecl"),
267+
)
268+
})
269+
}
270+
271+
/// Returns the kind of range (output) of this `FuncDecl`.
272+
pub fn range(&self) -> SortKind {
273+
let z3_ctx = self.ctx.z3_ctx.0;
274+
unsafe {
275+
Z3_get_sort_kind(
276+
z3_ctx,
277+
Z3_get_range(z3_ctx, self.z3_func_decl).expect("cannot get range of FuncDecl"),
278+
)
279+
}
280+
}
250281
}
251282

252283
impl fmt::Display for FuncDecl {

z3/tests/lib.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,17 @@ fn test_datatype_builder() {
794794
.unwrap();
795795
solver.assert(five.eq(&five_two));
796796

797+
let four = ast::Int::from_i64(4);
798+
let just_four = just_five
799+
.as_datatype()
800+
.unwrap()
801+
.update_field(&maybe_int.variants[1].accessors[0], &four);
802+
let four_two = maybe_int.variants[1].accessors[0]
803+
.apply(&[&just_four])
804+
.as_int()
805+
.unwrap();
806+
solver.assert(four.eq(four_two));
807+
797808
assert_eq!(solver.check(), SatResult::Sat);
798809
}
799810

@@ -1464,6 +1475,9 @@ fn test_ast_safe_decl() {
14641475
assert_eq!(x_not.safe_decl().unwrap().kind(), DeclKind::NOT);
14651476

14661477
let f = FuncDecl::new("f", &[&Sort::int()], &Sort::int());
1478+
assert_eq!(f.domain(0), Some(SortKind::Int));
1479+
assert_eq!(f.range(), SortKind::Int);
1480+
14671481
let x = ast::Int::new_const("x");
14681482
let f_x: ast::Int = f.apply(&[&x]).try_into().unwrap();
14691483
let f_x_pattern: Pattern = Pattern::new(&[&f_x]);

0 commit comments

Comments
 (0)