Skip to content

Commit c70fe0c

Browse files
aspiwackmaximedenes
authored andcommitted
Fix rocq-prover#4416: - Incorrect "Error: Incorrect number of goals"
In `Ftactic` the number of results could desynchronise with the number of goals when some goals were solved by side effect in a different branch of a `DISPATCH`. See [coq-bugs#4416](https://coq.inria.fr/bugs/show_bug.cgi?id=4416).
1 parent eb87cda commit c70fe0c

File tree

5 files changed

+41
-4
lines changed

5 files changed

+41
-4
lines changed

lib/monad.ml

+11
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ module type ListS = sig
6464
its second argument in a tail position. *)
6565
val iter : ('a -> unit t) -> 'a list -> unit t
6666

67+
(** Like the regular {!CList.map_filter}. The monadic effects are threaded left*)
68+
val map_filter : ('a -> 'b option t) -> 'a list -> 'b list t
69+
6770

6871
(** {6 Two-list iterators} *)
6972

@@ -138,6 +141,14 @@ module Make (M:Def) : S with type +'a t = 'a M.t = struct
138141
| a::b::l -> f a >> f b >> iter f l
139142

140143

144+
let rec map_filter f = function
145+
| [] -> return []
146+
| a::l ->
147+
f a >>= function
148+
| None -> map_filter f l
149+
| Some b ->
150+
map_filter f l >>= fun filtered ->
151+
return (b::filtered)
141152

142153
let rec fold_left2 r f x l1 l2 =
143154
match l1,l2 with

lib/monad.mli

+3
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ module type ListS = sig
6666
its second argument in a tail position. *)
6767
val iter : ('a -> unit t) -> 'a list -> unit t
6868

69+
(** Like the regular {!CList.map_filter}. The monadic effects are threaded left*)
70+
val map_filter : ('a -> 'b option t) -> 'a list -> 'b list t
71+
6972

7073
(** {6 Two-list iterators} *)
7174

proofs/proofview.ml

+4
Original file line numberDiff line numberDiff line change
@@ -1016,6 +1016,10 @@ module Goal = struct
10161016
in
10171017
tclUNIT (CList.map_filter map step.comb)
10181018

1019+
let unsolved { self=self } =
1020+
tclEVARMAP >>= fun sigma ->
1021+
tclUNIT (not (Option.is_empty (advance sigma self)))
1022+
10191023
(* compatibility *)
10201024
let goal { self=self } = self
10211025

proofs/proofview.mli

+4
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,10 @@ module Goal : sig
466466
(** Recover the list of current goals under focus, without evar-normalization *)
467467
val goals : [ `LZ ] t tactic list tactic
468468

469+
(** [unsolved g] is [true] if [g] is still unsolved in the current
470+
proof state. *)
471+
val unsolved : 'a t -> bool tactic
472+
469473
(** Compatibility: avoid if possible *)
470474
val goal : [ `NF ] t -> Evar.t
471475

tactics/ftactic.ml

+19-4
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,28 @@ let bind (type a) (type b) (m : a t) (f : a -> b t) : b t = m >>= function
2929
| Uniform x ->
3030
(** We dispatch the uniform result on each goal under focus, as we know
3131
that the [m] argument was actually dependent. *)
32-
Proofview.Goal.goals >>= fun l ->
33-
let ans = List.map (fun _ -> x) l in
32+
Proofview.Goal.goals >>= fun goals ->
33+
let ans = List.map (fun g -> (g,x)) goals in
3434
Proofview.tclUNIT ans
35-
| Depends l -> Proofview.tclUNIT l
35+
| Depends l ->
36+
Proofview.Goal.goals >>= fun goals ->
37+
Proofview.tclUNIT (List.combine goals l)
38+
in
39+
(* After the tactic has run, some goals which were previously
40+
produced may have been solved by side effects. The values
41+
attached to such goals must be discarded, otherwise the list of
42+
result would not have the same length as the list of focused
43+
goals, which is an invariant of the [Ftactic] module. It is the
44+
reason why a goal is attached to each result above. *)
45+
let filter (g,x) =
46+
g >>= fun g ->
47+
Proofview.Goal.unsolved g >>= function
48+
| true -> Proofview.tclUNIT (Some x)
49+
| false -> Proofview.tclUNIT None
3650
in
3751
Proofview.tclDISPATCHL (List.map f l) >>= fun l ->
38-
Proofview.tclUNIT (Depends (List.concat l))
52+
Proofview.Monad.List.map_filter filter (List.concat l) >>= fun filtered ->
53+
Proofview.tclUNIT (Depends filtered)
3954

4055
let nf_enter f =
4156
bind (Proofview.Goal.goals >>= fun l -> Proofview.tclUNIT (Depends l))

0 commit comments

Comments
 (0)