3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-04-03 18:31:08 +00:00

Add Z3_mk_polymorphic_datatype to Python, .NET, Go, and TypeScript bindings (#9181)

* Add Z3_mk_polymorphic_datatype to Python, .NET, Go, and TypeScript bindings

Agent-Logs-Url: https://github.com/Z3Prover/z3/sessions/13ef481d-61f5-47e1-8659-59cd91692fdd

Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>

* Improve Python error message for polymorphic datatype self-reference check

Agent-Logs-Url: https://github.com/Z3Prover/z3/sessions/13ef481d-61f5-47e1-8659-59cd91692fdd

Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
This commit is contained in:
Copilot 2026-03-31 14:15:34 -07:00 committed by GitHub
parent 56eeb5b52c
commit 56a8259717
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 292 additions and 0 deletions

View file

@ -1172,9 +1172,16 @@ export function createApi(Z3: Z3Core, em?: any): Z3HighLevel {
createDatatypes(...datatypes: DatatypeImpl[]): DatatypeSortImpl[] {
return createDatatypes(...datatypes);
},
createPolymorphicDatatype(typeParams: Sort<Name>[], datatype: DatatypeImpl): DatatypeSortImpl {
return createPolymorphicDatatype(typeParams, datatype);
},
},
);
function TypeVariable(name: string): Sort<Name> {
return new SortImpl(check(Z3.mk_type_variable(contextPtr, Z3.mk_string_symbol(contextPtr, name))));
}
////////////////
// Operations //
////////////////
@ -4689,6 +4696,10 @@ export function createApi(Z3: Z3Core, em?: any): Z3HighLevel {
const datatypes = createDatatypes(this);
return datatypes[0];
}
createPolymorphic(typeParams: Sort<Name>[]): DatatypeSort<Name> {
return createPolymorphicDatatype(typeParams, this);
}
}
class DatatypeSortImpl extends SortImpl implements DatatypeSort<Name> {
@ -4845,6 +4856,84 @@ export function createApi(Z3: Z3Core, em?: any): Z3HighLevel {
}
}
function createPolymorphicDatatype(typeParams: Sort<Name>[], datatype: DatatypeImpl): DatatypeSortImpl {
if (!(datatype instanceof DatatypeImpl)) {
throw new Error('Datatype instance expected');
}
const constructors: Z3_constructor[] = [];
try {
for (const [constructorName, fields] of datatype.constructors) {
const fieldNames: string[] = [];
const fieldSorts: Z3_sort[] = [];
const fieldRefs: number[] = [];
for (const [fieldName, fieldSort] of fields) {
fieldNames.push(fieldName);
if (fieldSort instanceof DatatypeImpl) {
// Self-recursive reference
if (fieldSort !== datatype) {
throw new Error(
`Referenced datatype "${fieldSort.name}" is not the polymorphic datatype being created; mutual recursion is not supported in createPolymorphicDatatype`,
);
}
fieldSorts.push(null as any);
fieldRefs.push(0);
} else {
fieldSorts.push((fieldSort as Sort<Name>).ptr);
fieldRefs.push(0);
}
}
const constructor = Z3.mk_constructor(
contextPtr,
Z3.mk_string_symbol(contextPtr, constructorName),
Z3.mk_string_symbol(contextPtr, `is_${constructorName}`),
fieldNames.map(name => Z3.mk_string_symbol(contextPtr, name)),
fieldSorts,
fieldRefs,
);
constructors.push(constructor);
}
const nameSymbol = Z3.mk_string_symbol(contextPtr, datatype.name);
const paramPtrs = typeParams.map(p => p.ptr);
const resultSort = Z3.mk_polymorphic_datatype(contextPtr, nameSymbol, paramPtrs, constructors);
const sortImpl = new DatatypeSortImpl(resultSort);
// Attach constructor, recognizer, and accessor functions dynamically
const numConstructors = sortImpl.numConstructors();
for (let j = 0; j < numConstructors; j++) {
const constructor = sortImpl.constructorDecl(j);
const recognizer = sortImpl.recognizer(j);
const constructorName = constructor.name().toString();
if (constructor.arity() === 0) {
(sortImpl as any)[constructorName] = constructor.call();
} else {
(sortImpl as any)[constructorName] = constructor;
}
(sortImpl as any)[`is_${constructorName}`] = recognizer;
for (let k = 0; k < constructor.arity(); k++) {
const accessor = sortImpl.accessor(j, k);
const accessorName = accessor.name().toString();
(sortImpl as any)[accessorName] = accessor;
}
}
return sortImpl;
} finally {
for (const constructor of constructors) {
Z3.del_constructor(contextPtr, constructor);
}
}
}
class QuantifierImpl<
QVarSorts extends NonEmptySortArray<Name>,
QSort extends BoolSort<Name> | SMTArraySort<Name, QVarSorts>,
@ -5292,6 +5381,7 @@ export function createApi(Z3: Z3Core, em?: any): Z3HighLevel {
Set,
FiniteSet,
Datatype,
TypeVariable,
////////////////
// Operations //

View file

@ -479,6 +479,12 @@ export interface Context<Name extends string = 'main'> {
/** @category Expressions */
readonly Datatype: DatatypeCreation<Name>;
/**
* Create a type variable sort for use as a parameter in polymorphic datatypes.
* @category Sorts
*/
TypeVariable(name: string): Sort<Name>;
////////////////
// Operations //
////////////////
@ -3136,6 +3142,15 @@ export interface Datatype<Name extends string = 'main'> {
* For mutually recursive datatypes, use Context.createDatatypes instead.
*/
create(): DatatypeSort<Name>;
/**
* Create a polymorphic datatype sort with explicit type parameters.
* Type parameters should be sorts created with Context.TypeVariable.
* Self-recursive fields may reference this Datatype object directly.
*
* @param typeParams Array of type variable sorts
*/
createPolymorphic(typeParams: AnySort<Name>[]): DatatypeSort<Name>;
}
/**
@ -3154,6 +3169,17 @@ export interface DatatypeCreation<Name extends string> {
* @returns Array of created DatatypeSort instances
*/
createDatatypes(...datatypes: Datatype<Name>[]): DatatypeSort<Name>[];
/**
* Create a single polymorphic datatype sort with explicit type parameters.
* Type parameters should be sorts created with Context.TypeVariable.
* Self-recursive fields in constructors may reference the Datatype object directly.
*
* @param typeParams Array of type variable sorts
* @param datatype Datatype declaration with constructors
* @returns Created DatatypeSort instance
*/
createPolymorphicDatatype(typeParams: AnySort<Name>[], datatype: Datatype<Name>): DatatypeSort<Name>;
}
/**