Skip to content

Generate :exhaust for simple properties. #1848

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Apr 29, 2025
Merged

Conversation

ChrisEPhifer
Copy link
Contributor

@ChrisEPhifer ChrisEPhifer commented Apr 28, 2025

Closes #1842.

This works by adding Text of the form:

```
:exhaust p
```

To the list of docstrings extracted from a module's Decls, when p is a Bit-typed declaration that has the property Pragma.

I wasn't set up to run every test in the regression suite (particularly those requiring CVC4/CVC5/Bitwuzla/Yices); I've marked this as a draft for now, and will use CI to determine which (if any) additional golden/.stdout files I need to update.

@ChrisEPhifer ChrisEPhifer added this to the ASAP milestone Apr 28, 2025
@ChrisEPhifer ChrisEPhifer requested a review from yav April 28, 2025 10:57
@ChrisEPhifer ChrisEPhifer self-assigned this Apr 28, 2025
@ChrisEPhifer ChrisEPhifer linked an issue Apr 28, 2025 that may be closed by this pull request
@ChrisEPhifer ChrisEPhifer changed the title Draft: Generate :ensure for simple properties. Generate :ensure for simple properties. Apr 28, 2025
@ChrisEPhifer
Copy link
Contributor Author

OK, CI seems happy, so I think this is ready for review / to be merged.

@RyanGlScott
Copy link
Contributor

I think I'm missing something: what is the :ensure command mentioned in the PR title? Did you mean to say ":exhaust", or is :ensure something different entirely?

@ChrisEPhifer
Copy link
Contributor Author

I think I'm missing something: what is the :ensure command mentioned in the PR title? Did you mean to say ":exhaust", or is :ensure something different entirely?

... Oops. You're right, sorry. Let's not think too hard about what time it is on the west coast...

@ChrisEPhifer ChrisEPhifer changed the title Generate :ensure for simple properties. Generate :exhaust for simple properties. Apr 28, 2025
Copy link
Contributor

@RyanGlScott RyanGlScott left a comment

Choose a reason for hiding this comment

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

This looks reasonable at a quick glance. I think it would be worth mentioning the fact that Cryptol implicitly :exhausts Bool-typed properties somewhere in the Documentation Comments section of the Cryptol user manual, however.

Comment on lines 15 to 18
:exhaust p
Using exhaustive testing.
Testing... Passed 1 tests.
Q.E.D.
Copy link
Contributor

Choose a reason for hiding this comment

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

This example already has an explicit :exhaust pragma in the docstrings:

```
:exhaust p
```

As such, this runs :exhaust p twice (you can see the output of the other :exhaust p invocation above). Is it possible to detect examples like this to avoid redundantly running :exhaust again?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea. I can poke around at the code consuming the gathered-up docstrings / see about de-duplicating what's extracted there, rather than trying to detect this based on the docstring text itself.

Copy link
Member

@yav yav Apr 28, 2025

Choose a reason for hiding this comment

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

How about we change the rule to be "if a piece of code has no code blocks and it is of type Bit, then add an implicit :exhaust" otherwise leave it alone. So this is a kind of default action for things of type Bit but if the user adds a code block, then they can say explicitly say what they want to do, so we don't add an implicit one as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh sure! If that's an acceptable adjustment to what we originally wanted, it's definitely an easy way to avoid duplicates without any kind of janky cleanup after gathering up / extracting all the code blocks.

I'll adjust what I had queued up re: changes to the reference manual and implement this check instead.

Copy link
Contributor Author

@ChrisEPhifer ChrisEPhifer Apr 28, 2025

Choose a reason for hiding this comment

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

Actually -- We don't know about the structure of the docstring code blocks until the extraction is done, so we'll have to move some of this into the REPL.Command module.

I was hoping to just replace <> with <|> where I'm adding the new doctring test, but this is too aggressive, as it'll skip adding the :exhaust if there are any docstring comments, even if there are no other code fences,

Pay no mind, I'm silly :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@@ -22,12 +22,32 @@ Checking module T10
Docstrings on T10::where_at__30_11::N
Docstrings on T10::F1::N
Docstrings on T10::M::q
:exhaust q
Copy link
Contributor

Choose a reason for hiding this comment

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

Relatedly, I wonder if this output should say something like ":exhaust q (implicit)" or some such to indicate that this is running due to the implicit behavior of how :check-docstrings works, rather than an explicit directive in the docstrings themselves.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Member

@yav yav left a comment

Choose a reason for hiding this comment

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

Looks good to me, but let's do the fix where we only add the :exhaust if there's no user-defined code blocks.

We should also update the docs, and the CHANGES files before merging.

If the given declaration is of Bit (Boolean) type and a property, return a
docstring code fence that uses :exhaust to validate the property.

Note that we return a Maybe value in order to easily integrate with the existing
declaration docstring handling.
Straightforward use of the Semigroup a => Semigroup (Maybe a) instance to
combine user-provided docstrings with our :exhaust tests (when we encounter a
property declaration of Bit/Boolean type, as described in the previous commit).
These show the new :exhaust tests being added as expected.

I'm not currently set up to run CVC4/5, Yices, or Bitwuzla - so I am unsure if
those tests need their golden/reference files updated.
This helps distinguish automatically-generated :exhaust checks from those that
were explicitly written by users.

Fortunately, the docstring/doctest extraction mechanism preserves the full text
-- so this was as simple as adding a valid line comment.
This function is useful to determine when to add implicit :exhaust commands to
property docstrings, but was too high in the Cryptol.* module dependency
hierarchy.
This adds the additional condition that the declaration's docstring contain no
runnable code blocks (i.e. code blocks that are unlabeled or labeled with repl).

This change 'fixes' docstring test T05, in particular by avoiding the duplicate
exhaustive testing the previous behavior caused.
@ChrisEPhifer ChrisEPhifer force-pushed the 1842-improve-project-checking branch from a535b85 to 6af7930 Compare April 29, 2025 06:59
@ChrisEPhifer
Copy link
Contributor Author

Looks good to me, but let's do the fix where we only add the :exhaust if there's no user-defined code blocks.

We should also update the docs, and the CHANGES files before merging.

e26fcf7 and ea49660

Copy link
Contributor

@RyanGlScott RyanGlScott left a comment

Choose a reason for hiding this comment

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

LGTM, aside from some minor quibbles.

-- | Extract the code blocks from the body of a docstring.
--
-- A single code block starts with at least 3 backticks followed by an
-- optional language specifier of "cryptol". This allowed other kinds
Copy link
Contributor

Choose a reason for hiding this comment

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

Haddock trick to prevent "cryptol" from being highlighted as a module identifier:

Suggested change
-- optional language specifier of "cryptol". This allowed other kinds
-- optional language specifier of \"cryptol\". This allowed other kinds

Copy link
Contributor Author

Choose a reason for hiding this comment

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

-- | Extract the code blocks from the body of a docstring.
--
-- A single code block starts with at least 3 backticks followed by an
-- optional language specifier of "cryptol". This allowed other kinds
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
-- optional language specifier of "cryptol". This allowed other kinds
-- optional language specifier of "cryptol". This allows other kinds

Copy link
Contributor Author

Choose a reason for hiding this comment

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

CHANGES.md Outdated
Comment on lines 5 to 7
* `Bit` properties (e.g. `property p = True`) will be checked with `:exhaust`,
unless their docstrings contain code blocks understood by `:check-docstrings`.
([#1842](https://github.com/GaloisInc/cryptol/issues/1842))
Copy link
Contributor

Choose a reason for hiding this comment

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

When I first read this sentence, I was under the false impression that all Bit properties would be checked with :exhaust. I think this should mention "when running :check-docstrings" upfront, as that is an important caveat. Something like:

Suggested change
* `Bit` properties (e.g. `property p = True`) will be checked with `:exhaust`,
unless their docstrings contain code blocks understood by `:check-docstrings`.
([#1842](https://github.com/GaloisInc/cryptol/issues/1842))
* When running the `:check-docstrings` command, `Bit` properties (e.g. `property p = True`) will be checked with `:exhaust`,
unless their docstrings contain code blocks understood by `:check-docstrings`.
([#1842](https://github.com/GaloisInc/cryptol/issues/1842))

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Member

@yav yav left a comment

Choose a reason for hiding this comment

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

I don't think Crypto.TypeCheck.AST is a good home for extractBlocks, let's find a better place.

@@ -1993,61 +1993,6 @@ moduleInfoCmd isFile name
rPutStrLn "}"
pure emptyCommandResult

Copy link
Member

Choose a reason for hiding this comment

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

Why did extractCodeBlocks get moved to Cryptol.TypeCheck.AST? I don't think that's a good place for it, as we already have too much stuff in that module. As far as I can see, it's only called from Command, so keeping it there is probably OK. If it does need to be moved for some reason, let's see what's a better place for it.

Copy link
Contributor

Choose a reason for hiding this comment

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

This PR updates the code to also call extractCodeBlocks from Cryptol.TypeCheck.AST (from gatherModuleDocstrings).

Copy link
Member

Choose a reason for hiding this comment

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

Oh I see, that was already there. I think we should make a new module called Docstrings (or something) in the same directory, and move both of these functions there. In general, the plan is that AST should contain the AST and any little convenience function for working with it, but things that provide additional functionality should be in their own modules.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK, no problem -- I didn't love it either, I was just trying to make minimally-invasive changes that made sense in the existing module hierarchy, but I'm happy to add this new module.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The new module is Cryptol.TypeCheck.Docstrings.
Copy link
Contributor Author

@ChrisEPhifer ChrisEPhifer left a comment

Choose a reason for hiding this comment

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

Alright, I've moved the docstring functions to a new module Cryptol.TypeCheck.Docstrings, and addressed the the small Haddock typos / lacking clarity Ryan caught in CHANGES.md.

@@ -1993,61 +1993,6 @@ moduleInfoCmd isFile name
rPutStrLn "}"
pure emptyCommandResult

Copy link
Contributor Author

Choose a reason for hiding this comment

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

CHANGES.md Outdated
Comment on lines 5 to 7
* `Bit` properties (e.g. `property p = True`) will be checked with `:exhaust`,
unless their docstrings contain code blocks understood by `:check-docstrings`.
([#1842](https://github.com/GaloisInc/cryptol/issues/1842))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

-- | Extract the code blocks from the body of a docstring.
--
-- A single code block starts with at least 3 backticks followed by an
-- optional language specifier of "cryptol". This allowed other kinds
Copy link
Contributor Author

Choose a reason for hiding this comment

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

-- | Extract the code blocks from the body of a docstring.
--
-- A single code block starts with at least 3 backticks followed by an
-- optional language specifier of "cryptol". This allowed other kinds
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@ChrisEPhifer ChrisEPhifer requested a review from yav April 29, 2025 20:34
Copy link
Member

@yav yav left a comment

Choose a reason for hiding this comment

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

Looks good, thanks!

@yav yav merged commit 6653adb into master Apr 29, 2025
50 checks passed
@yav yav deleted the 1842-improve-project-checking branch April 29, 2025 22:07
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.

Improve project checking to auto validate easy properties
4 participants