CurryInfo: failfree-4.0.0

categories:
Programming Analysis Verification
dependencies:
[Dependency "base" [[VGte "3.0.0",VLt "4.0.0"]],Dependency "cass-analysis" [[VGte "4.0.0",VLt "5.0.0"]],Dependency "cass" [[VGte "4.0.0",VLt "5.0.0"]],Dependency "containers" [[VGte "3.0.0",VLt "4.0.0"]],Dependency "contracts" [[VGte "3.0.0",VLt "4.0.0"]],Dependency "currypath" [[VGte "3.0.0",VLt "4.0.0"]],Dependency "directory" [[VGte "3.0.0",VLt "4.0.0"]],Dependency "execpath" [[VGte "3.0.0",VLt "4.0.0"]],Dependency "filepath" [[VGte "3.0.0",VLt "4.0.0"]],Dependency "flatcurry" [[VGte "3.0.0",VLt "5.0.0"]],Dependency "flatcurry-smt" [[VMajCompatible "2.0.0"]],Dependency "flatcurry-annotated" [[VGte "3.3.0",VLt "4.0.0"]],Dependency "flatcurry-type-annotated" [[VGte "3.3.0",VLt "4.0.0"]],Dependency "io-extra" [[VGte "3.0.0",VLt "4.0.0"]],Dependency "process" [[VGte "3.0.0",VLt "4.0.0"]],Dependency "profiling" [[VGte "3.0.0",VLt "4.0.0"]],Dependency "rw-data" [[VGte "1.0.0"]],Dependency "showflatcurry" [[VGte "3.0.0",VLt "4.0.0"]],Dependency "transformers" [[VGte "3.0.0",VLt "4.0.0"]],Dependency "wl-pprint" [[VGte "3.0.0",VLt "4.0.0"]]]
documentation:
failfree: A tool for verifying fail-free Curry programs
=======================================================

Basic idea of the tool:
-----------------------

The objective is this tool is to verify that all operations are non-failing,
i.e., their evaluation does not result in a failure, if they are called
with arguments satisfying the non-failing precondition of the operation.

Example:

    -- The operation `head` does not fail if this condition is satisfied:
    head'nonfail xs = not (null xs)
    
    head (x:xs) = x

Note that the non-failing precondition is not a precondition for `head`
in the sense of contract-based programming, i.e.,
it is still allowed to use `head` in a logical setting.
However, it can be used to verify that the following operation
is non-failing:

    readCommand = do
      putStr "Input a command:"
      s <- getLine
      let ws = words s
      if null ws then readCommand
                 else processCommand (head ws) (tail ws)

A detailed description can be found in the
[PPDP 2018 paper](https://doi.org/10.1145/3236950.3236957).
Basically, the following techniques are used to verify non-failing properties:

1. Test whether the operation is pattern-completely defined
   (i.e., branches on all patterns in all or-branches)
   for all inputs satisfying the non-failing precondition.
   If this is not the case, the operation is possibly failing.

2. Test whether the operations called in the right-hand side
   are used with satisfied non-failing preconditions
   for all inputs satisfying the non-failing precondition.
    
3. Test whether a call to `Prelude.failed` is unreachable, e.g., in

       abs x = if x>=0 then x
                       else if x<0 then (0 - x)
                                   else failed

   Note that this might be the result translating the following definition:

       abs x | x>=0 = x
             | x<0  = 0 - x

   This requires reasoning on integer arithmetic, as supported by SMT solvers.


Depending on the state of the operation `error`,
this could also verify the absence of run-time errors:

    readLine = do
      putStr "Input a non-empty string:"
      s <- getLine
      if null s then error "Empty input!"
                else do putStr "First char: "
                        putStrLn (head s)

If `error` is considered as an always failing operation
(which is done if the option `--error` is set),
`readLine` cannot be verified as non-failing.
However, this requires also a careful analysis
of all external operations (like `readFile`)
which might raise exceptions.

---------------------------------------------------------------------------

Current restrictions:
---------------------

- The non-fail condition should be a Boolean formula, i.e.,
  not a function with pattern matching or local definitions.
  Furthermore, it should be a first-order equation, i.e.,
  in eta-expanded form.
  

---------------------------------------------------------------------------

Notes:
------

- The current implementation uses the
  [Z3 theorem prover](https://github.com/Z3Prover), i.e.,
  the executable `z3` must be in the path when using the tool.

- Contracts and non-fail conditions can also be stored in separate
  files. When checking a module `m`, if there is a Curry module `m_SPEC`
  in the load path for module `m` or in the package directory `include`,
  the contents of `m_SPEC` is added to `m` before it is checked.

- Non-fail conditions for operators can also be specified by
  operations named by `op_xh1...hn'`, where each
  `hi` is a two digit hexadecimal number and the name
  of the operator corresponds to the ord values of `h1...hn`.
  For instance, the non-fail condition for `&>` can be named
  `op_x263E'nonfail`. To generate such names automatically,
  one can use the option `--name` of the tool.

- Operations defining contracts and properties are not verified.

---------------------------------------------------------------------------

Directories of the package:
---------------------------

* examples: some examples (and test suite)

* include: an include file for the SMT solver and non-fail conditions
  for various system modules

* src: source code of the implementation

---------------------------------------------------------------------------
exportedmodules:
PackageConfig Main ESMT VerifierState Curry2SMT ToolOptions FlatCurry.Typed.Types FlatCurry.Typed.Names FlatCurry.Typed.Simplify FlatCurry.Typed.Goodies FlatCurry.Typed.Read
modules:
PackageConfig Main ESMT VerifierState Curry2SMT ToolOptions FlatCurry.Typed.Types FlatCurry.Typed.Names FlatCurry.Typed.Simplify FlatCurry.Typed.Goodies FlatCurry.Typed.Read
version:
4.0.0