Skip to content

Commit

Permalink
Fix goals panel when no proof is active on Coq >= 8.16.
Browse files Browse the repository at this point in the history
Traditionally, Coq IDEs used the 'Goals' XML command to get the proof
state, which had the downside that the full details of non-foreground
goals would get serialized from coqidetop but never displayed. In Coq
8.16, the 'Subgoals' command was added, which allows more precise goal
fetching: IDEs can make one Subgoals call to request the focused goal in
full detail, and another call to request just the conclusions of the
other goals. Coqtail switched to this pattern in v1.7.1.

Unfortunately, the logic for merging results from the two calls was
slightly wrong. If the calls return None, then there is no proof in
progress, but the logic in Coqtail handled this as if there is an
in-progress proof with no remaining goals. This made the Goals panel
always show "0 subgoals" even when no proof was in progress.

Fix it. If the first call returns None, there is no proof in progress,
and we don't bother to make the second call. Else, we learned that there
is a proof in progress and what the foreground goal (if any) is; we make
the second call to learn the other goals, and then merge the results and
continue as before.

Fixes c077a72.
  • Loading branch information
jesboat committed Feb 14, 2024
1 parent ede74fb commit 0452064
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 11 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased ([main])

### Fixed
- Fix rendering of goals panel when no proof is active in Coq >= 8.16

## [1.7.1]

### Added
Expand Down
29 changes: 18 additions & 11 deletions python/coqtop.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,8 @@ def subgoals(
"""Get the current set of hypotheses and goals."""
assert self.xml is not None

# Get only the focused goals
# Get the current proof state, but only include focused
# goals in the goal list.
response_main, err_main = self.call(
self.xml.subgoal( # type: ignore
GoalMode.FULL,
Expand All @@ -333,6 +334,13 @@ def subgoals(
if isinstance(response_main, Err):
return (False, response_main.msg, None, err_main)

# If success but we didn't get a CoqGoals, then there's
# no proof in progress. We can return early.
if response_main.val is None:
# If the request was success but it returned None, then
# we're not in a proof. No need to run the second query.
return (True, response_main.msg, None, err_main)

# NOTE: Subgoals ignores `gf_flag = "short"` if proof diffs are
# enabled.
# See: https://github.com/coq/coq/issues/16564
Expand All @@ -356,19 +364,18 @@ def subgoals(
if isinstance(response_extra, Err):
return (False, msgs, None, errs)

assert response_extra.val is not None, \
"proof state changed unexpectedly?"

# Merge goals
fg = response_main.val.fg if response_main.val is not None else []
bg, shelved, given_up = (
(
response_extra.val.bg,
response_extra.val.shelved,
response_extra.val.given_up,
)
if response_extra.val is not None
else ([], [], [])
goals = Goals(
response_main.val.fg,
response_extra.val.bg,
response_extra.val.shelved,
response_extra.val.given_up,
)

return (True, msgs, Goals(fg, bg, shelved, given_up), errs)
return (True, msgs, goals, errs)

def do_option(
self,
Expand Down

0 comments on commit 0452064

Please sign in to comment.