Add FuncSortRef and fix QuantifierRef.sort for lambda expressions - #118
Merged
Conversation
QuantifierRef.sort() hardcoded the Boolean sort, so a lambda expression reported Bool instead of its actual function sort. Return the real sort for lambdas, and introduce FuncSortRef so that function sorts are more than an opaque SortRef. _to_sort_ref now routes function sorts to it, giving every function sort - a lambda's or an uninterpreted function's - the arity(), domain(), domain_n() and range() accessors. Those names mirror Z3Py's ArraySortRef, where lambdas have array sorts, so code inspecting a lambda's sort carries over from Z3Py. cvc5 keeps function and array sorts distinct, so is_array_sort() still reports False for them; add is_func_sort() to test for the new sort. FuncDeclRef.arity/domain/range now delegate to the sort instead of each re-deriving from getSort().getFunction*(), which is behavior-preserving: every FuncDeclRef is built from a function sort. This supersedes cvc5#115. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
daniel-larraz
requested review from
alex-ozdemir
and
a lite review from Copilot
August 12, 2026 13:34
There was a problem hiding this comment.
Pull request overview
This PR fixes sort reporting for lambda expressions and introduces a dedicated wrapper for function sorts so callers can introspect function sort domain/range consistently across lambdas and uninterpreted functions.
Changes:
- Route cvc5 function sorts through a new
FuncSortRefvia_to_sort_ref, exposing.arity(),.domain()/.domain_n(i), and.range(). - Fix
QuantifierRef.sort()to return the actual function sort forLambda(...)instead of hardcodingBool. - Simplify
FuncDeclRef.arity/domain/rangeby delegating toself.sort()’s accessors (centralizing the cvc5 function-sort queries).
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
This was referenced Aug 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
QuantifierRef.sort()hardcoded the Boolean sort, so a lambda expression reportedBoolinstead of its actual function sort:Changes
Returning the real sort is only half the fix:
_to_sort_refhad no branch for function sorts, so the result was an opaqueSortRefwith no way to reach the domain or range. This PR addsFuncSortRefand routes function sorts to it, which gives every function sort — a lambda's or an uninterpreted function's — these accessors:The names deliberately mirror
ArraySortRef. Z3Py models lambdas as arrays, so a lambda's sort there is an array sort and Z3Py code reaches for.domain()/.range()/.domain_n(i); matching those names lets such code carry over. cvc5 keeps function and array sorts genuinely distinct, sois_array_sort()still reportsFalsefor them andStore/Selectremain array-only —is_func_sort()is added to test for the new sort.Finally,
FuncDeclRef.arity/domain/rangenow delegate toself.sort()rather than each re-deriving fromgetSort().getFunction*(). This is behavior-preserving — everyFuncDeclRefis built from a function sort — and puts the three cvc5 calls in one place. The# type: ignorecomments follow the existingArrayRef.domain/rangeprecedent.Relation to #115
This supersedes #115, which fixed the
QuantifierRef.sort()half. That fix alone leavesLambda(...).sort()as a bareSortRef, so Z3Py code calling.domain()/.range()on it trades a wrong answer for anAttributeError. This PR closes that gap. Note also that #115's CI failure is unrelated to its change — it predates c66c2b7 (#116), which updated themultiple_solversexpected output.Testing
test_doc.py: 2080 doctests, 0 failures; the 32 new examples are all collected and passing.test_unit.py: OK.black --check --required-version 24: clean.pyright: 621 errors before and after this change — none new.🤖 Generated with Claude Code