Merge remote-tracking branch 'origin/master' into wip/cs

This commit is contained in:
Iavor S. Diatchki 2014-12-10 14:10:49 -08:00
commit 08cec44702
65 changed files with 1133 additions and 303 deletions

273
HACKING.md Normal file
View File

@ -0,0 +1,273 @@
# Cryptol development
This document explains our standards for developing Cryptol. Our goals
are to have a development process that:
- Consistently yields reliable software artifacts
- Quickly incorporates improvements and gets them into user hands
- Allows new contributors to have an immediate impact
It describes our methods and practices for:
- Testing and continuous integration
- Organizing, branching, and merging this repository
- Producing and publishing release artifacts
- **TODO**: documentation
- **TODO**: feature/release planning, ticket assignment, etc
This is a living document that is not (and possibly cannot be)
comprehensive. If something is missing or unclear, or if you have
suggestions for improving our processes, please file an issue or open
a pull request.
# Testing
Cryptol primarily uses golden testing on the Cryptol interpreter
executable. These tests provide the interpreter with input and then
check the output against an expected output file. We make at least one
test for each new issue, and keep the accumulated tests in our suite
as regression tests. The test suite itself is written using the
`test-framework` library, so it can readily output XML for consumption
by Jenkins and other CI systems.
## Running tests
To run the test suite, run `make test` from the root of the
repository. By default, you'll get output on the console for each test
that fails, either with an explanation for why it failed, or a command
line you can paste in order to compare the test results against the
expected output.
The `make test` target invokes the `cryptol-test-runner` executable,
which is defined in the `/tests/` directory. It is invoked with the
location of the `cryptol` executable, an output directory, and
standard `test-framework` command line arguments. The `test` target in
the `Makefile` provides a template for how to invoke it if you need to
use advanced parameters.
## Creaing a new test
A test consists at minimum of an `.icry` file, which is a batch-mode
file for the interpreter, and an `.icry.stdout` file, which contains
expected output (the "golden" file). As opposed to `.cry` Cryptol
source files, `.icry` files are run by the interpreter line-by-line as
if a user has typed each one in and pressed Enter.
Frequently, one creates an `.icry` file by interactively producing a
desired behavior in the interpreter, and then copying the relevant
lines of input into the file. Remember that, as with unit testing,
golden testing will only test the examples you give it, so make sure
your examples exercise many instances and corner cases of the bug or
feature.
## Expected test failures
We try to keep as few failing tests as possible in the `master`
branch. Usually tests for new features are merged into the `master`
branch in a working state. However if a new bug is reported, we often
write tests for it before it is fixed, particularly if it will take
some time to implement the fix.
To prevent confusion over which tests ought and ought not to be
failing, we add an `.icry.fails` file with an explanatory message
alongside the `.icry` script that defines the test. This will usually
reference an issue number, so that anyone running the test suite will
understand that the reason for the failure is not _their_ changes, but
rather a known issue that is already being handled.
### Example
Issue #6 was a feature request to add let-binding to the
interpreter. @dylanmc gave an example of the input he wanted to be
able to enter, so we created a file `/tests/issues/issue006.icry`
with the contents:
:let timesTwo x = x * 2
:let double x = x + x
:prove \x = timesTwo x == double x
We might not yet know what the expected output should be, so we
created a dummy file `/tests/issues/issue006.icry.stdout`:
TODO: once implemented, do something sensible here
Since this is not the output we got when running the `.icry` file,
this was now a failing test. To prevent confusion, we marked that it
was expected to fail by putting creating a
`/tests/issues/issue006.icry.fails` file with a reference to the
issue:
In development, see issue #6
As the issue progressed and we refined the design, @acfoltzer
implemented the `let` feature and came up with some additional
examples that stretch the legs of the feature further, so we updated
our `.icry` file, this time loading a supplemental `.cry` file so we
could test behavior within a module context.
`issue006.cry`:
f : [32] -> [32]
f x = x + 2
g : [32] -> [32]
g x = f x + 1
`issue006.icry`:
:l issue006.cry
g 5
let f x = 0
g 5
(f : [32] -> [32]) 5
let f x = if (x : [32]) == 0 then 1 else x * (f (x - 1))
f 5
let h x = g x
h 5
Since the feature was now implemented, we could also produce expected
output. The easiest way to do this is to interpret the `.icry` file
using the `-b` flag outside of the test runner, see if the results
look as expected, and then save those results as the new
`.icry.stdout`:
# start with a fresh build
% make
...
# tests are run from within the directory of the .icry file
% cd tests/issues
% ../../.cabal-sandbox/bin/cryptol -b issue006.icry
Loading module Cryptol
Loading module Cryptol
Loading module Main
0x00000008
0x00000008
0x00000000
0x00000078
0x00000008
At this point, it's very important to compare the results you see
against the results you expect from the inputs in the `.icry`
script. Since the results looked correct, we piped the same command
into the matching `.icry.stdout` file and removed the `.icry.fails`
file:
% ../../.cabal-sandbox/bin/cryptol -b issue006.icry.stdout
% rm issue006.icry.fails
Now the test case `issue006` passes, and will (hopefully!) break if
the let-binding feature breaks.
# Repository organization and practices
The top-level repository directories are:
- `/cryptol`: Haskell sources for the front-end `cryptol` executable
and read-eval-print loop
- `/docs`: LaTeX and Markdown sources for the Cryptol documentation
- `/examples`: Cryptol sources implementing several interesting
algorithms
- `/lib`: Cryptol standard library sources
- `/notebook`: Experimental Cryptol IPython Notebook implementation
- `/sbv`: Haskell sources for the `sbv` library, derived from Levent
Erkok's [`sbv` library](http://leventerkok.github.io/sbv/) (see
`/sbv/LICENSE`)
- `/src`: Haskell sources for the `cryptol` library (the bulk of the
implementation)
- `/tests`: Haskell sources for the Cryptol regression test suite, as
well as the Cryptol sources and expected outputs that comprise that
suite
## Branching and merging
Within the `GaloisInc/cryptol` repository, we use the
[git-flow model](http://nvie.com/posts/a-successful-git-branching-model/)
for branches and merging. Our version has two notable differences:
1. Our `master` (rather than `develop`) branch serves as the cutting
edge development branch, and our `release` (rather than `master`)
branch is where only pristine, tagged releases are committed.
2. We use `wip` (work-in-progress) branches as a centralized storage
place for (usually individual) work in progress. Whereas a
`feature` branch is expected to be relatively stable, all bets are
off with a `wip` branch. Typically `wip` branches are not actually
merged directly into `master`, but instead are rebased into a new
branch where the history is cleaned up before merging into
`master`.
In short:
- Any substantial new features should be developed on a branch
prefixed with `feature/`, and then merged into `master` when
completed.
- When we reach a feature freeze for a release, we create a new branch
prefixed with `release/`, for example `release/2.1.0`. When the
release is made, we merge those changes back into `master` and make
a snapshot commit on the `release` branch.
- If a critical bug emerges in already-released software, we create a
branch off of the relevant `release` branch commit prefixed with
`hotfix/2.1.1`. When the hotfix is complete, we merge those changes
back into `master` and make a snapshot commit on the `release`
branch.
# Releases
We take the stability and reliability of our releases very
seriously. To that end, our release process is based on principles of
_automation_, _reproducibility_, and _assurance_ (**TODO**: assurance
the right word here?).
Automation is essential for reducing the possibility of human
error. The checklist for a successful release is fairly lengthy, and
most of the steps need not be done by hand. The real points of
judgment for an individual release are deciding _when_ the codebase is
ready to be released, not _how_ it is released.
Reproducibility is essential for fixing bugs both in hotfixes and
future mainline development. If we cannot reproduce the circumstances
of a release, we might not be able to reproduce bugs that are reported
by users of that release. Bugs are often very particular about the
environment where they will arise, so it is critical to make the
environment of a release consistent.
Assurance is crucial due to the nature of development done with
Cryptol. When people use Cryptol to develop the next generations of
trustworthy systems, we want them to be sure the software was built by
the Cryptol developers, and was not corrupted during download or
replaced by a malicious third party. To this end, we sign our releases
with a [GPG key](http://www.cryptol.net/files/Galois.asc). (**TODO**:
OMG is this really not https?!)
## Cutting releases
**TODO**: make this relevant to folks outside Galois; right now the
build farm exists within the Galois network only, and Galois also
controls the release signing key.
The release process is:
1. Make sure the `release/n.n.n` branch is in a release/ready state,
with successful build artifacts across all platforms on the
relevant Jenkins job. **TODO**: get a Jenkins job running per
release branch, rather than just `master`.
1. Merge the `release/n.n.n` branch into the pristine `release` branch
and add a git tag.
1. Merge the `release/n.n.n` branch back into `master` for future
development, and delete the `release/n.n.n` branch.
1. Run the `cryptol-release` Jenkins job to create a draft
release. Specify the build number with the successful artifacts,
the textual version tag (e.g., "2.1.0"), whether it's a prerelease
(e.g., an alpha), and keep the `DRAFT` option checked.
1. On the Github page for the draft release and add a changelog
(**TODO**: how do we generate changelogs?).
1. (**TODO**: this part of the process needs to be better and
automated) Download the successfully-built artifacts _from
Jenkins_, and in the same directory run the script
`/release-infrastructure/sign.sh` from the `cryptol-internal.git`
repository. You must have the correct GPG key (D3103D7E) for this
to work.
1. Upload the `.sig` files to the draft release on Github.
1. Publish the release and announce it (**TODO**: compile mailing
lists, social media outlets, etc where we should make sure to
announce)

View File

@ -2,6 +2,7 @@ UNAME := $(shell uname -s)
ARCH := $(shell uname -m) ARCH := $(shell uname -m)
TESTS ?= issues regression renamer TESTS ?= issues regression renamer
TEST_DIFF ?= meld
CABAL_FLAGS ?= -j CABAL_FLAGS ?= -j
@ -67,11 +68,15 @@ ${CS_BIN}/happy: | ${CS}
src/GitRev.hs: src/GitRev.hs:
sh configure sh configure
# It would be nice to refine these dependencies some in order to avoid
# unnecessary rebuilds, but for now it's safest to just always cabal CRYPTOL_DEPS := \
# install. $(shell find src cryptol \( -name \*.hs -or -name \*.x -or -name \*.y \) -print) \
.PHONY: ${CS_BIN}/cryptol $(shell find lib -name \*.cry)
${CS_BIN}/cryptol: ${CS_BIN}/alex ${CS_BIN}/happy | ${CS}
print-%:
@echo $* = $($*)
${CS_BIN}/cryptol: ${CS_BIN}/alex ${CS_BIN}/happy $(CRYPTOL_DEPS) | ${CS}
$(CABAL) install . $(CABAL) install .
${CS_BIN}/cryptolnb: ${CS_BIN}/alex ${CS_BIN}/happy | ${CS} ${CS_BIN}/cryptolnb: ${CS_BIN}/alex ${CS_BIN}/happy | ${CS}
@ -127,6 +132,7 @@ test: ${CS_BIN}/cryptol-test-runner
-r output \ -r output \
-T --hide-successes \ -T --hide-successes \
-T --jxml=$(call adjust-path,$(CURDIR)/results.xml) \ -T --jxml=$(call adjust-path,$(CURDIR)/results.xml) \
$(if $(TEST_DIFF),-p $(TEST_DIFF),) \
) )
.PHONY: notebook .PHONY: notebook

View File

@ -153,10 +153,12 @@ send email to <cryptol@galois.com>.
## Developers ## Developers
If you plan to do development work on the Cryptol interpreter, please If you'd like to get involved with Cryptol development, see the list
make a fork of the GitHub repository and send along pull of
requests. This makes it easier for us to track development and to [low-hanging fruit](https://github.com/GaloisInc/cryptol/labels/low-hanging%20fruit). These
incorporate your changes. are tasks which should be straightforward to implement. Make a
fork of this GitHub repository and send along pull requests, and we'll
be happy to incorporate your changes.
### Repository Structure ### Repository Structure

View File

@ -117,6 +117,7 @@ library
Cryptol.Transform.Specialize, Cryptol.Transform.Specialize,
Cryptol.Eval, Cryptol.Eval,
Cryptol.Eval.Arch,
Cryptol.Eval.Env, Cryptol.Eval.Env,
Cryptol.Eval.Error, Cryptol.Eval.Error,
Cryptol.Eval.Type, Cryptol.Eval.Type,

View File

@ -304,13 +304,13 @@ qcCmd qcMode str =
prt msg = io (putStr msg >> hFlush stdout) prt msg = io (putStr msg >> hFlush stdout)
prtLn msg = io (putStrLn msg >> hFlush stdout) prtLn msg = io (putStrLn msg >> hFlush stdout)
ppProgress this tot = ppProgress this tot = unlessBatch $
let percent = show (div (100 * this) tot) ++ "%" let percent = show (div (100 * this) tot) ++ "%"
width = length percent width = length percent
pad = replicate (totProgressWidth - width) ' ' pad = replicate (totProgressWidth - width) ' '
in prt (pad ++ percent) in prt (pad ++ percent)
del n = prt (replicate n '\BS') del n = unlessBatch $ prt (replicate n '\BS')
delTesting = del (length testingMsg) delTesting = del (length testingMsg)
delProgress = del totProgressWidth delProgress = del totProgressWidth

View File

@ -157,6 +157,8 @@ module Data.SBV (
, Polynomial(..), crcBV, crc , Polynomial(..), crcBV, crc
-- ** Conditionals: Mergeable values -- ** Conditionals: Mergeable values
, Mergeable(..), ite, iteLazy, sBranch , Mergeable(..), ite, iteLazy, sBranch
-- ** Conditional symbolic simulation
, sAssert, sAssertCont
-- ** Symbolic equality -- ** Symbolic equality
, EqSymbolic(..) , EqSymbolic(..)
-- ** Symbolic ordering -- ** Symbolic ordering
@ -195,6 +197,10 @@ module Data.SBV (
-- ** Checking constraint vacuity -- ** Checking constraint vacuity
, isVacuous, isVacuousWith , isVacuous, isVacuousWith
-- * Checking safety
-- $safeIntro
, safe, safeWith, SExecutable(..)
-- * Proving properties using multiple solvers -- * Proving properties using multiple solvers
-- $multiIntro -- $multiIntro
, proveWithAll, proveWithAny, satWithAll, satWithAny, allSatWithAll, allSatWithAny , proveWithAll, proveWithAny, satWithAll, satWithAny, allSatWithAll, allSatWithAny
@ -212,7 +218,7 @@ module Data.SBV (
-- ** Inspecting proof results -- ** Inspecting proof results
-- $resultTypes -- $resultTypes
, ThmResult(..), SatResult(..), AllSatResult(..), SMTResult(..) , ThmResult(..), SatResult(..), AllSatResult(..), SMTResult(..), SafeResult(..)
-- ** Programmable model extraction -- ** Programmable model extraction
-- $programmableExtraction -- $programmableExtraction
@ -488,6 +494,46 @@ Note that the function 'sbvAvailableSolvers' will return all the installed solve
used as the first argument to all these functions, if you simply want to try all available solvers on a machine. used as the first argument to all these functions, if you simply want to try all available solvers on a machine.
-} -}
{- $safeIntro
The 'sAssert' and 'sAssertCont' functions allow users to introduce invariants through-out their code to make sure
certain properties hold at all times. This is another mechanism to provide further documentation/contract info
into SBV code. The functions 'safe' and 'safeWith' can then be used to statically discharge these proof assumptions.
If a violation is found, SBV will print a model showing which inputs lead to the invariant being violated.
Here's a simple example. Let's assume we have a function that does subtraction, and requires it's
first argument to be larger than the second:
>>> let sub x y = sAssert "sub: x >= y must hold!" (x .>= y) (x - y)
Clearly, this function is not safe, as there's nothing that ensures us to pass a larger second argument.
If we try to prove a theorem regarding sub, we'll get an exception:
>>> prove $ \x y -> sub x y .>= (0 :: SInt16)
*** Exception: Assertion failure: "sub: x >= y must hold!"
s0 = -32768 :: SInt16
s1 = -32767 :: SInt16
Of course, we can use, 'safe' to statically see if such a violation is possible before we attempt a proof:
>>> safe (sub :: SInt8 -> SInt8 -> SInt8)
Assertion failure: "sub: x >= y must hold!"
s0 = -128 :: SInt8
s1 = -127 :: SInt8
What happens if we make sure to arrange for this invariant? Consider this version:
>>> let safeSub x y = ite (x .>= y) (sub x y) (sub y x)
Clearly, 'safeSub' must be safe. And indeed, SBV can prove that:
>>> safe (safeSub :: SInt8 -> SInt8 -> SInt8)
No safety violations detected.
Note how we used 'sub' and 'safeSub' polymorphically. We only need to monomorphise our types when a proof
attempt is done, as we did in the 'safe' calls.
-}
{- $optimizeIntro {- $optimizeIntro
Symbolic optimization. A call of the form: Symbolic optimization. A call of the form:

View File

@ -32,7 +32,7 @@ module Data.SBV.BitVectors.Data
, sbvToSW, sbvToSymSW, forceSWArg , sbvToSW, sbvToSymSW, forceSWArg
, SBVExpr(..), newExpr , SBVExpr(..), newExpr
, cache, Cached, uncache, uncacheAI, HasKind(..) , cache, Cached, uncache, uncacheAI, HasKind(..)
, Op(..), NamedSymVar, UnintKind(..), getTableIndex, SBVPgm(..), Symbolic, runSymbolic, runSymbolic', State, getPathCondition, extendPathCondition , Op(..), NamedSymVar, UnintKind(..), getTableIndex, SBVPgm(..), Symbolic, SExecutable(..), runSymbolic, runSymbolic', State, getPathCondition, extendPathCondition
, inProofMode, SBVRunMode(..), Kind(..), Outputtable(..), Result(..) , inProofMode, SBVRunMode(..), Kind(..), Outputtable(..), Result(..)
, Logic(..), SMTLibLogic(..) , Logic(..), SMTLibLogic(..)
, getTraceInfo, getConstraints, addConstraint , getTraceInfo, getConstraints, addConstraint
@ -57,11 +57,11 @@ import Data.IORef (IORef, newIORef, modifyIORef, readIORef, writeIORef
import Data.List (intercalate, sortBy) import Data.List (intercalate, sortBy)
import Data.Maybe (isJust, fromJust) import Data.Maybe (isJust, fromJust)
import qualified Data.IntMap as IMap (IntMap, empty, size, toAscList, lookup, insert, insertWith) import qualified Data.IntMap as IMap (IntMap, empty, size, toAscList, lookup, insert, insertWith)
import qualified Data.Map as Map (Map, empty, toList, size, insert, lookup) import qualified Data.Map as Map (Map, empty, toList, size, insert, lookup)
import qualified Data.Set as Set (Set, empty, toList, insert) import qualified Data.Set as Set (Set, empty, toList, insert)
import qualified Data.Foldable as F (toList) import qualified Data.Foldable as F (toList)
import qualified Data.Sequence as S (Seq, empty, (|>)) import qualified Data.Sequence as S (Seq, empty, (|>))
import System.Exit (ExitCode(..)) import System.Exit (ExitCode(..))
import System.Mem.StableName import System.Mem.StableName
@ -1301,6 +1301,9 @@ instance NFData SMTResult where
instance NFData SMTModel where instance NFData SMTModel where
rnf (SMTModel assocs unints uarrs) = rnf assocs `seq` rnf unints `seq` rnf uarrs `seq` () rnf (SMTModel assocs unints uarrs) = rnf assocs `seq` rnf unints `seq` rnf uarrs `seq` ()
instance NFData SMTScript where
rnf (SMTScript b m) = rnf b `seq` rnf m `seq` ()
-- | SMT-Lib logics. If left unspecified SBV will pick the logic based on what it determines is needed. However, the -- | SMT-Lib logics. If left unspecified SBV will pick the logic based on what it determines is needed. However, the
-- user can override this choice using the 'useLogic' parameter to the configuration. This is especially handy if -- user can override this choice using the 'useLogic' parameter to the configuration. This is especially handy if
-- one is experimenting with custom logics that might be supported on new solvers. -- one is experimenting with custom logics that might be supported on new solvers.
@ -1372,7 +1375,7 @@ data SMTConfig = SMTConfig {
, timing :: Bool -- ^ Print timing information on how long different phases took (construction, solving, etc.) , timing :: Bool -- ^ Print timing information on how long different phases took (construction, solving, etc.)
, sBranchTimeOut :: Maybe Int -- ^ How much time to give to the solver for each call of 'sBranch' check. (In seconds. Default: No limit.) , sBranchTimeOut :: Maybe Int -- ^ How much time to give to the solver for each call of 'sBranch' check. (In seconds. Default: No limit.)
, timeOut :: Maybe Int -- ^ How much time to give to the solver. (In seconds. Default: No limit.) , timeOut :: Maybe Int -- ^ How much time to give to the solver. (In seconds. Default: No limit.)
, printBase :: Int -- ^ Print integral literals in this base (2, 8, and 10, and 16 are supported.) , printBase :: Int -- ^ Print integral literals in this base (2, 8, 10, and 16 are supported.)
, printRealPrec :: Int -- ^ Print algebraic real values with this precision. (SReal, default: 16) , printRealPrec :: Int -- ^ Print algebraic real values with this precision. (SReal, default: 16)
, solverTweaks :: [String] -- ^ Additional lines of script to give to the solver (user specified) , solverTweaks :: [String] -- ^ Additional lines of script to give to the solver (user specified)
, satCmd :: String -- ^ Usually "(check-sat)". However, users might tweak it based on solver characteristics. , satCmd :: String -- ^ Usually "(check-sat)". However, users might tweak it based on solver characteristics.
@ -1434,3 +1437,100 @@ data SMTSolver = SMTSolver {
instance Show SMTSolver where instance Show SMTSolver where
show = show . name show = show . name
-- | Symbolically executable program fragments. This class is mainly used for 'safe' calls, and is sufficently populated internally to cover most use
-- cases. Users can extend it as they wish to allow 'safe' checks for SBV programs that return/take types that are user-defined.
class SExecutable a where
sName_ :: a -> Symbolic ()
sName :: [String] -> a -> Symbolic ()
instance NFData a => SExecutable (Symbolic a) where
sName_ a = a >>= \r -> rnf r `seq` return ()
sName [] = sName_
sName xs = error $ "SBV.SExecutable.sName: Extra unmapped name(s): " ++ intercalate ", " xs
instance NFData a => SExecutable (SBV a) where
sName_ v = sName_ (output v)
sName xs v = sName xs (output v)
-- Unit output
instance SExecutable () where
sName_ () = sName_ (output ())
sName xs () = sName xs (output ())
-- List output
instance (NFData a, SymWord a) => SExecutable [SBV a] where
sName_ vs = sName_ (output vs)
sName xs vs = sName xs (output vs)
-- 2 Tuple output
instance (NFData a, SymWord a, NFData b, SymWord b) => SExecutable (SBV a, SBV b) where
sName_ (a, b) = sName_ (output a >> output b)
sName _ = sName_
-- 3 Tuple output
instance (NFData a, SymWord a, NFData b, SymWord b, NFData c, SymWord c) => SExecutable (SBV a, SBV b, SBV c) where
sName_ (a, b, c) = sName_ (output a >> output b >> output c)
sName _ = sName_
-- 4 Tuple output
instance (NFData a, SymWord a, NFData b, SymWord b, NFData c, SymWord c, NFData d, SymWord d) => SExecutable (SBV a, SBV b, SBV c, SBV d) where
sName_ (a, b, c, d) = sName_ (output a >> output b >> output c >> output c >> output d)
sName _ = sName_
-- 5 Tuple output
instance (NFData a, SymWord a, NFData b, SymWord b, NFData c, SymWord c, NFData d, SymWord d, NFData e, SymWord e) => SExecutable (SBV a, SBV b, SBV c, SBV d, SBV e) where
sName_ (a, b, c, d, e) = sName_ (output a >> output b >> output c >> output d >> output e)
sName _ = sName_
-- 6 Tuple output
instance (NFData a, SymWord a, NFData b, SymWord b, NFData c, SymWord c, NFData d, SymWord d, NFData e, SymWord e, NFData f, SymWord f) => SExecutable (SBV a, SBV b, SBV c, SBV d, SBV e, SBV f) where
sName_ (a, b, c, d, e, f) = sName_ (output a >> output b >> output c >> output d >> output e >> output f)
sName _ = sName_
-- 7 Tuple output
instance (NFData a, SymWord a, NFData b, SymWord b, NFData c, SymWord c, NFData d, SymWord d, NFData e, SymWord e, NFData f, SymWord f, NFData g, SymWord g) => SExecutable (SBV a, SBV b, SBV c, SBV d, SBV e, SBV f, SBV g) where
sName_ (a, b, c, d, e, f, g) = sName_ (output a >> output b >> output c >> output d >> output e >> output f >> output g)
sName _ = sName_
-- Functions
instance (SymWord a, SExecutable p) => SExecutable (SBV a -> p) where
sName_ k = forall_ >>= \a -> sName_ $ k a
sName (s:ss) k = forall s >>= \a -> sName ss $ k a
sName [] k = sName_ k
-- 2 Tuple input
instance (SymWord a, SymWord b, SExecutable p) => SExecutable ((SBV a, SBV b) -> p) where
sName_ k = forall_ >>= \a -> sName_ $ \b -> k (a, b)
sName (s:ss) k = forall s >>= \a -> sName ss $ \b -> k (a, b)
sName [] k = sName_ k
-- 3 Tuple input
instance (SymWord a, SymWord b, SymWord c, SExecutable p) => SExecutable ((SBV a, SBV b, SBV c) -> p) where
sName_ k = forall_ >>= \a -> sName_ $ \b c -> k (a, b, c)
sName (s:ss) k = forall s >>= \a -> sName ss $ \b c -> k (a, b, c)
sName [] k = sName_ k
-- 4 Tuple input
instance (SymWord a, SymWord b, SymWord c, SymWord d, SExecutable p) => SExecutable ((SBV a, SBV b, SBV c, SBV d) -> p) where
sName_ k = forall_ >>= \a -> sName_ $ \b c d -> k (a, b, c, d)
sName (s:ss) k = forall s >>= \a -> sName ss $ \b c d -> k (a, b, c, d)
sName [] k = sName_ k
-- 5 Tuple input
instance (SymWord a, SymWord b, SymWord c, SymWord d, SymWord e, SExecutable p) => SExecutable ((SBV a, SBV b, SBV c, SBV d, SBV e) -> p) where
sName_ k = forall_ >>= \a -> sName_ $ \b c d e -> k (a, b, c, d, e)
sName (s:ss) k = forall s >>= \a -> sName ss $ \b c d e -> k (a, b, c, d, e)
sName [] k = sName_ k
-- 6 Tuple input
instance (SymWord a, SymWord b, SymWord c, SymWord d, SymWord e, SymWord f, SExecutable p) => SExecutable ((SBV a, SBV b, SBV c, SBV d, SBV e, SBV f) -> p) where
sName_ k = forall_ >>= \a -> sName_ $ \b c d e f -> k (a, b, c, d, e, f)
sName (s:ss) k = forall s >>= \a -> sName ss $ \b c d e f -> k (a, b, c, d, e, f)
sName [] k = sName_ k
-- 7 Tuple input
instance (SymWord a, SymWord b, SymWord c, SymWord d, SymWord e, SymWord f, SymWord g, SExecutable p) => SExecutable ((SBV a, SBV b, SBV c, SBV d, SBV e, SBV f, SBV g) -> p) where
sName_ k = forall_ >>= \a -> sName_ $ \b c d e f g -> k (a, b, c, d, e, f, g)
sName (s:ss) k = forall s >>= \a -> sName ss $ \b c d e f g -> k (a, b, c, d, e, f, g)
sName [] k = sName_ k

View File

@ -22,7 +22,7 @@
module Data.SBV.BitVectors.Model ( module Data.SBV.BitVectors.Model (
Mergeable(..), EqSymbolic(..), OrdSymbolic(..), SDivisible(..), Uninterpreted(..), SIntegral Mergeable(..), EqSymbolic(..), OrdSymbolic(..), SDivisible(..), Uninterpreted(..), SIntegral
, ite, iteLazy, sBranch, sbvTestBit, sbvPopCount, setBitTo, sbvShiftLeft, sbvShiftRight, sbvSignedShiftArithRight , ite, iteLazy, sBranch, sAssert, sAssertCont, sbvTestBit, sbvPopCount, setBitTo, sbvShiftLeft, sbvShiftRight, sbvSignedShiftArithRight
, sbvRotateLeft, sbvRotateRight, mkUninterpreted , sbvRotateLeft, sbvRotateRight, mkUninterpreted
, allEqual, allDifferent, inRange, sElem, oneIf, blastBE, blastLE, fullAdder, fullMultiplier , allEqual, allDifferent, inRange, sElem, oneIf, blastBE, blastLE, fullAdder, fullMultiplier
, lsb, msb, genVar, genVar_, forall, forall_, exists, exists_ , lsb, msb, genVar, genVar_, forall, forall_, exists, exists_
@ -43,6 +43,10 @@ import Data.List (genericLength, genericIndex, unzip4, unzip5, unzip6, unz
import Data.Maybe (fromMaybe) import Data.Maybe (fromMaybe)
import Data.Word (Word8, Word16, Word32, Word64) import Data.Word (Word8, Word16, Word32, Word64)
import qualified Data.Map as M
import qualified Control.Exception as C
import Test.QuickCheck (Testable(..), Arbitrary(..)) import Test.QuickCheck (Testable(..), Arbitrary(..))
import qualified Test.QuickCheck as QC (whenFail) import qualified Test.QuickCheck as QC (whenFail)
import qualified Test.QuickCheck.Monadic as QC (monadicIO, run) import qualified Test.QuickCheck.Monadic as QC (monadicIO, run)
@ -52,10 +56,8 @@ import Data.SBV.BitVectors.AlgReals
import Data.SBV.BitVectors.Data import Data.SBV.BitVectors.Data
import Data.SBV.Utils.Boolean import Data.SBV.Utils.Boolean
-- The following two imports are only needed because of the doctest expressions we have. Sigh.. import Data.SBV.Provers.Prover (isSBranchFeasibleInState, isConditionSatisfiable, isVacuous, prove, defaultSMTCfg)
-- It might be a good idea to reorg some of the content to avoid this. import Data.SBV.SMT.SMT (SafeResult(..), SatResult(..), ThmResult, getModelDictionary)
import Data.SBV.Provers.Prover (isSBranchFeasibleInState, isVacuous, prove)
import Data.SBV.SMT.SMT (ThmResult)
-- | Newer versions of GHC (Starting with 7.8 I think), distinguishes between FiniteBits and Bits classes. -- | Newer versions of GHC (Starting with 7.8 I think), distinguishes between FiniteBits and Bits classes.
-- We should really use FiniteBitSize for SBV which would make things better. In the interim, just work -- We should really use FiniteBitSize for SBV which would make things better. In the interim, just work
@ -1136,7 +1138,19 @@ instance SDivisible SInt8 where
sDivMod = liftDMod sDivMod = liftDMod
liftQRem :: (SymWord a, Num a, SDivisible a) => SBV a -> SBV a -> (SBV a, SBV a) liftQRem :: (SymWord a, Num a, SDivisible a) => SBV a -> SBV a -> (SBV a, SBV a)
liftQRem x y = ite (y .== z) (z, x) (qr x y) liftQRem x y
| isConcreteZero x
= (x, x)
| isConcreteOne y
= (x, z)
{-------------------------------
- N.B. The seemingly innocuous variant when y == -1 only holds if the type is signed;
- and also is problematic around the minBound.. So, we refrain from that optimization
| isConcreteOnes y
= (-x, z)
--------------------------------}
| True
= ite (y .== z) (z, x) (qr x y)
where qr (SBV sgnsz (Left a)) (SBV _ (Left b)) = let (q, r) = sQuotRem a b in (SBV sgnsz (Left q), SBV sgnsz (Left r)) where qr (SBV sgnsz (Left a)) (SBV _ (Left b)) = let (q, r) = sQuotRem a b in (SBV sgnsz (Left q), SBV sgnsz (Left r))
qr a@(SBV sgnsz _) b = (SBV sgnsz (Right (cache (mk Quot))), SBV sgnsz (Right (cache (mk Rem)))) qr a@(SBV sgnsz _) b = (SBV sgnsz (Right (cache (mk Quot))), SBV sgnsz (Right (cache (mk Rem))))
where mk o st = do sw1 <- sbvToSW st a where mk o st = do sw1 <- sbvToSW st a
@ -1146,7 +1160,19 @@ liftQRem x y = ite (y .== z) (z, x) (qr x y)
-- Conversion from quotRem (truncate to 0) to divMod (truncate towards negative infinity) -- Conversion from quotRem (truncate to 0) to divMod (truncate towards negative infinity)
liftDMod :: (SymWord a, Num a, SDivisible a, SDivisible (SBV a)) => SBV a -> SBV a -> (SBV a, SBV a) liftDMod :: (SymWord a, Num a, SDivisible a, SDivisible (SBV a)) => SBV a -> SBV a -> (SBV a, SBV a)
liftDMod x y = ite (y .== z) (z, x) $ ite (signum r .== negate (signum y)) (q-1, r+y) qr liftDMod x y
| isConcreteZero x
= (x, x)
| isConcreteOne y
= (x, z)
{-------------------------------
- N.B. The seemingly innocuous variant when y == -1 only holds if the type is signed;
- and also is problematic around the minBound.. So, we refrain from that optimization
| isConcreteOnes y
= (-x, z)
--------------------------------}
| True
= ite (y .== z) (z, x) $ ite (signum r .== negate (signum y)) (q-1, r+y) qr
where qr@(q, r) = x `sQuotRem` y where qr@(q, r) = x `sQuotRem` y
z = sbvFromInteger (kindOf x) 0 z = sbvFromInteger (kindOf x) 0
@ -1249,6 +1275,33 @@ sBranch t a b
| True = symbolicMerge False c a b | True = symbolicMerge False c a b
where c = reduceInPathCondition t where c = reduceInPathCondition t
-- | Symbolic assert. Check that the given boolean condition is always true in the given path.
-- Otherwise symbolic simulation will stop with a run-time error.
sAssert :: Mergeable a => String -> SBool -> a -> a
sAssert msg = sAssertCont msg defCont
where defCont _ Nothing = C.throw (SafeAlwaysFails msg)
defCont cfg (Just md) = C.throw (SafeFailsInModel msg cfg (SMTModel (M.toList md) [] []))
-- | Symbolic assert with a programmable continuation. Check that the given boolean condition is always true in the given path.
-- Otherwise symbolic simulation will transfer the failing model to the given continuation. The
-- continuation takes the @SMTConfig@, and a possible model: If it receives @Nothing@, then it means that the condition
-- fails for all assignments to inputs. Otherwise, it'll receive @Just@ a dictionary that maps the
-- input variables to the appropriate @CW@ values that exhibit the failure. Note that the continuation
-- has no option but to display the result in some fashion and call error, due to its restricted type.
sAssertCont :: Mergeable a => String -> (forall b. SMTConfig -> Maybe (M.Map String CW) -> b) -> SBool -> a -> a
sAssertCont msg cont t a
| Just r <- unliteral t = if r then a else cont defaultSMTCfg Nothing
| True = symbolicMerge False cond a (die ["SBV.error: Internal-error, cannot happen: Reached false branch in checked s-Assert."])
where k = kindOf t
cond = SBV k $ Right $ cache c
die m = error $ intercalate "\n" $ ("Assertion failure: " ++ show msg) : m
c st = do let pc = getPathCondition st
chk = pc &&& bnot t
mbModel <- isConditionSatisfiable st chk
case mbModel of
Just (r@(SatResult (Satisfiable cfg _))) -> cont cfg $ Just $ getModelDictionary r
_ -> return trueSW
-- SBV -- SBV
instance SymWord a => Mergeable (SBV a) where instance SymWord a => Mergeable (SBV a) where
symbolicMerge force t a b symbolicMerge force t a b
@ -1662,16 +1715,16 @@ instance (SymWord h, SymWord g, SymWord f, SymWord e, SymWord d, SymWord c, SymW
kg = kindOf (undefined :: g) kg = kindOf (undefined :: g)
kh = kindOf (undefined :: h) kh = kindOf (undefined :: h)
result st | Just (_, v) <- mbCgData, inProofMode st = sbvToSW st (v arg0 arg1 arg2 arg3 arg4 arg5 arg6) result st | Just (_, v) <- mbCgData, inProofMode st = sbvToSW st (v arg0 arg1 arg2 arg3 arg4 arg5 arg6)
| True = do newUninterpreted st nm (SBVType [kh, kg, kf, ke, kd, kc, kb, ka]) (fst `fmap` mbCgData) | True = do newUninterpreted st nm (SBVType [kh, kg, kf, ke, kd, kc, kb, ka]) (fst `fmap` mbCgData)
sw0 <- sbvToSW st arg0 sw0 <- sbvToSW st arg0
sw1 <- sbvToSW st arg1 sw1 <- sbvToSW st arg1
sw2 <- sbvToSW st arg2 sw2 <- sbvToSW st arg2
sw3 <- sbvToSW st arg3 sw3 <- sbvToSW st arg3
sw4 <- sbvToSW st arg4 sw4 <- sbvToSW st arg4
sw5 <- sbvToSW st arg5 sw5 <- sbvToSW st arg5
sw6 <- sbvToSW st arg6 sw6 <- sbvToSW st arg6
mapM_ forceSWArg [sw0, sw1, sw2, sw3, sw4, sw5, sw6] mapM_ forceSWArg [sw0, sw1, sw2, sw3, sw4, sw5, sw6]
newExpr st ka $ SBVApp (Uninterpreted nm) [sw0, sw1, sw2, sw3, sw4, sw5, sw6] newExpr st ka $ SBVApp (Uninterpreted nm) [sw0, sw1, sw2, sw3, sw4, sw5, sw6]
-- Uncurried functions of two arguments -- Uncurried functions of two arguments
instance (SymWord c, SymWord b, HasKind a) => Uninterpreted ((SBV c, SBV b) -> SBV a) where instance (SymWord c, SymWord b, HasKind a) => Uninterpreted ((SBV c, SBV b) -> SBV a) where

View File

@ -21,8 +21,8 @@
module Data.SBV.Bridge.Boolector ( module Data.SBV.Bridge.Boolector (
-- * Boolector specific interface -- * Boolector specific interface
sbvCurrentSolver sbvCurrentSolver
-- ** Proving and checking satisfiability -- ** Proving, checking satisfiability, and safety
, prove, sat, allSat, isVacuous, isTheorem, isSatisfiable , prove, sat, safe, allSat, isVacuous, isTheorem, isSatisfiable
-- ** Optimization routines -- ** Optimization routines
, optimize, minimize, maximize , optimize, minimize, maximize
-- * Non-Boolector specific SBV interface -- * Non-Boolector specific SBV interface
@ -30,7 +30,7 @@ module Data.SBV.Bridge.Boolector (
, module Data.SBV , module Data.SBV
) where ) where
import Data.SBV hiding (prove, sat, allSat, isVacuous, isTheorem, isSatisfiable, optimize, minimize, maximize, sbvCurrentSolver) import Data.SBV hiding (prove, sat, safe, allSat, isVacuous, isTheorem, isSatisfiable, optimize, minimize, maximize, sbvCurrentSolver)
-- | Current solver instance, pointing to cvc4. -- | Current solver instance, pointing to cvc4.
sbvCurrentSolver :: SMTConfig sbvCurrentSolver :: SMTConfig
@ -48,6 +48,12 @@ sat :: Provable a
-> IO SatResult -- ^ Response of the SMT Solver, containing the model if found -> IO SatResult -- ^ Response of the SMT Solver, containing the model if found
sat = satWith sbvCurrentSolver sat = satWith sbvCurrentSolver
-- | Check safety, i.e., prove that all 'sAssert' conditions are statically true in all paths
safe :: SExecutable a
=> a -- ^ Program to check the safety of
-> IO SafeResult -- ^ Response of the SMT solver, containing the unsafe model if found
safe = safeWith sbvCurrentSolver
-- | Find all satisfying solutions, using the CVC4 SMT solver -- | Find all satisfying solutions, using the CVC4 SMT solver
allSat :: Provable a allSat :: Provable a
=> a -- ^ Property to check => a -- ^ Property to check

View File

@ -21,8 +21,8 @@
module Data.SBV.Bridge.CVC4 ( module Data.SBV.Bridge.CVC4 (
-- * CVC4 specific interface -- * CVC4 specific interface
sbvCurrentSolver sbvCurrentSolver
-- ** Proving and checking satisfiability -- ** Proving, checking satisfiability, and safety
, prove, sat, allSat, isVacuous, isTheorem, isSatisfiable , prove, sat, safe, allSat, isVacuous, isTheorem, isSatisfiable
-- ** Optimization routines -- ** Optimization routines
, optimize, minimize, maximize , optimize, minimize, maximize
-- * Non-CVC4 specific SBV interface -- * Non-CVC4 specific SBV interface
@ -30,7 +30,7 @@ module Data.SBV.Bridge.CVC4 (
, module Data.SBV , module Data.SBV
) where ) where
import Data.SBV hiding (prove, sat, allSat, isVacuous, isTheorem, isSatisfiable, optimize, minimize, maximize, sbvCurrentSolver) import Data.SBV hiding (prove, sat, safe, allSat, isVacuous, isTheorem, isSatisfiable, optimize, minimize, maximize, sbvCurrentSolver)
-- | Current solver instance, pointing to cvc4. -- | Current solver instance, pointing to cvc4.
sbvCurrentSolver :: SMTConfig sbvCurrentSolver :: SMTConfig
@ -48,6 +48,12 @@ sat :: Provable a
-> IO SatResult -- ^ Response of the SMT Solver, containing the model if found -> IO SatResult -- ^ Response of the SMT Solver, containing the model if found
sat = satWith sbvCurrentSolver sat = satWith sbvCurrentSolver
-- | Check safety, i.e., prove that all 'sAssert' conditions are statically true in all paths
safe :: SExecutable a
=> a -- ^ Program to check the safety of
-> IO SafeResult -- ^ Response of the SMT solver, containing the unsafe model if found
safe = safeWith sbvCurrentSolver
-- | Find all satisfying solutions, using the CVC4 SMT solver -- | Find all satisfying solutions, using the CVC4 SMT solver
allSat :: Provable a allSat :: Provable a
=> a -- ^ Property to check => a -- ^ Property to check

View File

@ -21,8 +21,8 @@
module Data.SBV.Bridge.MathSAT ( module Data.SBV.Bridge.MathSAT (
-- * MathSAT specific interface -- * MathSAT specific interface
sbvCurrentSolver sbvCurrentSolver
-- ** Proving and checking satisfiability -- ** Proving, checking satisfiability, and safety
, prove, sat, allSat, isVacuous, isTheorem, isSatisfiable , prove, sat, safe, allSat, isVacuous, isTheorem, isSatisfiable
-- ** Optimization routines -- ** Optimization routines
, optimize, minimize, maximize , optimize, minimize, maximize
-- * Non-MathSAT specific SBV interface -- * Non-MathSAT specific SBV interface
@ -30,7 +30,7 @@ module Data.SBV.Bridge.MathSAT (
, module Data.SBV , module Data.SBV
) where ) where
import Data.SBV hiding (prove, sat, allSat, isVacuous, isTheorem, isSatisfiable, optimize, minimize, maximize, sbvCurrentSolver) import Data.SBV hiding (prove, sat, safe, allSat, isVacuous, isTheorem, isSatisfiable, optimize, minimize, maximize, sbvCurrentSolver)
-- | Current solver instance, pointing to cvc4. -- | Current solver instance, pointing to cvc4.
sbvCurrentSolver :: SMTConfig sbvCurrentSolver :: SMTConfig
@ -48,6 +48,12 @@ sat :: Provable a
-> IO SatResult -- ^ Response of the SMT Solver, containing the model if found -> IO SatResult -- ^ Response of the SMT Solver, containing the model if found
sat = satWith sbvCurrentSolver sat = satWith sbvCurrentSolver
-- | Check safety, i.e., prove that all 'sAssert' conditions are statically true in all paths
safe :: SExecutable a
=> a -- ^ Program to check the safety of
-> IO SafeResult -- ^ Response of the SMT solver, containing the unsafe model if found
safe = safeWith sbvCurrentSolver
-- | Find all satisfying solutions, using the CVC4 SMT solver -- | Find all satisfying solutions, using the CVC4 SMT solver
allSat :: Provable a allSat :: Provable a
=> a -- ^ Property to check => a -- ^ Property to check

View File

@ -21,8 +21,8 @@
module Data.SBV.Bridge.Yices ( module Data.SBV.Bridge.Yices (
-- * Yices specific interface -- * Yices specific interface
sbvCurrentSolver sbvCurrentSolver
-- ** Proving and checking satisfiability -- ** Proving, checking satisfiability, and safety
, prove, sat, allSat, isVacuous, isTheorem, isSatisfiable , prove, sat, safe, allSat, isVacuous, isTheorem, isSatisfiable
-- ** Optimization routines -- ** Optimization routines
, optimize, minimize, maximize , optimize, minimize, maximize
-- * Non-Yices specific SBV interface -- * Non-Yices specific SBV interface
@ -30,7 +30,7 @@ module Data.SBV.Bridge.Yices (
, module Data.SBV , module Data.SBV
) where ) where
import Data.SBV hiding (prove, sat, allSat, isVacuous, isTheorem, isSatisfiable, optimize, minimize, maximize, sbvCurrentSolver) import Data.SBV hiding (prove, sat, safe, allSat, isVacuous, isTheorem, isSatisfiable, optimize, minimize, maximize, sbvCurrentSolver)
-- | Current solver instance, pointing to yices. -- | Current solver instance, pointing to yices.
sbvCurrentSolver :: SMTConfig sbvCurrentSolver :: SMTConfig
@ -48,6 +48,12 @@ sat :: Provable a
-> IO SatResult -- ^ Response of the SMT Solver, containing the model if found -> IO SatResult -- ^ Response of the SMT Solver, containing the model if found
sat = satWith sbvCurrentSolver sat = satWith sbvCurrentSolver
-- | Check safety, i.e., prove that all 'sAssert' conditions are statically true in all paths
safe :: SExecutable a
=> a -- ^ Program to check the safety of
-> IO SafeResult -- ^ Response of the SMT solver, containing the unsafe model if found
safe = safeWith sbvCurrentSolver
-- | Find all satisfying solutions, using the Yices SMT solver -- | Find all satisfying solutions, using the Yices SMT solver
allSat :: Provable a allSat :: Provable a
=> a -- ^ Property to check => a -- ^ Property to check

View File

@ -21,8 +21,8 @@
module Data.SBV.Bridge.Z3 ( module Data.SBV.Bridge.Z3 (
-- * Z3 specific interface -- * Z3 specific interface
sbvCurrentSolver sbvCurrentSolver
-- ** Proving and checking satisfiability -- ** Proving, checking satisfiability, and safety
, prove, sat, allSat, isVacuous, isTheorem, isSatisfiable , prove, sat, safe, allSat, isVacuous, isTheorem, isSatisfiable
-- ** Optimization routines -- ** Optimization routines
, optimize, minimize, maximize , optimize, minimize, maximize
-- * Non-Z3 specific SBV interface -- * Non-Z3 specific SBV interface
@ -30,7 +30,7 @@ module Data.SBV.Bridge.Z3 (
, module Data.SBV , module Data.SBV
) where ) where
import Data.SBV hiding (prove, sat, allSat, isVacuous, isTheorem, isSatisfiable, optimize, minimize, maximize, sbvCurrentSolver) import Data.SBV hiding (prove, sat, safe, allSat, isVacuous, isTheorem, isSatisfiable, optimize, minimize, maximize, sbvCurrentSolver)
-- | Current solver instance, pointing to z3. -- | Current solver instance, pointing to z3.
sbvCurrentSolver :: SMTConfig sbvCurrentSolver :: SMTConfig
@ -48,6 +48,12 @@ sat :: Provable a
-> IO SatResult -- ^ Response of the SMT Solver, containing the model if found -> IO SatResult -- ^ Response of the SMT Solver, containing the model if found
sat = satWith sbvCurrentSolver sat = satWith sbvCurrentSolver
-- | Check safety, i.e., prove that all 'sAssert' conditions are statically true in all paths
safe :: SExecutable a
=> a -- ^ Program to check the safety of
-> IO SafeResult -- ^ Response of the SMT solver, containing the unsafe model if found
safe = safeWith sbvCurrentSolver
-- | Find all satisfying solutions, using the Z3 SMT solver -- | Find all satisfying solutions, using the Z3 SMT solver
allSat :: Provable a allSat :: Provable a
=> a -- ^ Property to check => a -- ^ Property to check

View File

@ -487,10 +487,21 @@ ppExpr cfg consts (SBVApp op opArgs) = p op (map (showSW cfg consts) opArgs)
, (Equal, "=="), (NotEqual, "!="), (LessThan, "<"), (GreaterThan, ">"), (LessEq, "<="), (GreaterEq, ">=") , (Equal, "=="), (NotEqual, "!="), (LessThan, "<"), (GreaterThan, ">"), (LessEq, "<="), (GreaterEq, ">=")
, (And, "&"), (Or, "|"), (XOr, "^") , (And, "&"), (Or, "|"), (XOr, "^")
] ]
uninterpret "squareRoot" as = let f = case kindOf (head opArgs) of
KFloat -> text "sqrtf"
KDouble -> text "sqrt"
k -> die $ "squareRoot on unexpected kind: " ++ show k
in f <> parens (fsep (punctuate comma as))
uninterpret "fusedMA" as = let f = case kindOf (head opArgs) of
KFloat -> text "fmaf"
KDouble -> text "fma"
k -> die $ "fusedMA on unexpected kind: " ++ show k
in f <> parens (fsep (punctuate comma as))
uninterpret s [] = text "/* Uninterpreted constant */" <+> text s
uninterpret s as = text "/* Uninterpreted function */" <+> text s <> parens (fsep (punctuate comma as))
p (ArrRead _) _ = tbd "User specified arrays (ArrRead)" p (ArrRead _) _ = tbd "User specified arrays (ArrRead)"
p (ArrEq _ _) _ = tbd "User specified arrays (ArrEq)" p (ArrEq _ _) _ = tbd "User specified arrays (ArrEq)"
p (Uninterpreted s) [] = text "/* Uninterpreted constant */" <+> text s p (Uninterpreted s) as = uninterpret s as
p (Uninterpreted s) as = text "/* Uninterpreted function */" <+> text s <> parens (fsep (punctuate comma as))
p (Extract i j) [a] = extract i j (head opArgs) a p (Extract i j) [a] = extract i j (head opArgs) a
p Join [a, b] = join (let (s1 : s2 : _) = opArgs in (s1, s2, a, b)) p Join [a, b] = join (let (s1 : s2 : _) = opArgs in (s1, s2, a, b))
p (Rol i) [a] = rotate True i a (head opArgs) p (Rol i) [a] = rotate True i a (head opArgs)

View File

@ -79,7 +79,7 @@ extractMap inps _modelMap solverLines =
-- Boolector outputs in a non-parenthesized way; and also puts x's for don't care bits: -- Boolector outputs in a non-parenthesized way; and also puts x's for don't care bits:
cvt :: String -> String cvt :: String -> String
cvt s = case words s of cvt s = case words s of
[var, val] -> "((" ++ var ++ " #b" ++ map tr val ++ "))" [_, val, var] -> "((" ++ var ++ " #b" ++ map tr val ++ "))"
_ -> s -- good-luck.. _ -> s -- good-luck..
where tr 'x' = '0' where tr 'x' = '0'
tr x = x tr x = x

View File

@ -13,13 +13,15 @@
{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverlappingInstances #-} {-# LANGUAGE OverlappingInstances #-}
{-# LANGUAGE BangPatterns #-} {-# LANGUAGE BangPatterns #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Data.SBV.Provers.Prover ( module Data.SBV.Provers.Prover (
SMTSolver(..), SMTConfig(..), Predicate, Provable(..) SMTSolver(..), SMTConfig(..), Predicate, Provable(..)
, ThmResult(..), SatResult(..), AllSatResult(..), SMTResult(..) , ThmResult(..), SatResult(..), AllSatResult(..), SMTResult(..), SafeResult(..)
, isSatisfiable, isSatisfiableWith, isTheorem, isTheoremWith , isSatisfiable, isSatisfiableWith, isTheorem, isTheoremWith
, prove, proveWith , prove, proveWith
, sat, satWith , sat, satWith
, safe, safeWith
, allSat, allSatWith , allSat, allSatWith
, isVacuous, isVacuousWith , isVacuous, isVacuousWith
, SatModel(..), Modelable(..), displayModels, extractModels , SatModel(..), Modelable(..), displayModels, extractModels
@ -27,18 +29,21 @@ module Data.SBV.Provers.Prover (
, boolector, cvc4, yices, z3, mathSAT, defaultSMTCfg , boolector, cvc4, yices, z3, mathSAT, defaultSMTCfg
, compileToSMTLib, generateSMTBenchmarks , compileToSMTLib, generateSMTBenchmarks
, isSBranchFeasibleInState , isSBranchFeasibleInState
, isConditionSatisfiable
) where ) where
import Control.Monad (when, unless) import Control.Monad (when, unless)
import Control.Monad.Trans (liftIO) import Control.Monad.Trans (liftIO)
import Data.List (intercalate) import Data.List (intercalate)
import Data.Maybe (mapMaybe, fromMaybe) import Data.Maybe (mapMaybe, fromMaybe, isJust)
import System.FilePath (addExtension, splitExtension) import System.FilePath (addExtension, splitExtension)
import System.Time (getClockTime) import System.Time (getClockTime)
import System.IO.Unsafe (unsafeInterleaveIO) import System.IO.Unsafe (unsafeInterleaveIO)
import qualified Data.Set as Set (Set, toList) import qualified Data.Set as Set (Set, toList)
import qualified Control.Exception as C
import Data.SBV.BitVectors.Data import Data.SBV.BitVectors.Data
import Data.SBV.SMT.SMT import Data.SBV.SMT.SMT
import Data.SBV.SMT.SMTLib import Data.SBV.SMT.SMTLib
@ -232,6 +237,10 @@ prove = proveWith defaultSMTCfg
sat :: Provable a => a -> IO SatResult sat :: Provable a => a -> IO SatResult
sat = satWith defaultSMTCfg sat = satWith defaultSMTCfg
-- | Check if a given definition is safe; i.e., if all 'sAssert' conditions can be proven to hold.
safe :: SExecutable a => a -> IO SafeResult
safe = safeWith defaultSMTCfg
-- | Return all satisfying assignments for a predicate, equivalent to @'allSatWith' 'defaultSMTCfg'@. -- | Return all satisfying assignments for a predicate, equivalent to @'allSatWith' 'defaultSMTCfg'@.
-- Satisfying assignments are constructed lazily, so they will be available as returned by the solver -- Satisfying assignments are constructed lazily, so they will be available as returned by the solver
-- and on demand. -- and on demand.
@ -326,6 +335,19 @@ satWith :: Provable a => SMTConfig -> a -> IO SatResult
satWith config a = simulate cvt config True [] a >>= callSolver True "Checking Satisfiability.." SatResult config satWith config a = simulate cvt config True [] a >>= callSolver True "Checking Satisfiability.." SatResult config
where cvt = if useSMTLib2 config then toSMTLib2 else toSMTLib1 where cvt = if useSMTLib2 config then toSMTLib2 else toSMTLib1
-- | Check if a given definition is safe using the given solver configuration; i.e., if all 'sAssert' conditions can be proven to hold.
safeWith :: SExecutable a => SMTConfig -> a -> IO SafeResult
safeWith config a = C.catchJust choose checkSafe return
where checkSafe = do let msg = when (verbose config) . putStrLn . ("** " ++)
isTiming = timing config
msg "Starting safety checking symbolic simulation.."
res <- timeIf isTiming "problem construction" $ runSymbolic (False, Just config) $ sName_ a >>= output
msg $ "Generated symbolic trace:\n" ++ show res
return SafeNeverFails
choose e@(SafeNeverFails{}) = Just e
choose e@(SafeAlwaysFails{}) = Just e
choose e@(SafeFailsInModel{}) = Just e
-- | Determine if the constraints are vacuous using the given SMT-solver -- | Determine if the constraints are vacuous using the given SMT-solver
isVacuousWith :: Provable a => SMTConfig -> a -> IO Bool isVacuousWith :: Provable a => SMTConfig -> a -> IO Bool
isVacuousWith config a = do isVacuousWith config a = do
@ -443,17 +465,35 @@ isSBranchFeasibleInState st branch cond = do
let cfg = let pickedConfig = fromMaybe defaultSMTCfg (getSBranchRunConfig st) let cfg = let pickedConfig = fromMaybe defaultSMTCfg (getSBranchRunConfig st)
in pickedConfig { timeOut = sBranchTimeOut pickedConfig } in pickedConfig { timeOut = sBranchTimeOut pickedConfig }
msg = when (verbose cfg) . putStrLn . ("** " ++) msg = when (verbose cfg) . putStrLn . ("** " ++)
sw <- sbvToSW st cond check <- internalSATCheck cfg st cond ("sBranch: Checking " ++ show branch ++ " feasibility")
() <- forceSWArg sw
Result ki tr uic is cs ts as uis ax asgn cstr _ <- liftIO $ extractSymbolicSimulationState st
let -- Construct the corresponding sat-checker for the branch. Note that we need to
-- forget about the quantifiers and just use an "exist", as we're looking for a
-- point-satisfiability check here; whatever the original program was.
pgm = Result ki tr uic [(EX, n) | (_, n) <- is] cs ts as uis ax asgn cstr [sw]
cvt = if useSMTLib2 cfg then toSMTLib2 else toSMTLib1
check <- runProofOn cvt cfg True [] pgm >>= callSolver True ("sBranch: Checking " ++ show branch ++ " feasibility") SatResult cfg
res <- case check of res <- case check of
SatResult (Unsatisfiable _) -> return False SatResult (Unsatisfiable _) -> return False
_ -> return True -- No risks, even if it timed-our or anything else, we say it's feasible _ -> return True -- No risks, even if it timed-our or anything else, we say it's feasible
msg $ "sBranch: Conclusion: " ++ if res then "Feasible" else "Unfeasible" msg $ "sBranch: Conclusion: " ++ if res then "Feasible" else "Unfeasible"
return res return res
-- | Check if a boolean condition is satisfiable in the current state. If so, it returns such a satisfying assignment
isConditionSatisfiable :: State -> SBool -> IO (Maybe SatResult)
isConditionSatisfiable st cond = do
let cfg = fromMaybe defaultSMTCfg (getSBranchRunConfig st)
msg = when (verbose cfg) . putStrLn . ("** " ++)
check <- internalSATCheck cfg st cond "sAssert: Checking satisfiability"
res <- case check of
r@(SatResult (Satisfiable{})) -> return $ Just r
SatResult (Unsatisfiable _) -> return Nothing
_ -> error $ "sAssert: Unexpected external result: " ++ show check
msg $ "sAssert: Conclusion: " ++ if isJust res then "Satisfiable" else "Unsatisfiable"
return res
-- | Check the boolean SAT of an internal condition in the current execution state
internalSATCheck :: SMTConfig -> State -> SBool -> String -> IO SatResult
internalSATCheck cfg st cond msg = do
sw <- sbvToSW st cond
() <- forceSWArg sw
Result ki tr uic is cs ts as uis ax asgn cstr _ <- liftIO $ extractSymbolicSimulationState st
let -- Construct the corresponding sat-checker for the branch. Note that we need to
-- forget about the quantifiers and just use an "exist", as we're looking for a
-- point-satisfiability check here; whatever the original program was.
pgm = Result ki tr uic [(EX, n) | (_, n) <- is] cs ts as uis ax asgn cstr [sw]
cvt = if useSMTLib2 cfg then toSMTLib2 else toSMTLib1
runProofOn cvt cfg True [] pgm >>= callSolver True msg SatResult cfg

View File

@ -10,12 +10,14 @@
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE DeriveDataTypeable #-}
module Data.SBV.SMT.SMT where module Data.SBV.SMT.SMT where
import qualified Control.Exception as C import qualified Control.Exception as C
import Control.Concurrent (newEmptyMVar, takeMVar, putMVar, forkIO) import Control.Concurrent (newEmptyMVar, takeMVar, putMVar, forkIO)
import Control.DeepSeq (NFData(..))
import Control.Monad (when, zipWithM) import Control.Monad (when, zipWithM)
import Data.Char (isSpace) import Data.Char (isSpace)
import Data.Int (Int8, Int16, Int32, Int64) import Data.Int (Int8, Int16, Int32, Int64)
@ -27,6 +29,7 @@ import System.Exit (ExitCode(..))
import System.IO (hClose, hFlush, hPutStr, hGetContents, hGetLine) import System.IO (hClose, hFlush, hPutStr, hGetContents, hGetLine)
import qualified Data.Map as M import qualified Data.Map as M
import Data.Typeable
import Data.SBV.BitVectors.AlgReals import Data.SBV.BitVectors.AlgReals
import Data.SBV.BitVectors.Data import Data.SBV.BitVectors.Data
@ -84,6 +87,22 @@ instance Show AllSatResult where
Satisfiable{} -> True Satisfiable{} -> True
_ -> False _ -> False
-- | The result of an 'sAssert' call
data SafeResult = SafeNeverFails
| SafeAlwaysFails String
| SafeFailsInModel String SMTConfig SMTModel
deriving Typeable
-- | The show instance for SafeResult. Note that this is for display purposes only,
-- user programs are likely to pattern match on the output and proceed accordingly.
instance Show SafeResult where
show SafeNeverFails = "No safety violations detected."
show (SafeAlwaysFails s) = intercalate "\n" ["Assertion failure: " ++ show s, "*** Fails in all assignments to inputs"]
show (SafeFailsInModel s cfg md) = intercalate "\n" ["Assertion failure: " ++ show s, showModel cfg md]
-- | If a 'prove' or 'sat' call comes accross an 'sAssert' call that fails, they will throw a 'SafeResult' as an exception.
instance C.Exception SafeResult
-- | Instances of 'SatModel' can be automatically extracted from models returned by the -- | Instances of 'SatModel' can be automatically extracted from models returned by the
-- solvers. The idea is that the sbv infrastructure provides a stream of 'CW''s (constant-words) -- solvers. The idea is that the sbv infrastructure provides a stream of 'CW''s (constant-words)
-- coming from the solver, and the type @a@ is interpreted based on these constants. Many typical -- coming from the solver, and the type @a@ is interpreted based on these constants. Many typical
@ -352,11 +371,15 @@ pipeProcess cfg execName opts script cleanErrs = do
let nm = show (name (solver cfg)) let nm = show (name (solver cfg))
mbExecPath <- findExecutable execName mbExecPath <- findExecutable execName
case mbExecPath of case mbExecPath of
Nothing -> return $ Left $ "Unable to locate executable for " ++ nm Nothing -> return $ Left $ "Unable to locate executable for " ++ nm
++ "\nExecutable specified: " ++ show execName ++ "\nExecutable specified: " ++ show execName
Just execPath -> do (ec, contents, allErrors) <- runSolver cfg execPath opts script Just execPath ->
let errors = dropWhile isSpace (cleanErrs allErrors) do solverResult <- dispatchSolver cfg execPath opts script
case (null errors, xformExitCode (solver cfg) ec) of case solverResult of
Left s -> return $ Left s
Right (ec, contents, allErrors) ->
let errors = dropWhile isSpace (cleanErrs allErrors)
in case (null errors, xformExitCode (solver cfg) ec) of
(True, ExitSuccess) -> return $ Right $ map clean (filter (not . null) (lines contents)) (True, ExitSuccess) -> return $ Right $ map clean (filter (not . null) (lines contents))
(_, ec') -> let errors' = if null errors (_, ec') -> let errors' = if null errors
then (if null (dropWhile isSpace contents) then (if null (dropWhile isSpace contents)
@ -400,6 +423,14 @@ standardSolver config script cleanErrs failure success = do
Left e -> return $ failure (lines e) Left e -> return $ failure (lines e)
Right xs -> return $ success (mergeSExpr xs) Right xs -> return $ success (mergeSExpr xs)
-- | Wrap the solver call to protect against any exceptions
dispatchSolver :: SMTConfig -> FilePath -> [String] -> SMTScript -> IO (Either String (ExitCode, String, String))
dispatchSolver cfg execPath opts script = rnf script `seq` (Right `fmap` runSolver cfg execPath opts script) `C.catch` (\(e::C.SomeException) -> bad (show e))
where bad s = return $ Left $ unlines [ "Failed to start the external solver: " ++ s
, "Make sure you can start " ++ show execPath
, "from the command line without issues."
]
-- | A variant of 'readProcessWithExitCode'; except it knows about continuation strings -- | A variant of 'readProcessWithExitCode'; except it knows about continuation strings
-- and can speak SMT-Lib2 (just a little). -- and can speak SMT-Lib2 (just a little).
runSolver :: SMTConfig -> FilePath -> [String] -> SMTScript -> IO (ExitCode, String, String) runSolver :: SMTConfig -> FilePath -> [String] -> SMTScript -> IO (ExitCode, String, String)

View File

@ -210,11 +210,14 @@ cvtExp (SBVApp (ArrRead i) [a]) = "(select array_" ++ show i ++ " " ++ show a ++
cvtExp (SBVApp (Uninterpreted nm) []) = "uninterpreted_" ++ nm cvtExp (SBVApp (Uninterpreted nm) []) = "uninterpreted_" ++ nm
cvtExp (SBVApp (Uninterpreted nm) args) = "(uninterpreted_" ++ nm ++ " " ++ unwords (map show args) ++ ")" cvtExp (SBVApp (Uninterpreted nm) args) = "(uninterpreted_" ++ nm ++ " " ++ unwords (map show args) ++ ")"
cvtExp inp@(SBVApp op args) cvtExp inp@(SBVApp op args)
| allBools, Just f <- lookup op boolComps
= f (map show args)
| Just f <- lookup op smtOpTable | Just f <- lookup op smtOpTable
= f (any hasSign args) (all isBoolean args) (map show args) = f (any hasSign args) allBools (map show args)
| True | True
= error $ "SBV.SMT.SMTLib1.cvtExp: impossible happened; can't translate: " ++ show inp = error $ "SBV.SMT.SMTLib1.cvtExp: impossible happened; can't translate: " ++ show inp
where lift2 o _ _ [x, y] = "(" ++ o ++ " " ++ x ++ " " ++ y ++ ")" where allBools = all isBoolean args
lift2 o _ _ [x, y] = "(" ++ o ++ " " ++ x ++ " " ++ y ++ ")"
lift2 o _ _ sbvs = error $ "SBV.SMTLib1.cvtExp.lift2: Unexpected arguments: " ++ show (o, sbvs) lift2 o _ _ sbvs = error $ "SBV.SMTLib1.cvtExp.lift2: Unexpected arguments: " ++ show (o, sbvs)
lift2S oU oS sgn isB sbvs lift2S oU oS sgn isB sbvs
| sgn | sgn
@ -240,6 +243,18 @@ cvtExp inp@(SBVApp op args)
| True | True
= "(= " ++ lift2 "bvcomp" sgn isB sbvs ++ " bv1[1])" = "(= " ++ lift2 "bvcomp" sgn isB sbvs ++ " bv1[1])"
neq sgn isB sbvs = "(not " ++ eq sgn isB sbvs ++ ")" neq sgn isB sbvs = "(not " ++ eq sgn isB sbvs ++ ")"
-- Boolean comparisons.. SMTLib's bool type doesn't do comparisons, but Haskell does.. Sigh
boolComps = [ (LessThan, blt)
, (GreaterThan, blt . swp)
, (LessEq, blq)
, (GreaterEq, blq . swp)
]
where blt [x, y] = "(and (not " ++ x ++ ") " ++ y ++ ")"
blt xs = error $ "SBV.SMT.SMTLib1.boolComps.blt: Impossible happened, incorrect arity (expected 2): " ++ show xs
blq [x, y] = "(or (not " ++ x ++ ") " ++ y ++ ")"
blq xs = error $ "SBV.SMT.SMTLib1.boolComps.blq: Impossible happened, incorrect arity (expected 2): " ++ show xs
swp [x, y] = [y, x]
swp xs = error $ "SBV.SMT.SMTLib1.boolComps.swp: Impossible happened, incorrect arity (expected 2): " ++ show xs
smtOpTable = [ (Plus, lift2 "bvadd") smtOpTable = [ (Plus, lift2 "bvadd")
, (Minus, lift2 "bvsub") , (Minus, lift2 "bvsub")
, (Times, lift2 "bvmul") , (Times, lift2 "bvmul")

View File

@ -442,6 +442,8 @@ cvtExp rm skolemMap tableMap expr@(SBVApp _ arguments) = sh expr
sh inp@(SBVApp op args) sh inp@(SBVApp op args)
| intOp, Just f <- lookup op smtOpIntTable | intOp, Just f <- lookup op smtOpIntTable
= f True (map ssw args) = f True (map ssw args)
| boolOp, Just f <- lookup op boolComps
= f (map ssw args)
| bvOp, Just f <- lookup op smtOpBVTable | bvOp, Just f <- lookup op smtOpBVTable
= f (any hasSign args) (map ssw args) = f (any hasSign args) (map ssw args)
| realOp, Just f <- lookup op smtOpRealTable | realOp, Just f <- lookup op smtOpRealTable
@ -464,6 +466,18 @@ cvtExp rm skolemMap tableMap expr@(SBVApp _ arguments) = sh expr
, (LessEq, lift2S "bvule" "bvsle") , (LessEq, lift2S "bvule" "bvsle")
, (GreaterEq, lift2S "bvuge" "bvsge") , (GreaterEq, lift2S "bvuge" "bvsge")
] ]
-- Boolean comparisons.. SMTLib's bool type doesn't do comparisons, but Haskell does.. Sigh
boolComps = [ (LessThan, blt)
, (GreaterThan, blt . swp)
, (LessEq, blq)
, (GreaterEq, blq . swp)
]
where blt [x, y] = "(and (not " ++ x ++ ") " ++ y ++ ")"
blt xs = error $ "SBV.SMT.SMTLib2.boolComps.blt: Impossible happened, incorrect arity (expected 2): " ++ show xs
blq [x, y] = "(or (not " ++ x ++ ") " ++ y ++ ")"
blq xs = error $ "SBV.SMT.SMTLib2.boolComps.blq: Impossible happened, incorrect arity (expected 2): " ++ show xs
swp [x, y] = [y, x]
swp xs = error $ "SBV.SMT.SMTLib2.boolComps.swp: Impossible happened, incorrect arity (expected 2): " ++ show xs
smtOpRealTable = smtIntRealShared smtOpRealTable = smtIntRealShared
++ [ (Quot, lift2WM "/") ++ [ (Quot, lift2WM "/")
] ]

View File

@ -43,7 +43,7 @@ evalExpr env expr = case expr of
ECon con -> evalECon con ECon con -> evalECon con
EList es ty -> evalList env es (evalType env ty) EList es ty -> VSeq (isTBit (evalType env ty)) (map (evalExpr env) es)
ETuple es -> VTuple (map eval es) ETuple es -> VTuple (map eval es)
@ -208,15 +208,3 @@ evalMatch env m = case m of
-- they are typechecked that way; the read environment to evalDecl is the same -- they are typechecked that way; the read environment to evalDecl is the same
-- as the environment to bind a new name in. -- as the environment to bind a new name in.
Let d -> [evalDecl env d env] Let d -> [evalDecl env d env]
-- Lists -----------------------------------------------------------------------
-- | Evaluate a list literal, optionally packing them into a word.
evalList :: EvalEnv -> [Expr] -> TValue -> Value
evalList env es ty = toPackedSeq w ty (map (evalExpr env) es)
where
w = TValue $ tNum $ length es

26
src/Cryptol/Eval/Arch.hs Normal file
View File

@ -0,0 +1,26 @@
-- |
-- Module : $Header$
-- Copyright : (c) 2014 Galois, Inc.
-- License : BSD3
-- Maintainer : cryptol@galois.com
-- Stability : provisional
-- Portability : portable
--
-- Architecture-specific parts of the concrete evaluator go here.
{-# LANGUAGE CPP #-}
module Cryptol.Eval.Arch where
-- | This is the widest word we can have before gmp will fail to
-- allocate and bring down the whole program. According to
-- <https://gmplib.org/list-archives/gmp-bugs/2009-July/001538.html>
-- the sizes are 2^32-1 for 32-bit, and 2^37 for 64-bit, however
-- experiments show that it's somewhere under 2^37 at least on 64-bit
-- Mac OS X.
maxBigIntWidth :: Integer
#if i386_HOST_ARCH
maxBigIntWidth = 2^(32 :: Integer) - 0x1
#elif x86_64_HOST_ARCH
maxBigIntWidth = 2^(37 :: Integer) - 0x100
#else
#error unknown max width for gmp on this architecture
#endif

View File

@ -30,6 +30,7 @@ data EvalError
= InvalidIndex Integer = InvalidIndex Integer
| TypeCannotBeDemoted Type | TypeCannotBeDemoted Type
| DivideByZero | DivideByZero
| WordTooWide Integer
| UserError String | UserError String
deriving (Typeable,Show) deriving (Typeable,Show)
@ -38,6 +39,8 @@ instance PP EvalError where
InvalidIndex i -> text "invalid sequence index:" <+> integer i InvalidIndex i -> text "invalid sequence index:" <+> integer i
TypeCannotBeDemoted t -> text "type cannot be demoted:" <+> pp t TypeCannotBeDemoted t -> text "type cannot be demoted:" <+> pp t
DivideByZero -> text "division by 0" DivideByZero -> text "division by 0"
WordTooWide w ->
text "word too wide for memory:" <+> integer w <+> text "bits"
UserError x -> text "Run-time error:" <+> text x UserError x -> text "Run-time error:" <+> text x
instance X.Exception EvalError instance X.Exception EvalError
@ -54,6 +57,12 @@ typeCannotBeDemoted t = X.throw (TypeCannotBeDemoted t)
divideByZero :: a divideByZero :: a
divideByZero = X.throw DivideByZero divideByZero = X.throw DivideByZero
-- | For when we know that a word is too wide and will exceed gmp's
-- limits (though words approaching this size will probably cause the
-- system to crash anyway due to lack of memory)
wordTooWide :: Integer -> a
wordTooWide w = X.throw (WordTooWide w)
-- | For `error` -- | For `error`
cryUserError :: String -> a cryUserError :: String -> a
cryUserError msg = X.throw (UserError msg) cryUserError msg = X.throw (UserError msg)

View File

@ -9,10 +9,12 @@
{-# LANGUAGE PatternGuards #-} {-# LANGUAGE PatternGuards #-}
{-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE Safe #-} {-# LANGUAGE Safe #-}
module Cryptol.Eval.Value where module Cryptol.Eval.Value where
import qualified Cryptol.Eval.Arch as Arch
import Cryptol.Eval.Error import Cryptol.Eval.Error
import Cryptol.Prims.Syntax (ECon(..)) import Cryptol.Prims.Syntax (ECon(..))
import Cryptol.TypeCheck.AST import Cryptol.TypeCheck.AST
@ -77,6 +79,10 @@ finTValue tval =
data BV = BV !Integer !Integer -- ^ width, value data BV = BV !Integer !Integer -- ^ width, value
-- The value may contain junk bits -- The value may contain junk bits
-- | Smart constructor for 'BV's that checks for the width limit
mkBv :: Integer -> Integer -> BV
mkBv w i | w >= Arch.maxBigIntWidth = wordTooWide w
| otherwise = BV w i
-- | Generic value type, parameterized by bit and word types. -- | Generic value type, parameterized by bit and word types.
data GenValue b w data GenValue b w
@ -183,35 +189,45 @@ ppWord opts (BV width i)
-- Big-endian Words ------------------------------------------------------------ -- Big-endian Words ------------------------------------------------------------
class BitWord b w where
-- | NOTE this assumes that the sequence of bits is big-endian and finite, so the
-- first element of the list will be the most significant bit.
packWord :: [b] -> w
-- | NOTE this produces a list of bits that represent a big-endian word, so the
-- most significant bit is the first element of the list.
unpackWord :: w -> [b]
mask :: Integer -- ^ Bit-width mask :: Integer -- ^ Bit-width
-> Integer -- ^ Value -> Integer -- ^ Value
-> Integer -- ^ Masked result -> Integer -- ^ Masked result
mask w i = i .&. ((1 `shiftL` fromInteger w) - 1) mask w i | w >= Arch.maxBigIntWidth = wordTooWide w
| otherwise = i .&. ((1 `shiftL` fromInteger w) - 1)
-- NOTE this assumes that the sequence of bits is big-endian and finite, so the instance BitWord Bool BV where
-- first element of the list will be the most significant bit.
packWord :: [Bool] -> BV
packWord bits = BV (toInteger w) a
where
w = length bits
a = foldl set 0 (zip [w - 1, w - 2 .. 0] bits)
set acc (n,b) | b = setBit acc n
| otherwise = acc
-- NOTE this produces a list of bits that represent a big-endian word, so the packWord bits = BV (toInteger w) a
-- most significant bit is the first element of the list. where
unpackWord :: BV -> [Bool] w = case length bits of
unpackWord (BV w a) = [ testBit a n | n <- [w' - 1, w' - 2 .. 0] ] len | toInteger len >= Arch.maxBigIntWidth -> wordTooWide (toInteger len)
where | otherwise -> len
w' = fromInteger w a = foldl set 0 (zip [w - 1, w - 2 .. 0] bits)
set acc (n,b) | b = setBit acc n
| otherwise = acc
unpackWord (BV w a) = [ testBit a n | n <- [w' - 1, w' - 2 .. 0] ]
where
w' = fromInteger w
-- Value Constructors ---------------------------------------------------------- -- Value Constructors ----------------------------------------------------------
-- | Create a packed word of n bits. -- | Create a packed word of n bits.
word :: Integer -> Integer -> Value word :: Integer -> Integer -> Value
word n i = VWord (BV n (mask n i)) word n i = VWord (mkBv n (mask n i))
lam :: (GenValue b w -> GenValue b w) -> GenValue b w lam :: (GenValue b w -> GenValue b w) -> GenValue b w
lam = VFun lam = VFun
@ -265,7 +281,7 @@ fromVBit val = case val of
_ -> evalPanic "fromVBit" ["not a Bit"] _ -> evalPanic "fromVBit" ["not a Bit"]
-- | Extract a sequence. -- | Extract a sequence.
fromSeq :: Value -> [Value] fromSeq :: BitWord b w => GenValue b w -> [GenValue b w]
fromSeq val = case val of fromSeq val = case val of
VSeq _ vs -> vs VSeq _ vs -> vs
VWord bv -> map VBit (unpackWord bv) VWord bv -> map VBit (unpackWord bv)
@ -277,12 +293,11 @@ fromStr = map (toEnum . fromInteger . fromWord) . fromSeq
-- | Extract a packed word. -- | Extract a packed word.
-- Note that this does not clean-up any junk bits in the word. -- Note that this does not clean-up any junk bits in the word.
fromVWord :: Value -> BV fromVWord :: BitWord b w => GenValue b w -> w
fromVWord val = case val of fromVWord val = case val of
VWord bv -> bv -- this should always mask VWord bv -> bv -- this should always mask
VSeq isWord bs | isWord -> packWord (map fromVBit bs) VSeq isWord bs | isWord -> packWord (map fromVBit bs)
_ -> evalPanic "fromVWord" _ -> evalPanic "fromVWord" ["not a word"]
["not a word", show $ ppValue defaultPPOpts val]
vWordLen :: Value -> Maybe Integer vWordLen :: Value -> Maybe Integer
vWordLen val = case val of vWordLen val = case val of

View File

@ -36,49 +36,80 @@ import qualified Data.Map as Map
-- Errors ---------------------------------------------------------------------- -- Errors ----------------------------------------------------------------------
-- XXX make these located
data RenamerError data RenamerError
= MultipleSyms (Located QName) [NameOrigin] = MultipleSyms (Located QName) [NameOrigin]
-- ^ Multiple imported symbols contain this name -- ^ Multiple imported symbols contain this name
| UnboundSym (Located QName)
-- ^ Symbol is not bound to any definition | UnboundExpr (Located QName)
-- ^ Expression name is not bound to any definition
| UnboundType (Located QName)
-- ^ Type name is not bound to any definition
| OverlappingSyms [NameOrigin] | OverlappingSyms [NameOrigin]
-- ^ An environment has produced multiple overlapping symbols -- ^ An environment has produced multiple overlapping symbols
| BuiltInTypeDecl QName | ExpectedValue (Located QName)
-- ^ This is a built-in type name, and user may not shadow it. -- ^ When a value is expected from the naming environment, but one or more
-- types exist instead.
| ExpectedType (Located QName)
-- ^ When a type is missing from the naming environment, but one or more
-- values exist with the same name.
deriving (Show) deriving (Show)
instance PP RenamerError where instance PP RenamerError where
ppPrec _ e = case e of ppPrec _ e = case e of
MultipleSyms lqn qns -> MultipleSyms lqn qns ->
hang (text "[error] Multiple definitions for symbol:" <+> pp lqn) hang (text "[error] at" <+> pp (srcRange lqn))
4 (vcat (map pp qns)) 4 $ (text "Multiple definitions for symbol:" <+> pp (thing lqn))
$$ vcat (map pp qns)
UnboundSym lqn -> UnboundExpr lqn ->
text "[error] unbound symbol:" <+> pp lqn hang (text "[error] at" <+> pp (srcRange lqn))
4 (text "Value not in scope:" <+> pp (thing lqn))
UnboundType lqn ->
hang (text "[error] at" <+> pp (srcRange lqn))
4 (text "Type not in scope:" <+> pp (thing lqn))
-- XXX these really need to be located
OverlappingSyms qns -> OverlappingSyms qns ->
hang (text "[error] Overlapping symbols defined:") hang (text "[error]")
4 (vcat (map pp qns)) 4 $ text "Overlapping symbols defined:"
$$ vcat (map pp qns)
BuiltInTypeDecl q -> ExpectedValue lqn ->
hang (text "[error] Built-in type name may not be shadowed:") hang (text "[error] at" <+> pp (srcRange lqn))
4 (pp q) 4 (fsep [ text "Expected a value named", quotes (pp (thing lqn))
, text "but found a type instead"
, text "Did you mean `(" <> pp (thing lqn) <> text")?" ])
ExpectedType lqn ->
hang (text "[error] at" <+> pp (srcRange lqn))
4 (fsep [ text "Expected a type named", quotes (pp (thing lqn))
, text "but found a value instead" ])
-- Warnings -------------------------------------------------------------------- -- Warnings --------------------------------------------------------------------
data RenamerWarning data RenamerWarning
= SymbolShadowed [NameOrigin] [NameOrigin] = SymbolShadowed NameOrigin [NameOrigin]
deriving (Show) deriving (Show)
instance PP RenamerWarning where instance PP RenamerWarning where
ppPrec _ (SymbolShadowed original new) = ppPrec _ (SymbolShadowed new originals) =
hang (text "[warning] This binding for" <+> commaSep (map pp original) hang (text "[warning] at" <+> loc)
<+> text "shadows the existing binding") 4 $ fsep [ text "This binding for" <+> sym
4 (vcat (map pp new)) , text "shadows the existing binding" <> plural <+> text "from" ]
$$ vcat (map pp originals)
where
plural | length originals > 1 = char 's'
| otherwise = empty
(loc,sym) = case new of
Local lqn -> (pp (srcRange lqn), pp (thing lqn))
Imported qn -> (empty, pp qn)
-- Renaming Monad -------------------------------------------------------------- -- Renaming Monad --------------------------------------------------------------
@ -158,37 +189,35 @@ shadowNames names m = RenameM $ do
let ro' = ro { roNames = env `shadowing` roNames ro } let ro' = ro { roNames = env `shadowing` roNames ro }
local ro' (unRenameM m) local ro' (unRenameM m)
-- | Generate warnings when the the left environment shadows things defined in -- | Generate warnings when the left environment shadows things defined in
-- the right. Additionally, generate errors when two names overlap in the -- the right. Additionally, generate errors when two names overlap in the
-- left environment. -- left environment.
checkEnv :: NamingEnv -> NamingEnv -> Out checkEnv :: NamingEnv -> NamingEnv -> Out
checkEnv l r = Map.foldlWithKey (step False neExprs) mempty (neExprs l) checkEnv l r = Map.foldlWithKey (step neExprs) mempty (neExprs l)
`mappend` Map.foldlWithKey (step True neTypes) mempty (neTypes l) `mappend` Map.foldlWithKey (step neTypes) mempty (neTypes l)
where where
step isType prj acc k ns = acc `mappend` Out step prj acc k ns = acc `mappend` mempty
{ oWarnings = case Map.lookup k (prj r) of { oWarnings = case Map.lookup k (prj r) of
Nothing -> [] Nothing -> []
Just os -> [SymbolShadowed (map origin os) (map origin ns)] Just os -> [SymbolShadowed (origin (head ns)) (map origin os)]
, oErrors = containsOverlap ns , oErrors = containsOverlap ns
} `mappend` }
checkValidDecl isType k
containsOverlap ns = case ns of
[_] -> []
[] -> panic "Renamer" ["Invalid naming environment"]
_ -> [OverlappingSyms (map origin ns)]
checkValidDecl True nm@(QName _ (Name "width")) =
mempty { oErrors = [BuiltInTypeDecl nm] }
checkValidDecl _ _ = mempty
-- | Check the RHS of a single name rewrite for conflicting sources.
containsOverlap :: HasQName a => [a] -> [RenamerError]
containsOverlap [_] = []
containsOverlap [] = panic "Renamer" ["Invalid naming environment"]
containsOverlap ns = [OverlappingSyms (map origin ns)]
-- | Throw errors for any names that overlap in a rewrite environment. -- | Throw errors for any names that overlap in a rewrite environment.
checkNamingEnv :: NamingEnv -> ([RenamerError],[RenamerWarning]) checkNamingEnv :: NamingEnv -> ([RenamerError],[RenamerWarning])
checkNamingEnv env = (oErrors out, oWarnings out) checkNamingEnv env = (out, [])
where where
out = checkEnv env mempty out = Map.foldr check outTys (neExprs env)
outTys = Map.foldr check mempty (neTypes env)
check ns acc = containsOverlap ns ++ acc
-- Renaming -------------------------------------------------------------------- -- Renaming --------------------------------------------------------------------
@ -258,7 +287,13 @@ renameExpr qn = do
return qn return qn
Nothing -> Nothing ->
do n <- located qn do n <- located qn
record (UnboundSym n)
case Map.lookup qn (neTypes (roNames ro)) of
-- types existed with the name of the value expected
Just _ -> record (ExpectedValue n)
-- the value is just missing
Nothing -> record (UnboundExpr n)
return qn return qn
renameType :: QName -> RenameM QName renameType :: QName -> RenameM QName
@ -273,7 +308,15 @@ renameType qn = do
return qn return qn
Nothing -> Nothing ->
do n <- located qn do n <- located qn
record (UnboundSym n)
case Map.lookup qn (neExprs (roNames ro)) of
-- values exist with the same name, so throw a different error
Just _ -> record (ExpectedType n)
-- no terms with the same name, so the type is just unbound
Nothing -> record (UnboundType n)
return qn return qn
-- | Rename a schema, assuming that none of its type variables are already in -- | Rename a schema, assuming that none of its type variables are already in
@ -377,6 +420,7 @@ instance Rename Expr where
ESel e' s -> ESel <$> rename e' <*> pure s ESel e' s -> ESel <$> rename e' <*> pure s
EList es -> EList <$> rename es EList es -> EList <$> rename es
EFromTo s n e'-> EFromTo <$> rename s <*> rename n <*> rename e' EFromTo s n e'-> EFromTo <$> rename s <*> rename n <*> rename e'
EInfFrom a b -> EInfFrom<$> rename a <*> rename b
EComp e' bs -> do bs' <- mapM renameMatch bs EComp e' bs -> do bs' <- mapM renameMatch bs
shadowNames (namingEnv bs') shadowNames (namingEnv bs')
(EComp <$> rename e' <*> pure bs') (EComp <$> rename e' <*> pure bs')

View File

@ -510,8 +510,8 @@ list_expr :: { Expr }
| expr ',' expr '..' {% eFromTo $4 $1 (Just $3) Nothing } | expr ',' expr '..' {% eFromTo $4 $1 (Just $3) Nothing }
| expr ',' expr '..' expr {% eFromTo $4 $1 (Just $3) (Just $5) } | expr ',' expr '..' expr {% eFromTo $4 $1 (Just $3) (Just $5) }
| expr '...' { EApp (ECon ECInfFrom) $1 } | expr '...' { EInfFrom $1 Nothing }
| expr ',' expr '...' { EApp (EApp (ECon ECInfFromThen) $1) $3 } | expr ',' expr '...' { EInfFrom $1 (Just $3) }
list_alts :: { [[Match]] } list_alts :: { [[Match]] }

View File

@ -253,6 +253,7 @@ data Expr = EVar QName -- ^ @ x @
| ESel Expr Selector -- ^ @ e.l @ | ESel Expr Selector -- ^ @ e.l @
| EList [Expr] -- ^ @ [1,2,3] @ | EList [Expr] -- ^ @ [1,2,3] @
| EFromTo Type (Maybe Type) (Maybe Type) -- ^ @[1, 5 .. 117 ] @ | EFromTo Type (Maybe Type) (Maybe Type) -- ^ @[1, 5 .. 117 ] @
| EInfFrom Expr (Maybe Expr) -- ^ @ [1, 3 ...] @
| EComp Expr [[Match]] -- ^ @ [ 1 | x <- xs ] @ | EComp Expr [[Match]] -- ^ @ [ 1 | x <- xs ] @
| EApp Expr Expr -- ^ @ f x @ | EApp Expr Expr -- ^ @ f x @
| EAppT Expr [TypeInst] -- ^ @ f `{x = 8}, f`{8} @ | EAppT Expr [TypeInst] -- ^ @ f `{x = 8}, f`{8} @
@ -665,6 +666,8 @@ instance PP Expr where
EFromTo e1 e2 e3 -> brackets (pp e1 <> step <+> text ".." <+> end) EFromTo e1 e2 e3 -> brackets (pp e1 <> step <+> text ".." <+> end)
where step = maybe empty (\e -> comma <+> pp e) e2 where step = maybe empty (\e -> comma <+> pp e) e2
end = maybe empty pp e3 end = maybe empty pp e3
EInfFrom e1 e2 -> brackets (pp e1 <> step <+> text "...")
where step = maybe empty (\e -> comma <+> pp e) e2
EComp e mss -> brackets (pp e <+> vcat (map arm mss)) EComp e mss -> brackets (pp e <+> vcat (map arm mss))
where arm ms = text "|" <+> commaSep (map pp ms) where arm ms = text "|" <+> commaSep (map pp ms)
ETypeVal t -> text "`" <> ppPrec 5 t -- XXX ETypeVal t -> text "`" <> ppPrec 5 t -- XXX
@ -893,6 +896,7 @@ instance NoPos Expr where
ESel x y -> ESel (noPos x) y ESel x y -> ESel (noPos x) y
EList x -> EList (noPos x) EList x -> EList (noPos x)
EFromTo x y z -> EFromTo (noPos x) (noPos y) (noPos z) EFromTo x y z -> EFromTo (noPos x) (noPos y) (noPos z)
EInfFrom x y -> EInfFrom (noPos x) (noPos y)
EComp x y -> EComp (noPos x) (noPos y) EComp x y -> EComp (noPos x) (noPos y)
EApp x y -> EApp (noPos x) (noPos y) EApp x y -> EApp (noPos x) (noPos y)
EAppT x y -> EAppT (noPos x) (noPos y) EAppT x y -> EAppT (noPos x) (noPos y)

View File

@ -15,6 +15,7 @@ import Cryptol.Utils.PP
import Cryptol.Utils.Panic import Cryptol.Utils.Panic
import Data.Char(toLower) import Data.Char(toLower)
import Data.List(foldl')
import Data.Word(Word8) import Data.Word(Word8)
import Codec.Binary.UTF8.String(encodeChar) import Codec.Binary.UTF8.String(encodeChar)
@ -156,8 +157,7 @@ emitS t cfg p s z = emit (t s) cfg p s z
numToken :: Integer -> String -> TokenT numToken :: Integer -> String -> TokenT
numToken rad ds = Num (toVal ds) (fromInteger rad) (length ds) numToken rad ds = Num (toVal ds) (fromInteger rad) (length ds)
where where
toVal = sum . zipWith (\n x -> rad^n * x) [0 :: Integer ..] toVal = foldl' (\x c -> rad * x + toDig c) 0
. map toDig . reverse
toDig = if rad == 16 then fromHexDigit else fromDecDigit toDig = if rad == 16 then fromHexDigit else fromDecDigit
fromDecDigit :: Char -> Integer fromDecDigit :: Char -> Integer

View File

@ -84,6 +84,7 @@ namesE expr =
ESel e _ -> namesE e ESel e _ -> namesE e
EList es -> Set.unions (map namesE es) EList es -> Set.unions (map namesE es)
EFromTo _ _ _ -> Set.empty EFromTo _ _ _ -> Set.empty
EInfFrom e e' -> Set.union (namesE e) (maybe Set.empty namesE e')
EComp e arms -> let (dss,uss) = unzip (map namesArm arms) EComp e arms -> let (dss,uss) = unzip (map namesArm arms)
in Set.union (boundNames (concat dss) (namesE e)) in Set.union (boundNames (concat dss) (namesE e))
(Set.unions uss) (Set.unions uss)
@ -194,6 +195,7 @@ tnamesE expr =
EList es -> Set.unions (map tnamesE es) EList es -> Set.unions (map tnamesE es)
EFromTo a b c -> Set.union (tnamesT a) EFromTo a b c -> Set.union (tnamesT a)
(Set.union (maybe Set.empty tnamesT b) (maybe Set.empty tnamesT c)) (Set.union (maybe Set.empty tnamesT b) (maybe Set.empty tnamesT c))
EInfFrom e e' -> Set.union (tnamesE e) (maybe Set.empty tnamesE e')
EComp e mss -> Set.union (tnamesE e) (Set.unions (map tnamesM (concat mss))) EComp e mss -> Set.union (tnamesE e) (Set.unions (map tnamesM (concat mss)))
EApp e1 e2 -> Set.union (tnamesE e1) (tnamesE e2) EApp e1 e2 -> Set.union (tnamesE e1) (tnamesE e2)
EAppT e fs -> Set.union (tnamesE e) (Set.unions (map tnamesTI fs)) EAppT e fs -> Set.union (tnamesE e) (Set.unions (map tnamesTI fs))

View File

@ -25,6 +25,7 @@ import Control.Applicative(Applicative(..),(<$>))
import Data.Maybe(maybeToList) import Data.Maybe(maybeToList)
import Data.Either(partitionEithers) import Data.Either(partitionEithers)
import qualified Data.Map as Map import qualified Data.Map as Map
import Data.Traversable(traverse)
class RemovePatterns t where class RemovePatterns t where
@ -147,6 +148,7 @@ noPatE expr =
ESel e s -> ESel <$> noPatE e <*> return s ESel e s -> ESel <$> noPatE e <*> return s
EList es -> EList <$> mapM noPatE es EList es -> EList <$> mapM noPatE es
EFromTo {} -> return expr EFromTo {} -> return expr
EInfFrom e e' -> EInfFrom <$> noPatE e <*> traverse noPatE e'
EComp e mss -> EComp <$> noPatE e <*> mapM noPatArm mss EComp e mss -> EComp <$> noPatE e <*> mapM noPatArm mss
EApp e1 e2 -> EApp <$> noPatE e1 <*> noPatE e2 EApp e1 e2 -> EApp <$> noPatE e1 <*> noPatE e2
EAppT e ts -> EAppT <$> noPatE e <*> return ts EAppT e ts -> EAppT <$> noPatE e <*> return ts

View File

@ -20,10 +20,11 @@ module Cryptol.Prims.Eval where
import Cryptol.Prims.Syntax (ECon(..)) import Cryptol.Prims.Syntax (ECon(..))
import Cryptol.TypeCheck.AST import Cryptol.TypeCheck.AST
import Cryptol.TypeCheck.Solver.InfNat (Nat'(..),fromNat,genLog, nMul) import Cryptol.TypeCheck.Solver.InfNat (Nat'(..),fromNat,genLog, nMul)
import qualified Cryptol.Eval.Arch as Arch
import Cryptol.Eval.Error import Cryptol.Eval.Error
import Cryptol.Testing.Random (randomValue)
import Cryptol.Eval.Value
import Cryptol.Eval.Type(evalTF) import Cryptol.Eval.Type(evalTF)
import Cryptol.Eval.Value
import Cryptol.Testing.Random (randomValue)
import Cryptol.Utils.Panic (panic) import Cryptol.Utils.Panic (panic)
import Data.List (sortBy,transpose,genericTake,genericReplicate,genericSplitAt,genericIndex) import Data.List (sortBy,transpose,genericTake,genericReplicate,genericSplitAt,genericIndex)
@ -208,7 +209,7 @@ ecDemoteV :: Value
ecDemoteV = tlam $ \valT -> ecDemoteV = tlam $ \valT ->
tlam $ \bitT -> tlam $ \bitT ->
case (numTValue valT, numTValue bitT) of case (numTValue valT, numTValue bitT) of
(Nat v, Nat bs) -> VWord (BV bs v) (Nat v, Nat bs) -> VWord (mkBv bs v)
_ -> evalPanic "Cryptol.Eval.Prim.evalConst" _ -> evalPanic "Cryptol.Eval.Prim.evalConst"
["Unexpected Inf in constant." ["Unexpected Inf in constant."
, show valT , show valT
@ -310,7 +311,7 @@ arithBinary op = loop
| Just (len,a) <- isTSeq ty = case numTValue len of | Just (len,a) <- isTSeq ty = case numTValue len of
-- words and finite sequences -- words and finite sequences
Nat w | isTBit a -> VWord (BV w (op w (fromWord l) (fromWord r))) Nat w | isTBit a -> VWord (mkBv w (op w (fromWord l) (fromWord r)))
| otherwise -> VSeq False (zipWith (loop a) (fromSeq l) (fromSeq r)) | otherwise -> VSeq False (zipWith (loop a) (fromSeq l) (fromSeq r))
-- streams -- streams
@ -341,7 +342,7 @@ arithUnary op = loop
| Just (len,a) <- isTSeq ty = case numTValue len of | Just (len,a) <- isTSeq ty = case numTValue len of
-- words and finite sequences -- words and finite sequences
Nat w | isTBit a -> VWord (BV w (op (fromWord x))) Nat w | isTBit a -> VWord (mkBv w (op (fromWord x)))
| otherwise -> VSeq False (map (loop a) (fromSeq x)) | otherwise -> VSeq False (map (loop a) (fromSeq x))
Inf -> toStream (map (loop a) (fromSeq x)) Inf -> toStream (map (loop a) (fromSeq x))
@ -539,7 +540,7 @@ logicBinary op = loop
case numTValue len of case numTValue len of
-- words or finite sequences -- words or finite sequences
Nat w | isTBit aty -> VWord (BV w (op (fromWord l) (fromWord r))) Nat w | isTBit aty -> VWord (mkBv w (op (fromWord l) (fromWord r)))
| otherwise -> VSeq False (zipWith (loop aty) (fromSeq l) | otherwise -> VSeq False (zipWith (loop aty) (fromSeq l)
(fromSeq r)) (fromSeq r))
@ -573,7 +574,7 @@ logicUnary op = loop
case numTValue len of case numTValue len of
-- words or finite sequences -- words or finite sequences
Nat w | isTBit ety -> VWord (BV w (op (fromWord val))) Nat w | isTBit ety -> VWord (mkBv w (op (fromWord val)))
| otherwise -> VSeq False (map (loop ety) (fromSeq val)) | otherwise -> VSeq False (map (loop ety) (fromSeq val))
-- streams -- streams
@ -722,6 +723,8 @@ fromThenV =
tlamN $ \ bits -> tlamN $ \ bits ->
tlamN $ \ len -> tlamN $ \ len ->
case (first, next, len, bits) of case (first, next, len, bits) of
(_ , _ , _ , Nat bits')
| bits' >= Arch.maxBigIntWidth -> wordTooWide bits'
(Nat first', Nat next', Nat len', Nat bits') -> (Nat first', Nat next', Nat len', Nat bits') ->
let nums = enumFromThen first' next' let nums = enumFromThen first' next'
in VSeq False (genericTake len' (map (VWord . BV bits') nums)) in VSeq False (genericTake len' (map (VWord . BV bits') nums))
@ -734,7 +737,8 @@ fromToV =
tlamN $ \ lst -> tlamN $ \ lst ->
tlamN $ \ bits -> tlamN $ \ bits ->
case (first, lst, bits) of case (first, lst, bits) of
(_ , _ , Nat bits')
| bits' >= Arch.maxBigIntWidth -> wordTooWide bits'
(Nat first', Nat lst', Nat bits') -> (Nat first', Nat lst', Nat bits') ->
let nums = enumFromThenTo first' (first' + 1) lst' let nums = enumFromThenTo first' (first' + 1) lst'
len = 1 + (lst' - first') len = 1 + (lst' - first')
@ -751,7 +755,8 @@ fromThenToV =
tlamN $ \ bits -> tlamN $ \ bits ->
tlamN $ \ len -> tlamN $ \ len ->
case (first, next, lst, len, bits) of case (first, next, lst, len, bits) of
(_ , _ , _ , _ , Nat bits')
| bits' >= Arch.maxBigIntWidth -> wordTooWide bits'
(Nat first', Nat next', Nat lst', Nat len', Nat bits') -> (Nat first', Nat next', Nat lst', Nat len', Nat bits') ->
let nums = enumFromThenTo first' next' lst' let nums = enumFromThenTo first' next' lst'
in VSeq False (genericTake len' (map (VWord . BV bits') nums)) in VSeq False (genericTake len' (map (VWord . BV bits') nums))

View File

@ -97,7 +97,7 @@ evalECon econ =
VFun $ \xs -> VFun $ \xs ->
VFun $ \y -> VFun $ \y ->
case xs of case xs of
VWord x -> VWord (SBV.sbvShiftLeft x (fromWord y)) VWord x -> VWord (SBV.sbvShiftLeft x (fromVWord y))
_ -> selectV shl y _ -> selectV shl y
where where
shl :: Integer -> Value shl :: Integer -> Value
@ -114,7 +114,7 @@ evalECon econ =
VFun $ \xs -> VFun $ \xs ->
VFun $ \y -> VFun $ \y ->
case xs of case xs of
VWord x -> VWord (SBV.sbvShiftRight x (fromWord y)) VWord x -> VWord (SBV.sbvShiftRight x (fromVWord y))
_ -> selectV shr y _ -> selectV shr y
where where
shr :: Integer -> Value shr :: Integer -> Value
@ -131,7 +131,7 @@ evalECon econ =
VFun $ \xs -> VFun $ \xs ->
VFun $ \y -> VFun $ \y ->
case xs of case xs of
VWord x -> VWord (SBV.sbvRotateLeft x (fromWord y)) VWord x -> VWord (SBV.sbvRotateLeft x (fromVWord y))
_ -> selectV rol y _ -> selectV rol y
where where
rol :: Integer -> Value rol :: Integer -> Value
@ -145,7 +145,7 @@ evalECon econ =
VFun $ \xs -> VFun $ \xs ->
VFun $ \y -> VFun $ \y ->
case xs of case xs of
VWord x -> VWord (SBV.sbvRotateRight x (fromWord y)) VWord x -> VWord (SBV.sbvRotateRight x (fromVWord y))
_ -> selectV ror y _ -> selectV ror y
where where
ror :: Integer -> Value ror :: Integer -> Value
@ -206,7 +206,7 @@ evalECon econ =
VFun $ \xs -> VFun $ \xs ->
VFun $ \ys -> VFun $ \ys ->
let err = zeroV a -- default for out-of-bounds accesses let err = zeroV a -- default for out-of-bounds accesses
in mapV (selectV (\i -> nthV err xs i)) ys in mapV (isTBit a) (selectV (\i -> nthV err xs i)) ys
ECAtBack -> -- {n,a,i} (fin n, fin i) => [n]a -> [i] -> a ECAtBack -> -- {n,a,i} (fin n, fin i) => [n]a -> [i] -> a
tlam $ \(finTValue -> n) -> tlam $ \(finTValue -> n) ->
@ -225,7 +225,7 @@ evalECon econ =
VFun $ \xs -> VFun $ \xs ->
VFun $ \ys -> VFun $ \ys ->
let err = zeroV a -- default for out-of-bounds accesses let err = zeroV a -- default for out-of-bounds accesses
in mapV (selectV (\i -> nthV err xs (n - 1 - i))) ys in mapV (isTBit a) (selectV (\i -> nthV err xs (n - 1 - i))) ys
ECFromThen -> fromThenV ECFromThen -> fromThenV
ECFromTo -> fromToV ECFromTo -> fromToV
@ -233,13 +233,13 @@ evalECon econ =
ECInfFrom -> ECInfFrom ->
tlam $ \(finTValue -> bits) -> tlam $ \(finTValue -> bits) ->
lam $ \(fromWord -> first) -> lam $ \(fromVWord -> first) ->
toStream [ VWord (first + SBV.literal (bv (fromInteger bits) i)) | i <- [0 ..] ] toStream [ VWord (first + SBV.literal (bv (fromInteger bits) i)) | i <- [0 ..] ]
ECInfFromThen -> -- {a} (fin a) => [a] -> [a] -> [inf][a] ECInfFromThen -> -- {a} (fin a) => [a] -> [a] -> [inf][a]
tlam $ \_ -> tlam $ \_ ->
lam $ \(fromWord -> first) -> lam $ \(fromVWord -> first) ->
lam $ \(fromWord -> next) -> lam $ \(fromVWord -> next) ->
toStream (map VWord (iterate (+ (next - first)) first)) toStream (map VWord (iterate (+ (next - first)) first))
-- {at,len} (fin len) => [len][8] -> at -- {at,len} (fin len) => [len][8] -> at
@ -315,17 +315,17 @@ nthV err v n =
VBit (SBV.sbvTestBit x i) VBit (SBV.sbvTestBit x i)
_ -> err _ -> err
mapV :: (Value -> Value) -> Value -> Value mapV :: Bool -> (Value -> Value) -> Value -> Value
mapV f v = mapV isBit f v =
case v of case v of
VSeq b xs -> VSeq b (map f xs) VSeq _ xs -> VSeq isBit (map f xs)
VStream xs -> VStream (map f xs) VStream xs -> VStream (map f xs)
_ -> panic "Cryptol.Symbolic.Prims.mapV" [ "non-mappable value" ] _ -> panic "Cryptol.Symbolic.Prims.mapV" [ "non-mappable value" ]
catV :: Value -> Value -> Value catV :: Value -> Value -> Value
catV xs (VStream ys) = VStream (fromSeq xs ++ ys) catV xs (VStream ys) = VStream (fromSeq xs ++ ys)
catV (VWord x) ys = VWord (cat x (fromWord ys)) catV (VWord x) ys = VWord (cat x (fromVWord ys))
catV xs (VWord y) = VWord (cat (fromWord xs) y) catV xs (VWord y) = VWord (cat (fromVWord xs) y)
catV (VSeq b xs) (VSeq _ ys) = VSeq b (xs ++ ys) catV (VSeq b xs) (VSeq _ ys) = VSeq b (xs ++ ys)
catV _ _ = panic "Cryptol.Symbolic.Prims.catV" [ "non-concatenable value" ] catV _ _ = panic "Cryptol.Symbolic.Prims.catV" [ "non-concatenable value" ]
@ -395,7 +395,7 @@ arithBinary op = loop . toTypeVal
loop ty l r = loop ty l r =
case ty of case ty of
TVBit -> evalPanic "arithBinop" ["Invalid arguments"] TVBit -> evalPanic "arithBinop" ["Invalid arguments"]
TVSeq _ TVBit -> VWord (op (fromWord l) (fromWord r)) TVSeq _ TVBit -> VWord (op (fromVWord l) (fromVWord r))
TVSeq _ t -> VSeq False (zipWith (loop t) (fromSeq l) (fromSeq r)) TVSeq _ t -> VSeq False (zipWith (loop t) (fromSeq l) (fromSeq r))
TVStream t -> VStream (zipWith (loop t) (fromSeq l) (fromSeq r)) TVStream t -> VStream (zipWith (loop t) (fromSeq l) (fromSeq r))
TVTuple ts -> VTuple (zipWith3 loop ts (fromVTuple l) (fromVTuple r)) TVTuple ts -> VTuple (zipWith3 loop ts (fromVTuple l) (fromVTuple r))
@ -409,7 +409,7 @@ arithUnary op = loop . toTypeVal
loop ty v = loop ty v =
case ty of case ty of
TVBit -> evalPanic "arithUnary" ["Invalid arguments"] TVBit -> evalPanic "arithUnary" ["Invalid arguments"]
TVSeq _ TVBit -> VWord (op (fromWord v)) TVSeq _ TVBit -> VWord (op (fromVWord v))
TVSeq _ t -> VSeq False (map (loop t) (fromSeq v)) TVSeq _ t -> VSeq False (map (loop t) (fromSeq v))
TVStream t -> VStream (map (loop t) (fromSeq v)) TVStream t -> VStream (map (loop t) (fromSeq v))
TVTuple ts -> VTuple (zipWith loop ts (fromVTuple v)) TVTuple ts -> VTuple (zipWith loop ts (fromVTuple v))
@ -451,8 +451,8 @@ cmpValue fb fw = cmp
[ "Functions are not comparable" ] [ "Functions are not comparable" ]
(VPoly {} , VPoly {} ) -> panic "Cryptol.Symbolic.Prims.cmpValue" (VPoly {} , VPoly {} ) -> panic "Cryptol.Symbolic.Prims.cmpValue"
[ "Polymorphic values are not comparable" ] [ "Polymorphic values are not comparable" ]
(VWord w1 , _ ) -> fw w1 (fromWord v2) k (VWord w1 , _ ) -> fw w1 (fromVWord v2) k
(_ , VWord w2 ) -> fw (fromWord v1) w2 k (_ , VWord w2 ) -> fw (fromVWord v1) w2 k
(_ , _ ) -> panic "Cryptol.Symbolic.Prims.cmpValue" (_ , _ ) -> panic "Cryptol.Symbolic.Prims.cmpValue"
[ "type mismatch" ] [ "type mismatch" ]
@ -543,7 +543,7 @@ logicBinary bop op = loop . toTypeVal
loop ty l r = loop ty l r =
case ty of case ty of
TVBit -> VBit (bop (fromVBit l) (fromVBit r)) TVBit -> VBit (bop (fromVBit l) (fromVBit r))
TVSeq _ TVBit -> VWord (op (fromWord l) (fromWord r)) TVSeq _ TVBit -> VWord (op (fromVWord l) (fromVWord r))
TVSeq _ t -> VSeq False (zipWith (loop t) (fromSeq l) (fromSeq r)) TVSeq _ t -> VSeq False (zipWith (loop t) (fromSeq l) (fromSeq r))
TVStream t -> VStream (zipWith (loop t) (fromSeq l) (fromSeq r)) TVStream t -> VStream (zipWith (loop t) (fromSeq l) (fromSeq r))
TVTuple ts -> VTuple (zipWith3 loop ts (fromVTuple l) (fromVTuple r)) TVTuple ts -> VTuple (zipWith3 loop ts (fromVTuple l) (fromVTuple r))
@ -556,7 +556,7 @@ logicUnary bop op = loop . toTypeVal
loop ty v = loop ty v =
case ty of case ty of
TVBit -> VBit (bop (fromVBit v)) TVBit -> VBit (bop (fromVBit v))
TVSeq _ TVBit -> VWord (op (fromWord v)) TVSeq _ TVBit -> VWord (op (fromVWord v))
TVSeq _ t -> VSeq False (map (loop t) (fromSeq v)) TVSeq _ t -> VSeq False (map (loop t) (fromSeq v))
TVStream t -> VStream (map (loop t) (fromSeq v)) TVStream t -> VStream (map (loop t) (fromSeq v))
TVTuple ts -> VTuple (zipWith loop ts (fromVTuple v)) TVTuple ts -> VTuple (zipWith loop ts (fromVTuple v))

View File

@ -8,6 +8,7 @@
{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeSynonymInstances #-} {-# LANGUAGE TypeSynonymInstances #-}
module Cryptol.Symbolic.Value module Cryptol.Symbolic.Value
@ -15,7 +16,7 @@ module Cryptol.Symbolic.Value
, TValue, numTValue, toNumTValue, finTValue, isTBit, isTFun, isTSeq, isTTuple, isTRec, tvSeq , TValue, numTValue, toNumTValue, finTValue, isTBit, isTFun, isTSeq, isTTuple, isTRec, tvSeq
, GenValue(..), lam, tlam, toStream, toFinSeq, toSeq , GenValue(..), lam, tlam, toStream, toFinSeq, toSeq
, fromVBit, fromVFun, fromVPoly, fromVTuple, fromVRecord, lookupRecord , fromVBit, fromVFun, fromVPoly, fromVTuple, fromVRecord, lookupRecord
, fromSeq, fromWord , fromSeq, fromVWord
, evalPanic , evalPanic
) )
where where
@ -23,8 +24,8 @@ module Cryptol.Symbolic.Value
import Data.Bits (bitSize) import Data.Bits (bitSize)
import Cryptol.Eval.Value (TValue, numTValue, toNumTValue, finTValue, isTBit, isTFun, isTSeq, isTTuple, isTRec, tvSeq, import Cryptol.Eval.Value (TValue, numTValue, toNumTValue, finTValue, isTBit, isTFun, isTSeq, isTTuple, isTRec, tvSeq,
GenValue(..), lam, tlam, toStream, toFinSeq, toSeq, GenValue(..), BitWord(..), lam, tlam, toStream, toFinSeq, toSeq, fromSeq,
fromVBit, fromVFun, fromVPoly, fromVTuple, fromVRecord, lookupRecord) fromVBit, fromVWord, fromVFun, fromVPoly, fromVTuple, fromVRecord, lookupRecord)
import Cryptol.Symbolic.BitVector import Cryptol.Symbolic.BitVector
import Cryptol.Utils.Panic (panic) import Cryptol.Utils.Panic (panic)
@ -44,11 +45,11 @@ instance Mergeable Value where
(VBit b1 , VBit b2 ) -> VBit $ symbolicMerge f c b1 b2 (VBit b1 , VBit b2 ) -> VBit $ symbolicMerge f c b1 b2
(VWord w1 , VWord w2 ) -> VWord $ symbolicMerge f c w1 w2 (VWord w1 , VWord w2 ) -> VWord $ symbolicMerge f c w1 w2
(VSeq b1 vs1, VSeq _ vs2 ) -> VSeq b1 $ symbolicMerge f c vs1 vs2 (VSeq b1 vs1, VSeq _ vs2 ) -> VSeq b1 $ symbolicMerge f c vs1 vs2
(VStream vs1, VStream vs2) -> VStream $ symbolicMerge f c vs1 vs2 (VStream vs1, VStream vs2) -> VStream $ mergeStream vs1 vs2
(VFun f1 , VFun f2 ) -> VFun $ symbolicMerge f c f1 f2 (VFun f1 , VFun f2 ) -> VFun $ symbolicMerge f c f1 f2
(VPoly f1 , VPoly f2 ) -> VPoly $ symbolicMerge f c f1 f2 (VPoly f1 , VPoly f2 ) -> VPoly $ symbolicMerge f c f1 f2
(VWord w1 , _ ) -> VWord $ symbolicMerge f c w1 (fromWord v2) (VWord w1 , _ ) -> VWord $ symbolicMerge f c w1 (fromVWord v2)
(_ , VWord w2 ) -> VWord $ symbolicMerge f c (fromWord v1) w2 (_ , VWord w2 ) -> VWord $ symbolicMerge f c (fromVWord v1) w2
(_ , _ ) -> panic "Cryptol.Symbolic.Value" (_ , _ ) -> panic "Cryptol.Symbolic.Value"
[ "symbolicMerge: incompatible values" ] [ "symbolicMerge: incompatible values" ]
where where
@ -56,25 +57,14 @@ instance Mergeable Value where
| n1 == n2 = (n1, symbolicMerge f c x1 x2) | n1 == n2 = (n1, symbolicMerge f c x1 x2)
| otherwise = panic "Cryptol.Symbolic.Value" | otherwise = panic "Cryptol.Symbolic.Value"
[ "symbolicMerge.mergeField: incompatible values" ] [ "symbolicMerge.mergeField: incompatible values" ]
mergeStream xs ys =
symbolicMerge f c (head xs) (head ys) : mergeStream (tail xs) (tail ys)
-- Big-endian Words ------------------------------------------------------------ -- Big-endian Words ------------------------------------------------------------
unpackWord :: SWord -> [SBool] instance BitWord SBool SWord where
unpackWord s = [ sbvTestBit s i | i <- reverse [0 .. bitSize s - 1] ] packWord bs = Data.SBV.fromBitsBE bs
unpackWord w = [ sbvTestBit w i | i <- reverse [0 .. bitSize w - 1] ]
-- Constructors and Accessors --------------------------------------------------
fromWord :: Value -> SWord
fromWord (VWord s) = s
fromWord v = Data.SBV.fromBitsBE (map fromVBit (fromSeq v))
-- | Extract a sequence.
fromSeq :: Value -> [Value]
fromSeq v = case v of
VSeq _ vs -> vs
VWord s -> map VBit (unpackWord s)
VStream vs -> vs
_ -> evalPanic "fromSeq" ["not a sequence"]
-- Errors ---------------------------------------------------------------------- -- Errors ----------------------------------------------------------------------

View File

@ -133,6 +133,7 @@ appTys expr ts =
P.ESel {} -> mono P.ESel {} -> mono
P.EList {} -> mono P.EList {} -> mono
P.EFromTo {} -> mono P.EFromTo {} -> mono
P.EInfFrom {} -> mono
P.EComp {} -> mono P.EComp {} -> mono
P.EApp {} -> mono P.EApp {} -> mono
P.EIf {} -> mono P.EIf {} -> mono
@ -249,6 +250,12 @@ inferE expr =
| (x,y) <- ("first",t1) : fs | (x,y) <- ("first",t1) : fs
] ]
P.EInfFrom e1 Nothing ->
inferE $ P.EApp (P.ECon ECInfFrom) e1
P.EInfFrom e1 (Just e2) ->
inferE $ P.EApp (P.EApp (P.ECon ECInfFromThen) e1) e2
P.EComp e mss -> P.EComp e mss ->
do (mss', dss, ts) <- unzip3 `fmap` zipWithM inferCArm [ 1 .. ] mss do (mss', dss, ts) <- unzip3 `fmap` zipWithM inferCArm [ 1 .. ] mss
w <- smallest ts w <- smallest ts

View File

@ -405,7 +405,7 @@ instance PP (WithNames Error) where
TypeVariableEscaped t xs -> TypeVariableEscaped t xs ->
nested (text "The type" <+> ppWithNames names t <+> nested (text "The type" <+> ppWithNames names t <+>
text "is not sufficiently polymorphic.") text "is not sufficiently polymorphic.")
(text "It may not depend on quantified variables:" <+> (text "It cannot depend on quantified variables:" <+>
sep (punctuate comma (map (ppWithNames names) xs))) sep (punctuate comma (map (ppWithNames names) xs)))
NotForAll x t -> NotForAll x t ->

View File

@ -33,6 +33,7 @@ import Data.Set (Set)
import Data.List(find) import Data.List(find)
import Data.Maybe(mapMaybe) import Data.Maybe(mapMaybe)
import MonadLib import MonadLib
import qualified Control.Applicative as A
import Control.Monad.Fix(MonadFix(..)) import Control.Monad.Fix(MonadFix(..))
import Data.Functor import Data.Functor
@ -179,6 +180,10 @@ data RW = RW
instance Functor InferM where instance Functor InferM where
fmap f (IM m) = IM (fmap f m) fmap f (IM m) = IM (fmap f m)
instance A.Applicative InferM where
pure = return
(<*>) = ap
instance Monad InferM where instance Monad InferM where
return x = IM (return x) return x = IM (return x)
fail x = IM (fail x) fail x = IM (fail x)
@ -295,10 +300,18 @@ newGoalName = newName $ \s -> let x = seedGoal s
-- | Generate a new free type variable. -- | Generate a new free type variable.
newTVar :: Doc -> Kind -> InferM TVar newTVar :: Doc -> Kind -> InferM TVar
newTVar src k = newTVar src k = newTVar' src Set.empty k
-- | Generate a new free type variable that depends on these additional
-- type parameters.
newTVar' :: Doc -> Set TVar -> Kind -> InferM TVar
newTVar' src extraBound k =
do bound <- getBoundInScope do bound <- getBoundInScope
let vs = Set.union extraBound bound
newName $ \s -> let x = seedTVar s newName $ \s -> let x = seedTVar s
in (TVFree x k bound src, s { seedTVar = x + 1 }) in (TVFree x k vs src, s { seedTVar = x + 1 })
-- | Generate a new free type variable. -- | Generate a new free type variable.
newTParam :: Maybe QName -> Kind -> InferM TParam newTParam :: Maybe QName -> Kind -> InferM TParam
@ -551,6 +564,10 @@ data KRW = KRW { typeParams :: Map QName Kind -- ^ kinds of (known) vars.
instance Functor KindM where instance Functor KindM where
fmap f (KM m) = KM (fmap f m) fmap f (KM m) = KM (fmap f m)
instance A.Applicative KindM where
pure = return
(<*>) = ap
instance Monad KindM where instance Monad KindM where
return x = KM (return x) return x = KM (return x)
fail x = KM (fail x) fail x = KM (fail x)
@ -604,7 +621,10 @@ kRecordWarning w = kInInferM $ recordWarning w
-- | Generate a fresh unification variable of the given kind. -- | Generate a fresh unification variable of the given kind.
kNewType :: Doc -> Kind -> KindM Type kNewType :: Doc -> Kind -> KindM Type
kNewType src k = kInInferM $ newType src k kNewType src k =
do tps <- KM $ do vs <- asks lazyTVars
return $ Set.fromList [ tv | TVar tv <- Map.elems vs ]
kInInferM $ TVar `fmap` newTVar' src tps k
-- | Lookup the definition of a type synonym. -- | Lookup the definition of a type synonym.
kLookupTSyn :: QName -> KindM (Maybe TySyn) kLookupTSyn :: QName -> KindM (Maybe TySyn)

View File

@ -468,9 +468,7 @@ tfWidth _ ty
, TCon (TF TCExp) [ TCon (TC (TCNum 2)) _, t2 ] <- t1 = Just t2 , TCon (TF TCExp) [ TCon (TC (TCNum 2)) _, t2 ] <- t1 = Just t2
tfWidth _ t tfWidth _ t
| Just (Nat 0) <- arg = return $ tNum (0 :: Int) | Just (Nat x) <- arg = return $ tNum (widthInteger x)
| Just (Nat x) <- arg = do (n,_) <- genLog x 2
return $ tNum $ n + 1
| Just Inf <- arg = Just tInf | Just Inf <- arg = Just tInf
| otherwise = Nothing | otherwise = Nothing

View File

@ -12,6 +12,7 @@
{-# LANGUAGE Safe #-} {-# LANGUAGE Safe #-}
module Cryptol.TypeCheck.Solver.InfNat where module Cryptol.TypeCheck.Solver.InfNat where
import Data.Bits
import Cryptol.Utils.Panic import Cryptol.Utils.Panic
-- | Natural numbers with an infinity element -- | Natural numbers with an infinity element
@ -123,11 +124,7 @@ nLg2 (Nat n) = case genLog n 2 of
-- from 0 to n, inclusive. @nWidth x = nLg2 (x + 1)@. -- from 0 to n, inclusive. @nWidth x = nLg2 (x + 1)@.
nWidth :: Nat' -> Nat' nWidth :: Nat' -> Nat'
nWidth Inf = Inf nWidth Inf = Inf
nWidth (Nat 0) = Nat 0 nWidth (Nat n) = Nat (widthInteger n)
nWidth (Nat n) = case genLog n 2 of
Just (x,_) -> Nat (x + 1)
Nothing -> panic "Cryptol.TypeCheck.Solver.InfNat.nWidth"
[ "genLog returned Nothing" ]
{- | @length ([ x, y .. ] : [_][w])@ {- | @length ([ x, y .. ] : [_][w])@
@ -186,4 +183,13 @@ genLog x base = Just (exactLoop 0 x)
| otherwise = let s1 = s + 1 in s1 `seq` underLoop s1 (div i base) | otherwise = let s1 = s + 1 in s1 `seq` underLoop s1 (div i base)
-- | Compute the number of bits required to represent the given integer.
widthInteger :: Integer -> Integer
widthInteger x = go' 0 (if x < 0 then complement x else x)
where
go s 0 = s
go s n = let s' = s + 1 in s' `seq` go s' (n `shiftR` 1)
go' s n
| n < bit 32 = go s n
| otherwise = let s' = s + 32 in s' `seq` go' s' (n `shiftR` 32)

View File

@ -22,7 +22,8 @@ import System.FilePath
((</>),(<.>),takeExtension,splitFileName,splitDirectories,pathSeparator ((</>),(<.>),takeExtension,splitFileName,splitDirectories,pathSeparator
,isRelative) ,isRelative)
import System.Process import System.Process
(createProcess,CreateProcess(..),StdStream(..),proc,waitForProcess) (createProcess,CreateProcess(..),StdStream(..),proc,waitForProcess
,readProcessWithExitCode)
import System.IO import System.IO
(hGetContents,IOMode(..),withFile,SeekMode(..),Handle,hSetBuffering (hGetContents,IOMode(..),withFile,SeekMode(..),Handle,hSetBuffering
,BufferMode(..)) ,BufferMode(..))
@ -56,7 +57,7 @@ data Options = Options
, optHelp :: Bool , optHelp :: Bool
, optResultDir :: FilePath , optResultDir :: FilePath
, optTests :: [TestStrategy] , optTests :: [TestStrategy]
, optDiff :: String , optDiff :: Maybe String
} deriving (Show) } deriving (Show)
defaultOptions :: Options defaultOptions :: Options
@ -66,14 +67,14 @@ defaultOptions = Options
, optHelp = False , optHelp = False
, optResultDir = "output" , optResultDir = "output"
, optTests = [] , optTests = []
, optDiff = "meld" , optDiff = Nothing
} }
setHelp :: Endo Options setHelp :: Endo Options
setHelp = Endo (\ opts -> opts { optHelp = True } ) setHelp = Endo (\ opts -> opts { optHelp = True } )
setDiff :: String -> Endo Options setDiff :: String -> Endo Options
setDiff diff = Endo (\opts -> opts { optDiff = diff }) setDiff diff = Endo (\opts -> opts { optDiff = Just diff })
setCryptol :: String -> Endo Options setCryptol :: String -> Endo Options
setCryptol path = Endo (\ opts -> opts { optCryptol = path } ) setCryptol path = Endo (\ opts -> opts { optCryptol = path } )
@ -192,11 +193,19 @@ generateAssertion opts dir file = testCase file $ do
Right _ -> assertFailure $ Right _ -> assertFailure $
"Test completed successfully. Please remove " ++ knownFailureFile "Test completed successfully. Please remove " ++ knownFailureFile
| otherwise = | otherwise =
assertFailure $ case mbKnown of
case mbKnown of
Left (X.SomeException {}) -> Left (X.SomeException {})
unwords [ optDiff opts, goldFile, resultOut ] | Just prog <- optDiff opts ->
Right fail_msg -> fail_msg do goldFile' <- canonicalizePath goldFile
assertFailure (unwords [ prog, goldFile', "\\\n ", resultOut ])
| otherwise ->
do goldFile' <- canonicalizePath goldFile
(_,out,_) <- readProcessWithExitCode "diff" [ goldFile', resultOut ] ""
assertFailure out
Right fail_msg -> assertFailure fail_msg
-- Test Discovery -------------------------------------------------------------- -- Test Discovery --------------------------------------------------------------

14
tests/issues/T146.cry Normal file
View File

@ -0,0 +1,14 @@
mk_curve_ops f = undefined
where
c = { field = f
, v1 = ec_v1 f
, v2 = ec_v2 c
}
ec_v1 : {fv} { v0: fv } -> fv
ec_v1 = undefined
ec_v2 : {fv} _ -> fv
ec_v2 p = p.field.v0
where _ = p.field.v0

1
tests/issues/T146.icry Normal file
View File

@ -0,0 +1 @@
:l T146.cry

View File

@ -0,0 +1 @@
Known problem. See #146.

View File

View File

@ -0,0 +1,3 @@
1 : [(2^^37)-0x100]
let f x y = (x : [(2^^37)-(2^^5)]) + y
f zero zero

View File

@ -0,0 +1,5 @@
Loading module Cryptol
word too wide for memory: 137438953216 bits
word too wide for memory: 137438953440 bits

View File

@ -3,7 +3,7 @@ Loading module Cryptol
Loading module Main Loading module Main
property t0 Using exhaustive testing. property t0 Using exhaustive testing.
0%passed 1 tests. 0%passed 1 tests.
QED Q.E.D.
property t1 Using random testing. property t1 Using random testing.
testing... 0% 1% 2% 3% 4% 5% 6% 7% 8% 9% 10% 11% 12% 13% 14% 15% 16% 17% 18% 19% 20% 21% 22% 23% 24% 25% 26% 27% 28% 29% 30% 31% 32% 33% 34% 35% 36% 37% 38% 39% 40% 41% 42% 43% 44% 45% 46% 47% 48% 49% 50% 51% 52% 53% 54% 55% 56% 57% 58% 59% 60% 61% 62% 63% 64% 65% 66% 67% 68% 69% 70% 71% 72% 73% 74% 75% 76% 77% 78% 79% 80% 81% 82% 83% 84% 85% 86% 87% 88% 89% 90% 91% 92% 93% 94% 95% 96% 97% 98% 99%passed 100 tests. testing... 0% 1% 2% 3% 4% 5% 6% 7% 8% 9% 10% 11% 12% 13% 14% 15% 16% 17% 18% 19% 20% 21% 22% 23% 24% 25% 26% 27% 28% 29% 30% 31% 32% 33% 34% 35% 36% 37% 38% 39% 40% 41% 42% 43% 44% 45% 46% 47% 48% 49% 50% 51% 52% 53% 54% 55% 56% 57% 58% 59% 60% 61% 62% 63% 64% 65% 66% 67% 68% 69% 70% 71% 72% 73% 74% 75% 76% 77% 78% 79% 80% 81% 82% 83% 84% 85% 86% 87% 88% 89% 90% 91% 92% 93% 94% 95% 96% 97% 98% 99%passed 100 tests.
Coverage: 0.00% (100 of 2^^32 values) Coverage: 0.00% (100 of 2^^32 values)

View File

@ -1,7 +1,7 @@
Loading module Cryptol Loading module Cryptol
Using random testing. Using random testing.
testing... 0% 1% 2% 3% 4% 5% 6% 7% 8% 9% 10% 11% 12% 13% 14% 15% 16% 17% 18% 19% 20% 21% 22% 23% 24% 25% 26% 27% 28% 29% 30% 31% 32% 33% 34% 35% 36% 37% 38% 39% 40% 41% 42% 43% 44% 45% 46% 47% 48% 49% 50% 51% 52% 53% 54% 55% 56% 57% 58% 59% 60% 61% 62% 63% 64% 65% 66% 67% 68% 69% 70% 71% 72% 73% 74% 75% 76% 77% 78% 79% 80% 81% 82% 83% 84% 85% 86% 87% 88% 89% 90% 91% 92% 93% 94% 95% 96% 97% 98% 99%passed 100 tests. testing...passed 100 tests.
Coverage: 39.06% (100 of 256 values) Coverage: 39.06% (100 of 256 values)
Using exhaustive testing. Using exhaustive testing.
0% 0% 0% 1% 1% 1% 2% 2% 3% 3% 3% 4% 4% 5% 5% 5% 6% 6% 7% 7% 7% 8% 8% 8% 9% 9% 10% 10% 10% 11% 11% 12% 12% 12% 13% 13% 14% 14% 14% 15% 15% 16% 16% 16% 17% 17% 17% 18% 18% 19% 19% 19% 20% 20% 21% 21% 21% 22% 22% 23% 23% 23% 24% 24% 25% 25% 25% 26% 26% 26% 27% 27% 28% 28% 28% 29% 29% 30% 30% 30% 31% 31% 32% 32% 32% 33% 33% 33% 34% 34% 35% 35% 35% 36% 36% 37% 37% 37% 38% 38% 39% 39% 39% 40% 40% 41% 41% 41% 42% 42% 42% 43% 43% 44% 44% 44% 45% 45% 46% 46% 46% 47% 47% 48% 48% 48% 49% 49% 50% 50% 50% 51% 51% 51% 52% 52% 53% 53% 53% 54% 54% 55% 55% 55% 56% 56% 57% 57% 57% 58% 58% 58% 59% 59% 60% 60% 60% 61% 61% 62% 62% 62% 63% 63% 64% 64% 64% 65% 65% 66% 66% 66% 67% 67% 67% 68% 68% 69% 69% 69% 70% 70% 71% 71% 71% 72% 72% 73% 73% 73% 74% 74% 75% 75% 75% 76% 76% 76% 77% 77% 78% 78% 78% 79% 79% 80% 80% 80% 81% 81% 82% 82% 82% 83% 83% 83% 84% 84% 85% 85% 85% 86% 86% 87% 87% 87% 88% 88% 89% 89% 89% 90% 90% 91% 91% 91% 92% 92% 92% 93% 93% 94% 94% 94% 95% 95% 96% 96% 96% 97% 97% 98% 98% 98% 99% 99%passed 256 tests. passed 256 tests.
QED Q.E.D.

View File

@ -2,5 +2,5 @@ Loading module Cryptol
Run-time error: undefined Run-time error: undefined
Using exhaustive testing. Using exhaustive testing.
0%
invalid sequence index: 1 invalid sequence index: 1

View File

@ -0,0 +1,4 @@
copy : [inf] -> [inf]
copy ([b] # x) = if b then [True] # copy x else [False] # copy x
property ok = copy ([True] # zero) @ 0

View File

@ -0,0 +1,3 @@
:l issue128.cry
:check ok
:prove ok

View File

@ -0,0 +1,7 @@
Loading module Cryptol
Loading module Cryptol
Loading module Main
Using exhaustive testing.
passed 1 tests.
Q.E.D.
Q.E.D.

10
tests/issues/issue130.cry Normal file
View File

@ -0,0 +1,10 @@
parity xs = ys!0
where ys = [False] # [y ^ x | x <- xs | y <- ys ]
foldl1 f xs = ys!0
where ys = [xs@0] # [ f y x | y <- ys | x <- tail xs ]
par = foldl1 (^)
parOK : {n} [n+1] -> Bit
property parOK x = par x == parity x

View File

@ -0,0 +1,3 @@
:l issue130.cry
:check parOK`{2}
:prove parOK`{2}

View File

@ -0,0 +1,7 @@
Loading module Cryptol
Loading module Cryptol
Loading module Main
Using exhaustive testing.
passed 8 tests.
Q.E.D.
Q.E.D.

View File

@ -1,5 +1,3 @@
example1 : {a} (a >= 1, 2 >= a) => [16*a][8] -> [16][8] gcd : [8] -> [8] -> [8]
example1 k = drop`{16} ((zero : [16*(2 - a)][8]) #k) gcd a b = if(b == 0) then a
else gcd b (a%b)
example2 : {a} (a >= 1, 2 >= a) => [16*a][8] -> [16][8]
example2 k = drop`{16} (zero # k)

View File

@ -1,3 +1,3 @@
:load issue133.cry :load issue133.cry
:type example1 :exhaust \x -> gcd 0 x == x
:type example2 :prove \x -> gcd 0 x == x

View File

@ -1,5 +1,7 @@
Loading module Cryptol Loading module Cryptol
Loading module Cryptol Loading module Cryptol
Loading module Main Loading module Main
example1 : {a} (a >= 1, 2 >= a) => [16 * a][8] -> [16][8] Using exhaustive testing.
example2 : {a} (a >= 1, 2 >= a) => [16 * a][8] -> [16][8] passed 256 tests.
Q.E.D.
Q.E.D.

View File

@ -0,0 +1,2 @@
:sat \(x : Bit) (y : Bit) -> x < y
:prove \(x : Bit) (y : Bit) -> x <= y || y <= x

View File

@ -0,0 +1,3 @@
Loading module Cryptol
(\(x : Bit) (y : Bit) -> x < y) False True = True
Q.E.D.

View File

@ -1,56 +1,56 @@
Loading module Cryptol Loading module Cryptol
0xf432e198 0xf7e937b5
[0xdbf8eedb6bd59796, 0x9749e08c37d123ee, 0x3b79a2a98701e9ae, [0xd4d4cc91cd7a9857, 0x4f3d263304e8ca85, 0x6723eafdcc46836f,
0x1a34d8f4efee5604, 0xfb0983cd5d80e611, ...] 0x20e6c946662f2183, 0x6a760db62889b212, ...]
[[0xaa, 0x2c, 0x08, 0xd7, 0x7a, 0xc3, 0xa9, 0xc8, 0xa7, 0xfe, 0x71, [[0x01, 0x83, 0x5f, 0x2e, 0xd1, 0x1a, 0x00, 0x1f, 0xfe, 0x55, 0xc8,
0x3f, 0x76, 0x8e, 0x47, 0x73, 0x82, 0x53, 0x33, 0x32, 0xaf, 0x66, 0x96, 0xcd, 0xe5, 0x9e, 0xca, 0xd9, 0xaa, 0x8a, 0x89, 0x06, 0xbd,
0x19, 0xe9, 0x50, 0xe4, 0x56, 0x37, 0x34, 0x91, 0x14, 0x08], 0x70, 0x40, 0xa7, 0x3b, 0xad, 0x8e, 0x8b, 0xe8, 0x6b, 0x5f],
[0x5a, 0x83, 0xba, 0x1a, 0x48, 0xeb, 0xd7, 0x2c, 0xeb, 0x8c, 0xae, [0xb1, 0xda, 0x11, 0x71, 0x9f, 0x42, 0x2e, 0x83, 0x42, 0xe3, 0x05,
0x54, 0x97, 0xa9, 0x11, 0x84, 0x2b, 0x07, 0x4e, 0x80, 0xe5, 0x1f, 0xab, 0xee, 0x00, 0x68, 0xdb, 0x82, 0x5e, 0xa5, 0xd7, 0x3c, 0x76,
0x42, 0x62, 0x6b, 0x82, 0x98, 0xed, 0x11, 0x3e, 0x44, 0xf6], 0x99, 0xb9, 0xc2, 0xd9, 0xef, 0x44, 0x68, 0x95, 0x9b, 0x4d],
[0xd4, 0x7b, 0x0b, 0x91, 0x19, 0x21, 0x6d, 0xde, 0x04, 0x62, 0x1a, [0x2b, 0xd2, 0x62, 0xe8, 0x70, 0x78, 0xc4, 0x35, 0x5b, 0xb9, 0x71,
0x64, 0x62, 0xac, 0x36, 0xd4, 0x44, 0x5e, 0xa4, 0xf4, 0x20, 0x9a, 0xbb, 0xb9, 0x03, 0x8d, 0x2b, 0x9b, 0xb5, 0xfb, 0x4b, 0x77, 0xf1,
0x96, 0x52, 0x13, 0x24, 0x70, 0x83, 0x86, 0xac, 0xbb, 0xe6], 0xed, 0xa9, 0x6a, 0x7b, 0xc7, 0xda, 0xdd, 0x03, 0x12, 0x3d],
[0x0a, 0x99, 0x74, 0x3e, 0xa1, 0x8e, 0xe2, 0xba, 0x81, 0xa0, 0xbd, [0x61, 0xf0, 0xcb, 0x95, 0xf8, 0xe5, 0x39, 0x11, 0xd8, 0xf7, 0x14,
0x6a, 0xe9, 0x9a, 0xbc, 0xc4, 0x5d, 0x13, 0xe2, 0x0b, 0xc0, 0xf4, 0xc1, 0x40, 0xf1, 0x13, 0x1b, 0xb4, 0x6a, 0x39, 0x62, 0x17, 0x4b,
0x35, 0x34, 0xc4, 0x26, 0xce, 0x01, 0xf9, 0x5e, 0xe9, 0x1b], 0x8c, 0x8b, 0x1b, 0x7d, 0x25, 0x58, 0x50, 0xb5, 0x40, 0x72],
[0x5c, 0xa9, 0xb1, 0xd4, 0xa3, 0xab, 0x9f, 0x2e, 0x50, 0x1d, 0xe0, [0xb3, 0x00, 0x08, 0x2b, 0xfa, 0x02, 0xf6, 0x85, 0xa7, 0x74, 0x37,
0xf2, 0x4d, 0xd6, 0x1c, 0xb7, 0x0d, 0xd6, 0x86, 0x14, 0x7b, 0xd2, 0x49, 0xa4, 0x2d, 0x73, 0x0e, 0x64, 0x2d, 0xdd, 0x6b, 0xd2, 0x29,
0x44, 0x83, 0x91, 0x75, 0x22, 0xec, 0x32, 0x68, 0x16, 0x94], 0x9b, 0xda, 0xe8, 0xcc, 0x79, 0x43, 0x89, 0xbf, 0x6d, 0xeb],
[0x99, 0x36, 0xff, 0xc2, 0x00, 0x61, 0xe2, 0x84, 0xd2, 0xe6, 0xf7, [0xf0, 0x8d, 0x56, 0x19, 0x57, 0xb8, 0x39, 0xdb, 0x29, 0x3d, 0x4e,
0x94, 0xf3, 0x96, 0xe8, 0x1f, 0xd4, 0x70, 0xf9, 0x03, 0x04, 0x6b, 0xeb, 0x4a, 0xed, 0x3f, 0x76, 0x2b, 0xc7, 0x50, 0x5a, 0x5b, 0xc2,
0x51, 0xcf, 0x8c, 0x8b, 0xbd, 0x29, 0x7a, 0x81, 0x1d, 0x6b], 0xa8, 0x26, 0xe3, 0xe2, 0x14, 0x80, 0xd1, 0xd8, 0x74, 0xc2],
[0xc3, 0xea, 0x2a, 0x4a, 0xf5, 0x90, 0x98, 0xa0, 0x40, 0x4e, 0xea, [0x1a, 0x41, 0x81, 0xa1, 0x4c, 0xe7, 0xef, 0xf7, 0x97, 0xa5, 0x41,
0xbb, 0x58, 0x20, 0x9f, 0x91, 0x3d, 0x6d, 0x70, 0xcf, 0x43, 0xf4, 0x12, 0xaf, 0x77, 0xf6, 0xe8, 0x94, 0xc4, 0xc7, 0x26, 0x9a, 0x4b,
0xa3, 0x12, 0x99, 0x8e, 0x6c, 0xcd, 0x56, 0xa0, 0xe9, 0x1e], 0xfa, 0x69, 0xf0, 0xe5, 0xc3, 0x24, 0xad, 0xf7, 0x40, 0x75],
[0x80, 0xb3, 0xa4, 0xca, 0x62, 0x8a, 0xcd, 0x34, 0x73, 0xa9, 0x0c, [0xd7, 0x0a, 0xfb, 0x21, 0xb9, 0xe1, 0x24, 0x8b, 0xca, 0x00, 0x63,
0x62, 0xed, 0x8f, 0x99, 0x72, 0x9a, 0x40, 0xfb, 0x95, 0xd5, 0x85, 0xb9, 0x44, 0xe6, 0xf0, 0xc9, 0xf1, 0x97, 0x52, 0xec, 0x2c, 0xdc,
0xe0, 0xf9, 0x8e, 0x50, 0x8c, 0x96, 0x2b, 0xc7, 0x7c, 0x5a], 0x37, 0x50, 0xe5, 0xa7, 0xe3, 0xed, 0x82, 0x1e, 0xd3, 0xb1],
[0xca, 0x1d, 0xcf, 0xcd, 0x44, 0xd8, 0xc7, 0x95, 0xe4, 0xb7, 0x27, [0x21, 0x74, 0x26, 0x24, 0x9b, 0x2f, 0x1e, 0xec, 0x3b, 0x0e, 0x7e,
0xa9, 0xd7, 0x6a, 0xc3, 0x16, 0x29, 0xf9, 0x81, 0x71, 0x3c, 0xc1, 0x00, 0x2e, 0xc1, 0x1a, 0x6d, 0x80, 0x50, 0xd8, 0xc8, 0x93, 0x18,
0x57, 0xc8, 0xda, 0x51, 0xe6, 0x12, 0x66, 0xd2, 0x97, 0x8e], 0xae, 0x1f, 0x31, 0xa8, 0x3d, 0x69, 0xbd, 0x29, 0xee, 0xe5],
[0xba, 0xfb, 0x31, 0x91, 0xcb, 0x57, 0xd1, 0xb5, 0x35, 0x5c, 0xd1, [0x11, 0x52, 0x88, 0xe8, 0x22, 0xae, 0x28, 0x0c, 0x8c, 0xb3, 0x28,
0x45, 0x6b, 0x88, 0x39, 0x28, 0x13, 0xb5, 0x6d, 0xe1, 0x75, 0xf9, 0x9c, 0xc2, 0xdf, 0x90, 0x7f, 0x6a, 0x0c, 0xc4, 0x38, 0xcc, 0x50,
0xc4, 0xb3, 0x98, 0xea, 0x24, 0xd1, 0x5d, 0xa7, 0x22, 0x37], 0x1b, 0x0a, 0xef, 0x41, 0x7b, 0x28, 0xb4, 0xfe, 0x79, 0x8e],
[0x3b, 0xa3, 0xdd, 0xda, 0x73, 0xcf, 0x8f, 0x0d, 0xea, 0x2f, 0x79, [0x92, 0xfa, 0x34, 0x31, 0xca, 0x26, 0xe6, 0x64, 0x41, 0x86, 0xd0,
0xb7, 0x07, 0xc9, 0x71, 0x82, 0x00, 0x9a, 0xa5, 0x4d, 0xd4, 0x64, 0x0e, 0x5e, 0x20, 0xc8, 0xd9, 0x57, 0xf1, 0xfc, 0xa4, 0x2b, 0xbb,
0xe3, 0xbd, 0x22, 0x29, 0xe1, 0x30, 0xd1, 0x9a, 0x96, 0x49], 0x3a, 0x14, 0x79, 0x80, 0x38, 0x87, 0x28, 0xf1, 0xed, 0xa0],
[0xd8, 0xac, 0x92, 0x67, 0xa9, 0x82, 0xfd, 0x36, 0x50, 0x3d, 0x60, [0x2f, 0x03, 0xe9, 0xbe, 0x00, 0xd9, 0x54, 0x8d, 0xa7, 0x94, 0xb7,
0x1d, 0x19, 0xeb, 0x4e, 0x42, 0x71, 0x3a, 0xb4, 0xc7, 0x40, 0x6a, 0x74, 0x70, 0x42, 0xa5, 0x99, 0xc8, 0x91, 0x0b, 0x1e, 0x97, 0xc1,
0x0c, 0xbb, 0xad, 0xb3, 0x4c, 0x47, 0xee, 0x6c, 0x36, 0x1d], 0x63, 0x12, 0x04, 0x0a, 0xa3, 0x9e, 0x45, 0xc3, 0x8d, 0x74],
[0xd0, 0x2b, 0xaa, 0x04, 0xca, 0x5b, 0xa4, 0x3b, 0xbc, 0x17, 0x56, [0x27, 0x82, 0x01, 0x5b, 0x21, 0xb2, 0xfb, 0x92, 0x13, 0x6e, 0xad,
0x1b, 0x81, 0x8f, 0xce, 0xfe, 0x74, 0xae, 0xee, 0xd0, 0x07, 0xeb, 0x72, 0xd8, 0xe6, 0x25, 0x55, 0xcb, 0x05, 0x45, 0x27, 0x5e, 0x42,
0xf9, 0x08, 0x6b, 0xf8, 0xba, 0x4c, 0xad, 0x04, 0x01, 0xc0], 0x50, 0x5f, 0xc2, 0x4f, 0x11, 0xa3, 0x04, 0x5b, 0x58, 0x17],
[0x4d, 0x04, 0x7b, 0x0a, 0xcc, 0xa3, 0x7f, 0x5d, 0xa0, 0x87, 0x30, [0xa4, 0x5b, 0xd2, 0x61, 0x23, 0xfa, 0xd6, 0xb4, 0xf7, 0xde, 0x87,
0x67, 0x0b, 0xa9, 0x0c, 0xe6, 0x32, 0x45, 0xb8, 0x52, 0x02, 0x6d, 0xbe, 0x62, 0x00, 0x63, 0x3d, 0x89, 0x9c, 0x0f, 0xa9, 0x59, 0xc4,
0xfa, 0xdf, 0xad, 0x18, 0xd6, 0xc5, 0xe6, 0x7b, 0xb9, 0xd4], 0x51, 0x36, 0x04, 0x6f, 0x2d, 0x1c, 0x3d, 0xd2, 0x10, 0x2b],
[0x0c, 0xaa, 0xfa, 0xcf, 0x98, 0xc7, 0x90, 0x3a, 0x11, 0x1e, 0x5c, [0x63, 0x01, 0x51, 0x26, 0xef, 0x1e, 0xe7, 0x91, 0x68, 0x75, 0xb3,
0x8b, 0x72, 0x81, 0x82, 0x9e, 0x59, 0x91, 0x76, 0x96, 0x41, 0x09, 0xe2, 0xc9, 0xd8, 0xd9, 0xf5, 0xb0, 0xe8, 0xcd, 0xed, 0x98, 0x60,
0x55, 0x27, 0x9f, 0xae, 0xbd, 0x86, 0x7c, 0xc9, 0x84, 0xc7], 0xac, 0x7e, 0xf6, 0x05, 0x14, 0xdd, 0xd3, 0x20, 0xdb, 0x1e],
[0xa5, 0x6a, 0xe2, 0xf5, 0x4f, 0x5d, 0x07, 0x00, 0x8d, 0x14, 0x7c, [0xfc, 0xc1, 0x39, 0x4c, 0xa6, 0xb4, 0x5e, 0x57, 0xe4, 0x6b, 0xd3,
0xe6, 0xd8, 0x1a, 0x1a, 0x1e, 0x85, 0x07, 0x86, 0x23, 0x64, 0x20, 0x3d, 0x2f, 0x71, 0x71, 0x75, 0xdc, 0x5e, 0xdd, 0x7a, 0xbb, 0x77,
0x89, 0xd7, 0x2e, 0x80, 0x71, 0xcf, 0x2a, 0x3c, 0x5d, 0x22]] 0xe0, 0x2e, 0x85, 0xd7, 0xc8, 0x26, 0x81, 0x93, 0xb4, 0x79]]
(0xf432e198, 0x2add) (0xf7e937b5, 0x2b34)
{x = 0xa155580c, y = 0x8353} {x = 0x5a314507, y = 0x83aa}
0x00000000 0x00000000
0x7ea4fc59 0x45beaedf

5
tests/issues/trac133.cry Normal file
View File

@ -0,0 +1,5 @@
example1 : {a} (a >= 1, 2 >= a) => [16*a][8] -> [16][8]
example1 k = drop`{16} ((zero : [16*(2 - a)][8]) #k)
example2 : {a} (a >= 1, 2 >= a) => [16*a][8] -> [16][8]
example2 k = drop`{16} (zero # k)

View File

@ -0,0 +1,3 @@
:load trac133.cry
:type example1
:type example2

View File

@ -0,0 +1,5 @@
Loading module Cryptol
Loading module Cryptol
Loading module Main
example1 : {a} (a >= 1, 2 >= a) => [16 * a][8] -> [16][8]
example2 : {a} (a >= 1, 2 >= a) => [16 * a][8] -> [16][8]

View File

@ -1,14 +1,18 @@
Loading module Cryptol Loading module Cryptol
Loading module Cryptol Loading module Cryptol
Loading module Main Loading module Main
[warning] This binding for (at check09.cry:4:1--4:6, Main::initL) shadows the existing binding [warning] at check09.cry:22:5--22:10
(at check09.cry:22:5--22:10, initL) This binding for initL shadows the existing binding from
[warning] This binding for (at check09.cry:3:1--3:6, Main::initS) shadows the existing binding (at check09.cry:4:1--4:6, Main::initL)
(at check09.cry:21:5--21:10, initS) [warning] at check09.cry:21:5--21:10
[warning] This binding for (at check09.cry:8:1--8:3, Main::ls) shadows the existing binding This binding for initS shadows the existing binding from
(at check09.cry:27:5--27:7, ls) (at check09.cry:3:1--3:6, Main::initS)
[warning] This binding for (at check09.cry:5:1--5:3, Main::ss) shadows the existing binding [warning] at check09.cry:27:5--27:7
(at check09.cry:23:5--23:7, ss) This binding for ls shadows the existing binding from
(at check09.cry:8:1--8:3, Main::ls)
[warning] at check09.cry:23:5--23:7
This binding for ss shadows the existing binding from
(at check09.cry:5:1--5:3, Main::ss)
[warning] at check09.cry:17:1--30:54: [warning] at check09.cry:17:1--30:54:
Defaulting 4th type parameter Defaulting 4th type parameter
of expression (@@) of expression (@@)

View File

@ -1,8 +1,9 @@
Loading module Cryptol Loading module Cryptol
Loading module Cryptol Loading module Cryptol
Loading module check25 Loading module check25
[warning] This binding for (at check25.cry:3:1--3:3, check25::tz) shadows the existing binding [warning] at check25.cry:6:9--6:11
(at check25.cry:6:9--6:11, tz) This binding for tz shadows the existing binding from
(at check25.cry:3:1--3:3, check25::tz)
[warning] at check25.cry:1:1--8:19: [warning] at check25.cry:1:1--8:19:
Defaulting 1st type parameter Defaulting 1st type parameter
of expression check25::tx of expression check25::tx

View File

@ -2,9 +2,11 @@ Loading module Cryptol
Loading module Cryptol Loading module Cryptol
Loading module comp02 Loading module comp02
[error] Overlapping symbols defined: [error]
Overlapping symbols defined:
(at comp02.cry:4:12--4:13, a) (at comp02.cry:4:12--4:13, a)
(at comp02.cry:5:12--5:13, a) (at comp02.cry:5:12--5:13, a)
[error] Multiple definitions for symbol: (at comp02.cry:4:8--4:9, a) [error] at comp02.cry:4:8--4:9
Multiple definitions for symbol: a
(at comp02.cry:4:12--4:13, a) (at comp02.cry:4:12--4:13, a)
(at comp02.cry:5:12--5:13, a) (at comp02.cry:5:12--5:13, a)