Skip to content

Fix SMT encoding for polymorphic Sequence preconditions (#1201)#1205

Open
PROgram52bc wants to merge 2 commits into
merge-with-main-2026-05-20from
htd/issue-1201-smt-encoding
Open

Fix SMT encoding for polymorphic Sequence preconditions (#1201)#1205
PROgram52bc wants to merge 2 commits into
merge-with-main-2026-05-20from
htd/issue-1201-smt-encoding

Conversation

@PROgram52bc
Copy link
Copy Markdown
Contributor

Summary

  • Fixes SMT encoding errors in #1197 #1201PrecondElim no longer leaves %a in obligations from polymorphic Sequence.* preconditions, and the SMT encoder no longer fails on residual unresolved type variables.
  • Preconditions.lean: derives a call-site type substitution from the actuals' types (with the .op annotation as fallback) and applies it to the substituted precondition expression.
  • SMTEncoder.lean: encodes a leftover .ftvar as a fresh uninterpreted sort instead of returning Unimplemented encoding for type var. Verification reports unknown for those cases (sound, just weaker).

Why this branch

The two failing tests (sha256_compact_indexed.lean, seq_slicing's seqOutOfBoundsSeed) were added in this branch's Boole language-extensions work (#1075) and are what surfaced the bug — main's existing Sequence tests use Core's Sequence.empty<T>() syntax which annotates the .op with a concrete type and masks the bug. A backport PR against main will follow with the same source-file fixes.

Why two changes

Most call sites (e.g. Sequence.select(state_out, 0) with state_out : Sequence bv32) get a concrete substitution from arg types and produce well-typed obligations. The encoder fallback covers the remaining cases the issue calls out: calls inside a polymorphic function body (Seq_lib_insert<T>) and calls whose every argument is itself polymorphic (Sequence.select(Sequence.empty_int, 0)).

Test plan

  • lake build StrataTest — all 614 targets pass.
  • StrataTest/DL/Lambda/PreconditionsTests.lean — added two cases pinning the new behaviour: annotated .op path and argument-type fallback.
  • StrataTest/Languages/Boole/FeatureRequests/seq_slicing.leanseqOutOfBoundsSeed #guard_msgs updated; the SMT encoding error is gone, replaced by unknown.
  • StrataTest/Languages/Boole/FeatureRequests/sha256_compact_indexed.lean#guard_msgs updated to include the new bounds-check obligations (unknown where the procedure has no length precondition, pass where it does).
  • lake test — only pre-existing failure is the ion-java jar fixture, unrelated.

PR #1100 introduced bounds preconditions on `Sequence.select`/`update`/
`take`/`drop`. Their precondition expressions carry the type variable
`%a` (e.g. `Sequence.length(s : Sequence %a)`), and `PrecondElim` runs
before type checking — so `%a` survives into the generated obligation
and the SMT encoder fails with `Unimplemented encoding for type var`.

Two fixes:

- `Lambda.Preconditions.collectWFObligations` now applies a call-site
  type substitution to the substituted precondition. The substitution
  is derived from the actuals' types (via `LFunc.opTypeSubst` /
  argument unification), so a call like `Sequence.select(s, 0)` with
  `s : Sequence bv32` produces an obligation with `Sequence bv32`
  rather than `Sequence %a`.
- `Core.SMTEncoder.LMonoTy.toSMTType` treats unresolved `.ftvar`
  encodings as fresh uninterpreted sorts instead of erroring out. This
  covers the residual cases where no concrete type is reachable (e.g.
  inside a polymorphic function body like `Seq_lib_insert<T>`, or when
  every argument is itself polymorphic). The solver then reports
  `unknown` instead of the verifier crashing.

Tests:

- `PreconditionsTests`: two new cases pinning the new substitution
  behaviour for an annotated `.op` and for the argument-type fallback.
- `seq_slicing`: `seqOutOfBoundsSeed` `#guard_msgs` now reflects the
  bounds-check obligation (now `unknown`, no encoder error).
- `sha256_compact_indexed`: `#guard_msgs` updated to include the new
  bounds obligations (`unknown` for the unproven ones, `pass` where
  contracts already discharge them).
@PROgram52bc
Copy link
Copy Markdown
Contributor Author

PROgram52bc commented May 21, 2026

Seems like a similar fix is needed for main, but the problem is surfaced only on main2 (by tests added in PR #1075).
I think either cherry-picking the specific commit or merging main2 back to main should do it.

@PROgram52bc PROgram52bc requested a review from atomb May 21, 2026 20:15
Copy link
Copy Markdown
Contributor

@MikaelMayer MikaelMayer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖🔍 Clean fix for the polymorphic precondition encoding issue. The two-pronged approach (resolve at the precondition level + graceful fallback in the encoder) is sound. One design concern about code duplication.

Comment thread Strata/DL/Lambda/Preconditions.lean
Address review feedback on #1205: the docstring now explicitly names
`LFunc.computeTypeSubst` in `Factory.lean`, explains why the priority
is reversed (pre- vs. post-typecheck `.op` reliability), and notes
why the two helpers cannot be merged behind a flag without breaking
the `Semantics.lean` proofs that depend on `computeTypeSubst`'s shape.
Copy link
Copy Markdown
Contributor

@MikaelMayer MikaelMayer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖🔍 All previous comments appear addressed — reviewer sign-off still needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants