The should-not-typecheck package

This is a package candidate release! Here you can preview how this package release will appear once published to the main package index (which can be accomplished via the 'maintain' link below). Please note that once a package has been published to the main package index it cannot be undone! Please consult the package uploading documentation for more information.

Maintainers' corner

Readme for should-not-typecheck-2.0.1

should-not-typecheck

should-not-typecheck is a Haskell library which allows you to assert that an expression does not typecheck in your tests. It provides one function, shouldNotTypecheck, which takes an expression and will fail the test if it typechecks. shouldNotTypecheck returns an HUnit Assertion (so it can be used with both HUnit and hspec).

Example (hspec)

The secret sauce is the Deferred Type Errors GHC extension. This allows you to write a ill-typed expression which will throw an exception at run time (rather than erroring out at compile time). shouldNotTypecheck tries to catch that exception and fails the test if no deferred type error is caught.

NFData a constraint

Haskell is a lazy language - deferred type errors will not get evaluated unless we explicitly and deeply force (evaluate) the value. NFData is a typeclass from the deepseq library which allows you to describe how to fully evaluate an expression (convert it to Normal Form). shouldNotTypecheck uses this typeclass to fully evaluate expressions passed to it. For vanilla Haskell types you only need to derive Generic and the deepseq class will handle it for you:

With deepseq >= 1.4, this autoderiving Generic option is included with the library. With deepseq <= 1.3 you'll have to use the deepseq-generics library as well.

GADTs

With more complex datatypes, like GADTs and those existentially quantified, DeriveGeneric does not work. You will need to provide an instance for NFData yourself, but not to worry as it follows a pattern:

Will create a warning at compile time but not an error. All of the ill-typed expressions we are testing will also produce warnings and it will hard to immediately see which ones matter. The upside is that the test-suite will still fail if there are errors.

Workaround

You can separate out the ill-typed expressions we are testing and test boilerplate into separate files and only turn on deferred type errors for the expressions. This means that type errors in test code will still be found at compile time. The downside is your tests may now be harder to read.