Skip to content

Commit 5e04bf6

Browse files
committed
TC: drain pending TC-constraints before [try_delta]'s tc_reduce check
Closes the parametric-Path-B witness encoding gap that left class- lemma applications at parametric carriers ([apply (addrC<:c poly>)] inside [section ; declare type c <: comring]) unusable. **The bug.** [opentvi] creates a [TCIUni] for each opened tparam's TC bound and posts a [`TcCtt] problem, but doesn't itself drain the queue. The TCIUni stays parked in [tcenv.problems] until something else triggers [unify_core]. Meanwhile a proof-term carrying [(+)<:c poly[TCIUni #a [0;0]]>] arrives at the matcher's [try_delta], which tries [Op.tc_reducible env (+) tys] — and [tc_core_reduce] raises [NotReducible] on TCIUni witnesses, since it can only walk [TCIConcrete]/[TCIAbstract] forms. So [try_delta] falls through to [default]'s [is_conv], which doesn't TC-reduce either; matching fails, [pf_form_match] raises MatchFailure, [t_apply] reports "the given proof-term proves: ... it does not apply to the goal". **The fix.** Two changes: 1. [EcUnify.UniEnv.flush_tc_problems env ue] (new): runs [Unify.unify_core] on a trivial-true [`TyUni] problem, which re-pushes every parked [`TcCtt] in [tcenv.problems] and lets the strategy dispatcher resolve them. After the call, the resolution map contains a witness for every [TCIUni] that any strategy (Modes #1..#6) could pin. 2. In [EcMatching.f_match_core]'s [try_delta]: before destructuring the heads, call [flush_tc_problems env ue] and re-normalise both sides via [norm]. The substitution machinery in [tcw_subst] (ecCoreSubst.ml:209) dereferences resolved TCIUnis through [fs_tw_uni], so after [norm] both forms carry the concrete witness; [tc_reducible] then succeeds and [doit_tc_reduce] produces the renamed structural op (e.g. [polyD] for poly's addgroup-via-class-(+)), which conv'ing against the goal succeeds. Combined with the earlier framework fixes [0dd7d21] (infer-via- abs-decl) and [c182895] (alpha-equivalent chain reuse), this lets [apply (addrC<:c poly> p q)] and [apply (mulrA<:c poly> p q r)] inside a [c <: comring] section discharge directly, without requiring users to fall back to the underlying [polyD_addrC<:c>] / [polyM_mulrA] structural lemmas. The TcPoly port's structural-form workaround in Phase 6 / Phase 7 / smoke test stays as-is for the already-written code, but new code can use the natural class form. Validates: tcalgebra suite (TcMonoid/TcRing/TcInt/TcBigop/TcBigalg/ TcNumber/TcPoly/TcPolySmokeTest) all pass; the parametric Path B reproducer at /tmp/repro_pathb.ec now closes [test_path_b] via [apply (addrC<:c poly>)] without admit.
1 parent edfc385 commit 5e04bf6

3 files changed

Lines changed: 30 additions & 0 deletions

File tree

src/ecMatching.ml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1217,6 +1217,16 @@ let f_match_core opts hyps (ue, ev) f1 f2 =
12171217
let try_delta () =
12181218
if not opts.fm_delta then
12191219
failure ();
1220+
(* Drain pending TC constraints before checking [tc_reducible]:
1221+
a [TCIUni] witness on a TC op-head needs to be committed in
1222+
the resolution map (and then dereferenced via [norm]) for
1223+
[tc_core_reduce] to fire. Without this drain, a parametric-
1224+
carrier proof-term carrying an unresolved [TCIUni] would
1225+
fail to reduce here even when the carrier's TC instance is
1226+
registered in the env. *)
1227+
EcUnify.UniEnv.flush_tc_problems env ue;
1228+
let f1 = norm f1 in
1229+
let f2 = norm f2 in
12201230
match fst_map f_node (destr_app f1),
12211231
fst_map f_node (destr_app f2)
12221232
with

src/ecUnify.ml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -999,6 +999,20 @@ module UniEnv = struct
999999
Unify.check_closed (!ue).ue_uc;
10001000
assubst ue
10011001

1002+
(* Drain the pending TcCtt queue: invokes [Unify.unify_core] on a
1003+
trivially-true [TyUni] problem, which causes the unifier to first
1004+
re-process every parked [TcCtt] in [tcenv.problems]. After this,
1005+
any constraint that the strategies (Mode #1 .. #6) can resolve is
1006+
committed to [tcenv.resolution]. Constraints that defer (ambiguous
1007+
or carrier-with-univars) stay parked. *)
1008+
let flush_tc_problems (env : EcEnv.env) (ue : unienv) : unit =
1009+
if not (TcUni.Muid.is_empty (!ue).ue_uc.tcenv.problems) then
1010+
try
1011+
let trig = tunit in
1012+
let uc = Unify.unify_core env (!ue).ue_uc (`TyUni (trig, trig)) in
1013+
ue := { !ue with ue_uc = uc }
1014+
with UnificationFailure _ -> ()
1015+
10021016
let tparams (ue : unienv) =
10031017
let close = Unify.close (!ue).ue_uc in
10041018
let deref_tc (tc : typeclass) : typeclass =

src/ecUnify.mli

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ module UniEnv : sig
5959
val assubst : unienv -> ty TyUni.Muid.t
6060
val tw_assubst : unienv -> tcwitness TcUni.Muid.t
6161
val tparams : unienv -> ty_params
62+
63+
(* Drain the pending TC-constraint queue, attempting to resolve every
64+
[TcCtt] problem currently parked. Useful before TC-op reduction
65+
attempts (e.g. in matcher's [try_delta]) where a [TCIUni] witness
66+
needs to be committed before [tc_core_reduce] can fire. *)
67+
val flush_tc_problems : EcEnv.env -> unienv -> unit
6268
end
6369

6470
val unify : EcEnv.env -> unienv -> ty -> ty -> unit

0 commit comments

Comments
 (0)