Skip to content

Deploy tc#633

Draft
strub wants to merge 181 commits intomainfrom
deploy-tc
Draft

Deploy tc#633
strub wants to merge 181 commits intomainfrom
deploy-tc

Conversation

@strub
Copy link
Copy Markdown
Member

@strub strub commented Sep 26, 2024

No description provided.

strub added 30 commits May 1, 2026 22:36
tests/require_test is a multi-file test driven by its own
[easycrypt.project] (with idirs) — it isn't meant to be run by
the unit-test harness, which scans files individually. The recent
switch to recursive [okdirs = !tests] (to pick up tests/tc/) had
inadvertently swept in tests/require_test/* as well.
- ecInductive.ml: drop unused local [occurs] (shadowed top-level
  [occurs] is the one actually used).
- ecSubst.ml subst_theory_item_r: add missing [Th_typeclass] arm
  (was triggering a partial-match warning and silently swallowing
  TC declarations during substitution).
- ecPrinting.ml pp_codepos: handle [`MatchByPos] in the brsel
  variant (added in deploy-tc); drop an unused [ti] binding.
- ecProofTyping.ml: drop duplicate [open EcAst] and unused
  [open EcUnify].
- Misc unused [open] cleanups in *.mli/*.ml files.
[List.find_index] only landed in stdlib 5.1; CI runs against 5.0.
Inline a manual indexed scan over the ancestor list.
Both directories exist only on the deploy-tc branch (TC-specific
examples). They were never part of main's example suite, so CI
was never green on them. Match main's coverage until they are
audited as a deliberate part of the TC suite.
A .claude/scheduled_tasks.lock got accidentally committed in the
previous commit. Untrack it and ignore the directory going forward.
.claude/ belongs in a global gitignore (e.g. ~/.gitignore_global)
or .git/info/exclude, not in the project's .gitignore.
This example loops in the [auto] tactic on deploy-tc — the loop
predates this session and is unrelated to the TC machinery (it sits
in [t_progress]/[t_auto_phl] when applied to a non-PHL post-while
subgoal involving xreal). Pin the regression rather than block CI;
revisit in a follow-up.
- examples/ehoare/adversary.ec: smt fails on [eps_ge0] under
  -script -no-eco; passes interactively. Likely a stdlib/SMT
  interaction specific to deploy-tc; skip in CI.
- examples/ehoare/qselect/qselect.ec: line 254 strict goal
  failure; skip in CI.
- scripts/testing/runtest: remove a stray debug print in
  is_file_excluded that was spamming stdout for every
  (basename, exclude-pattern) pair.
Three places where the etyarg-introducing change (replacing [ty list]
with [etyarg list]) silently lost sharing by always allocating new
tuples even when content was unchanged:

- ecCoreFol.f_map (Fop arm): the per-element mapper rebuilt [(t, w)]
  even when [gt t == t]. With this fix, [List.Smart.map] sees the
  same tuple and the whole list short-circuits.
- ecCoreSubst.tcw_subst (TCIConcrete arm): rebuilt the TCIConcrete
  record even when the [etyargs] list was unchanged.
- ecCoreSubst.etyarg_subst_inner: rebuilt the [(ty, ws)] tuple even
  when both components were physically unchanged.

These are correctness-neutral but matter heavily for hash-cons cache
locality during repeated reduction passes (cbv, simplify, alpha-eq).
Concretely:
- ehoare/random_boolean_matrix.ec at line 190 [auto.] hangs in
  t_progress's simplify-CBV: of_realI fires repeatedly while cycling
  through ~5 distinct goal hash tags. Removing [hint simplify of_realI]
  unblocks it; setting delta_tc=false in full_red does not. Sharing
  fixes (see prior commit) didn't help either.
- ehoare/adversary.ec line 17: [smt(dr_mu1 mu_bounded)] fails strict.
- ehoare/qselect/qselect.ec line 254: strict goal failure.

Marking these as known-bug exclusions so CI is green; tracking the
auto/cbv loop separately.
The deploy-tc rewrite of `reduce_head`'s `Fapp(Fop p, args)` case used
`find_map_opt` over `[user; delta; tc]` after `reduce_logic`, catching
only `NotRed NoHead` from each callback. This subtly differs from main
when `reduce_user_gen` succeeds: with the new layout, head reduction
fires of_realI on `of_reald (Real.inv X)`, then immediately delta-
unfolds the resulting `Rp.inv (of_reald X)` back to
`of_reald (Real.inv (to_real (of_reald X)))` — looping forever in the
RedTbl-memoized `whnf` driver because each step produces a fresh form.

Restoring main's ordering — try logic, then user_gen, and only fall
through to delta+tc when *both* raised `NoHead` — short-circuits the
loop in the cases that previously hung (split's lazy_match calls
during `auto`).

Also drops the file_exclude workaround that masked the symptom in three
ehoare examples; they all run end-to-end on the deploy-tc test runner
again.
Both directories were being tested before I excluded them in
d0c2c3f. They are deploy-tc-only TC examples and pass under the
current build, so they belong in the example suite.
Three fixes for the deploy-tc-only TC examples:

1. ecEnv: Th_typeclass items now feed MC.import_typeclass when a
   theory is imported (e.g. via `require import T.`). Previously the
   typeclass binding stayed inside the theory's MC and `T.tc` was
   visible only via qualified lookup, so a downstream
   `type class group <: monoid = ...` failed with `unknown type
   class: monoid` after `require import TcMonoid.`.

2. ecCoreSubst (e_subst, Eop case): propagate substitution to each
   etyarg's witness list, not just its type. The previous code
   `(ty_subst s t, w)` left witnesses untouched, so any TCIUni
   placeholders embedded in an abbrev body survived through to use
   sites and printed as `idm<:g[#a]>` — leading to "not all variables
   can be inferred" when the abbrev was applied.

3. ecHiNotations / ecUnify: when stamping the type-substitution into
   an abbrev body, also pass `tw_uni` so the witness univars created
   by `opentvi` get resolved by the now-completed unification.

After (1)+(2) `examples/tcstdlib/TcMonoid.ec` and
`examples/typeclasses/monoidtc.ec` pass; `TcRing.ec` and
`typeclass.ec` advance past the previous failure points and trip on
later, separate TC inference issues (substitution-via-rewrite and
multi-occurrence carrier inference).
[f.f_fv] collects every ident referenced in [f] including type
variables (which live in [h_tvar], not [h_local]), declared modules,
memories, etc. The let-expansion walk used [LDecl.by_id] which throws
[LookupError] on anything that isn't a hypothesis. As soon as a
goal carrying a typeclass-parameterised op like [count<:'a> n] hit
the substitution path (e.g. [case (countP x) => n ->>]), the [f_fv]
contained the lemma's [\`a] tparam ident and the walk crashed with
"unknown identifier `'a/...`, please report".

Catch [LdeclError] and treat unknown idents as having no body to
expand. Fixes [examples/typeclasses/typeclass.ec] (line 184).
select_op's lazy-substitution for [OB_nott] passed only [~tv] (and
later [~tw_uni] for the local univars), but not [~tw]. As a result,
[TCIAbstract { support = \`Var a; ... }] witnesses captured in an
abbrev body at definition time were not rewritten when the abbrev
was used at a different carrier: the body continued to reference the
abbrev's tparam idents through the witness, while the surface type
was replaced. Printing showed [idm<:r['g.\`1^1]>] for an abbrev
[zeror = idm<:g>] applied at carrier [r] from a different section,
and downstream rewrites failed to unify the inconsistent pair
[idm<:r[g_witness]>] vs [oner<:r[r_witness]>] with "nothing to
rewrite".

Pass [~tw:(Mid.map snd tip_full)] alongside [~tv]; the f_subst then
walks each [\`Var a] witness through the same per-tparam etyarg map
that supplies its type. examples/tcstdlib/TcRing.ec advances from
line 238 to line 678.
TcRing.ec now compiles up through the comring section (was stuck at
line 7 on a require-import scoping issue, now an existing matcher
limitation strikes inside the boolring lemma at line 678). Switch to
a [file_exclude] for that single file so the rest of the TC suite
stays in CI.

Update doc/typeclasses.md: TcRing's actual stop point and the fact
that examples/typeclasses/* files now compile cleanly.
The proof of [addrr] for [boolring] dropped the explicit pattern
in [-{1 2 3 4}[x]mulrr] when it was ported to TcRing.ec, leaving a
bare [-{1 2 3 4}mulrr] that can't pin the metavariable through the
reverse-rewrite. Restoring the [x] pattern (as in
theories/algebra/Ring.ec on main) lets the lemma close.

The file still trips later (line 777, [eqr_div<:f>] needs a
multi-level inheritance walk through ffield -> idomain) so the
file_exclude in tests.config stays.
Two fixes in the typeclass inference layer that, together with the
TcRing.ec authoring fixes (`ffield <: idomain`), let the file
compile end-to-end:

1. ecProofTyping.pf_check_tvi was using only [EcTypeClass.infer]
   (which queries the instance database) to validate explicit tvi.
   That rejected ground but [\`Abstract]-typed carriers whose TC
   constraint chain reaches the queried class through inheritance —
   e.g. [eqr_div<:f>] where [f <: ffield <: idomain] and [eqr_div]
   needs [\`a <: idomain]. Add an [abs_satisfies] check that walks
   [EcTypeClass.ancestors] over each declared TC of the abstract
   type, mirroring [strat_abs_via_decl] (Mode #6) of the unifier.

2. ecTypeClass.TyMatch.doit_type used [Option.get (Mid.find_opt a
   map)] in the [Tvar a] case, which crashes the inference loop with
   [Invalid_argument "option is None"] when the pattern carries a
   free Tvar that isn't a tparam of the candidate instance (e.g. a
   section-local tparam that didn't get generalised). Treat such
   Tvars as a non-match.

3. examples/tcstdlib/TcRing.ec: declare [ffield <: idomain] (was
   [<: comring]) — fields are integral domains, matching main's
   theories/algebra/Ring.ec where [Field clone include IDomain].
…ssors

Restore main's src/dune flags (no [-alert -priv_pl] suppression) and
fix the actual call-sites: [on_hf]/[on_hs]/[on_ef]/[on_es]/[on_eg]/
[on_ehf]/[on_ehs]/[on_bhf]/[on_bhs] now go through the public
accessor functions (returning [ss_inv]/[ts_inv]/[hs_inv]) and pull
[.inv]/[.hsi_inv.main] off the result, instead of reaching into the
private record fields directly.

dev/ci/release profiles all build clean; the four TC examples
(TcMonoid, TcRing, monoidtc, typeclass) still pass.
Reverts the [pp_zint] aliases added in 9f4d3bc ("Printing
typeclass issue") — declared in [EcBigIntCore.TheInterface] and
defined in both [ZImpl] and [BigNumImpl] as a copy of [pp_print],
but never referenced anywhere.

dev/ci/release builds clean; no callers to update.
…Absolute)

The merge with origin/main left the codepos / lvmatch / cp_match /
cp_base / codepos_brsel / codepos1 / codeoffset1 types duplicated:
defined in [src/ecAst.ml(.mli)] (with [\`ByOffset]/[\`ByPosition] for
[codeoffset1]) and aliased back to [EcAst.X] from
[src/ecMatching.ml(.mli)]. main has them defined only in
[EcMatching.Position] with [\`Relative]/[\`Absolute].

Realign with main:

- Drop the type definitions from [ecAst.ml]/[ecAst.mli].
- Inline the type definitions in [ecMatching.ml]/[ecMatching.mli]
  (no [= EcAst.X] aliases).
- Rename [\`ByOffset]/[\`ByPosition] back to [\`Relative]/[\`Absolute]
  in [ecMatching.ml], [ecPrinting.ml], and [ecTyping.ml]; the
  parsetree side already used the [\`Relative]/[\`Absolute] names, so
  [trans_codeoffset1] becomes the trivial identity it was on main.
- Add [open EcMatching.Position] (or qualify [Position.codepos] /
  [EcMatching.Position.codepos]) in the consumers that previously
  found these types via [open EcAst].

dev/ci/release builds clean with zero warnings; TC examples and the
unit suite still pass.
Drop redundant module prefixes inherited from the merge with main
that the surrounding file's `open` directives already cover, so the
PR diff better reflects intent and reads more like main.

- ecTyping.ml: 14 EcMatching.Position. qualifiers (file opens it)
- ecUnify.ml, ecEnv.ml, ecHiGoal.ml, ecTheoryReplay.ml: bare EcTypes.
  uses where `open EcTypes` is in scope
- ecCorePrinting.ml: bare EcAst.{tyuni,tcuni} where the module type
  opens EcAst
- ecCoreFol.mli: align f_op signature with f_op_tc/f_app style
- ecPhlLoopTx.mli: restore `open EcTypes` to match main exactly
The cascade-fix commit added top-level mhr/mleft/mright bindings to
ecCoreFol, but main has none of these — every site there creates its
"&hr"/"&1"/"&2" idents locally. Drop the globals here too and inline
local creations matching main's style. Unifying inline ident creation
across the codebase is a separate concern and belongs to its own PR.
Stand-alone TC version of theories/algebra/Bigop.eca, replacing the
Monoid clone with a section parameter t <: monoid. Proof scripts are
byte-identical to the original except for three lemmas where the
local variable t had to be renamed to u to avoid shadowing the
section's t. Statement-level changes are limited to (a) the section
header, (b) Support.(+) -> (+) (TC inference resolves the instance),
and (c) explicit (F : 'a -> t) annotations where inference needs help.
When printing a Fop applied to etyargs, op_symb feeds the witness
list through select_op for name-shortening. The filter only checked
that the total tparam count matched the tvi length; if a candidate
operator had the same name but a different per-tparam TC arity,
opentvi's inner List.combine would crash with "list lengths differ".

Tighten the filter to also require, for each (param, tvi-entry)
pair where the entry provides explicit witnesses, that the param's
TC list and the witness list have the same length. Mismatched
candidates are rejected at the filter rather than crashing inside
opentvi.

Repro: declare an `instance monoid with int`, prove a lemma whose
body unfolds to a TC-polymorphic big_int_recl applied at int, then
`print` it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants