3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-05-25 11:26:21 +00:00

simplify Go bindings: extract CGo slice conversion helpers

Add three package-internal helper functions in z3.go to eliminate
repeated boilerplate for converting Go slices to CGo arrays:

- exprsToASTs([]*Expr) ([]C.Z3_ast, *C.Z3_ast)
- sortsToCSorts([]*Sort) ([]C.Z3_sort, *C.Z3_sort)
- intsToCs([]int) ([]C.int, *C.int)

Each helper returns both the slice (to keep the backing array alive
during CGo calls) and a pointer to its first element (or nil if empty).
This replaces 13 instances of 4-9 line slice construction patterns.

Also simplify the verbose C.bool assignment pattern in MkQuantifier
and MkQuantifierConst from 5-line if/else blocks to single-line
C.bool(isForall) conversions.

Net: -66 lines in z3.go with no functional changes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
github-actions[bot] 2026-05-04 21:14:37 +00:00 committed by GitHub
parent 1c6943c2cb
commit 0759e2fdde
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -240,6 +240,45 @@ func newExpr(ctx *Context, ptr C.Z3_ast) *Expr {
return expr return expr
} }
// intsToCs converts a []int slice to []C.int, returning the slice and
// a pointer to its first element (nil if empty).
func intsToCs(ints []int) ([]C.int, *C.int) {
if len(ints) == 0 {
return nil, nil
}
cInts := make([]C.int, len(ints))
for i, v := range ints {
cInts[i] = C.int(v)
}
return cInts, &cInts[0]
}
// exprsToASTs converts a []*Expr slice to []C.Z3_ast, returning the slice and
// a pointer to its first element (nil if empty).
func exprsToASTs(exprs []*Expr) ([]C.Z3_ast, *C.Z3_ast) {
if len(exprs) == 0 {
return nil, nil
}
cExprs := make([]C.Z3_ast, len(exprs))
for i, e := range exprs {
cExprs[i] = e.ptr
}
return cExprs, &cExprs[0]
}
// sortsToCSorts converts a []*Sort slice to []C.Z3_sort, returning the slice and
// a pointer to its first element (nil if empty).
func sortsToCSorts(sorts []*Sort) ([]C.Z3_sort, *C.Z3_sort) {
if len(sorts) == 0 {
return nil, nil
}
cSorts := make([]C.Z3_sort, len(sorts))
for i, s := range sorts {
cSorts[i] = s.ptr
}
return cSorts, &cSorts[0]
}
// String returns the string representation of the expression. // String returns the string representation of the expression.
func (e *Expr) String() string { func (e *Expr) String() string {
return C.GoString(C.Z3_ast_to_string(e.ctx.ptr, e.ptr)) return C.GoString(C.Z3_ast_to_string(e.ctx.ptr, e.ptr))
@ -368,11 +407,8 @@ func (c *Context) MkAnd(exprs ...*Expr) *Expr {
if len(exprs) == 1 { if len(exprs) == 1 {
return exprs[0] return exprs[0]
} }
cExprs := make([]C.Z3_ast, len(exprs)) _, cExprsPtr := exprsToASTs(exprs)
for i, e := range exprs { return newExpr(c, C.Z3_mk_and(c.ptr, C.uint(len(exprs)), cExprsPtr))
cExprs[i] = e.ptr
}
return newExpr(c, C.Z3_mk_and(c.ptr, C.uint(len(exprs)), &cExprs[0]))
} }
// MkOr creates a disjunction. // MkOr creates a disjunction.
@ -383,11 +419,8 @@ func (c *Context) MkOr(exprs ...*Expr) *Expr {
if len(exprs) == 1 { if len(exprs) == 1 {
return exprs[0] return exprs[0]
} }
cExprs := make([]C.Z3_ast, len(exprs)) _, cExprsPtr := exprsToASTs(exprs)
for i, e := range exprs { return newExpr(c, C.Z3_mk_or(c.ptr, C.uint(len(exprs)), cExprsPtr))
cExprs[i] = e.ptr
}
return newExpr(c, C.Z3_mk_or(c.ptr, C.uint(len(exprs)), &cExprs[0]))
} }
// MkNot creates a negation. // MkNot creates a negation.
@ -422,38 +455,21 @@ func (c *Context) MkDistinct(exprs ...*Expr) *Expr {
if len(exprs) <= 1 { if len(exprs) <= 1 {
return c.MkTrue() return c.MkTrue()
} }
cExprs := make([]C.Z3_ast, len(exprs)) _, cExprsPtr := exprsToASTs(exprs)
for i, e := range exprs { return newExpr(c, C.Z3_mk_distinct(c.ptr, C.uint(len(exprs)), cExprsPtr))
cExprs[i] = e.ptr
}
return newExpr(c, C.Z3_mk_distinct(c.ptr, C.uint(len(exprs)), &cExprs[0]))
} }
// Pseudo-Boolean / cardinality constraints // Pseudo-Boolean / cardinality constraints
// MkAtMost encodes p1 + p2 + ... + pn <= k. // MkAtMost encodes p1 + p2 + ... + pn <= k.
func (c *Context) MkAtMost(args []*Expr, k uint) *Expr { func (c *Context) MkAtMost(args []*Expr, k uint) *Expr {
cArgs := make([]C.Z3_ast, len(args)) _, cArgsPtr := exprsToASTs(args)
for i, a := range args {
cArgs[i] = a.ptr
}
var cArgsPtr *C.Z3_ast
if len(cArgs) > 0 {
cArgsPtr = &cArgs[0]
}
return newExpr(c, C.Z3_mk_atmost(c.ptr, C.uint(len(args)), cArgsPtr, C.uint(k))) return newExpr(c, C.Z3_mk_atmost(c.ptr, C.uint(len(args)), cArgsPtr, C.uint(k)))
} }
// MkAtLeast encodes p1 + p2 + ... + pn >= k. // MkAtLeast encodes p1 + p2 + ... + pn >= k.
func (c *Context) MkAtLeast(args []*Expr, k uint) *Expr { func (c *Context) MkAtLeast(args []*Expr, k uint) *Expr {
cArgs := make([]C.Z3_ast, len(args)) _, cArgsPtr := exprsToASTs(args)
for i, a := range args {
cArgs[i] = a.ptr
}
var cArgsPtr *C.Z3_ast
if len(cArgs) > 0 {
cArgsPtr = &cArgs[0]
}
return newExpr(c, C.Z3_mk_atleast(c.ptr, C.uint(len(args)), cArgsPtr, C.uint(k))) return newExpr(c, C.Z3_mk_atleast(c.ptr, C.uint(len(args)), cArgsPtr, C.uint(k)))
} }
@ -462,20 +478,8 @@ func (c *Context) MkPBLe(args []*Expr, coeffs []int, k int) *Expr {
if len(args) != len(coeffs) { if len(args) != len(coeffs) {
panic("MkPBLe: args and coeffs must have the same length") panic("MkPBLe: args and coeffs must have the same length")
} }
cArgs := make([]C.Z3_ast, len(args)) _, cArgsPtr := exprsToASTs(args)
for i, a := range args { _, cCoeffsPtr := intsToCs(coeffs)
cArgs[i] = a.ptr
}
cCoeffs := make([]C.int, len(coeffs))
for i, v := range coeffs {
cCoeffs[i] = C.int(v)
}
var cArgsPtr *C.Z3_ast
var cCoeffsPtr *C.int
if len(cArgs) > 0 {
cArgsPtr = &cArgs[0]
cCoeffsPtr = &cCoeffs[0]
}
return newExpr(c, C.Z3_mk_pble(c.ptr, C.uint(len(args)), cArgsPtr, cCoeffsPtr, C.int(k))) return newExpr(c, C.Z3_mk_pble(c.ptr, C.uint(len(args)), cArgsPtr, cCoeffsPtr, C.int(k)))
} }
@ -484,20 +488,8 @@ func (c *Context) MkPBGe(args []*Expr, coeffs []int, k int) *Expr {
if len(args) != len(coeffs) { if len(args) != len(coeffs) {
panic("MkPBGe: args and coeffs must have the same length") panic("MkPBGe: args and coeffs must have the same length")
} }
cArgs := make([]C.Z3_ast, len(args)) _, cArgsPtr := exprsToASTs(args)
for i, a := range args { _, cCoeffsPtr := intsToCs(coeffs)
cArgs[i] = a.ptr
}
cCoeffs := make([]C.int, len(coeffs))
for i, v := range coeffs {
cCoeffs[i] = C.int(v)
}
var cArgsPtr *C.Z3_ast
var cCoeffsPtr *C.int
if len(cArgs) > 0 {
cArgsPtr = &cArgs[0]
cCoeffsPtr = &cCoeffs[0]
}
return newExpr(c, C.Z3_mk_pbge(c.ptr, C.uint(len(args)), cArgsPtr, cCoeffsPtr, C.int(k))) return newExpr(c, C.Z3_mk_pbge(c.ptr, C.uint(len(args)), cArgsPtr, cCoeffsPtr, C.int(k)))
} }
@ -506,20 +498,8 @@ func (c *Context) MkPBEq(args []*Expr, coeffs []int, k int) *Expr {
if len(args) != len(coeffs) { if len(args) != len(coeffs) {
panic("MkPBEq: args and coeffs must have the same length") panic("MkPBEq: args and coeffs must have the same length")
} }
cArgs := make([]C.Z3_ast, len(args)) _, cArgsPtr := exprsToASTs(args)
for i, a := range args { _, cCoeffsPtr := intsToCs(coeffs)
cArgs[i] = a.ptr
}
cCoeffs := make([]C.int, len(coeffs))
for i, v := range coeffs {
cCoeffs[i] = C.int(v)
}
var cArgsPtr *C.Z3_ast
var cCoeffsPtr *C.int
if len(cArgs) > 0 {
cArgsPtr = &cArgs[0]
cCoeffsPtr = &cCoeffs[0]
}
return newExpr(c, C.Z3_mk_pbeq(c.ptr, C.uint(len(args)), cArgsPtr, cCoeffsPtr, C.int(k))) return newExpr(c, C.Z3_mk_pbeq(c.ptr, C.uint(len(args)), cArgsPtr, cCoeffsPtr, C.int(k)))
} }
@ -569,54 +549,26 @@ func (f *FuncDecl) GetRange() *Sort {
// MkFuncDecl creates a function declaration. // MkFuncDecl creates a function declaration.
func (c *Context) MkFuncDecl(name *Symbol, domain []*Sort, range_ *Sort) *FuncDecl { func (c *Context) MkFuncDecl(name *Symbol, domain []*Sort, range_ *Sort) *FuncDecl {
cDomain := make([]C.Z3_sort, len(domain)) _, domainPtr := sortsToCSorts(domain)
for i, s := range domain {
cDomain[i] = s.ptr
}
var domainPtr *C.Z3_sort
if len(domain) > 0 {
domainPtr = &cDomain[0]
}
return newFuncDecl(c, C.Z3_mk_func_decl(c.ptr, name.ptr, C.uint(len(domain)), domainPtr, range_.ptr)) return newFuncDecl(c, C.Z3_mk_func_decl(c.ptr, name.ptr, C.uint(len(domain)), domainPtr, range_.ptr))
} }
// MkRecFuncDecl creates a recursive function declaration. // MkRecFuncDecl creates a recursive function declaration.
// After creating, use AddRecDef to provide the function body. // After creating, use AddRecDef to provide the function body.
func (c *Context) MkRecFuncDecl(name *Symbol, domain []*Sort, range_ *Sort) *FuncDecl { func (c *Context) MkRecFuncDecl(name *Symbol, domain []*Sort, range_ *Sort) *FuncDecl {
cDomain := make([]C.Z3_sort, len(domain)) _, domainPtr := sortsToCSorts(domain)
for i, s := range domain {
cDomain[i] = s.ptr
}
var domainPtr *C.Z3_sort
if len(domain) > 0 {
domainPtr = &cDomain[0]
}
return newFuncDecl(c, C.Z3_mk_rec_func_decl(c.ptr, name.ptr, C.uint(len(domain)), domainPtr, range_.ptr)) return newFuncDecl(c, C.Z3_mk_rec_func_decl(c.ptr, name.ptr, C.uint(len(domain)), domainPtr, range_.ptr))
} }
// AddRecDef adds the definition (body) for a recursive function created with MkRecFuncDecl. // AddRecDef adds the definition (body) for a recursive function created with MkRecFuncDecl.
func (c *Context) AddRecDef(f *FuncDecl, args []*Expr, body *Expr) { func (c *Context) AddRecDef(f *FuncDecl, args []*Expr, body *Expr) {
cArgs := make([]C.Z3_ast, len(args)) _, argsPtr := exprsToASTs(args)
for i, a := range args {
cArgs[i] = a.ptr
}
var argsPtr *C.Z3_ast
if len(args) > 0 {
argsPtr = &cArgs[0]
}
C.Z3_add_rec_def(c.ptr, f.ptr, C.uint(len(args)), argsPtr, body.ptr) C.Z3_add_rec_def(c.ptr, f.ptr, C.uint(len(args)), argsPtr, body.ptr)
} }
// MkApp creates a function application. // MkApp creates a function application.
func (c *Context) MkApp(decl *FuncDecl, args ...*Expr) *Expr { func (c *Context) MkApp(decl *FuncDecl, args ...*Expr) *Expr {
cArgs := make([]C.Z3_ast, len(args)) _, argsPtr := exprsToASTs(args)
for i, a := range args {
cArgs[i] = a.ptr
}
var argsPtr *C.Z3_ast
if len(args) > 0 {
argsPtr = &cArgs[0]
}
return newExpr(c, C.Z3_mk_app(c.ptr, decl.ptr, C.uint(len(args)), argsPtr)) return newExpr(c, C.Z3_mk_app(c.ptr, decl.ptr, C.uint(len(args)), argsPtr))
} }
@ -691,16 +643,8 @@ func (e *Expr) Substitute(from, to []*Expr) *Expr {
// SubstituteVars replaces free variables in the expression with the expressions in to. // SubstituteVars replaces free variables in the expression with the expressions in to.
// Variable with de-Bruijn index i is replaced with to[i]. // Variable with de-Bruijn index i is replaced with to[i].
func (e *Expr) SubstituteVars(to []*Expr) *Expr { func (e *Expr) SubstituteVars(to []*Expr) *Expr {
n := len(to) _, toPtr := exprsToASTs(to)
cTo := make([]C.Z3_ast, n) return newExpr(e.ctx, C.Z3_substitute_vars(e.ctx.ptr, e.ptr, C.uint(len(to)), toPtr))
for i, t := range to {
cTo[i] = t.ptr
}
var toPtr *C.Z3_ast
if n > 0 {
toPtr = &cTo[0]
}
return newExpr(e.ctx, C.Z3_substitute_vars(e.ctx.ptr, e.ptr, C.uint(n), toPtr))
} }
// SubstituteFuns replaces every occurrence of from[i] applied to arguments // SubstituteFuns replaces every occurrence of from[i] applied to arguments
@ -816,12 +760,7 @@ func (q *Quantifier) String() string {
// MkQuantifier creates a quantifier with patterns // MkQuantifier creates a quantifier with patterns
func (c *Context) MkQuantifier(isForall bool, weight int, sorts []*Sort, names []*Symbol, body *Expr, patterns []*Pattern) *Quantifier { func (c *Context) MkQuantifier(isForall bool, weight int, sorts []*Sort, names []*Symbol, body *Expr, patterns []*Pattern) *Quantifier {
var forallInt C.bool forallInt := C.bool(isForall)
if isForall {
forallInt = true
} else {
forallInt = false
}
numBound := len(sorts) numBound := len(sorts)
if numBound != len(names) { if numBound != len(names) {
@ -864,12 +803,7 @@ func (c *Context) MkQuantifier(isForall bool, weight int, sorts []*Sort, names [
// MkQuantifierConst creates a quantifier using constant bound variables // MkQuantifierConst creates a quantifier using constant bound variables
func (c *Context) MkQuantifierConst(isForall bool, weight int, bound []*Expr, body *Expr, patterns []*Pattern) *Quantifier { func (c *Context) MkQuantifierConst(isForall bool, weight int, bound []*Expr, body *Expr, patterns []*Pattern) *Quantifier {
var forallInt C.bool forallInt := C.bool(isForall)
if isForall {
forallInt = true
} else {
forallInt = false
}
numBound := len(bound) numBound := len(bound)
var cBound []C.Z3_app var cBound []C.Z3_app