diff --git a/.travis.yml b/.travis.yml
--- a/.travis.yml
+++ b/.travis.yml
@@ -12,8 +12,6 @@
       env: CABALVER="1.24" GHCVER="8.0.1" TESTS="test_c"
       compiler: ": #GHC 8.0.1"
     - env: CABALVER="1.20" GHCVER="7.6.3" TESTS="test_c"
-      # separate caches for different compiler versions
-      # until https://github.com/travis-ci/travis-ci/issues/4393 is resolved
       compiler: ": #GHC 7.6.3"
       addons: {apt: {packages: [cabal-install-1.20,ghc-7.6.3,cppcheck,hscolour], sources: [hvr-ghc]}}
     - env: CABALVER="1.20" GHCVER="7.8.4" TESTS="test_c"
@@ -58,9 +56,9 @@
   - env
   - if [[ $TRAVIS_OS_NAME == 'osx' ]];
     then
-        brew update; brew install ghc; brew install cabal-install;
-        brew install libffi; brew install pkg-config; brew install cppcheck;
-        brew install gnu-sed;
+        brew update;
+        brew outdated pkgconfig || brew install pkgconfig;
+        brew install ghc cabal-install libffi cppcheck gnu-sed;
         export PATH=$HOME/.cabal/bin:$PATH;
         export SED=gsed;
         export ZCAT=gzcat;
diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,11 +1,11 @@
-# New in 0.13:
+# New in 0.99:
 
 ## Language updates
 
 * `record` syntax now allows updating fields, including nested fields,
   by applying a function using the `$=` operator.  For example:
 
-  ```
+  ```idris
   record Score where
          constructor MkScore
          correct : Nat
@@ -21,6 +21,16 @@
                         score->attempted $= (+1) } st
   ```
 
+* Implicit parameter to interfaces are now allowed. For example:
+
+  ```idris
+  interface Shows (ts : Vect k Type) where
+    shows : HVect ts -> Vect k String
+  ```
+  In this interface, `k` is an implicit parameter, but previously needed to
+  be explicit
+
+
 ## Library updates
 
 * The File Effect has been updated to take into account changes in
@@ -40,18 +50,25 @@
 
 * Idris' documentation system now displays the documentation for auto
   implicits in the output of `:doc`. This is tested for in `docs005`.
-
 * New command line flag `--info` that displays information about the installation.
-
 * New command line flag `--sourcepath <dir>` that allows adding directories to the source search path.
+* Allow 'installation' of a package's IdrisDoc documentation into a central location. The default location is the subdirectory `docs` of Idris' data directory.
+  * New flag `--installdoc <ipkg>` provided to install documentation
+  * New flag `--docdir` provided to show default documentation installation location.
+  * New environment variable `IDRIS_DOC_PATH` to allow specification of an alternative installation path for documentation.
+* Semantic meaning behind several environment variables has been clarified in documentation and code. See compilation section of the reference manual for more details.
+* Interface parameter constraints are now printed in the output of `:doc`. This
+  is tested for in `docs006`.
+
 ## Miscellaneous updates
 
+* New, faster, better, implementation of the coverage checker
 * The test suite now uses [tasty-golden](https://hackage.haskell.org/package/tasty-golden). New tests must be registered in `test/TestData.hs`, as explained in the relevant `README.md`.
 * Added OSX and Windows continous integration with Travis and Appveyor.
 
 ## UI Changes
 
-* The :e command can now handle an $EDITOR with arguments in it, like "emacs -nw" 
+* The :e command can now handle an $EDITOR with arguments in it, like "emacs -nw"
 
 
 # New in 0.12:
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -1,56 +1,215 @@
 Thanks to the following for their help and contributions:
 
-Ozgur Akgun
+a3gis
+Aaron Craelius
+Adam Sandberg Eriksson
+Adam Schønemann
+Adolfo Ochagavía
 Ahmad Salim Al-Sibahi
-Edward Chadwick Amsden
-Michael R. Bernstein
-Jan Bessai
-Nicola Botta
-Edwin Brady
-Vitaly Bragilevsky
-Jakob Brünker
+Aistis Raulinaitis
+Alex Feldman-Crough
+Alexander Berntsen
+Alexander Shabalin
 Alyssa Carter
+Andreas Bogk
+Andreas Reuleaux
+Andrei Dziahel
+Andrew Cann
+Andrew Stewart Gibson
+Andy Morris
+Anthony Cantor
+Anthony---faineance
+Apostolis Xekoukoulotakis
+Athan Clark
+Bartosz Przygoda
+Ben Gamari
+Ben Sherman
+ben-schulz
+Benjamin Hodgson
+Benjamin Saunders
+Björn Aili
+bmastenbrook
+Brent Yorgey
+Brian Koropoff
+Brian McKenna
+Bryn Keller
+Calvin Beck
+Carsten König
 Carter Charbonneau
+Casper M. H. Holmgreen
+cchantep
+Cezar Ionescu
+Chao-Hong Chen
+Chetan Taralekar
+Chris Allen
+Christopher Schwaab
+Cliff Harvey
+Cliff L. Biffle
+Colin Adams
+comco
+Craig McLaughlin
+cswords
+Daniel Waterworth
+Daniël Heres
+Darin Morrison
+David Feuer
+David Kraeutmann
 David Raymond Christiansen
-Aaron Craelius
-Jason Dagit
-Adam Sandberg Eriksson
-Guglielmo Fachini
-Simon Fowler
+defanor
+Dennis Griffith
+Dirk Ullrich
+Dmitry Bushev
+Dmitry Tsygankov
+Dominic Mulligan
+Dominik Peteler
+Echo Nolan
+Eduard Nicodei
+Edward Amsden
+Edward O'Callaghan
+Edwin Brady
+Eric Casteleijn
+Eric Mertens
+Eric Walkingshaw
+Eric Weinstein
+Erkin Batu Altunbaş
+Ertugrul Söylemez
+EvanR
+Fabian Thorand
+fiendfan1
+Franklin Chen
+Frederic Koehler
+Friedrich von Never
+Gabe McArthur
+Gabor Greif
+Gabriel Garcia
+George Leontiev
+Gleb Alexeyev
 Google
-Zack Grannan
-Sean Hunt
-Cezar Ionescu
+Greg Anderson
+Greg Pfeil
+Guglielmo Fachini
+Hannes Mehnert
 Heath Johns
+Heather
+Hector A. Escobedo IV
+identical snowflake
+Ignas Vyšniauskas
+Ilan Godik
+Imuli
 Irene Knapp
-Paul Koerbitz
-Niklas Larsson
-Shea Levy
+Jack Henahan
+Jacob Mitchell
+Jakob Brünker
+Jan Bessai
+Jan de Muijnck-Hughes
+Jan Doms
+Jan Stolarek
+Jason Dagit
+Jason Gross
+Jean-Remi Desjardins
+Jeff Hemphill
+Jefferson Carpenter
+Jens Petersen
+Jeremy W. Sherman
+jhegedus42
+joe9
+Johannes Griebler
+John Connor
+John Dobronszki
+John Wiegley
+Jon Atack
+Jonas Westerlund
+Jonathan Sterling
+Joseph Huang
+Josh Vera
+JP Smith
+Juliusz Chroboczek
+Jurriën Stutterheim
+Jürgen Peters
+Karlos Kaeeikaas
+Kester Tong
+lambdadomain
+Langston Barrett
+Leif Warner
+Leon Schoorl
+Luke Palmer
+Mark Farrell
+Markus Klink
+Markus Pfeiffer
 Mathnerd314
-Hannes Mehnert
+Mattias Lundell
+Matvey B. Aksenov
+Matúš Tejiščák
+Maxim Ivanov
 Mekeor Melire
 Melissa Mozifian
-Jan de Muijnck-Hughes
-Dominic Mulligan
-Echo Nolan
-Tom Prince
-raichoo
+Melvar Chen
+Michael A. Smith
+Michael Bernstein
+Michael Gilliland
+Michael Hensler
+Michael Maloney
+Michael McGirr
+Michael Thompson
+Michael Weiss
+Miikka Koskinen
+Mitchell Rosen
+Miëtek Bak
+Mort Yao
+Nathan Dinsmore
+Nicola Botta
+Niklas Larsson
+Norbert Melzer
+Oskar Wickström
+Ozgur Akgun
+Patrik Jansson
+Paul Koerbitz
+Per Fredelius
+Peter Minten
 Philip Rasmussen
-Aistis Raulinaitis
+PoroCYon
+raichoo
 Reynir Reynisson
+Ricky Elrod
+Robert Clipsham
+Robert Edström
+Ross Meikleham
+Ryan Scott
+Sam Elliott
+Sam T
+Saurabh Rawat
+Sean Hunt
+Sebastian de Bellefon
+Sebastian Dröge
 Seo Sanghyeon
-Benjamin Saunders
-Alexander Shabalin
-Jeremy W. Sherman
-Timo Petteri Sinnemäki
-JP Smith
+Sergei Trofimovich
+Shane Pearman
+Shea Levy
+Simon Fowler
 startling
-Chetan T
-Matúš Tejiščák
-Dirk Ullrich
-Leif Warner
-Daniel Waterworth
-Eric Weinstein
-Jonas Westerlund
-Björn Aili
+Stefan Bleibinhaus
+stepcut
+Stephen Drodge
+Steven Shaw
+Stuart Gale
+suhorng
+Sune Alkærsig
+Sven Koschnicke
+tdidriksen
+Tenor Biel
+Thomas Cooper
+Tim Dysinger
+Tim McGilchrist
+Timo Petteri Sinnemäki
+Tom Prince
+TorosFanny
+Trevor Elliott
+uwap
+Vitaly Bragilevsky
+xged
+XIE Yuheng
+Yacine Hmito
+Zack Grannan
 Zheng Jihui
+zjhmale
+Сухарик
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -6,6 +6,7 @@
 [![Hackage](https://budueba.com/hackage/idris)](https://hackage.haskell.org/package/idris)
 [![Stackage LTS](http://stackage.org/package/idris/badge/lts)](http://stackage.org/lts/package/idris)
 [![Stackage Nightly](http://stackage.org/package/idris/badge/nightly)](http://stackage.org/nightly/package/idris)
+[![IRC](https://img.shields.io/badge/IRC-%23idris-1e72ff.svg?style=flat)](https://www.irccloud.com/invite?channel=%23idris&hostname=irc.freenode.net&port=6697&ssl=1)
 
 Idris (http://idris-lang.org/) is a general-purpose functional programming
 language with dependent types.
diff --git a/Setup.hs b/Setup.hs
--- a/Setup.hs
+++ b/Setup.hs
@@ -254,7 +254,7 @@
       target = datadir $ L.absoluteInstallDirs pkg local copy
 
       installStdLib = do
-        let target' = target </> "libs"
+        let target' = target -- </> "libs"
         putStrLn $ "Installing libraries in " ++ target'
         makeInstall "libs" target'
 
@@ -267,7 +267,6 @@
          let mandest = mandir (L.absoluteInstallDirs pkg local copy) ++ "/man1"
          notice verbosity $ unwords ["Copying man page to", mandest]
          installOrdinaryFiles verbosity mandest [("man", "idris.1")]
-
 
       makeInstall src target =
          make verbosity [ "-C", src, "install" , "TARGET=" ++ target, "IDRIS=" ++ idrisCmd local]
diff --git a/codegen/idris-codegen-c/Main.hs b/codegen/idris-codegen-c/Main.hs
--- a/codegen/idris-codegen-c/Main.hs
+++ b/codegen/idris-codegen-c/Main.hs
@@ -1,19 +1,21 @@
 module Main where
 
-import Idris.Core.TT
 import Idris.AbsSyntax
+import Idris.Core.TT
 import Idris.ElabDecls
 import Idris.Main
-import IRTS.Compiler
 import IRTS.CodegenC
+import IRTS.Compiler
 
+import Util.System
+
+import Paths_idris
+
+import Control.Monad
 import System.Environment
 import System.Exit
-import Control.Monad
 
-import Paths_idris
 
-import Util.System
 
 data Opts = Opts { inputs :: [FilePath],
                    interface :: Bool,
diff --git a/codegen/idris-codegen-javascript/Main.hs b/codegen/idris-codegen-javascript/Main.hs
--- a/codegen/idris-codegen-javascript/Main.hs
+++ b/codegen/idris-codegen-javascript/Main.hs
@@ -1,16 +1,17 @@
 module Main where
 
-import Idris.Core.TT
 import Idris.AbsSyntax
+import Idris.Core.TT
 import Idris.ElabDecls
 import Idris.Main
-import IRTS.Compiler
 import IRTS.CodegenJavaScript
+import IRTS.Compiler
 
+import Paths_idris
+
 import System.Environment
 import System.Exit
 
-import Paths_idris
 
 data Opts = Opts {
                    inputs :: [FilePath]
diff --git a/codegen/idris-codegen-node/Main.hs b/codegen/idris-codegen-node/Main.hs
--- a/codegen/idris-codegen-node/Main.hs
+++ b/codegen/idris-codegen-node/Main.hs
@@ -1,17 +1,16 @@
 module Main where
 
-import Idris.Core.TT
 import Idris.AbsSyntax
+import Idris.Core.TT
 import Idris.ElabDecls
 import Idris.Main
-
-import IRTS.Compiler
 import IRTS.CodegenJavaScript
+import IRTS.Compiler
 
+import Paths_idris
+
 import System.Environment
 import System.Exit
-
-import Paths_idris
 
 data Opts = Opts { inputs :: [FilePath]
                  , output :: FilePath
diff --git a/docs/conf.py b/docs/conf.py
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -59,9 +59,9 @@
 # built documents.
 #
 # The short X.Y version.
-version = '0.12.3'
+version = '0.99'
 # The full version, including alpha/beta/rc tags.
-release = '0.12.3'
+release = '0.99'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
@@ -216,16 +216,76 @@
 
 # -- Options for LaTeX output ---------------------------------------------
 
+latex_title_page = r'''
+\begin{titlepage}
+    \vspace*{\fill}
+    \begin{center}
+        \includegraphics[width=0.25\textwidth]{idris-512x512.png}\par
+        \vspace{1cm}
+        {\huge\sffamily\bfseries Documentation for the Idris Language\par}
+        \vspace{1cm}
+        {\Large Version \version\par}
+    \end{center}
+    \vspace*{\fill}
+\end{titlepage}
+'''
+
 latex_elements = {
 # The paper size ('letterpaper' or 'a4paper').
 'papersize': 'a4paper',
 
+'fontpkg': '',
+'inputenc': '',
+'utf8extra': '',
+'releasename': 'Version',
+
 # The font size ('10pt', '11pt' or '12pt').
 'pointsize': '10pt',
 
 # Additional stuff for the LaTeX preamble.
-#'preamble': '',
+'preamble': r'''
+\usepackage{lmodern}
+\usepackage[T1]{fontenc}
+\usepackage[utf8x]{inputenc}
+\usepackage{titlesec}
+%
+\usepackage{fancyhdr}
+\fancypagestyle{plain}{%
+  \renewcommand{\headrulewidth}{0pt}%
+  \fancyhf{}%
+  \fancyfoot[C]{\textsf{\thepage}}
+}
+\pagestyle{fancy}
+\fancyhf{}
+\fancyhead[LE,RO]{\textsf{\bfseries{v\version}}}
+\fancyhead[LO,RE]{\textsf{\bfseries\leftmark}}
+%\fancyhead[LO]{\textsf{\bfseries{\leftmark}}}
+%\fancyhead[RO]{\textsf{\bfseries{v\version}}}
+%\fancyhead[RE]{\textsf{\bfseries{\leftmark}}}
+%\fancyhead[LE]{\textsf{\bfseries{v\version}}}
+\fancyfoot[C]{\textsf{\thepage}}
+\renewcommand{\footrulewidth}{0pt}
+\renewcommand{\headrulewidth}{0pt}
+%
+\usepackage[font={small,it}]{caption}
+\titleformat{\section}
+  {\normalfont\sffamily\Large\bfseries\color{black}}
+  {\thesection}{1em}{}
+\titleformat{\subsection}
+  {\sffamily\large\bfseries\color{black}}
+  {\thesubsection}{1em}{}
+\titleformat{\subsubsection}
+  {\sffamily\normalsize\bfseries\color{black}}
+  {\thesubsubsection}{1em}{}
+\titleformat{\paragraph}{\normalfont\normalsize\slshape}{\theparagraph}{1em}{}
+\setlength{\parskip}{1em}
+%
+\hypersetup{colorlinks = false}
+\definecolor{VerbatimBorderColor}{rgb}{1,1,1}
+''',
 
+'maketitle': latex_title_page
+
 # Latex figure (float) alignment
 #'figure_align': 'htbp',
 }
@@ -234,15 +294,16 @@
 # (source start file, target name, title,
 #  author, documentclass [howto, manual, or own class]).
 latex_documents = [
-  ('tutorial/index',  'idris-tutorial.tex',  u'The Idris Tutorial',    u'The Idris Community', 'manual'),
-  ('guides/index',    'idris-guides.tex',    u'Idris Tutorial Series', u'The Idris Community', 'manual'),
-#  ('reference/index', 'idris-reference.tex', u'The Idris Reference',   u'The Idris Community', 'manual'),
-    ('effects/index',  'eff-tutorial.tex',  u'The Effects Tutorial',    u'The Idris Community', 'manual')
-    ]
+  ('index',  'idris.tex',  u'Documentation for the Idris Language',    u'The Idris Community', 'report')
+]
 
+
+latex_show_pagerefs = True
+latex_show_url = 'footnote'
+
 # The name of an image file (relative to this directory) to place at the top of
 # the title page.
-#latex_logo = None
+latex_logo = '../icons/idris-512x512.png'
 
 # For "manual" documents, if this is true, then toplevel headings are parts,
 # not chapters.
diff --git a/docs/effects/simpleeff.rst b/docs/effects/simpleeff.rst
--- a/docs/effects/simpleeff.rst
+++ b/docs/effects/simpleeff.rst
@@ -495,8 +495,8 @@
     Env = List (String, Integer)
 
     eval : Expr -> Eff Integer [EXCEPTION String, STATE Env]
-    eval (Val x) = return x
-    eval (Add l r) = return $ !(eval l) + !(eval r)
+    eval (Val x)   = pure x
+    eval (Add l r) = pure $ !(eval l) + !(eval r)
 
 Note that we are using ``!``-notation to avoid having to bind
 subexpressions in a ``do`` block. Next, we add a case for evaluating
@@ -506,7 +506,7 @@
 
     eval (Var x) = case lookup x !get of
                         Nothing => raise $ "No such variable " ++ x
-                        Just val => return val
+                        Just val => pure val
 
 This retrieves the state (with ``get``, supported by the ``STATE Env``
 effect) and raises an exception if the variable is not in the
@@ -559,7 +559,7 @@
 
     eval (Random upper) = do val <- rndInt 0 upper
                              putStrLn (show val)
-                             return val
+                             pure val
 
 If we try this without extending the effects list, we would see an
 error something like the following:
diff --git a/docs/guides/type-providers-ffi.rst b/docs/guides/type-providers-ffi.rst
--- a/docs/guides/type-providers-ffi.rst
+++ b/docs/guides/type-providers-ffi.rst
@@ -53,8 +53,8 @@
       putStrLn "I'm sorry, I don't know how big size_t is. Can you tell me, in bytes?"
       resp <- getLine
       case readInt resp of
-         Just sizeTSize => return (Provide sizeTSize)
-         Nothing => return (Error "I'm sorry, I don't understand.")
+         Just sizeTSize => pure (Provide sizeTSize)
+         Nothing => pure (Error "I'm sorry, I don't understand.")
     -- the readInt function is left as an exercise
 
 We assume that whoever's compiling the library knows the size of
diff --git a/docs/listing/idris-prompt-helloworld.txt b/docs/listing/idris-prompt-helloworld.txt
--- a/docs/listing/idris-prompt-helloworld.txt
+++ b/docs/listing/idris-prompt-helloworld.txt
@@ -1,7 +1,7 @@
 $ idris hello.idr
      ____    __     _
     /  _/___/ /____(_)____
-    / // __  / ___/ / ___/     Version 0.12.3
+    / // __  / ___/ / ___/     Version 0.99
   _/ // /_/ / /  / (__  )      http://www.idris-lang.org/
  /___/\__,_/_/  /_/____/       Type :? for help
 
diff --git a/docs/listing/idris-prompt-interp.txt b/docs/listing/idris-prompt-interp.txt
--- a/docs/listing/idris-prompt-interp.txt
+++ b/docs/listing/idris-prompt-interp.txt
@@ -1,7 +1,7 @@
 $ idris interp.idr
      ____    __     _
     /  _/___/ /____(_)____
-    / // __  / ___/ / ___/     Version 0.12.3
+    / // __  / ___/ / ___/     Version 0.99
   _/ // /_/ / /  / (__  )      http://www.idris-lang.org/
  /___/\__,_/_/  /_/____/       Type :? for help
 
diff --git a/docs/listing/idris-prompt-start.txt b/docs/listing/idris-prompt-start.txt
--- a/docs/listing/idris-prompt-start.txt
+++ b/docs/listing/idris-prompt-start.txt
@@ -1,7 +1,7 @@
 $ idris
     ____    __     _
    /  _/___/ /____(_)____
-   / // __  / ___/ / ___/     Version 0.12.3
+   / // __  / ___/ / ___/     Version 0.99
  _/ // /_/ / /  / (__  )      http://www.idris-lang.org/
 /___/\__,_/_/  /_/____/       Type :? for help
 
diff --git a/docs/reference/compilation.rst b/docs/reference/compilation.rst
--- a/docs/reference/compilation.rst
+++ b/docs/reference/compilation.rst
@@ -86,22 +86,30 @@
 
 * `IDRIS_CC` Change the `C` compiler used by the `C` backend.
 * `IDRIS_CFLAGS` Change the `C` flags passed to the `C` compiler.
-* `TARGET`   Change the target directory to generate files.
-* `IDRIS_LIBRARY_PATH` Change the location of where installed packages are found.
+* `TARGET`   Change the target directory i.e. `data dir` where Idris installs files when installing using Cabal/Stack.
+* `IDRIS_LIBRARY_PATH` Change the location of where installed packages are found/installed.
+* `IDRIS_DOC_PATH`  Change the location of where generated idrisdoc for packages are installed.
 
-Alternativly, and perhaps a cleaner approach is to configure these
-options using the CLI options.  Idris also supports options to augment
-the paths used, and pass options to the code generator backend.
+.. note::
 
-The option `--cg-opt <ARG>` can be used to pass options to the code
-generator. The format of `<ARG>` is dependent on the selected backend.
+   In versions of Idris prior to 0.12.3 the environment variables
+   `IDRIS_LIBRARY_PATH` and `TARGET` were both used to affect the
+   installation of single packages and direct where Idris installed
+   its data. The meaning of these variables has changed, and command
+   line options are preferred when changing where individual packages
+   are installed.
 
-Further, Idris does support multiple include paths.  The CLI option
-`-i <dir>` allows you to add a directory to the library search path; this
-option can be used multiple times. This is a cleaner option when you
-wish to add single directories to the `IDRIS_LIBRARY_PATH` than
-ammending `IDRIS_LIBRARY_PATH` directly.
-To add directories to the source search path, use the `--sourcepath <dir>` option.
+The CLI option `--ibcsubdir` can be used to direct where generated IBC
+files are placed.  However, this means Idris will install files in a
+non-standard location separate from the rest of the installed
+packages. The CLI option `--idrispath <dir>` allows you to add a
+directory to the library search path; this option can be used multiple
+times and can be shortened to `-i <dir>`. Similary, the `--sourcepath
+<dir>` option can be used to add directories to the source search
+path. There is no shortened version for this option as `-s` is a
+reserved flag.
 
-Moreover, rather than using `TARGET` the CLI option `--ibcsubdir` can
-be used to direct where built IBC files are placed.
+Further, Idris also supports options to augment the paths used, and
+pass options to the code generator backend.  The option `--cg-opt
+<ARG>` can be used to pass options to the code generator. The format
+of `<ARG>` is dependent on the selected backend.
diff --git a/docs/reference/ffi.rst b/docs/reference/ffi.rst
--- a/docs/reference/ffi.rst
+++ b/docs/reference/ffi.rst
@@ -361,4 +361,4 @@
       timeout <- jscall "setTimeout(%0, %1)"
                         (JsFn (() -> JS_IO ()) -> Int -> JS_IO Ptr)
                         (MkJsFn f) millis
-      return $ MkTimeout timeout
+      pure $ MkTimeout timeout
diff --git a/docs/reference/uniqueness-types.rst b/docs/reference/uniqueness-types.rst
--- a/docs/reference/uniqueness-types.rst
+++ b/docs/reference/uniqueness-types.rst
@@ -212,7 +212,7 @@
     foo xs = do let f = \x : Int => showU xs
                 putStrLn $ free xs
                 putStrLn $ f 42
-                return ()
+                pure ()
 
 Since ``lend`` is implicit, in practice for functions to lend and borrow
 values merely requires the argument to be marked as ``Borrowed``. We can
diff --git a/docs/tutorial/interfaces.rst b/docs/tutorial/interfaces.rst
--- a/docs/tutorial/interfaces.rst
+++ b/docs/tutorial/interfaces.rst
@@ -232,7 +232,7 @@
     m_add : Maybe Int -> Maybe Int -> Maybe Int
     m_add x y = do x' <- x -- Extract value from x
                    y' <- y -- Extract value from y
-                   return (x' + y') -- Add them
+                   pure (x' + y') -- Add them
 
 This function will extract the values from ``x`` and ``y``, if they
 are both available, or return ``Nothing`` if one or both are not ("fail fast"). Managing the
@@ -270,7 +270,7 @@
 .. code-block:: idris
 
     readNumbers : IO (Maybe (Nat, Nat))
-    readNumbers = 
+    readNumbers =
       do x <- readNumber
          case x of
               Nothing => pure Nothing
@@ -286,7 +286,7 @@
 .. code-block:: idris
 
     readNumbers : IO (Maybe (Nat, Nat))
-    readNumbers = 
+    readNumbers =
       do Just x_ok <- readNumber
          Just y_ok <- readNumber
          pure (Just (x_ok, y_ok))
@@ -298,7 +298,7 @@
 .. code-block:: idris
 
     readNumbers : IO (Maybe (Nat, Nat))
-    readNumbers = 
+    readNumbers =
       do Just x_ok <- readNumber | Nothing => pure Nothing
          Just y_ok <- readNumber | Nothing => pure Nothing
          pure (Just (x_ok, y_ok))
@@ -321,7 +321,7 @@
 .. code-block:: idris
 
     m_add : Maybe Int -> Maybe Int -> Maybe Int
-    m_add x y = return (!x + !y)
+    m_add x y = pure (!x + !y)
 
 The notation ``!expr`` means that the expression ``expr`` should be
 evaluated and then implicitly bound. Conceptually, we can think of
@@ -388,7 +388,7 @@
 
 .. code-block:: idris
 
-    do { qual1; qual2; ...; qualn; return exp; }
+    do { qual1; qual2; ...; qualn; pure exp; }
 
 Using monad comprehensions, an alternative definition for ``m_add``
 would be:
diff --git a/docs/tutorial/typesfuns.rst b/docs/tutorial/typesfuns.rst
--- a/docs/tutorial/typesfuns.rst
+++ b/docs/tutorial/typesfuns.rst
@@ -635,12 +635,12 @@
 type ``IO a``, and puts the result, of type ``a`` into the variable
 ``x``. In this case, ``getLine`` returns an ``IO String``, so ``name``
 has type ``String``. Indentation is significant — each statement in
-the do block must begin in the same column. The ``return`` operation
+the do block must begin in the same column. The ``pure`` operation
 allows us to inject a value directly into an IO operation:
 
 .. code-block:: idris
 
-    return : a -> IO a
+    pure : a -> IO a
 
 As we will see later, ``do`` notation is more general than this, and
 can be overloaded.
diff --git a/docs/tutorial/views.rst b/docs/tutorial/views.rst
--- a/docs/tutorial/views.rst
+++ b/docs/tutorial/views.rst
@@ -92,6 +92,27 @@
 We will return to this function in Section :ref:`sect-provisional` to
 complete the definition of ``parity``.
 
+With and proofs
+===============
+To use a dependent pattern match for theorem proving, it is sometimes necessary
+to explicitly construct the proof resulting from the pattern match.
+To do this, you can postfix the with clause with ``proof p`` and the proof
+generated by the pattern match will be in scope and named ``p``. For example:
+
+.. code-block:: idris
+
+    data Foo = FInt Int | FBool Bool
+
+    optional : Foo -> Maybe Int
+    optional (FInt x) = Just x
+    optional (FBool b) = Nothing
+
+    isFInt : (foo:Foo) -> Maybe (x : Int ** (optional foo = Just x))
+    isFInt foo with (optional foo) proof p
+      isFInt foo | Nothing = Nothing           -- here, p : Nothing = optional foo
+      isFInt foo | (Just x) = Just (x ** Refl) -- here, p : Just x = optional foo
+
+
 .. [1] Conor McBride and James McKinna. 2004. The view from the
        left. J. Funct. Program. 14, 1 (January 2004),
        69-111. DOI=10.1017/S0956796803004829
diff --git a/idris.cabal b/idris.cabal
--- a/idris.cabal
+++ b/idris.cabal
@@ -1,5 +1,5 @@
 Name:           idris
-Version:        0.12.3
+Version:        0.99
 License:        BSD3
 License-file:   LICENSE
 Author:         Edwin Brady
@@ -40,7 +40,7 @@
                 .
                 * Hugs style interactive environment
 
-Cabal-Version:  >= 1.8
+Cabal-Version:  >= 1.8.1
 
 Build-type:     Custom
 
@@ -209,6 +209,7 @@
                 , Idris.REPL
                 , Idris.REPL.Parser
                 , Idris.REPL.Commands
+                , Idris.Termination
                 , Idris.Transforms
                 , Idris.TypeSearch
                 , Idris.Unlit
@@ -251,7 +252,7 @@
                 , Tools_idris
 
   Build-depends:  base >=4 && <5
-                , aeson >= 0.6 && < 0.12
+                , aeson >= 0.6 && < 1.1
                 , annotated-wl-pprint >= 0.7 && < 0.8
                 , ansi-terminal < 0.7
                 , ansi-wl-pprint < 0.7
@@ -271,7 +272,7 @@
                 , ieee754 >= 0.7 && < 0.8
                 , mtl >= 2.1 && < 2.3
                 , network < 2.7
-                , optparse-applicative >= 0.11 && < 0.13
+                , optparse-applicative >= 0.11 && < 0.14
                 , parsers >= 0.9 && < 0.13
                 , pretty < 1.2
                 , regex-tdfa >= 1.2
@@ -288,7 +289,7 @@
                 , vector < 0.12
                 , vector-binary-instances < 0.3
                 , zip-archive > 0.2.3.5 && < 0.4
-                , safe
+                , safe == 0.3.9
                 , fsnotify >= 0.2 && < 2.2
                 , async < 2.2
 
@@ -362,7 +363,7 @@
                , filepath
                , directory
                , haskeline >= 0.7
-               , optparse-applicative >= 0.11 && < 0.13
+               , optparse-applicative >= 0.11 && < 0.14
                , tagged
                , tasty >= 0.8
                , tasty-golden >= 2.0
@@ -374,7 +375,7 @@
 
 
   ghc-prof-options: -auto-all -caf-all
-  ghc-options:      -threaded -rtsopts -funbox-strict-fields
+  ghc-options:      -threaded -rtsopts -with-rtsopts=-N -funbox-strict-fields
 
 Executable idris-codegen-c
   Main-is:        Main.hs
diff --git a/libs/Makefile b/libs/Makefile
--- a/libs/Makefile
+++ b/libs/Makefile
@@ -34,5 +34,4 @@
 	$(MAKE)	-C effects doc_clean
 	$(MAKE)	-C pruviloj doc_clean
 
-
 .PHONY: build install clean doc doc_clean
diff --git a/libs/base/Data/HVect.idr b/libs/base/Data/HVect.idr
--- a/libs/base/Data/HVect.idr
+++ b/libs/base/Data/HVect.idr
@@ -59,16 +59,16 @@
       decEq (z::xs) (z::ys) | Yes Refl | No ctr = No (ctr . hvectInjective2)
     decEq (x::xs) (y::ys) | No ctr = No (ctr . hvectInjective1)
 
-interface Shows (k : Nat) (ts : Vect k Type) where
+interface Shows (ts : Vect k Type) where
   shows : HVect ts -> Vect k String
 
-implementation Shows Z [] where
+implementation Shows [] where
   shows [] = []
 
-implementation (Show t, Shows k ts) => Shows (S k) (t::ts) where
+implementation (Show t, Shows ts) => Shows (t::ts) where
   shows (x::xs) = show x :: shows xs
 
-implementation (Shows k ts) => Show (HVect ts) where
+implementation (Shows ts) => Show (HVect ts) where
   show xs = "[" ++ (pack . intercalate [','] . map unpack . toList $ shows xs) ++ "]"
 
 ||| Extract an arbitrary element of the correct type.
diff --git a/libs/base/Data/List/Views.idr b/libs/base/Data/List/Views.idr
--- a/libs/base/Data/List/Views.idr
+++ b/libs/base/Data/List/Views.idr
@@ -187,7 +187,7 @@
 data VList : List a -> Type where
      VNil : VList []
      VOne : VList [x]
-     VCons : {x : a} -> {y : a} -> {xs : List a} -> 
+     VCons : {x : a} -> {y : a} -> .{xs : List a} -> 
              (rec : VList xs) -> VList (x :: xs ++ [y])
 
 total
diff --git a/libs/base/Data/Vect.idr b/libs/base/Data/Vect.idr
--- a/libs/base/Data/Vect.idr
+++ b/libs/base/Data/Vect.idr
@@ -9,13 +9,15 @@
 infixr 7 ::
 
 ||| Vectors: Generic lists with explicit length in the type
+||| @ len the length of the list
+||| @ elem the type of elements
 %elim
-data Vect : Nat -> Type -> Type where
+data Vect : (len : Nat) -> (elem : Type) -> Type where
   ||| Empty vector
-  Nil  : Vect Z a
-  ||| A non-empty vector of length `S k`, consisting of a head element and
-  ||| the rest of the list, of length `k`.
-  (::) : (x : a) -> (xs : Vect k a) -> Vect (S k) a
+  Nil  : Vect Z elem
+  ||| A non-empty vector of length `S len`, consisting of a head element and
+  ||| the rest of the list, of length `len`.
+  (::) : (x : elem) -> (xs : Vect len elem) -> Vect (S len) elem
 
 -- Hints for interactive editing
 %name Vect xs,ys,zs,ws
@@ -28,14 +30,14 @@
 |||
 ||| **Note**: this is only useful if you don't already statically know the length
 ||| and you want to avoid matching the implicit argument for erasure reasons.
-||| @ n the length (provably equal to the return value)
+||| @ len the length (provably equal to the return value)
 ||| @ xs the vector
-length : (xs : Vect n a) -> Nat
+length : (xs : Vect len elem) -> Nat
 length [] = 0
 length (x::xs) = 1 + length xs
 
 ||| Show that the length function on vectors in fact calculates the length
-private lengthCorrect : (n : Nat) -> (xs : Vect n a) -> length xs = n
+private lengthCorrect : (len : Nat) -> (xs : Vect len elem) -> length xs = len
 lengthCorrect Z     []        = Refl
 lengthCorrect (S n) (x :: xs) = rewrite lengthCorrect n xs in Refl
 
@@ -44,44 +46,44 @@
 --------------------------------------------------------------------------------
 
 ||| All but the first element of the vector
-tail : Vect (S n) a -> Vect n a
+tail : Vect (S len) elem -> Vect len elem
 tail (x::xs) = xs
 
 ||| Only the first element of the vector
-head : Vect (S n) a -> a
+head : Vect (S len) elem -> elem
 head (x::xs) = x
 
 ||| The last element of the vector
-last : Vect (S n) a -> a
+last : Vect (S len) elem -> elem
 last (x::[])    = x
 last (x::y::ys) = last $ y::ys
 
 ||| All but the last element of the vector
-init : Vect (S n) a -> Vect n a
+init : Vect (S len) elem -> Vect len elem
 init (x::[])    = []
 init (x::y::ys) = x :: init (y::ys)
 
 ||| Extract a particular element from a vector
-index : Fin n -> Vect n a -> a
+index : Fin len -> Vect len elem -> elem
 index FZ     (x::xs) = x
 index (FS k) (x::xs) = index k xs
 
 
 ||| Insert an element at a particular index
-insertAt : Fin (S n) -> a -> Vect n a -> Vect (S n) a
+insertAt : Fin (S len) -> elem -> Vect len elem -> Vect (S len) elem
 insertAt FZ     y xs      = y :: xs
 insertAt (FS k) y (x::xs) = x :: insertAt k y xs
 insertAt (FS k) y []      = absurd k
 
 ||| Construct a new vector consisting of all but the indicated element
-deleteAt : Fin (S n) -> Vect (S n) a -> Vect n a
-deleteAt           FZ     (x::xs) = xs
-deleteAt {n = S m} (FS k) (x::xs) = x :: deleteAt k xs
-deleteAt {n = Z}   (FS k) (x::xs) = absurd k
-deleteAt           _      []      impossible
+deleteAt : Fin (S len) -> Vect (S len) elem -> Vect len elem
+deleteAt             FZ     (x::xs) = xs
+deleteAt {len = S m} (FS k) (x::xs) = x :: deleteAt k xs
+deleteAt {len = Z}   (FS k) (x::xs) = absurd k
+deleteAt             _      []      impossible
 
 ||| Replace an element at a particlar index with another
-replaceAt : Fin n -> t -> Vect n t -> Vect n t
+replaceAt : Fin len -> elem -> Vect len elem -> Vect len elem
 replaceAt FZ     y (x::xs) = y :: xs
 replaceAt (FS k) y (x::xs) = x :: replaceAt k y xs
 
@@ -89,7 +91,7 @@
 ||| @ i the index to replace at
 ||| @ f the update function
 ||| @ xs the vector to replace in
-updateAt : (i : Fin n) -> (f : t -> t) -> (xs : Vect n t) -> Vect n t
+updateAt : (i : Fin len) -> (f : elem -> elem) -> (xs : Vect len elem) -> Vect len elem
 updateAt FZ     f (x::xs) = f x :: xs
 updateAt (FS k) f (x::xs) = x :: updateAt k f xs
 
@@ -99,13 +101,13 @@
 
 ||| Get the first n elements of a Vect
 ||| @ n the number of elements to take
-take : (n : Nat) -> Vect (n + m) a -> Vect n a
+take : (n : Nat) -> Vect (n + m) elem -> Vect n elem
 take Z     xs        = []
 take (S k) (x :: xs) = x :: take k xs
 
 ||| Remove the first n elements of a Vect
 ||| @ n the number of elements to remove
-drop : (n : Nat) -> Vect (n + m) a -> Vect m a
+drop : (n : Nat) -> Vect (n + m) elem -> Vect m elem
 drop Z     xs        = xs
 drop (S k) (x :: xs) = drop k xs
 
@@ -113,7 +115,7 @@
 ||| Boolean predicate.
 |||
 ||| @ p the predicate
-takeWhile : (p : a -> Bool) -> Vect n a -> (q ** Vect q a)
+takeWhile : (p : elem -> Bool) -> Vect len elem -> (q ** Vect q elem)
 takeWhile p []      = (_ ** [])
 takeWhile p (x::xs) =
   let (len ** ys) = takeWhile p xs
@@ -126,7 +128,7 @@
 ||| Boolean predicate.
 |||
 ||| @ p the predicate
-dropWhile : (p : a -> Bool) -> Vect n a -> (q ** Vect q a)
+dropWhile : (p : elem -> Bool) -> Vect len elem -> (q ** Vect q elem)
 dropWhile p [] = (_ ** [])
 dropWhile p (x::xs) =
   if p x then
@@ -139,9 +141,9 @@
 --------------------------------------------------------------------------------
 
 ||| Reverse the order of the elements of a vector
-reverse : Vect n a -> Vect n a
+reverse : Vect len elem -> Vect len elem
 reverse xs = go [] xs
-  where go : Vect n a -> Vect m a -> Vect (n+m) a
+  where go : Vect n elem -> Vect m elem -> Vect (n+m) elem
         go {n}         acc []        = rewrite plusZeroRightNeutral n in acc
         go {n} {m=S m} acc (x :: xs) = rewrite sym $ plusSuccRightSucc n m
                                        in go (x::acc) xs
@@ -149,11 +151,11 @@
 ||| Alternate an element between the other elements of a vector
 ||| @ sep the element to intersperse
 ||| @ xs the vector to separate with `sep`
-intersperse : (sep : a) -> (xs : Vect n a) -> Vect (n + pred n) a
+intersperse : (sep : elem) -> (xs : Vect len elem) -> Vect (len + pred len) elem
 intersperse sep []      = []
 intersperse sep (x::xs) = x :: intersperse' sep xs
   where
-    intersperse' : a -> Vect n a -> Vect (n + n) a
+    intersperse' : elem -> Vect n elem -> Vect (n + n) elem
     intersperse'         sep []      = []
     intersperse' {n=S n} sep (x::xs) = rewrite sym $ plusSuccRightSucc n n
                                        in sep :: x :: intersperse' sep xs
@@ -163,17 +165,17 @@
 --------------------------------------------------------------------------------
 
 
-fromList' : Vect n a -> (l : List a) -> Vect (length l + n) a
+fromList' : Vect len elem -> (l : List elem) -> Vect (length l + len) elem
 fromList' ys [] = ys
-fromList' {n} ys (x::xs) =
-  rewrite (plusSuccRightSucc (length xs) n) ==>
-          Vect (plus (length xs) (S n)) a in
+fromList' {len} ys (x::xs) =
+  rewrite (plusSuccRightSucc (length xs) len) ==>
+          Vect (plus (length xs) (S len)) elem in
   fromList' (x::ys) xs
 
 ||| Convert a list to a vector.
 |||
 ||| The length of the list should be statically known.
-fromList : (l : List a) -> Vect (length l) a
+fromList : (l : List elem) -> Vect (length l) elem
 fromList l =
   rewrite (sym $ plusZeroRightNeutral (length l)) in
   reverse $ fromList' [] l
@@ -183,30 +185,31 @@
 --------------------------------------------------------------------------------
 
 ||| Append two vectors
-(++) : Vect m a -> Vect n a -> Vect (m + n) a
+(++) : (xs : Vect m elem) -> (ys : Vect n elem) -> Vect (m + n) elem
 (++) []      ys = ys
 (++) (x::xs) ys = x :: xs ++ ys
 
-||| Repeate some value n times
-||| @ n the number of times to repeat it
+||| Repeate some value some number of times.
+|||
+||| @ len the number of times to repeat it
 ||| @ x the value to repeat
-replicate : (n : Nat) -> (x : a) -> Vect n a
+replicate : (len : Nat) -> (x : elem) -> Vect len elem
 replicate Z     x = []
 replicate (S k) x = x :: replicate k x
 
 ||| Merge two ordered vectors
-mergeBy : (a -> a -> Ordering) -> Vect n a -> Vect m a -> Vect (n + m) a
+mergeBy : (elem -> elem -> Ordering) -> (xs : Vect n elem) -> (ys : Vect m elem) -> Vect (n + m) elem
 mergeBy order [] [] = []
 mergeBy order [] (x :: xs) = x :: xs
-mergeBy {n = S k} order (x :: xs) [] = rewrite plusZeroRightNeutral (S k) in  
+mergeBy {n = S k} order (x :: xs) [] = rewrite plusZeroRightNeutral (S k) in
                                                x :: xs
-mergeBy {n = S k} {m = S k'} order (x :: xs) (y :: ys) 
+mergeBy {n = S k} {m = S k'} order (x :: xs) (y :: ys)
      = case order x y of
             LT => x :: mergeBy order xs (y :: ys)
-            _  => rewrite sym (plusSuccRightSucc k k') in 
+            _  => rewrite sym (plusSuccRightSucc k k') in
                              y :: mergeBy order (x :: xs) ys
 
-merge : Ord a => Vect n a -> Vect m a -> Vect (n + m) a
+merge : Ord elem => Vect n elem -> Vect m elem -> Vect (n + m) elem
 merge = mergeBy compare
 
 --------------------------------------------------------------------------------
@@ -223,26 +226,26 @@
 zipWith f (x::xs) (y::ys) = f x y :: zipWith f xs ys
 
 ||| Combine three equal-length vectors into a vector with some function
-zipWith3 : (a -> b -> c -> d) -> Vect n a -> Vect n b -> Vect n c -> Vect n d
+zipWith3 : (a -> b -> c -> d) -> (xs : Vect n a) -> (ys : Vect n b) -> (zs : Vect n c) -> Vect n d
 zipWith3 f []      []      []      = []
 zipWith3 f (x::xs) (y::ys) (z::zs) = f x y z :: zipWith3 f xs ys zs
 
 ||| Combine two equal-length vectors pairwise
-zip : Vect n a -> Vect n b -> Vect n (a, b)
+zip : (xs : Vect n a) -> (ys : Vect n b) -> Vect n (a, b)
 zip = zipWith (\x,y => (x,y))
 
 ||| Combine three equal-length vectors elementwise into a vector of tuples
-zip3 : Vect n a -> Vect n b -> Vect n c -> Vect n (a, b, c)
+zip3 : (xs : Vect n a) -> (ys : Vect n b) -> (zs : Vect n c) -> Vect n (a, b, c)
 zip3 = zipWith3 (\x,y,z => (x,y,z))
 
 ||| Convert a vector of pairs to a pair of vectors
-unzip : Vect n (a, b) -> (Vect n a, Vect n b)
+unzip : (xs : Vect n (a, b)) -> (Vect n a, Vect n b)
 unzip []           = ([], [])
 unzip ((l, r)::xs) with (unzip xs)
   | (lefts, rights) = (l::lefts, r::rights)
 
 ||| Convert a vector of three-tuples to a triplet of vectors
-unzip3 : Vect n (a, b, c) -> (Vect n a, Vect n b, Vect n c)
+unzip3 : (xs : Vect n (a, b, c)) -> (Vect n a, Vect n b, Vect n c)
 unzip3 []            = ([], [], [])
 unzip3 ((l,c,r)::xs) with (unzip3 xs)
   | (lefts, centers, rights) = (l::lefts, c::centers, r::rights)
@@ -251,7 +254,7 @@
 -- Equality
 --------------------------------------------------------------------------------
 
-implementation (Eq a) => Eq (Vect n a) where
+implementation (Eq elem) => Eq (Vect len elem) where
   (==) []      []      = True
   (==) (x::xs) (y::ys) = x == y && xs == ys
 
@@ -260,7 +263,7 @@
 -- Order
 --------------------------------------------------------------------------------
 
-implementation Ord a => Ord (Vect n a) where
+implementation Ord elem => Ord (Vect len elem) where
   compare []      []      = EQ
   compare (x::xs) (y::ys) = compare x y `thenCompare` compare xs ys
 
@@ -283,7 +286,7 @@
 |||
 ||| @ f the partial function (expressed by returning `Maybe`)
 ||| @ xs the vector to check for results
-mapMaybe : (f : a -> Maybe b) -> (xs : Vect n a) -> (m : Nat ** Vect m b)
+mapMaybe : (f : a -> Maybe b) -> (xs : Vect len a) -> (m : Nat ** Vect m b)
 mapMaybe f []      = (_ ** [])
 mapMaybe f (x::xs) =
   let (len ** ys) = mapMaybe f xs
@@ -308,7 +311,7 @@
 --------------------------------------------------------------------------------
 
 ||| Flatten a vector of equal-length vectors
-concat : Vect m (Vect n a) -> Vect (m * n) a
+concat : (xss : Vect m (Vect n elem)) -> Vect (m * n) elem
 concat []      = []
 concat (v::vs) = v ++ concat vs
 
@@ -323,7 +326,7 @@
 -- Scans
 --------------------------------------------------------------------------------
 
-scanl : (b -> a -> b) -> b -> Vect n a -> Vect (S n) b
+scanl : (res -> elem -> res) -> res -> Vect len elem -> Vect (S len) res
 scanl f q []      = [q]
 scanl f q (x::xs) = q :: scanl f (f q x) xs
 
@@ -335,37 +338,37 @@
 ||| @ p the equality test
 ||| @ e the item to search for
 ||| @ xs the vector to search in
-elemBy : (p : a -> a -> Bool) -> (e : a) -> (xs : Vect n a) -> Bool
+elemBy : (p : elem -> elem -> Bool) -> (e : elem) -> (xs : Vect len elem) -> Bool
 elemBy p e []      = False
 elemBy p e (x::xs) = p e x || elemBy p e xs
 
 ||| Use the default Boolean equality on elements to search for an item
 ||| @ x what to search for
 ||| @ xs where to search
-elem : Eq a => (x : a) -> (xs : Vect n a) -> Bool
+elem : Eq elem => (x : elem) -> (xs : Vect len elem) -> Bool
 elem = elemBy (==)
 
 ||| Find the association of some key with a user-provided comparison
 ||| @ p the comparison operator for keys (True if they match)
 ||| @ e the key to look for
-lookupBy : (p : a -> a -> Bool) -> (e : a) -> (xs : Vect n (a, b)) -> Maybe b
+lookupBy : (p : key -> key -> Bool) -> (e : key) -> (xs : Vect n (key, val)) -> Maybe val
 lookupBy p e []           = Nothing
 lookupBy p e ((l, r)::xs) = if p e l then Just r else lookupBy p e xs
 
 ||| Find the assocation of some key using the default Boolean equality test
-lookup : Eq a => a -> Vect n (a, b) -> Maybe b
+lookup : Eq key => key -> Vect n (key, val) -> Maybe val
 lookup = lookupBy (==)
 
 ||| Check if any element of xs is found in elems by a user-provided comparison
 ||| @ p the comparison operator
 ||| @ elems the vector to search
 ||| @ xs what to search for
-hasAnyBy : (p : a -> a -> Bool) -> (elems : Vect m a) -> (xs : Vect n a) -> Bool
+hasAnyBy : (p : elem -> elem -> Bool) -> (elems : Vect m elem) -> (xs : Vect len elem) -> Bool
 hasAnyBy p elems []      = False
 hasAnyBy p elems (x::xs) = elemBy p x elems || hasAnyBy p elems xs
 
 ||| Check if any element of xs is found in elems using the default Boolean equality test
-hasAny : Eq a => Vect m a -> Vect n a -> Bool
+hasAny : Eq elem => Vect m elem -> Vect len elem -> Bool
 hasAny = hasAnyBy (==)
 
 --------------------------------------------------------------------------------
@@ -374,31 +377,31 @@
 
 ||| Find the first element of the vector that satisfies some test
 ||| @ p the test to satisfy
-find : (p : a -> Bool) -> (xs : Vect n a) -> Maybe a
+find : (p : elem -> Bool) -> (xs : Vect len elem) -> Maybe elem
 find p []      = Nothing
 find p (x::xs) = if p x then Just x else find p xs
 
 ||| Find the index of the first element of the vector that satisfies some test
-findIndex : (a -> Bool) -> Vect n a -> Maybe (Fin n)
+findIndex : (elem -> Bool) -> Vect len elem -> Maybe (Fin len)
 findIndex p []        = Nothing
 findIndex p (x :: xs) = if p x then Just 0 else map FS (findIndex p xs)
 
 ||| Find the indices of all elements that satisfy some test
-findIndices : (a -> Bool) -> Vect m a -> List (Fin m)
+findIndices : (elem -> Bool) -> Vect m elem -> List (Fin m)
 findIndices p []        = []
 findIndices p (x :: xs) = let is = map FS $ findIndices p xs
                            in if p x then 0 :: is else is
 
-elemIndexBy : (a -> a -> Bool) -> a -> Vect m a -> Maybe (Fin m)
+elemIndexBy : (elem -> elem -> Bool) -> elem -> Vect m elem -> Maybe (Fin m)
 elemIndexBy p e = findIndex $ p e
 
-elemIndex : Eq a => a -> Vect m a -> Maybe (Fin m)
+elemIndex : Eq elem => elem -> Vect m elem -> Maybe (Fin m)
 elemIndex = elemIndexBy (==)
 
-elemIndicesBy : (a -> a -> Bool) -> a -> Vect m a -> List (Fin m)
+elemIndicesBy : (elem -> elem -> Bool) -> elem -> Vect m elem -> List (Fin m)
 elemIndicesBy p e = findIndices $ p e
 
-elemIndices : Eq a => a -> Vect m a -> List (Fin m)
+elemIndices : Eq elem => elem -> Vect m elem -> List (Fin m)
 elemIndices = elemIndicesBy (==)
 
 --------------------------------------------------------------------------------
@@ -406,7 +409,7 @@
 --------------------------------------------------------------------------------
 
 ||| Find all elements of a vector that satisfy some test
-filter : (a -> Bool) -> Vect n a -> (p ** Vect p a)
+filter : (elem -> Bool) -> Vect len elem -> (p ** Vect p elem)
 filter p []      = ( _ ** [] )
 filter p (x::xs) =
   let (_ ** tail) = filter p xs
@@ -416,10 +419,10 @@
         (_ ** tail)
 
 ||| Make the elements of some vector unique by some test
-nubBy : (a -> a -> Bool) -> Vect n a -> (p ** Vect p a)
+nubBy : (elem -> elem -> Bool) -> Vect len elem -> (p ** Vect p elem)
 nubBy = nubBy' []
   where
-    nubBy' : Vect m a -> (a -> a -> Bool) -> Vect n a -> (p ** Vect p a)
+    nubBy' : Vect m elem -> (elem -> elem -> Bool) -> Vect len elem -> (p ** Vect p elem)
     nubBy' acc p []      = (_ ** [])
     nubBy' acc p (x::xs) with (elemBy p x acc)
       | True  = nubBy' acc p xs
@@ -427,16 +430,16 @@
         | (_ ** tail) = (_ ** x::tail)
 
 ||| Make the elements of some vector unique by the default Boolean equality
-nub : Eq a => Vect n a -> (p ** Vect p a)
+nub : Eq elem => Vect len elem -> (p ** Vect p elem)
 nub = nubBy (==)
 
-deleteBy : (a -> a -> Bool) -> a -> Vect n a -> (p ** Vect p a)
+deleteBy : (elem -> elem -> Bool) -> elem -> Vect len elem -> (p ** Vect p elem)
 deleteBy _  _ []      = (_ ** [])
 deleteBy eq x (y::ys) =
   let (len ** zs) = deleteBy eq x ys
   in if x `eq` y then (_ ** ys) else (S len ** y ::zs)
 
-delete : (Eq a) => a -> Vect n a -> (p ** Vect p a)
+delete : (Eq elem) => elem -> Vect len elem -> (p ** Vect p elem)
 delete = deleteBy (==)
 
 --------------------------------------------------------------------------------
@@ -448,10 +451,10 @@
 ||| It is equivalent to (take n xs, drop n xs)
 ||| @ n   the index to split at
 ||| @ xs  the Vect to split in two
-splitAt : (n : Nat) -> (xs : Vect (n + m) a) -> (Vect n a, Vect m a)
+splitAt : (n : Nat) -> (xs : Vect (n + m) elem) -> (Vect n elem, Vect m elem)
 splitAt n xs = (take n xs, drop n xs)
 
-partition : (a -> Bool) -> Vect n a -> ((p ** Vect p a), (q ** Vect q a))
+partition : (elem -> Bool) -> Vect len elem -> ((p ** Vect p elem), (q ** Vect q elem))
 partition p []      = ((_ ** []), (_ ** []))
 partition p (x::xs) =
   let ((leftLen ** lefts), (rightLen ** rights)) = partition p xs in
@@ -464,29 +467,29 @@
 -- Predicates
 --------------------------------------------------------------------------------
 
-isPrefixOfBy : (a -> a -> Bool) -> Vect m a -> Vect n a -> Bool
+isPrefixOfBy : (elem -> elem -> Bool) -> Vect m elem -> Vect len elem -> Bool
 isPrefixOfBy p [] right        = True
 isPrefixOfBy p left []         = False
 isPrefixOfBy p (x::xs) (y::ys) = p x y && isPrefixOfBy p xs ys
 
-isPrefixOf : Eq a => Vect m a -> Vect n a -> Bool
+isPrefixOf : Eq elem => Vect m elem -> Vect len elem -> Bool
 isPrefixOf = isPrefixOfBy (==)
 
-isSuffixOfBy : (a -> a -> Bool) -> Vect m a -> Vect n a -> Bool
+isSuffixOfBy : (elem -> elem -> Bool) -> Vect m elem -> Vect len elem -> Bool
 isSuffixOfBy p left right = isPrefixOfBy p (reverse left) (reverse right)
 
-isSuffixOf : Eq a => Vect m a -> Vect n a -> Bool
+isSuffixOf : Eq elem => Vect m elem -> Vect len elem -> Bool
 isSuffixOf = isSuffixOfBy (==)
 
 --------------------------------------------------------------------------------
 -- Conversions
 --------------------------------------------------------------------------------
 
-maybeToVect : Maybe a -> (p ** Vect p a)
+maybeToVect : Maybe elem -> (p ** Vect p elem)
 maybeToVect Nothing  = (_ ** [])
 maybeToVect (Just j) = (_ ** [j])
 
-vectToMaybe : Vect n a -> Maybe a
+vectToMaybe : Vect len elem -> Maybe elem
 vectToMaybe []      = Nothing
 vectToMaybe (x::xs) = Just x
 
@@ -494,25 +497,25 @@
 -- Misc
 --------------------------------------------------------------------------------
 
-catMaybes : Vect n (Maybe a) -> (p ** Vect p a)
+catMaybes : Vect n (Maybe elem) -> (p ** Vect p elem)
 catMaybes []             = (_ ** [])
 catMaybes (Nothing::xs)  = catMaybes xs
 catMaybes ((Just j)::xs) =
   let (_ ** tail) = catMaybes xs
    in (_ ** j::tail)
 
-diag : Vect n (Vect n a) -> Vect n a
+diag : Vect len (Vect len elem) -> Vect len elem
 diag []             = []
 diag ((x::xs)::xss) = x :: diag (map tail xss)
 
-range : {n : Nat} -> Vect n (Fin n)
-range {n=Z}   = []
-range {n=S _} = FZ :: map FS range
+range : {len : Nat} -> Vect len (Fin len)
+range {len=Z}   = []
+range {len=S _} = FZ :: map FS range
 
 ||| Transpose a Vect of Vects, turning rows into columns and vice versa.
 |||
 ||| As the types ensure rectangularity, this is an involution, unlike `Prelude.List.transpose`.
-transpose : {n : Nat} -> Vect m (Vect n a) -> Vect n (Vect m a)
+transpose : {n : Nat} -> Vect m (Vect n elem) -> Vect n (Vect m elem)
 transpose []        = replicate _ []
 transpose (x :: xs) = zipWith (::) x (transpose xs)
 
@@ -527,7 +530,7 @@
 
 ||| This monad is different from the List monad, (>>=)
 ||| uses the diagonal.
-implementation Monad (Vect n) where
+implementation Monad (Vect len) where
     m >>= f = diag (map f m)
 
 implementation Traversable (Vect n) where
@@ -538,14 +541,14 @@
 -- Show
 --------------------------------------------------------------------------------
 
-implementation Show a => Show (Vect n a) where
+implementation Show elem => Show (Vect len elem) where
     show = show . toList
 
 --------------------------------------------------------------------------------
 -- Properties
 --------------------------------------------------------------------------------
 
-vectConsCong : (x : a) -> (xs : Vect n a) -> (ys : Vect m a) -> (xs = ys) -> (x :: xs = x :: ys)
+vectConsCong : (x : elem) -> (xs : Vect len elem) -> (ys : Vect m elem) -> (xs = ys) -> (x :: xs = x :: ys)
 vectConsCong x xs xs Refl = Refl
 
 vectNilRightNeutral : (xs : Vect n a) -> xs ++ [] = xs
@@ -553,7 +556,10 @@
 vectNilRightNeutral (x :: xs) =
   vectConsCong _ _ _ (vectNilRightNeutral xs)
 
-vectAppendAssociative : (x : Vect xLen a) -> (y : Vect yLen a) -> (z : Vect zLen a) -> x ++ (y ++ z) = (x ++ y) ++ z
+vectAppendAssociative : (xs : Vect xLen elem) ->
+                        (ys : Vect yLen elem) ->
+                        (zs : Vect zLen elem) ->
+                        xs ++ (ys ++ zs) = (xs ++ ys) ++ zs
 vectAppendAssociative [] y z = Refl
 vectAppendAssociative (x :: xs) ys zs =
   vectConsCong _ _ _ (vectAppendAssociative xs ys zs)
@@ -599,7 +605,7 @@
 noEmptyElem Here impossible
 
 Uninhabited (Elem x []) where
-  uninhabited = noEmptyElem 
+  uninhabited = noEmptyElem
 
 ||| An item not in the head and not in the tail is not in the Vect at all
 neitherHereNorThere : {x, y : a} -> {xs : Vect n a} -> Not (x = y) -> Not (Elem x xs) -> Not (Elem x (y :: xs))
@@ -634,7 +640,7 @@
 ||| length in its type, otherwise return Nothing
 ||| @len the required length
 ||| @xs the vector with the desired length
--- Needs to be Maybe rather than Dec, because if 'n' is unequal to m, we 
+-- Needs to be Maybe rather than Dec, because if 'n' is unequal to m, we
 -- only know we don't know how to make a Vect n a, not that one can't exist.
 exactLength : {m : Nat} -> -- expected at run-time
               (len : Nat) -> (xs : Vect m a) -> Maybe (Vect len a)
@@ -654,4 +660,3 @@
          = Just (0 ** xs)
   overLength {m = plus n (S x)} n xs | (CmpGT x)
          = Just (S x ** rewrite plusCommutative (S x) n in xs)
-
diff --git a/libs/base/Makefile b/libs/base/Makefile
--- a/libs/base/Makefile
+++ b/libs/base/Makefile
@@ -4,8 +4,9 @@
 build:
 	$(IDRIS) --build ${PKG}.ipkg
 
-install: 
+install:
 	$(IDRIS) --install ${PKG}.ipkg
+	${IDRIS} --installdoc ${PKG}.ipkg
 
 clean:
 	$(IDRIS) --clean ${PKG}.ipkg
@@ -21,4 +22,4 @@
 linecount:
 	find . -name '*.idr' | xargs wc -l
 
-.PHONY: build install clean rebuild linecount
+.PHONY: build install clean rebuild linecount doc doc_clean
diff --git a/libs/base/System/Concurrency/Channels.idr b/libs/base/System/Concurrency/Channels.idr
--- a/libs/base/System/Concurrency/Channels.idr
+++ b/libs/base/System/Concurrency/Channels.idr
@@ -16,10 +16,13 @@
      MkPID : (pid : Ptr) -> PID
 
 ||| Spawn a process in a new thread, returning the process ID
+||| Returns `Nothing` if there are not enough resources to create the new thread
 export
-spawn : (process : IO ()) -> IO PID
+spawn : (process : IO ()) -> IO (Maybe PID)
 spawn proc = do pid <- fork proc
-                pure (MkPID pid)
+                if !(nullPtr pid)
+                   then pure Nothing
+                   else pure (Just (MkPID pid))
 
 ||| Create a channel which connects this process to another process
 export
@@ -61,3 +64,7 @@
 unsafeRecv : (expected : Type) -> Channel -> IO (Maybe expected)
 unsafeRecv a (MkConc pid ch_id) = getMsgFrom {a} pid ch_id
 
+||| Exit the thread immediately
+export
+stopThread : IO a
+stopThread = Raw.stopThread 
diff --git a/libs/base/System/Concurrency/Raw.idr b/libs/base/System/Concurrency/Raw.idr
--- a/libs/base/System/Concurrency/Raw.idr
+++ b/libs/base/System/Concurrency/Raw.idr
@@ -106,3 +106,9 @@
              foreign FFI_C "idris_freeMsg" (Ptr -> IO ()) m
              pure (Just x)
 
+stopThread : IO a
+stopThread = do vm <- getMyVM
+                MkRaw res <- foreign FFI_C "idris_stopThread" (Ptr -> IO (Raw a)) vm
+                pure res
+
+
diff --git a/libs/contrib/Data/Fin/Extra.idr b/libs/contrib/Data/Fin/Extra.idr
new file mode 100644
--- /dev/null
+++ b/libs/contrib/Data/Fin/Extra.idr
@@ -0,0 +1,9 @@
+module Data.Fin.Extra
+
+import Data.Fin
+
+||| Proof that an element **n** of Fin **m** , when converted to Nat is smaller than the bound **m**.
+public export
+elemSmallerThanBound : (n : Fin m) -> LTE (finToNat n) m
+elemSmallerThanBound FZ = LTEZero
+elemSmallerThanBound (FS x) = LTESucc (elemSmallerThanBound x)
diff --git a/libs/contrib/Makefile b/libs/contrib/Makefile
--- a/libs/contrib/Makefile
+++ b/libs/contrib/Makefile
@@ -4,8 +4,9 @@
 build:
 	$(IDRIS) --build ${PKG}.ipkg
 
-install: 
+install:
 	$(IDRIS) --install ${PKG}.ipkg
+	${IDRIS} --installdoc ${PKG}.ipkg
 
 clean:
 	$(IDRIS) --clean ${PKG}.ipkg
@@ -21,4 +22,4 @@
 linecount:
 	find . -name '*.idr' | xargs wc -l
 
-.PHONY: build install clean rebuild linecount
+.PHONY: build install clean rebuild linecount doc doc_clean
diff --git a/libs/contrib/contrib.ipkg b/libs/contrib/contrib.ipkg
--- a/libs/contrib/contrib.ipkg
+++ b/libs/contrib/contrib.ipkg
@@ -25,4 +25,6 @@
 
           Network.Cgi, Network.Socket,
 
-          System.Concurrency.Process
+          System.Concurrency.Process,
+
+          Data.Fin.Extra
diff --git a/libs/effects/Makefile b/libs/effects/Makefile
--- a/libs/effects/Makefile
+++ b/libs/effects/Makefile
@@ -9,6 +9,7 @@
 
 install:
 	$(IDRIS) --install ${PKG}.ipkg
+	${IDRIS} --installdoc ${PKG}.ipkg
 
 rebuild: clean build
 
diff --git a/libs/prelude/Builtins.idr b/libs/prelude/Builtins.idr
--- a/libs/prelude/Builtins.idr
+++ b/libs/prelude/Builtins.idr
@@ -160,7 +160,8 @@
 par (Delay x) = x
 
 ||| Assert to the totality checker that y is always structurally smaller than
-||| x (which is typically a pattern argument)
+||| x (which is typically a pattern argument, and *must* be in normal form
+||| for this to work)
 ||| @ x the larger value (typically a pattern argument)
 ||| @ y the smaller value (typically an argument to a recursive call)
 assert_smaller : (x : a) -> (y : b) -> b
diff --git a/libs/prelude/Makefile b/libs/prelude/Makefile
--- a/libs/prelude/Makefile
+++ b/libs/prelude/Makefile
@@ -4,8 +4,9 @@
 build:
 	$(IDRIS) --build ${PKG}.ipkg
 
-install: 
+install:
 	$(IDRIS) --install ${PKG}.ipkg
+	${IDRIS} --installdoc ${PKG}.ipkg
 
 clean:
 	$(IDRIS) --clean ${PKG}.ipkg
diff --git a/libs/prelude/Prelude.idr b/libs/prelude/Prelude.idr
--- a/libs/prelude/Prelude.idr
+++ b/libs/prelude/Prelude.idr
@@ -156,8 +156,15 @@
 total natEnumFromThenTo' : Nat -> Nat -> Nat -> List Nat
 natEnumFromThenTo' _ Z       _ = []
 natEnumFromThenTo' n (S inc) m = map (plus n . (* (S inc))) (natRange (S (divNatNZ (minus m n) (S inc) SIsNotZ)))
+
 total natEnumFromThenTo : Nat -> Nat -> Nat -> List Nat
-natEnumFromThenTo n next m = natEnumFromThenTo' n (minus next n) m
+natEnumFromThenTo n next m = if n == m then [n]
+                             else if n < m then natEnumFromThenTo' n (minus next n) m
+                             else case minus n next of
+                                  Z => []
+                                  S step => List.reverse . map (+ (modNatNZ (minus n m) (S step) SIsNotZ)) $ natEnumFromThenTo' m (minus n next) n
+    where modNatNZ : Nat -> (m : Nat) -> Not (m = 0) -> Nat
+          modNatNZ n m nz = minus n $ mult m $ divNatNZ n m nz
 
 interface Enum a where
   total pred : a -> a
@@ -197,8 +204,9 @@
           go' n (x :: xs) = n + cast x :: go' n xs
           go : Integer -> Integer -> List Integer
           go n m = go' n (natRange (S (cast {to = Nat} (m - n))))
-  enumFromThenTo _ 0   _ = []
-  enumFromThenTo n next m = go (natRange (S (divNatNZ (fromInteger (abs (m - n))) (S (fromInteger ((abs (next - n)) - 1))) SIsNotZ)))
+  enumFromThenTo n next m = if n == m then [n]
+                            else if next - n == 0 || next - n < 0 /= m - n < 0 then []
+                            else go (natRange (S (divNatNZ (fromInteger (abs (m - n))) (S (fromInteger ((abs (next - n)) - 1))) SIsNotZ)))
     where go : List Nat -> List Integer
           go [] = []
           go (x :: xs) = n + (cast x * (next - n)) :: go xs
@@ -217,8 +225,9 @@
           go : Int -> Int -> List Int
           go n m = go' [] (cast {to = Nat} (m - n)) m
   enumFromThen n inc = n :: enumFromThen (inc + n) inc
-  enumFromThenTo _ 0   _ = []
-  enumFromThenTo n next m = go (natRange (S (divNatNZ (cast {to=Nat} (abs (m - n))) (S (cast {to=Nat} ((abs (next - n)) - 1))) SIsNotZ)))
+  enumFromThenTo n next m = if n == m then [n]
+                            else if next - n == 0 || next - n < 0 /= m - n < 0 then []
+                            else go (natRange (S (divNatNZ (cast {to=Nat} (abs (m - n))) (S (cast {to=Nat} ((abs (next - n)) - 1))) SIsNotZ)))
     where go : List Nat -> List Int
           go [] = []
           go (x :: xs) = n + (cast x * (next - n)) :: go xs
diff --git a/libs/prelude/Prelude/Interactive.idr b/libs/prelude/Prelude/Interactive.idr
--- a/libs/prelude/Prelude/Interactive.idr
+++ b/libs/prelude/Prelude/Interactive.idr
@@ -89,6 +89,16 @@
 getChar : IO Char
 getChar = map cast $ foreign FFI_C "getchar" (IO Int)
 
+||| Disables buffering in both stdin and stdout:
+||| so that output is written immediately (never stored in the buffer)
+||| and the next input item is read and returned
+|||
+||| this is useful to circumvent problems with IO on some Windows systems
+||| where stdout output right before a prompt is only shown after
+||| the input-line from stdin is produced
+disableBuffering : IO ()
+disableBuffering = foreign FFI_C "idris_disableBuffering" (IO ())
+
 ||| Get the command-line arguments that the program was called with.
 partial
 getArgs : IO (List String)
diff --git a/libs/prelude/Prelude/Maybe.idr b/libs/prelude/Prelude/Maybe.idr
--- a/libs/prelude/Prelude/Maybe.idr
+++ b/libs/prelude/Prelude/Maybe.idr
@@ -7,6 +7,7 @@
 import Prelude.Cast
 import Prelude.Interfaces
 import Prelude.Foldable
+import Prelude.Uninhabited
 
 %access public export
 %default total
@@ -37,6 +38,14 @@
 ||| Proof that some `Maybe` is actually `Just`
 data IsJust : Maybe a -> Type where
   ItIsJust : IsJust (Just x)
+
+Uninhabited (IsJust Nothing) where
+  uninhabited ItIsJust impossible
+
+||| Decide whether a 'Maybe' is 'Just'
+isItJust : (v : Maybe a) -> Dec (IsJust v)
+isItJust (Just x) = Yes ItIsJust
+isItJust Nothing = No absurd
 
 --------------------------------------------------------------------------------
 -- Misc
diff --git a/libs/prelude/Prelude/Nat.idr b/libs/prelude/Prelude/Nat.idr
--- a/libs/prelude/Prelude/Nat.idr
+++ b/libs/prelude/Prelude/Nat.idr
@@ -310,9 +310,19 @@
 -- Division and modulus
 --------------------------------------------------------------------------------
 
+||| The proof that no successor of a natural number can be zero.
+|||
+||| ```idris example
+||| modNatNZ 10 3 SIsNotZ
+||| ```
 SIsNotZ : {x: Nat} -> (S x = Z) -> Void
 SIsNotZ Refl impossible
 
+||| Modulus function where the divisor is not zero.
+|||
+||| ```idris example
+||| modNatNZ 100 2 SIsNotZ
+||| ```
 modNatNZ : Nat -> (y: Nat) -> Not (y = Z) -> Nat
 modNatNZ left Z         p = void (p Refl)
 modNatNZ left (S right) _ = mod' left left right
@@ -329,6 +339,11 @@
 modNat : Nat -> Nat -> Nat
 modNat left (S right) = modNatNZ left (S right) SIsNotZ
 
+||| Division where the divisor is not zero.
+|||
+||| ```idris example
+||| divNatNZ 100 2 SIsNotZ
+||| ```
 divNatNZ : Nat -> (y: Nat) -> Not (y = Z) -> Nat
 divNatNZ left Z         p = void (p Refl)
 divNatNZ left (S right) _ = div' left left right
diff --git a/libs/prelude/Prelude/Show.idr b/libs/prelude/Prelude/Show.idr
--- a/libs/prelude/Prelude/Show.idr
+++ b/libs/prelude/Prelude/Show.idr
@@ -46,7 +46,7 @@
   ||| @ x the value to convert
   partial
   show : (x : ty) -> String
-  show = showPrec Open
+  show x = showPrec Open x -- Eta expand to help totality checker
 
   ||| Convert a value to its `String` representation in a certain precedence
   ||| context.
@@ -63,7 +63,7 @@
   ||| @ x the value to convert
   partial
   showPrec : (d : Prec) -> (x : ty) -> String
-  showPrec _ = show
+  showPrec _ x = show x
 
 ||| Surround a `String` with parentheses depending on a condition.
 |||
diff --git a/libs/prelude/Prelude/Strings.idr b/libs/prelude/Prelude/Strings.idr
--- a/libs/prelude/Prelude/Strings.idr
+++ b/libs/prelude/Prelude/Strings.idr
@@ -328,7 +328,7 @@
 toLower x with (strM x)
   toLower ""             | StrNil = ""
   toLower (strCons c cs) | (StrCons c cs) =
-    strCons (toLower c) (toLower (assert_smaller (strCons c cs) cs))
+    strCons (toLower c) (toLower (assert_smaller (prim__strCons c cs) cs))
 
 ||| Uppercases all characters in the string.
 |||
@@ -339,7 +339,7 @@
 toUpper x with (strM x)
   toUpper ""             | StrNil = ""
   toUpper (strCons c cs) | (StrCons c cs) =
-    strCons (toUpper c) (toUpper (assert_smaller (strCons c cs) cs ))
+    strCons (toUpper c) (toUpper (assert_smaller (prim__strCons c cs) cs ))
 
 --------------------------------------------------------------------------------
 -- Predicates
diff --git a/libs/pruviloj/Makefile b/libs/pruviloj/Makefile
--- a/libs/pruviloj/Makefile
+++ b/libs/pruviloj/Makefile
@@ -9,6 +9,7 @@
 
 install:
 	$(IDRIS) --install ${PKG}.ipkg
+	${IDRIS} --installdoc ${PKG}.ipkg
 
 rebuild: clean build
 
diff --git a/libs/pruviloj/Pruviloj/Derive/Eliminators.idr b/libs/pruviloj/Pruviloj/Derive/Eliminators.idr
--- a/libs/pruviloj/Pruviloj/Derive/Eliminators.idr
+++ b/libs/pruviloj/Pruviloj/Derive/Eliminators.idr
@@ -3,7 +3,7 @@
 import Language.Reflection.Utils
 import Data.Vect
 
-import Pruviloj.Core
+import public Pruviloj.Core
 import Pruviloj.Internals.TyConInfo
 import Pruviloj.Internals
 import Pruviloj.Renamers
@@ -63,7 +63,7 @@
                 focus ihT
                 attack
                 for_ {b=()} argArgs $ \(n, b) =>
-                  forall n (getBinderTy b)
+                  forall n (binderTy b)
                 let argTm : Raw = mkApp (Var recArg) (map (Var . fst) argArgs)
                 argTmTy <- forget (snd !(check !getEnv argTm))
                 argHoles <- apply (Var motiveName)
@@ -239,7 +239,7 @@
 
   where bindLam : List (TTName, Binder Raw) -> Raw -> Raw
         bindLam [] x = x
-        bindLam ((n, b)::rest) x = RBind n (Lam (getBinderTy b)) $ bindLam rest x
+        bindLam ((n, b)::rest) x = RBind n (Lam (binderTy b)) $ bindLam rest x
 
 getElimClauses : TyConInfo -> (elimn : TTName) ->
                  List (TTName, List CtorArg, Raw) -> Elab (List (FunClause Raw))
diff --git a/libs/pruviloj/Pruviloj/Internals.idr b/libs/pruviloj/Pruviloj/Internals.idr
--- a/libs/pruviloj/Pruviloj/Internals.idr
+++ b/libs/pruviloj/Pruviloj/Internals.idr
@@ -1,7 +1,7 @@
 ||| Internal details of the library, not for public consumption.
 module Pruviloj.Internals
 
-
+import Language.Reflection.Utils
 import Pruviloj.Core
 import Pruviloj.Renamers
 
@@ -50,16 +50,6 @@
 extractBinders tm = ([], tm)
 
 
-||| Get the type annotation from a binder
-getBinderTy : Binder t -> t
-getBinderTy (Lam t) = t
-getBinderTy (Pi t _) = t
-getBinderTy (Let t _) = t
-getBinderTy (Hole t) = t
-getBinderTy (GHole t) = t
-getBinderTy (Guess t _) = t
-getBinderTy (PVar t) = t
-getBinderTy (PVTy t) = t
 
 ||| Map a list `[x1, x2, ..., xn]` to `[(0, x1), (1, x2), ..., (n-1, xn)]`
 enumerate : List a -> List (Nat, a)
@@ -70,11 +60,11 @@
 
 bindPats : List (TTName, Binder Raw) -> Raw -> Raw
 bindPats [] res = res
-bindPats ((n, b)::bs) res = RBind n (PVar (getBinderTy b)) $ bindPats bs res
+bindPats ((n, b)::bs) res = RBind n (PVar (binderTy b)) $ bindPats bs res
 
 bindPatTys : List (TTName, Binder Raw) -> Raw -> Raw
 bindPatTys [] res = res
-bindPatTys ((n, b)::bs) res = RBind n (PVTy (getBinderTy b)) $ bindPatTys bs res
+bindPatTys ((n, b)::bs) res = RBind n (PVTy (binderTy b)) $ bindPatTys bs res
 
 
 ||| Helper for elaborating pattern clauses. This helper takes care of
diff --git a/libs/pruviloj/Pruviloj/Internals/TyConInfo.idr b/libs/pruviloj/Pruviloj/Internals/TyConInfo.idr
--- a/libs/pruviloj/Pruviloj/Internals/TyConInfo.idr
+++ b/libs/pruviloj/Pruviloj/Internals/TyConInfo.idr
@@ -1,4 +1,4 @@
-module Pruviloj.Derive.TyConInfo
+module Pruviloj.Internals.TyConInfo
 
 import Pruviloj.Core
 import Pruviloj.Internals
diff --git a/main/Main.hs b/main/Main.hs
--- a/main/Main.hs
+++ b/main/Main.hs
@@ -1,17 +1,22 @@
 module Main where
 
-import Control.Monad ( when )
-import System.Exit ( exitSuccess )
+import System.Exit ( ExitCode(..), exitWith, exitSuccess )
 
+import Control.Monad ( unless, when, (>=>) )
+import Data.Maybe    ( fromMaybe )
+import Data.Foldable ( foldrM )
+
 import Idris.AbsSyntax
-import Idris.Error
 import Idris.CmdOptions
-import Idris.Info
+import Idris.Error
 import Idris.Info.Show
-import Idris.Package
 import Idris.Main
+import Idris.Package
 
+import Util.System (setupBundledCC)
+
 import Util.System ( setupBundledCC )
+import System.Exit ( ExitCode(..), exitWith)
 
 processShowOptions :: [Opt] -> Idris ()
 processShowOptions opts = runIO $ do
@@ -19,7 +24,8 @@
   when (ShowLoggingCats `elem` opts)  $ showExitIdrisLoggingCategories
   when (ShowIncs `elem` opts)         $ showExitIdrisFlagsInc
   when (ShowLibs `elem` opts)         $ showExitIdrisFlagsLibs
-  when (ShowLibdir `elem` opts)       $ showExitIdrisLibDir
+  when (ShowLibDir `elem` opts)       $ showExitIdrisLibDir
+  when (ShowDocDir `elem` opts)       $ showExitIdrisDocDir
   when (ShowPkgs `elem` opts)         $ showExitIdrisInstalledPackages
 
 check :: [Opt] -> (Opt -> Maybe a) -> ([a] -> Idris ()) -> Idris ()
@@ -31,7 +37,8 @@
 
 processClientOptions :: [Opt] -> Idris ()
 processClientOptions opts = check opts getClient $ \fs -> case fs of
-  (c:_) -> do
+  []      -> ifail "No --client argument. This indicates a bug. Please report."
+  (c : _) -> do
     setVerbose False
     setQuiet True
     case getPort opts of
@@ -48,7 +55,13 @@
   check opts getPkgMkDoc $ \fs -> runIO $ do
     mapM_ (documentPkg opts) fs
   check opts getPkgTest $ \fs -> runIO $ do
-    mapM_ (testPkg opts) fs
+
+    codes <- mapM (testPkg opts) fs
+    -- check if any of the tests exited with an exit code other
+    -- than zero; if they did, exit with exit code 1
+    unless (null $ filter (/= ExitSuccess) codes) $
+       exitWith (ExitFailure 1)
+
   check opts getPkg $ \fs -> runIO $ do
     mapM_ (buildPkg opts (WarnOnly `elem` opts)) fs
   check opts getPkgREPL $ \fs -> case fs of
diff --git a/man/idris.1 b/man/idris.1
--- a/man/idris.1
+++ b/man/idris.1
@@ -1,6 +1,6 @@
 .\" Manpage for Idris.
 .\" Contact <> to correct errors or typos.
-.TH man 1 "25 March 2016" "0.12.3" "Idris man page"
+.TH man 1 "28 November 2016" "0.99" "Idris man page"
 .SH NAME
 idris -\ a general purpose pure functional programming language with dependent types.
 .SH SYNOPSIS
@@ -13,17 +13,29 @@
 evaluation. Its features are influenced by Haskell and ML.
 
 + Full dependent types with dependent pattern matching
+
 + Simple case expressions, where-clauses, with-rule
+
 + Pattern matching let- and lambda-bindings
+
 + Overloading via Interfaces (Type class-like), Monad comprehensions
+
 + do-notation, idiom brackets
+
 + Syntactic conveniences for lists, tuples, dependent pairs
+
 + Totality checking
+
 + Coinductive types
+
 + Indentation significant syntax, Extensible syntax
+
 + Tactic based theorem proving (influenced by Coq)
+
 + Cumulative universes
+
 + Simple Foreign Function Interface
+
 + Hugs style interactive environment
 
 It is important to note that Idris is first and foremost a research tool
diff --git a/mkpkg.sh b/mkpkg.sh
--- a/mkpkg.sh
+++ b/mkpkg.sh
@@ -1,26 +1,64 @@
 #!/bin/sh
 
-VERSION=$1
+set -euo pipefail
 
-echo "Building version-$VERSION\n\n"
-echo "Have you: set the release flag, checked the demos and the tutorial?"
-read $foo
+if [ "$#" -lt 1 ]; then
+    echo "Usage $0 [version number] ?[idris bin location]"
+    echo ""
+    echo "The first argument is the version number"
+    echo ""
+    echo "The second argument is optional, and used to point to a"
+    echo "custom location in which idris was recently built i.e."
+    echo "withing .stack-work or .cabal-sandbox. The location must"
+    echo "be given relative to the project root of a package in the "
+    echo "libs/ directory."
+    exit 1
+fi
 
+VERSION=${1:-}
+
+echo "==> Building version-$VERSION"
+echo ""
+echo "Q: Have you: (a) set the release flag & (b) checked the demos and the tutorial?"
+read ${FOO:-}
+
 git tag v$VERSION -a
 
+echo "==> Building Source Distribution"
 cabal sdist
 
 # Generate Idris library docs and put them in lib_docs.tar.gz in the root
-make lib_doc
+echo "==> Generating API Documentation."
+echo "==> Determining version of Idris to use."
+if [ -z ${2+x} ];
+then
+    echo "==> Using default location.";
+    make lib_doc
+else
+    echo "==> Using custom location.";
+    make -C libs IDRIS=$2 doc
+fi
+
 DOCDIR=`mktemp -d /tmp/docsXXXXX`
+
 cp -r libs/base/base_doc "$DOCDIR"
 cp -r libs/prelude/prelude_doc "$DOCDIR"
 cp -r libs/effects/effects_doc "$DOCDIR"
 cp -r libs/contrib/contrib_doc "$DOCDIR"
+
 tar -czvf lib_docs.tar.gz -C "$DOCDIR" prelude_doc base_doc effects_doc contrib_doc
 
+echo "==> Building Binaries"
 cabal configure --prefix=/usr/local
+
 cabal build
+
+echo "==> Creating Package"
+mkdir -p /tmp/idris-pkg/
+
 cabal copy --destdir=/tmp/idris-pkg/
-pkgbuild --id org.idris-lang --root /tmp/idris-pkg/ idris-$VERSION.pkg 
 
+pkgbuild --identifier org.idris-lang \
+         --version "v$VERSION"       \
+         --root /tmp/idris-pkg/      \
+         idris-$VERSION.pkg
diff --git a/rts/idris_rts.c b/rts/idris_rts.c
--- a/rts/idris_rts.c
+++ b/rts/idris_rts.c
@@ -748,11 +748,22 @@
 
     callvm->processes++;
 
-    pthread_create(&t, &attr, runThread, td);
+    int ok = pthread_create(&t, &attr, runThread, td);
 //    usleep(100);
-    return vm;
+    if (ok == 0) {
+        return vm;
+    } else {
+        terminate(vm);
+        return NULL;
+    }
 }
 
+void* idris_stopThread(VM* vm) {
+    close_vm(vm);
+    pthread_exit(NULL);
+    return NULL;
+}
+
 // VM is assumed to be a different vm from the one x lives on
 
 VAL doCopyTo(VM* vm, VAL x) {
@@ -1069,6 +1080,11 @@
 
 const char* idris_getArg(int i) {
     return __idris_argv[i];
+}
+
+void idris_disableBuffering() {
+  setvbuf(stdin, NULL, _IONBF, 0);
+  setvbuf(stdout, NULL, _IONBF, 0);
 }
 
 void stackOverflow() {
diff --git a/rts/idris_rts.h b/rts/idris_rts.h
--- a/rts/idris_rts.h
+++ b/rts/idris_rts.h
@@ -309,6 +309,7 @@
 void init_signals();
 
 void* vmThread(VM* callvm, func f, VAL arg);
+void* idris_stopThread(VM* vm);
 
 // Copy a structure to another vm's heap
 VAL copyTo(VM* newVM, VAL x);
@@ -392,6 +393,9 @@
 
 int idris_numArgs();
 const char *idris_getArg(int i);
+
+// disable stdin/stdout buffering
+void idris_disableBuffering();
 
 // Handle stack overflow.
 // Just reports an error and exits.
diff --git a/samples/effects/TreeTag.idr b/samples/effects/TreeTag.idr
--- a/samples/effects/TreeTag.idr
+++ b/samples/effects/TreeTag.idr
@@ -20,13 +20,13 @@
                       (Node Leaf "Bob" Leaf))
 
 treeTagAux : BTree a -> { [STATE Int] } Eff (BTree (Int, a))
-treeTagAux Leaf = return Leaf
+treeTagAux Leaf = pure Leaf
 treeTagAux (Node l x r)
     = do l' <- treeTagAux l
          i <- get
          put (i + 1)
          r' <- treeTagAux r
-         return (Node l' (i, x) r')
+         pure (Node l' (i, x) r')
 
 treeTag : (i : Int) -> BTree a -> BTree (Int, a)
 treeTag i x = runPure (do put i
diff --git a/samples/tutorial/classes.idr b/samples/tutorial/classes.idr
--- a/samples/tutorial/classes.idr
+++ b/samples/tutorial/classes.idr
@@ -1,7 +1,7 @@
 m_add : Maybe Int -> Maybe Int -> Maybe Int
 m_add x y = do x' <- x -- Extract value from x
                y' <- y -- Extract value from y
-               return (x' + y') -- Add them
+               pure (x' + y') -- Add them
 
 m_add' : Maybe Int -> Maybe Int -> Maybe Int
 m_add' x y = [ x' + y' | x' <- x, y' <- y ]
diff --git a/src/IRTS/BCImp.hs b/src/IRTS/BCImp.hs
--- a/src/IRTS/BCImp.hs
+++ b/src/IRTS/BCImp.hs
@@ -7,9 +7,9 @@
 -}
 module IRTS.BCImp where
 
+import Idris.Core.TT
 import IRTS.Lang
 import IRTS.Simplified
-import Idris.Core.TT
 
 data Reg = RVal | L Int
 
diff --git a/src/IRTS/Bytecode.hs b/src/IRTS/Bytecode.hs
--- a/src/IRTS/Bytecode.hs
+++ b/src/IRTS/Bytecode.hs
@@ -21,10 +21,11 @@
 module IRTS.Bytecode where
 
 
+import Idris.Core.TT
+import IRTS.Defunctionalise
 import IRTS.Lang
 import IRTS.Simplified
-import IRTS.Defunctionalise
-import Idris.Core.TT
+
 import Data.Maybe
 
 data Reg = RVal | L Int | T Int | Tmp
diff --git a/src/IRTS/CodegenC.hs b/src/IRTS/CodegenC.hs
--- a/src/IRTS/CodegenC.hs
+++ b/src/IRTS/CodegenC.hs
@@ -8,27 +8,27 @@
 module IRTS.CodegenC (codegenC) where
 
 import Idris.AbsSyntax
+import Idris.Core.TT
 import IRTS.Bytecode
+import IRTS.CodegenCommon
+import IRTS.Defunctionalise
 import IRTS.Lang
 import IRTS.Simplified
-import IRTS.Defunctionalise
 import IRTS.System
-import IRTS.CodegenCommon
-import Idris.Core.TT
+
 import Util.System
 
-import Numeric
-import Data.Char
+import Control.Monad
 import Data.Bits
+import Data.Char
 import Data.List (intercalate, nubBy)
-import System.Process
+import Debug.Trace
+import Numeric
+import System.Directory
 import System.Exit
+import System.FilePath ((<.>), (</>))
 import System.IO
-import System.Directory
-import System.FilePath ((</>), (<.>))
-import Control.Monad
-
-import Debug.Trace
+import System.Process
 
 codegenC :: CodeGenerator
 codegenC ci = do codegenC' (simpleDecls ci)
@@ -66,8 +66,8 @@
          let h = concatMap toDecl (map fst bc)
          let cc = concatMap (uncurry toC) bc
          let hi = concatMap ifaceC (concatMap getExp exports)
-         d <- getDataDir
-         mprog <- readFile (d </> "rts" </> "idris_main" <.> "c")
+         d <- getIdrisCRTSDir
+         mprog <- readFile (d </> "idris_main" <.> "c")
          let cout = headers incs ++ debug dbg ++ h ++ wrappers ++ cc ++
                      (if (exec == Executable) then mprog else hi)
          case exec of
diff --git a/src/IRTS/CodegenCommon.hs b/src/IRTS/CodegenCommon.hs
--- a/src/IRTS/CodegenCommon.hs
+++ b/src/IRTS/CodegenCommon.hs
@@ -8,11 +8,11 @@
 -}
 module IRTS.CodegenCommon where
 
-import GHC.Generics (Generic)
-
 import Idris.Core.TT
-import IRTS.Simplified
 import IRTS.Defunctionalise
+import IRTS.Simplified
+
+import GHC.Generics (Generic)
 
 data DbgLevel = NONE | DEBUG | TRACE deriving Eq
 data OutputType = Raw | Object | Executable deriving (Eq, Show, Generic)
diff --git a/src/IRTS/CodegenJavaScript.hs b/src/IRTS/CodegenJavaScript.hs
--- a/src/IRTS/CodegenJavaScript.hs
+++ b/src/IRTS/CodegenJavaScript.hs
@@ -5,44 +5,41 @@
 License     : BSD3
 Maintainer  : The Idris Community.
 -}
-{-# LANGUAGE PatternGuards #-}
-{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE OverloadedStrings, PatternGuards #-}
 module IRTS.CodegenJavaScript (codegenJavaScript
                              , codegenNode
                              , JSTarget(..)
                              ) where
 
-import IRTS.JavaScript.AST
-
 import Idris.AbsSyntax hiding (TypeCase)
+import Idris.Core.TT
 import IRTS.Bytecode
-import IRTS.Lang
+import IRTS.CodegenCommon
+import IRTS.Defunctionalise
 import IRTS.Exports
+import IRTS.JavaScript.AST
+import IRTS.Lang
 import IRTS.Simplified
-import IRTS.Defunctionalise
-import IRTS.CodegenCommon
-import Idris.Core.TT
 import IRTS.System
 import Util.System
 
+import Control.Applicative (pure, (<$>), (<*>))
 import Control.Arrow
 import Control.Monad (mapM)
-import Control.Applicative ((<$>), (<*>), pure)
 import Control.Monad.RWS hiding (mapM)
 import Control.Monad.State
 import Data.Char
-import Numeric
 import Data.List
+import qualified Data.Map.Strict as M
 import Data.Maybe
-import Data.Word
+import qualified Data.Text as T
+import qualified Data.Text.IO as TIO
 import Data.Traversable hiding (mapM)
-import System.IO
+import Data.Word
+import Numeric
 import System.Directory
 import System.FilePath
-
-import qualified Data.Map.Strict as M
-import qualified Data.Text as T
-import qualified Data.Text.IO as TIO
+import System.IO
 
 
 data CompileInfo = CompileInfo { compileInfoApplyCases  :: [Int]
@@ -121,27 +118,27 @@
   -> OutputType
   -> IO ()
 codegenJS_all target definitions includes libs filename exports outputType = do
-  let bytecode = map toBC definitions
-  let info = initCompileInfo bytecode
-  let js = concatMap (translateDecl info) bytecode
-  let full = concatMap processFunction js
+  let bytecode      = map toBC definitions
+  let info          = initCompileInfo bytecode
+  let js            = concatMap (translateDecl info) bytecode
+  let full          = concatMap processFunction js
   let exportedNames = map translateName ((getExpNames exports) ++ [sUN "call__IO"])
-  let code = deadCodeElim exportedNames full
-  let ext = takeExtension filename
-  let isHtml = target == JavaScript && ext == ".html"
-  let htmlPrologue = T.pack "<!doctype html><html><head><script>\n"
-  let htmlEpilogue = T.pack "\n</script></head><body></body></html>"
-  let (cons, opt) = optimizeConstructors code
-  let (header, rt) = case target of
-                          Node -> ("#!/usr/bin/env node\n", "-node")
+  let code          = deadCodeElim exportedNames full
+  let ext           = takeExtension filename
+  let isHtml        = target == JavaScript && ext == ".html"
+  let htmlPrologue  = T.pack "<!doctype html><html><head><script>\n"
+  let htmlEpilogue  = T.pack "\n</script></head><body></body></html>"
+  let (cons, opt)   = optimizeConstructors code
+  let (header, rt)   = case target of
+                          Node       -> ("#!/usr/bin/env node\n", "-node")
                           JavaScript -> ("", "-browser")
 
   included   <- concat <$> getIncludes includes
-  path       <- (++) <$> getDataDir <*> (pure "/jsrts/")
-  idrRuntime <- readFile $ path ++ "Runtime-common.js"
-  tgtRuntime <- readFile $ concat [path, "Runtime", rt, ".js"]
+  path       <- getIdrisJSRTSDir
+  idrRuntime <- readFile $ path </> "Runtime-common.js"
+  tgtRuntime <- readFile $ path </> concat ["Runtime", rt, ".js"]
   jsbn       <- if compileInfoNeedsBigInt info
-                   then readFile $ path ++ "jsbn/jsbn.js"
+                   then readFile $ path </> "jsbn/jsbn.js"
                    else return ""
   let runtime = (  header
                 ++ includeLibs libs
diff --git a/src/IRTS/Compiler.hs b/src/IRTS/Compiler.hs
--- a/src/IRTS/Compiler.hs
+++ b/src/IRTS/Compiler.hs
@@ -5,55 +5,50 @@
 License     : BSD3
 Maintainer  : The Idris Community.
 -}
-{-# LANGUAGE PatternGuards, TypeSynonymInstances, CPP #-}
+{-# LANGUAGE CPP, PatternGuards, TypeSynonymInstances #-}
 
 module IRTS.Compiler(compile, generate) where
 
-import IRTS.Lang
-import IRTS.LangOpts
-import IRTS.Defunctionalise
-import IRTS.Simplified
-import IRTS.CodegenCommon
-import IRTS.CodegenC
-import IRTS.DumpBC
-import IRTS.CodegenJavaScript
-import IRTS.Inliner
-import IRTS.Exports
-import IRTS.Portable
-
 import Idris.AbsSyntax
 import Idris.AbsSyntaxTree
 import Idris.ASTUtils
+import Idris.Core.CaseTree
+import Idris.Core.Evaluate
+import Idris.Core.TT
 import Idris.Erasure
 import Idris.Error
 import Idris.Output
-
-import Debug.Trace
-
-import Idris.Core.TT
-import Idris.Core.Evaluate
-import Idris.Core.CaseTree
+import IRTS.CodegenC
+import IRTS.CodegenCommon
+import IRTS.CodegenJavaScript
+import IRTS.Defunctionalise
+import IRTS.DumpBC
+import IRTS.Exports
+import IRTS.Inliner
+import IRTS.Lang
+import IRTS.LangOpts
+import IRTS.Portable
+import IRTS.Simplified
 
-import Control.Category
 import Prelude hiding (id, (.))
 
 import Control.Applicative
+import Control.Category
 import Control.Monad.State
-
-import           Data.Maybe
-import           Data.List
-import           Data.Ord
-import           Data.IntSet (IntSet)
-import qualified Data.IntSet          as IS
-import qualified Data.Map             as M
-import qualified Data.Set             as S
-
-import System.Process
-import System.IO
-import System.Exit
+import Data.IntSet (IntSet)
+import qualified Data.IntSet as IS
+import Data.List
+import qualified Data.Map as M
+import Data.Maybe
+import Data.Ord
+import qualified Data.Set as S
+import Debug.Trace
 import System.Directory
 import System.Environment
-import System.FilePath ((</>), addTrailingPathSeparator)
+import System.Exit
+import System.FilePath (addTrailingPathSeparator, (</>))
+import System.IO
+import System.Process
 
 -- |  Compile to simplified forms and return CodegenInfo
 compile :: Codegen -> FilePath -> Maybe Term -> Idris CodegenInfo
diff --git a/src/IRTS/Defunctionalise.hs b/src/IRTS/Defunctionalise.hs
--- a/src/IRTS/Defunctionalise.hs
+++ b/src/IRTS/Defunctionalise.hs
@@ -24,15 +24,15 @@
                           , module IRTS.Lang
                           ) where
 
-import IRTS.Lang
-import Idris.Core.TT
 import Idris.Core.CaseTree
+import Idris.Core.TT
+import IRTS.Lang
 
-import Debug.Trace
-import Data.Maybe
-import Data.List
 import Control.Monad
 import Control.Monad.State
+import Data.List
+import Data.Maybe
+import Debug.Trace
 
 data DExp = DV LVar
           | DApp Bool Name [DExp] -- True = tail call
diff --git a/src/IRTS/DumpBC.hs b/src/IRTS/DumpBC.hs
--- a/src/IRTS/DumpBC.hs
+++ b/src/IRTS/DumpBC.hs
@@ -7,11 +7,11 @@
 -}
 module IRTS.DumpBC where
 
+import Idris.Core.TT
+import IRTS.Bytecode
 import IRTS.Lang
 import IRTS.Simplified
-import Idris.Core.TT
 
-import IRTS.Bytecode
 import Data.List
 
 interMap :: [a] -> [b] -> (a -> [b]) -> [b]
diff --git a/src/IRTS/Exports.hs b/src/IRTS/Exports.hs
--- a/src/IRTS/Exports.hs
+++ b/src/IRTS/Exports.hs
@@ -9,9 +9,9 @@
 module IRTS.Exports(findExports, getExpNames) where
 
 import Idris.AbsSyntax
-import Idris.Core.TT
 import Idris.Core.CaseTree
 import Idris.Core.Evaluate
+import Idris.Core.TT
 import Idris.Error
 import IRTS.Lang
 
diff --git a/src/IRTS/Inliner.hs b/src/IRTS/Inliner.hs
--- a/src/IRTS/Inliner.hs
+++ b/src/IRTS/Inliner.hs
@@ -8,7 +8,6 @@
 module IRTS.Inliner where
 
 import Idris.Core.TT
-
 import IRTS.Defunctionalise
 
 inline :: DDefs -> DDefs
diff --git a/src/IRTS/JavaScript/AST.hs b/src/IRTS/JavaScript/AST.hs
--- a/src/IRTS/JavaScript/AST.hs
+++ b/src/IRTS/JavaScript/AST.hs
@@ -5,14 +5,12 @@
 License     : BSD3
 Maintainer  : The Idris Community.
 -}
-{-# LANGUAGE PatternGuards #-}
-{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE OverloadedStrings, PatternGuards #-}
 module IRTS.JavaScript.AST where
 
-import Data.Word
 import Data.Char (isDigit)
-
 import qualified Data.Text as T
+import Data.Word
 
 data JSType = JSIntTy
             | JSStringTy
diff --git a/src/IRTS/Lang.hs b/src/IRTS/Lang.hs
--- a/src/IRTS/Lang.hs
+++ b/src/IRTS/Lang.hs
@@ -5,16 +5,15 @@
 License     : BSD3
 Maintainer  : The Idris Community.
 -}
-{-# LANGUAGE PatternGuards, DeriveFunctor, DeriveGeneric #-}
+{-# LANGUAGE DeriveFunctor, DeriveGeneric, PatternGuards #-}
 
 module IRTS.Lang where
 
-import Control.Monad.State hiding (lift)
-import Control.Applicative hiding (Const)
-
-import Idris.Core.TT
 import Idris.Core.CaseTree
+import Idris.Core.TT
 
+import Control.Applicative hiding (Const)
+import Control.Monad.State hiding (lift)
 import Data.List
 import Debug.Trace
 import GHC.Generics (Generic)
@@ -319,7 +318,7 @@
                                        LCon lv t cn args'
 lsubst n new (LOp op args) = let args' = map (lsubst n new) args in
                                  LOp op args'
-lsubst n new (LForeign fd rd args) 
+lsubst n new (LForeign fd rd args)
      = let args' = map (\(d, a) -> (d, lsubst n new a)) args in
            LForeign fd rd args'
 lsubst n new (LCase t e alts) = let e' = lsubst n new e
diff --git a/src/IRTS/LangOpts.hs b/src/IRTS/LangOpts.hs
--- a/src/IRTS/LangOpts.hs
+++ b/src/IRTS/LangOpts.hs
@@ -5,16 +5,16 @@
 License     : BSD3
 Maintainer  : The Idris Community.
 -}
-{-# LANGUAGE PatternGuards, DeriveFunctor #-}
+{-# LANGUAGE DeriveFunctor, PatternGuards #-}
 
 module IRTS.LangOpts where
 
-import Control.Monad.State hiding (lift)
-import Control.Applicative hiding (Const)
-
-import IRTS.Lang
-import Idris.Core.TT
 import Idris.Core.CaseTree
+import Idris.Core.TT
+import IRTS.Lang
+
+import Control.Applicative hiding (Const)
+import Control.Monad.State hiding (lift)
 import Data.List
 import Debug.Trace
 
diff --git a/src/IRTS/Portable.hs b/src/IRTS/Portable.hs
--- a/src/IRTS/Portable.hs
+++ b/src/IRTS/Portable.hs
@@ -8,19 +8,17 @@
 {-# LANGUAGE OverloadedStrings #-}
 module IRTS.Portable (writePortable) where
 
-import Data.Aeson
-import qualified Data.ByteString.Lazy as B
-import qualified Data.Text as T
-
 import Idris.Core.CaseTree
 import Idris.Core.TT
-
 import IRTS.Bytecode
 import IRTS.CodegenCommon
 import IRTS.Defunctionalise
 import IRTS.Lang
 import IRTS.Simplified
 
+import Data.Aeson
+import qualified Data.ByteString.Lazy as B
+import qualified Data.Text as T
 import System.IO
 
 data CodegenFile = CGFile {
diff --git a/src/IRTS/Simplified.hs b/src/IRTS/Simplified.hs
--- a/src/IRTS/Simplified.hs
+++ b/src/IRTS/Simplified.hs
@@ -7,13 +7,13 @@
 -}
 module IRTS.Simplified(simplifyDefs, SDecl(..), SExp(..), SAlt(..)) where
 
-import IRTS.Defunctionalise
-import Idris.Core.TT
 import Idris.Core.CaseTree
+import Idris.Core.TT
 import Idris.Core.Typecheck
-import Data.Maybe
-import Control.Monad.State
+import IRTS.Defunctionalise
 
+import Control.Monad.State
+import Data.Maybe
 import Debug.Trace
 
 data SExp = SV LVar
diff --git a/src/IRTS/System.hs b/src/IRTS/System.hs
--- a/src/IRTS/System.hs
+++ b/src/IRTS/System.hs
@@ -7,47 +7,58 @@
 -}
 {-# LANGUAGE CPP #-}
 module IRTS.System( getDataFileName
-                  , getDataDir
-                  , getTargetDir
                   , getCC
                   , getLibFlags
+                  , getIdrisDataDir
                   , getIdrisLibDir
+                  , getIdrisDocDir
+                  , getIdrisCRTSDir
+                  , getIdrisJSRTSDir
                   , getIncFlags
                   , getEnvFlags
                   , version
                   ) where
 
-import Data.List.Split
-
-import Control.Applicative ((<$>))
-import Data.Maybe (fromMaybe)
-import System.FilePath ((</>), addTrailingPathSeparator)
-import System.Environment
-
 #ifdef FREESTANDING
-import Target_idris
 import Paths_idris (version)
+import Target_idris
 #else
 import Paths_idris
 #endif
 
-overrideDataDirWith :: String -> IO FilePath
-overrideDataDirWith envVar = do
-  envValue <- lookupEnv envVar
+import Control.Applicative ((<$>))
+import Data.List.Split
+import Data.Maybe (fromMaybe)
+import System.Environment
+import System.FilePath (addTrailingPathSeparator, (</>))
+
+
+getIdrisDataDir :: IO String
+getIdrisDataDir = do
+  envValue <- lookupEnv "TARGET"
   case envValue of
     Nothing -> do
       ddir <- getDataDir
-      return (ddir </> "libs")
+      return ddir
     Just ddir -> return ddir
 
+overrideIdrisSubDirWith :: String  -- ^ Sub directory in `getDataDir` location.
+                        -> String  -- ^ Environment variable to get new location from.
+                        -> IO FilePath
+overrideIdrisSubDirWith fp envVar = do
+  envValue <- lookupEnv envVar
+  case envValue of
+    Nothing -> do
+      ddir <- getIdrisDataDir
+      return (ddir </> fp)
+    Just ddir -> return ddir
+
 getCC :: IO String
 getCC = fromMaybe "gcc" <$> lookupEnv "IDRIS_CC"
 
 getEnvFlags :: IO [String]
 getEnvFlags = maybe [] (splitOn " ") <$> lookupEnv "IDRIS_CFLAGS"
 
-getTargetDir :: IO String
-getTargetDir = overrideDataDirWith "TARGET"
 
 #if defined(freebsd_HOST_OS) || defined(dragonfly_HOST_OS)\
     || defined(openbsd_HOST_OS) || defined(netbsd_HOST_OS)
@@ -64,11 +75,21 @@
 gmpLib = []
 #endif
 
-getLibFlags = do dir <- getDataDir
-                 return $ ["-L" ++ (dir </> "rts"),
+getLibFlags = do dir <- getIdrisCRTSDir
+                 return $ ["-L" ++ dir,
                            "-lidris_rts"] ++ extraLib ++ gmpLib ++ ["-lpthread"]
 
-getIdrisLibDir = addTrailingPathSeparator <$> overrideDataDirWith "IDRIS_LIBRARY_PATH"
+getIdrisLibDir = addTrailingPathSeparator <$> overrideIdrisSubDirWith "libs" "IDRIS_LIBRARY_PATH"
 
-getIncFlags = do dir <- getDataDir
-                 return $ ("-I" ++ dir </> "rts") : extraInclude
+getIdrisDocDir = addTrailingPathSeparator <$> overrideIdrisSubDirWith "docs" "IDRIS_DOC_PATH"
+
+getIdrisJSRTSDir = do
+  ddir <- getIdrisDataDir
+  return $ addTrailingPathSeparator (ddir </> "jsrts")
+
+getIdrisCRTSDir = do
+  ddir <- getIdrisDataDir
+  return $ addTrailingPathSeparator (ddir </> "rts")
+
+getIncFlags = do dir <- getIdrisCRTSDir
+                 return $ ("-I" ++ dir) : extraInclude
diff --git a/src/Idris/ASTUtils.hs b/src/Idris/ASTUtils.hs
--- a/src/Idris/ASTUtils.hs
+++ b/src/Idris/ASTUtils.hs
@@ -41,19 +41,20 @@
     Field(), cg_usedpos, ctxt_lookup, fgetState, fmodifyState
   , fputState, idris_fixities, ist_callgraph, ist_optimisation
   , known_interfaces, known_terms, opt_detaggable, opt_inaccessible
-  , opts_idrisCmdline, repl_definitions
+  , opt_forceable, opts_idrisCmdline, repl_definitions
   ) where
 
-import Control.Category
+import Idris.AbsSyntaxTree
+import Idris.Core.Evaluate
+import Idris.Core.TT
+
+import Prelude hiding (id, (.))
+
 import Control.Applicative
+import Control.Category
 import Control.Monad.State.Class
 import Data.Maybe
-import Prelude hiding (id, (.))
 
-import Idris.Core.TT
-import Idris.Core.Evaluate
-import Idris.AbsSyntaxTree
-
 data Field rec fld = Field
     { fget :: rec -> fld
     , fset :: fld -> rec -> rec
@@ -110,6 +111,7 @@
       maybe_default Optimise
         { inaccessible = []
         , detaggable = False
+        , forceable = []
         }
     . ctxt_lookup n
     . Field idris_optimisation (\v ist -> ist{ idris_optimisation = v })
@@ -121,12 +123,14 @@
 opt_detaggable :: Field OptInfo Bool
 opt_detaggable = Field detaggable (\v opt -> opt{ detaggable = v })
 
+opt_forceable :: Field OptInfo [Int]
+opt_forceable = Field forceable (\v opt -> opt{ forceable = v })
 
 -- | callgraph record for the given (exact) name
 ist_callgraph :: Name -> Field IState CGInfo
 ist_callgraph n =
       maybe_default CGInfo
-        { calls = [], scg = [], usedpos = []
+        { calls = [], allCalls = Nothing, scg = [], usedpos = []
         }
     . ctxt_lookup n
     . Field idris_callgraph (\v ist -> ist{ idris_callgraph = v })
diff --git a/src/Idris/AbsSyntax.hs b/src/Idris/AbsSyntax.hs
--- a/src/Idris/AbsSyntax.hs
+++ b/src/Idris/AbsSyntax.hs
@@ -5,53 +5,47 @@
 License     : BSD3
 Maintainer  : The Idris Community.
 -}
-{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, DeriveFunctor,
-             TypeSynonymInstances, PatternGuards #-}
+{-# LANGUAGE DeriveFunctor, FlexibleInstances, MultiParamTypeClasses,
+             PatternGuards, TypeSynonymInstances #-}
 
 module Idris.AbsSyntax(
     module Idris.AbsSyntax
   , module Idris.AbsSyntaxTree
   ) where
 
-import Idris.Core.TT
-import Idris.Core.Evaluate
-import Idris.Core.Elaborate hiding (Tactic(..))
-import Idris.Core.Typecheck
 import Idris.AbsSyntaxTree
 import Idris.Colours
+import Idris.Core.Elaborate hiding (Tactic(..))
+import Idris.Core.Evaluate
+import Idris.Core.TT
+import Idris.Core.Typecheck
 import Idris.Docstrings
 import Idris.IdeMode hiding (Opt(..))
 import IRTS.CodegenCommon
-import Util.DynamicLinker
 
-import System.Console.Haskeline
-import System.IO
-import System.Directory (canonicalizePath, doesFileExist)
+import Util.DynamicLinker
+import Util.Pretty
+import Util.ScreenSize
+import Util.System
 
 import Control.Applicative
 import Control.Monad (liftM3)
 import Control.Monad.State
-
-import Data.List hiding (insert,union)
 import Data.Char
-import qualified Data.Text as T
 import Data.Either
+import Data.Generics.Uniplate.Data (descend, descendM)
+import Data.List hiding (insert, union)
 import qualified Data.Map as M
 import Data.Maybe
 import qualified Data.Set as S
+import qualified Data.Text as T
 import Data.Word (Word)
-
-import Data.Generics.Uniplate.Data (descend, descendM)
-
 import Debug.Trace
-
-import System.IO.Error(isUserError, ioeGetErrorString, tryIOError)
-
 import Network (PortID(PortNumber))
-
-import Util.Pretty
-import Util.ScreenSize
-import Util.System
+import System.Console.Haskeline
+import System.Directory (canonicalizePath, doesFileExist)
+import System.IO
+import System.IO.Error (ioeGetErrorString, isUserError, tryIOError)
 
 getContext :: Idris Context
 getContext = do i <- getIState; return (tt_ctxt i)
@@ -214,6 +208,13 @@
 setFlags :: Name -> [FnOpt] -> Idris ()
 setFlags n fs = do i <- getIState; putIState $ i { idris_flags = addDef n fs (idris_flags i) }
 
+addFnOpt :: Name -> FnOpt -> Idris ()
+addFnOpt n f = do i <- getIState
+                  let fls = case lookupCtxtExact n (idris_flags i) of
+                                 Nothing -> []
+                                 Just x -> x
+                  setFlags n (f : fls)
+
 setFnInfo :: Name -> FnInfo -> Idris ()
 setFnInfo n fs = do i <- getIState; putIState $ i { idris_fninfo = addDef n fs (idris_fninfo i) }
 
@@ -270,9 +271,9 @@
 addCalls n calls
    = do i <- getIState
         case lookupCtxtExact n (idris_callgraph i) of
-             Nothing -> addToCG n (CGInfo calls [] [])
-             Just (CGInfo cs scg used) ->
-                addToCG n (CGInfo (nub (calls ++ cs)) scg used)
+             Nothing -> addToCG n (CGInfo calls Nothing [] [])
+             Just (CGInfo cs ans scg used) ->
+                addToCG n (CGInfo (nub (calls ++ cs)) ans scg used)
 
 addTyInferred :: Name -> Idris ()
 addTyInferred n
@@ -364,15 +365,36 @@
 
 -- | Trace all the names in a call graph starting at the given name
 getAllNames :: Name -> Idris [Name]
-getAllNames n = allNames [] n
+getAllNames n = do i <- getIState
+                   case getCGAllNames i n of
+                        Just ns -> return ns
+                        Nothing -> do ns <- allNames [] n
+                                      addCGAllNames i n ns
+                                      return ns
 
+getCGAllNames :: IState -> Name -> Maybe [Name]
+getCGAllNames i n = case lookupCtxtExact n (idris_callgraph i) of
+                         Just ci -> allCalls ci
+                         _ -> Nothing
+
+addCGAllNames :: IState -> Name -> [Name] -> Idris ()
+addCGAllNames i n ns
+      = case lookupCtxtExact n (idris_callgraph i) of
+             Just ci -> addToCG n (ci { allCalls = Just ns })
+             _ -> addToCG n (CGInfo [] (Just ns) [] [])
+
 allNames :: [Name] -> Name -> Idris [Name]
 allNames ns n | n `elem` ns = return []
 allNames ns n = do i <- getIState
-                   case lookupCtxtExact n (idris_callgraph i) of
-                      Just ns' -> do more <- mapM (allNames (n:ns)) (calls ns')
-                                     return (nub (n : concat more))
-                      _ -> return [n]
+                   case getCGAllNames i n of
+                        Just ns -> return ns
+                        Nothing -> case lookupCtxtExact n (idris_callgraph i) of
+                                        Just ci -> 
+                                          do more <- mapM (allNames (n:ns)) (calls ci)
+                                             let ns' = nub (n : concat more)
+                                             addCGAllNames i n ns'
+                                             return ns'
+                                        _ -> return [n]
 
 addCoercion :: Name -> Idris ()
 addCoercion n = do i <- getIState
@@ -450,10 +472,10 @@
 addImplementation int res n i
     = do ist <- getIState
          case lookupCtxt n (idris_interfaces ist) of
-                [CI a b c d e ins fds] ->
-                     do let cs = addDef n (CI a b c d e (addI i ins) fds) (idris_interfaces ist)
+                [CI a b c d e f g ins fds] ->
+                     do let cs = addDef n (CI a b c d e f g (addI i ins) fds) (idris_interfaces ist)
                         putIState $ ist { idris_interfaces = cs }
-                _ -> do let cs = addDef n (CI (sMN 0 "none") [] [] [] [] [(i, res)] []) (idris_interfaces ist)
+                _ -> do let cs = addDef n (CI (sMN 0 "none") [] [] [] [] [] [] [(i, res)] []) (idris_interfaces ist)
                         putIState $ ist { idris_interfaces = cs }
   where addI, insI :: Name -> [(Name, Bool)] -> [(Name, Bool)]
         addI i ins | int = (i, res) : ins
@@ -668,9 +690,9 @@
    where pErase (CaseOp c t tys orig tot cds)
             = CaseOp c t tys orig [] (pErase' cds)
          pErase x = x
-         pErase' (CaseDefs _ (cs, c) _ rs)
+         pErase' (CaseDefs (cs, c) rs)
              = let c' = (cs, fmap pEraseType c) in
-                   CaseDefs c' c' c' rs
+                   CaseDefs c' rs
 
 checkUndefined :: FC -> Name -> Idris ()
 checkUndefined fc n
@@ -2545,7 +2567,7 @@
 getPkgDir _ = Nothing
 
 getPkg :: Opt -> Maybe (Bool, String)
-getPkg (PkgBuild str) = Just (False, str)
+getPkg (PkgBuild   str) = Just (False, str)
 getPkg (PkgInstall str) = Just (True, str)
 getPkg _ = Nothing
 
@@ -2563,9 +2585,10 @@
 
 -- | Returns None if given an Opt which is not PkgMkDoc
 --   Otherwise returns Just x, where x is the contents of PkgMkDoc
-getPkgMkDoc :: Opt          -- ^ Opt to extract
-            -> Maybe String -- ^ Result
-getPkgMkDoc (PkgMkDoc str) = Just str
+getPkgMkDoc :: Opt                  -- ^ Opt to extract
+            -> Maybe (Bool, String) -- ^ Result
+getPkgMkDoc (PkgDocBuild  str)  = Just (False,str)
+getPkgMkDoc (PkgDocInstall str) = Just (True,str)
 getPkgMkDoc _              = Nothing
 
 getPkgTest :: Opt          -- ^ the option to extract
diff --git a/src/Idris/AbsSyntaxTree.hs b/src/Idris/AbsSyntaxTree.hs
--- a/src/Idris/AbsSyntaxTree.hs
+++ b/src/Idris/AbsSyntaxTree.hs
@@ -5,54 +5,48 @@
 License     : BSD3
 Maintainer  : The Idris Community.
 -}
-{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, DeriveFunctor,
-             DeriveDataTypeable, DeriveGeneric, TypeSynonymInstances,
-             PatternGuards #-}
+{-# LANGUAGE DeriveDataTypeable, DeriveFunctor, DeriveGeneric,
+             FlexibleInstances, MultiParamTypeClasses, PatternGuards,
+             TypeSynonymInstances #-}
 
 module Idris.AbsSyntaxTree where
 
-import Idris.Core.TT
-import Idris.Core.Evaluate
+import Idris.Colours
 import Idris.Core.Elaborate hiding (Tactic(..))
+import Idris.Core.Evaluate
+import Idris.Core.TT
 import Idris.Core.Typecheck
 import Idris.Docstrings
-import IRTS.Lang
 import IRTS.CodegenCommon
-import Util.Pretty
+import IRTS.Lang
 import Util.DynamicLinker
-
-import Idris.Colours
-
-import System.Console.Haskeline
-import System.IO
+import Util.Pretty
 
 import Prelude hiding ((<$>))
 
 import Control.Applicative ((<|>))
-
-import Control.Monad.Trans.State.Strict
-import Control.Monad.Trans.Except
 import qualified Control.Monad.Trans.Class as Trans (lift)
-
+import Control.Monad.Trans.Except
+import Control.Monad.Trans.State.Strict
+import Data.Char
 import Data.Data (Data)
+import Data.Either
+import Data.Foldable (Foldable)
 import Data.Function (on)
-import Data.Generics.Uniplate.Data (universe, children)
+import Data.Generics.Uniplate.Data (children, universe)
 import Data.List hiding (group)
-import Data.Char
 import qualified Data.Map.Strict as M
-import qualified Data.Text as T
-import Data.Either
-import qualified Data.Set as S
-import Data.Word (Word)
 import Data.Maybe (fromMaybe, mapMaybe, maybeToList)
+import qualified Data.Set as S
+import qualified Data.Text as T
 import Data.Traversable (Traversable)
 import Data.Typeable
-import Data.Foldable (Foldable)
-import GHC.Generics (Generic)
-import Network.Socket(PortNumber)
-
+import Data.Word (Word)
 import Debug.Trace
-
+import GHC.Generics (Generic)
+import Network.Socket (PortNumber)
+import System.Console.Haskeline
+import System.IO
 import Text.PrettyPrint.Annotated.Leijen
 
 data ElabWhat = ETypes | EDefns | EAll
@@ -327,9 +321,10 @@
 type UsageReason = (Name, Int)  -- fn_name, its_arg_number
 
 data CGInfo = CGInfo {
-    calls   :: [Name]
-  , scg     :: [SCGEntry]
-  , usedpos :: [(Int, [UsageReason])]
+    calls    :: [Name] -- Immediate calls
+  , allCalls :: Maybe [Name] -- Calls and descendents (built as required, for PE)
+  , scg      :: [SCGEntry]
+  , usedpos  :: [(Int, [UsageReason])]
   } deriving (Show, Generic)
 {-!
 deriving instance Binary CGInfo
@@ -367,7 +362,7 @@
               | IBCMetaInformation Name MetaInformation
               | IBCTotal Name Totality
               | IBCInjective Name Injectivity
-              | IBCFlags Name [FnOpt]
+              | IBCFlags Name
               | IBCFnInfo Name FnInfo
               | IBCTrans Name (Term, Term)
               | IBCErrRev (Term, Term)
@@ -492,7 +487,8 @@
          | IdemodeSocket
          | ShowAll
          | ShowLibs
-         | ShowLibdir
+         | ShowLibDir
+         | ShowDocDir
          | ShowIncs
          | ShowPkgs
          | ShowLoggingCats
@@ -524,7 +520,8 @@
          | PkgClean String
          | PkgCheck String
          | PkgREPL String
-         | PkgMkDoc String -- IdrisDoc
+         | PkgDocBuild String -- IdrisDoc
+         | PkgDocInstall String
          | PkgTest String
          | PkgIndex FilePath
          | WarnOnly
@@ -589,7 +586,7 @@
 
 
 data Static = Static | Dynamic
-  deriving (Show, Eq, Data, Generic, Typeable)
+  deriving (Show, Eq, Ord, Data, Generic, Typeable)
 {-!
 deriving instance Binary Static
 !-}
@@ -612,7 +609,7 @@
                       , pstatic  :: Static
                       , pscript  :: PTerm
                       }
-             deriving (Show, Eq, Data, Generic, Typeable)
+             deriving (Show, Eq, Ord, Data, Generic, Typeable)
 
 {-!
 deriving instance Binary Plicity
@@ -640,11 +637,13 @@
 
 data FnOpt = Inlinable -- ^ always evaluate when simplifying
            | TotalFn | PartialFn | CoveringFn
-           | Coinductive | AssertTotal
+           | AllGuarded -- ^ all delayed arguments guaranteed guarded by constructors
+           | AssertTotal
 
            -- | interface dictionary, eval only when a function
            -- argument, and further evaluation results.
            | Dictionary
+           | OverlappingDictionary -- ^ Interface dictionary which may overlap
            | Implicit                       -- ^ implicit coercion
            | NoImplicit                     -- ^ do not apply implicit coercions
            | CExport String                 -- ^ export, with a C name
@@ -652,6 +651,12 @@
            | ErrorReverse                   -- ^ attempt to reverse normalise before showing in error
            | Reflection                     -- ^ a reflecting function, compile-time only
            | Specialise [(Name, Maybe Int)] -- ^ specialise it, freeze these names
+           | UnfoldIface Name [Name]
+                  -- ^ Unfold given interface name in the definition, the
+                  -- top level methods, and anything which has
+                  -- the interface name as an argument. This is to unfold
+                  -- things for termination checking, as interfaces will otherwise
+                  -- cause problems
            | Constructor -- ^ Data constructor type
            | AutoHint    -- ^ use in auto implicit search
            | PEGenerated -- ^ generated by partial evaluator
@@ -1035,7 +1040,7 @@
 data PunInfo = IsType
              | IsTerm
              | TypeOrTerm
-             deriving (Eq, Show, Data, Typeable, Generic)
+             deriving (Eq, Show, Ord, Data, Typeable, Generic)
 
 -- | High level language terms
 data PTerm = PQuote Raw         -- ^ Inclusion of a core term into the
@@ -1101,12 +1106,12 @@
            | PConstSugar FC PTerm
              -- ^ A desugared constant. The FC is a precise source
              -- location that will be used to highlight it later.
-       deriving (Eq, Data, Typeable, Generic)
+       deriving (Eq, Ord, Data, Typeable, Generic)
 
 data PAltType = ExactlyOne Bool -- ^ flag sets whether delay is allowed
               | FirstSuccess
               | TryImplicit
-       deriving (Eq, Data, Generic, Typeable)
+       deriving (Eq, Ord, Data, Generic, Typeable)
 
 -- | Transform the FCs in a PTerm. The first function transforms the
 -- general-purpose FCs, and the second transforms those that are used
@@ -1225,7 +1230,7 @@
                 | TFail [ErrorReportPart]
                 | Qed | Abandon
                 | SourceFC
-    deriving (Show, Eq, Functor, Foldable, Traversable, Data, Generic, Typeable)
+    deriving (Show, Eq, Ord, Functor, Foldable, Traversable, Data, Generic, Typeable)
 {-!
 deriving instance Binary PTactic'
 !-}
@@ -1271,7 +1276,7 @@
             | DoBindP FC t t [(t,t)]
             | DoLet  FC Name FC t t   -- ^ second FC is precise name location
             | DoLetP FC t t
-    deriving (Eq, Functor, Data, Generic, Typeable)
+    deriving (Eq, Ord, Functor, Data, Generic, Typeable)
 {-!
 deriving instance Binary PDo'
 !-}
@@ -1311,13 +1316,13 @@
                             , getScript :: t
                             , getTm     :: t
                             }
-             deriving (Show, Eq, Functor, Data, Generic, Typeable)
+             deriving (Show, Eq, Ord, Functor, Data, Generic, Typeable)
 
 data ArgOpt = AlwaysShow
             | HideDisplay
             | InaccessibleArg
             | UnknownImp
-            deriving (Show, Eq, Data, Generic, Typeable)
+            deriving (Show, Eq, Ord, Data, Generic, Typeable)
 
 instance Sized a => Sized (PArg' a) where
   size (PImp p _ l nm trm)            = 1 + size nm + size trm
@@ -1402,7 +1407,9 @@
   , interface_methods                  :: [(Name, (Bool, FnOpts, PTerm))] -- ^ flag whether it's a "data" method
   , interface_defaults                 :: [(Name, (Name, PDecl))]         -- ^ method name -> default impl
   , interface_default_super_interfaces :: [PDecl]
+  , interface_impparams                :: [Name]
   , interface_params                   :: [Name]
+  , interface_constraints              :: [PTerm]
   , interface_implementations          :: [(Name, Bool)] -- ^ the Bool is whether to include in implementation search, so named implementations are excluded
   , interface_determiners              :: [Int]
   } deriving (Show, Generic)
@@ -1433,6 +1440,7 @@
 data OptInfo = Optimise {
     inaccessible :: [(Int,Name)]  -- includes names for error reporting
   , detaggable :: Bool
+  , forceable :: [Int] -- argument positions which are forced by other values
   } deriving (Show, Generic)
 {-!
 deriving instance Binary OptInfo
@@ -1789,9 +1797,18 @@
       | Just n <- snat ppo d p e = depth d $ annotate (AnnData "Nat" "") (text (show n))
     prettySe d p bnd (PRef fc _ n) = prettyName True (ppopt_impl ppo) bnd n
     prettySe d p bnd (PLam fc n nfc ty sc) =
-      depth d . bracket p startPrec . group . align . hang 2 $
-      text "\\" <> prettyBindingOf n False <+> text "=>" <$>
-      prettySe (decD d) startPrec ((n, False):bnd) sc
+      let (ns, sc') = getLamNames [n] sc in
+          depth d . bracket p startPrec . group . align . hang 2 $
+          text "\\" <> prettyBindingsOf ns False <+> text "=>" <$>
+          prettySe (decD d) startPrec ((n, False):bnd) sc'
+      where
+        getLamNames acc (PLam fc n nfc ty sc) = getLamNames (n : acc) sc
+        getLamNames acc sc = (reverse acc, sc)
+
+        prettyBindingsOf [] t = text ""
+        prettyBindingsOf [n] t = prettyBindingOf n t
+        prettyBindingsOf (n : ns) t = prettyBindingOf n t <> text "," <+>
+                                      prettyBindingsOf ns t
     prettySe d p bnd (PLet fc n nfc ty v sc) =
       depth d . bracket p startPrec . group . align $
       kwd "let" <+> (group . align . hang 2 $ prettyBindingOf n False <+> text "=" <$> prettySe (decD d) startPrec bnd v) </>
@@ -2548,5 +2565,5 @@
 getErasureInfo :: IState -> Name -> [Int]
 getErasureInfo ist n =
     case lookupCtxtExact n (idris_optimisation ist) of
-        Just (Optimise inacc detagg) -> map fst inacc
+        Just (Optimise inacc detag force) -> map fst inacc
         Nothing -> []
diff --git a/src/Idris/Apropos.hs b/src/Idris/Apropos.hs
--- a/src/Idris/Apropos.hs
+++ b/src/Idris/Apropos.hs
@@ -8,12 +8,12 @@
 module Idris.Apropos (apropos, aproposModules) where
 
 import Idris.AbsSyntax
-import Idris.Core.Evaluate (ctxtAlist, Def(..))
-import Idris.Core.TT (Name(..), Type, TT(..), NameType(..), Binder(..), Const(..),
-                      lookupCtxtExact, toAlist)
-import Idris.Docstrings (Docstring, DocTerm, containsText)
+import Idris.Core.Evaluate (Def(..), ctxtAlist)
+import Idris.Core.TT (Binder(..), Const(..), Name(..), NameType(..), TT(..),
+                      Type, lookupCtxtExact, toAlist)
+import Idris.Docstrings (DocTerm, Docstring, containsText)
 
-import Data.List (nub, nubBy, intersperse)
+import Data.List (intersperse, nub, nubBy)
 import qualified Data.Text as T
 
 -- | Find definitions that are relevant to all space-delimited components of
diff --git a/src/Idris/CaseSplit.hs b/src/Idris/CaseSplit.hs
--- a/src/Idris/CaseSplit.hs
+++ b/src/Idris/CaseSplit.hs
@@ -28,33 +28,29 @@
   ) where
 
 import Idris.AbsSyntax
-import Idris.AbsSyntaxTree (Idris, IState, PTerm)
-import Idris.ElabDecls
+import Idris.AbsSyntaxTree (IState, Idris, PTerm)
+import Idris.Core.Evaluate
+import Idris.Core.TT
+import Idris.Core.Typecheck
 import Idris.Delaborate
-import Idris.Parser
-import Idris.Parser.Helpers
+import Idris.Elab.Term
+import Idris.Elab.Value
+import Idris.ElabDecls
 import Idris.Error
 import Idris.Output
-
-import Idris.Elab.Value
-import Idris.Elab.Term
-
-import Idris.Core.TT
-import Idris.Core.Typecheck
-import Idris.Core.Evaluate
+import Idris.Parser
+import Idris.Parser.Helpers
 
-import Data.Maybe
-import Data.Char
-import Data.List (isPrefixOf, isSuffixOf)
 import Control.Monad
 import Control.Monad.State.Strict
-
+import Data.Char
+import Data.List (isPrefixOf, isSuffixOf)
+import Data.Maybe
+import Debug.Trace
+import Text.Parser.Char (anyChar)
 import Text.Parser.Combinators
-import Text.Parser.Char(anyChar)
-import Text.Trifecta(Result(..), parseString)
+import Text.Trifecta (Result(..), parseString)
 import Text.Trifecta.Delta
-
-import Debug.Trace
 
 -- | Given a variable to split, and a term application, return a list
 -- of variable updates, paired with a flag to say whether the given
diff --git a/src/Idris/Chaser.hs b/src/Idris/Chaser.hs
--- a/src/Idris/Chaser.hs
+++ b/src/Idris/Chaser.hs
@@ -11,22 +11,21 @@
   , ModuleTree(..)
   ) where
 
-import Idris.Core.TT
-import Idris.Parser
 import Idris.AbsSyntax
-import Idris.Imports
-import Idris.Unlit
+import Idris.Core.TT
 import Idris.Error
 import Idris.IBC
+import Idris.Imports
+import Idris.Parser
+import Idris.Unlit
 
-import System.FilePath
-import System.Directory
-import Data.Time.Clock
-import Control.Monad.Trans
 import Control.Monad.State
+import Control.Monad.Trans
 import Data.List
-
+import Data.Time.Clock
 import Debug.Trace
+import System.Directory
+import System.FilePath
 import Util.System (readSource, writeSource)
 
 data ModuleTree = MTree { mod_path :: IFileType,
diff --git a/src/Idris/CmdOptions.hs b/src/Idris/CmdOptions.hs
--- a/src/Idris/CmdOptions.hs
+++ b/src/Idris/CmdOptions.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {-|
 Module      : Idris.CmdOptions
 Description : A parser for the CmdOptions for the Idris executable.
@@ -13,27 +14,27 @@
   , getPkgREPL, getPkgTest, getPort, getIBCSubDir
   ) where
 
+import Idris.AbsSyntax (getClient, getIBCSubDir, getPkg, getPkgCheck,
+                        getPkgClean, getPkgMkDoc, getPkgREPL, getPkgTest,
+                        getPort, opt)
 import Idris.AbsSyntaxTree
-import Idris.AbsSyntax (opt, getClient, getPkg, getPkgCheck, getPkgClean, getPkgMkDoc
-  , getPkgREPL, getPkgTest, getPort, getIBCSubDir)
--- import Idris.REPL
 import Idris.Info (getIdrisVersion)
-
+-- import Idris.REPL
 import IRTS.CodegenCommon
 
-import Options.Applicative
-import Options.Applicative.Arrows
-import Options.Applicative.Types (ReadM(..))
 import Control.Monad.Trans (lift)
-import Control.Monad.Trans.Reader (ask)
 import Control.Monad.Trans.Except (throwE)
+import Control.Monad.Trans.Reader (ask)
 import Data.Char
 import Data.Maybe
-
-import Text.ParserCombinators.ReadP hiding (many, option)
-
+#if MIN_VERSION_optparse_applicative(0,13,0)
+import Data.Monoid ((<>))
+#endif
+import Options.Applicative
+import Options.Applicative.Arrows
+import Options.Applicative.Types (ReadM(..))
 import Safe (lastMay)
-
+import Text.ParserCombinators.ReadP hiding (many, option)
 import qualified Text.PrettyPrint.ANSI.Leijen as PP
 
 runArgParser :: IO [Opt]
@@ -129,7 +130,8 @@
   <|> flag' ShowLoggingCats (long "listlogcats" <> help "Display logging categories")
   <|> flag' ShowLibs        (long "link"        <> help "Display link flags")
   <|> flag' ShowPkgs        (long "listlibs"    <> help "Display installed libraries")
-  <|> flag' ShowLibdir      (long "libdir"      <> help "Display library directory")
+  <|> flag' ShowLibDir      (long "libdir"      <> help "Display library directory")
+  <|> flag' ShowDocDir      (long "docdir"      <> help "Display idrisdoc install directory")
   <|> flag' ShowIncs        (long "include"     <> help "Display the includes flags")
 
   <|> flag' Verbose (short 'V' <> long "verbose" <> help "Loud verbosity")
@@ -144,13 +146,14 @@
   <|> (Port <$> option portReader (long "port" <> metavar "PORT" <> help "REPL TCP port - pass \"none\" to not bind any port"))
 
   -- Package commands
-  <|> (PkgBuild   <$> strOption (long "build"    <> metavar "IPKG" <> help "Build package"))
-  <|> (PkgInstall <$> strOption (long "install"  <> metavar "IPKG" <> help "Install package"))
-  <|> (PkgREPL    <$> strOption (long "repl"     <> metavar "IPKG" <> help "Launch REPL, only for executables"))
-  <|> (PkgClean   <$> strOption (long "clean"    <> metavar "IPKG" <> help "Clean package"))
-  <|> (PkgMkDoc   <$> strOption (long "mkdoc"    <> metavar "IPKG" <> help "Generate IdrisDoc for package"))
-  <|> (PkgCheck   <$> strOption (long "checkpkg" <> metavar "IPKG" <> help "Check package only"))
-  <|> (PkgTest    <$> strOption (long "testpkg"  <> metavar "IPKG" <> help "Run tests for package"))
+  <|> (PkgBuild      <$> strOption (long "build"      <> metavar "IPKG" <> help "Build package"))
+  <|> (PkgInstall    <$> strOption (long "install"    <> metavar "IPKG" <> help "Install package"))
+  <|> (PkgREPL       <$> strOption (long "repl"       <> metavar "IPKG" <> help "Launch REPL, only for executables"))
+  <|> (PkgClean      <$> strOption (long "clean"      <> metavar "IPKG" <> help "Clean package"))
+  <|> (PkgDocBuild   <$> strOption (long "mkdoc"      <> metavar "IPKG" <> help "Generate IdrisDoc for package"))
+  <|> (PkgDocInstall <$> strOption (long "installdoc" <> metavar "IPKG" <> help "Install IdrisDoc for package"))
+  <|> (PkgCheck      <$> strOption (long "checkpkg"   <> metavar "IPKG" <> help "Check package only"))
+  <|> (PkgTest       <$> strOption (long "testpkg"    <> metavar "IPKG" <> help "Run tests for package"))
 
   -- Misc options
   <|> (BCAsm <$> strOption (long "bytecode"))
diff --git a/src/Idris/Completion.hs b/src/Idris/Completion.hs
--- a/src/Idris/Completion.hs
+++ b/src/Idris/Completion.hs
@@ -7,28 +7,26 @@
 -}
 module Idris.Completion (replCompletion, proverCompletion) where
 
-import Idris.Core.Evaluate (definitions, ctxtAlist)
-import Idris.Core.TT
-
 import Idris.AbsSyntax (runIO)
 import Idris.AbsSyntaxTree
+import Idris.Colours
+import Idris.Core.Evaluate (ctxtAlist, definitions)
+import Idris.Core.TT
 import Idris.Help
 import Idris.Imports (installedPackages)
-import Idris.Colours
-import Idris.Parser.Helpers(opChars)
+import Idris.Parser.Expr (TacticArg(..))
 import qualified Idris.Parser.Expr (constants, tactics)
-import Idris.Parser.Expr (TacticArg (..))
+import Idris.Parser.Helpers (opChars)
 import Idris.REPL.Parser (allHelp, setOptions)
-import Control.Monad.State.Strict
 
+import Control.Monad.State.Strict
+import Data.Char (toLower)
 import Data.List
-import Data.Maybe
-import Data.Char(toLower)
 import qualified Data.Map.Strict as Map
+import Data.Maybe
 import qualified Data.Text as T
-
-import System.Console.Haskeline
 import System.Console.ANSI (Color)
+import System.Console.Haskeline
 
 commands = [ n | (names, _, _) <- allHelp ++ extraHelp, n <- names ]
 
diff --git a/src/Idris/Core/Binary.hs b/src/Idris/Core/Binary.hs
--- a/src/Idris/Core/Binary.hs
+++ b/src/Idris/Core/Binary.hs
@@ -8,15 +8,15 @@
 {-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
 module Idris.Core.Binary where
 
-import Control.Applicative ((<*>), (<$>))
-import Control.Monad (liftM2)
-import Control.DeepSeq (($!!))
+import Idris.Core.TT
 
+import Control.Applicative ((<$>), (<*>))
+import Control.DeepSeq (($!!))
+import Control.Monad (liftM2)
 import Data.Binary
-import Data.Vector.Binary
 import qualified Data.Text as T
 import qualified Data.Text.Encoding as E
-import Idris.Core.TT
+import Data.Vector.Binary
 
 instance Binary ErrorReportPart where
   put (TextPart msg) = do putWord8 0 ; put msg
@@ -639,6 +639,7 @@
                 TType x1 -> do putWord8 7
                                put x1
                 Impossible -> putWord8 8
+                Inferred x1 -> put x1 -- drop the 'Inferred'
                 UType x1 -> do putWord8 10
                                put x1
         get
diff --git a/src/Idris/Core/CaseTree.hs b/src/Idris/Core/CaseTree.hs
--- a/src/Idris/Core/CaseTree.hs
+++ b/src/Idris/Core/CaseTree.hs
@@ -18,8 +18,8 @@
 in order to allow for better optimisation opportunities.
 
 -}
-{-# LANGUAGE PatternGuards, DeriveFunctor, TypeSynonymInstances,
-    DeriveGeneric #-}
+{-# LANGUAGE DeriveFunctor, DeriveGeneric, PatternGuards, TypeSynonymInstances
+             #-}
 
 module Idris.Core.CaseTree (
     CaseDef(..), SC, SC'(..), CaseAlt, CaseAlt'(..), ErasureInfo
@@ -31,11 +31,12 @@
 import Idris.Core.TT
 
 import Control.Applicative hiding (Const)
-import Control.Monad.State
 import Control.Monad.Reader
-import Data.Maybe
+import Control.Monad.State
 import Data.List hiding (partition)
-import qualified Data.List(partition)
+import qualified Data.List (partition)
+import Data.Maybe
+import qualified Data.Set as S
 import Debug.Trace
 import GHC.Generics (Generic)
 
@@ -153,33 +154,34 @@
 findCalls = findCalls' False
 
 findCalls' :: Bool -> SC -> [Name] -> [(Name, [[Name]])]
-findCalls' ignoreasserts sc topargs = nub $ nu' topargs sc where
-    nu' ps (Case _ n alts) = nub (concatMap (nua (n : ps)) alts)
-    nu' ps (ProjCase t alts) = nub $ nut ps t ++ concatMap (nua ps) alts
-    nu' ps (STerm t)     = nub $ nut ps t
-    nu' ps _ = []
+findCalls' ignoreasserts sc topargs = S.toList $ nu' topargs sc where
+    nu' ps (Case _ n alts) = S.unions $ map (nua (n : ps)) alts
+    nu' ps (ProjCase t alts) = S.unions $ nut ps t : map (nua ps) alts
+    nu' ps (STerm t)     = nut ps t
+    nu' ps _ = S.empty
 
-    nua ps (ConCase n i args sc) = nub (nu' (ps ++ args) sc)
-    nua ps (FnCase n args sc) = nub (nu' (ps ++ args) sc)
+    nua ps (ConCase n i args sc) = nu' (ps ++ args) sc
+    nua ps (FnCase n args sc) = nu' (ps ++ args) sc
     nua ps (ConstCase _ sc) = nu' ps sc
     nua ps (SucCase _ sc) = nu' ps sc
     nua ps (DefaultCase sc) = nu' ps sc
 
-    nut ps (P _ n _) | n `elem` ps = []
-                     | otherwise = [(n, [])] -- tmp
+    nut ps (P _ n _) | n `elem` ps = S.empty
+                     | otherwise = S.singleton (n, [])
     nut ps fn@(App _ f a)
         | (P _ n _, args) <- unApply fn
-             = if ignoreasserts && n == sUN "assert_total" 
-                  then []
-                  else if n `elem` ps 
-                          then nut ps f ++ nut ps a
-                          else [(n, map argNames args)] ++ concatMap (nut ps) args
-        | (P (TCon _ _) n _, _) <- unApply fn = []
-        | otherwise = nut ps f ++ nut ps a
-    nut ps (Bind n (Let t v) sc) = nut ps v ++ nut (n:ps) sc
+             = if ignoreasserts && n == sUN "assert_total"
+                  then S.empty
+                  else if n `elem` ps
+                          then S.union (nut ps f) (nut ps a)
+                          else S.insert (n, map argNames args) 
+                                   (S.unions $ map (nut ps) args)
+        | (P (TCon _ _) n _, _) <- unApply fn = S.empty
+        | otherwise = S.union (nut ps f) (nut ps a)
+    nut ps (Bind n (Let t v) sc) = S.union (nut ps v) (nut (n:ps) sc)
     nut ps (Proj t _) = nut ps t
     nut ps (Bind n b sc) = nut (n:ps) sc
-    nut ps _ = []
+    nut ps _ = S.empty
 
     argNames tm = let ns = directUse tm in
                       filter (\x -> x `elem` ns) topargs
@@ -242,14 +244,18 @@
 runCaseBuilder :: ErasureInfo -> CaseBuilder a -> (CS -> (a, CS))
 runCaseBuilder ei bld = runState $ runReaderT bld ei
 
-data Phase = CompileTime | RunTime
+data Phase = CoverageCheck [Int] -- list of positions explicitly given
+           | CompileTime 
+           | RunTime
     deriving (Show, Eq)
 
 -- Generate a simple case tree
 -- Work Right to Left
 
 simpleCase :: Bool -> SC -> Bool ->
-              Phase -> FC -> [Int] -> 
+              Phase -> FC -> 
+              -- Following two can be empty lists when Phase = CoverageCheck
+              [Int] -> -- Inaccessible argument positions
               [(Type, Bool)] -> -- (Argument type, whether it's canonical)
               [([Name], Term, Term)] ->
               ErasureInfo ->
@@ -289,7 +295,7 @@
           -- Check that all pattern variables are reachable by a case split
           -- Otherwise, they won't make sense on the RHS.
           chkAccessible (avs, l, c)
-               | phase == RunTime || reflect = return (l, c)
+               | phase /= CompileTime || reflect = return (l, c)
                | otherwise = do mapM_ (acc l) avs
                                 return (l, c)
 
@@ -343,6 +349,7 @@
 
 data Pat = PCon Bool Name Int [Pat]
          | PConst Const
+         | PInferred Pat
          | PV Name Type
          | PSuc Pat -- special case for n+1 on Integer
          | PReflected Name [Pat]
@@ -381,6 +388,7 @@
 
     toPat' []   (P Bound n ty) = PV n ty
     toPat' args (App _ f a)    = toPat' (a : args) f
+    toPat' args (Inferred tm)  = PInferred (toPat' args tm)
     toPat' [] (Constant x) | isTypeConst x = PTyPat
                            | otherwise     = PConst x
 
@@ -431,12 +439,26 @@
 -- The first argument means [(Name, IsInaccessible)].
 
 order :: Phase -> [(Name, Bool)] -> [Clause] -> [Bool] -> ([Name], [Clause])
--- do nothing at compile time: FIXME (EB): Put this in after checking 
+-- do nothing at compile time: FIXME (EB): Put this in after checking
 -- implications for Franck's reflection work... see issue 3233
--- order CompileTime ns cs _ = (map fst ns, cs) 
+-- order CompileTime ns cs _ = (map fst ns, cs)
 order _ []  cs cans = ([], cs)
 order _ ns' [] cans = (map fst ns', [])
-order phase ns' cs cans 
+order (CoverageCheck pos) ns' cs cans 
+    = let ns_out = pick 0 [] (map fst ns')
+          cs_out = map pickClause cs in
+          (ns_out, cs_out)
+  where
+    pickClause (pats, def) = (pick 0 [] pats, def)
+
+    -- Order the list so that things in a position in 'pos' are in the first
+    -- part, then all the other things later. Otherwise preserve order.
+    pick i skipped [] = reverse skipped
+    pick i skipped (x : xs) 
+         | i `elem` pos = x : pick (i + 1) skipped xs
+         | otherwise    = pick (i + 1) (x : skipped) xs
+
+order phase ns' cs cans
     = let patnames = transpose (map (zip ns') (map (zip cans) (map fst cs)))
           -- only sort the arguments where there is no clash in
           -- constructor tags between families, the argument type is canonical,
@@ -444,7 +466,7 @@
           -- clash, because otherwise we can't reliable make the
           -- case distinction on evaluation
           (patnames_ord, patnames_rest)
-                = Data.List.partition (noClash . map snd) patnames 
+                = Data.List.partition (noClash . map snd) patnames
           patnames_ord' = case phase of
                                CompileTime -> patnames_ord
                                -- reversing tends to make better case trees
@@ -460,7 +482,7 @@
     rebuild patnames clause = (map (snd . snd) patnames, snd clause)
 
     noClash [] = True
-    noClash ((can, p) : ps) = can && not (any (clashPat p) (map snd ps)) 
+    noClash ((can, p) : ps) = can && not (any (clashPat p) (map snd ps))
                                   && noClash ps
 
     clashPat (PCon _ _ _ _) (PConst _) = True
@@ -471,7 +493,7 @@
     clashPat _ _ = False
 
     -- this compares (+isInaccessible, -numberOfCases)
-    moreDistinct xs ys 
+    moreDistinct xs ys
         = compare (snd . fst . head $ xs, numNames [] (map snd ys))
                   (snd . fst . head $ ys, numNames [] (map snd xs))
 
@@ -482,6 +504,41 @@
     numNames xs (_ : ps) = numNames xs ps
     numNames xs [] = length xs
 
+-- Reorder the patterns in the clause so that the PInferred patterns come
+-- last. Also strip 'PInferred' from the top level patterns so that we can
+-- go ahead and match.
+orderByInf :: [Name] -> [Clause] -> ([Name], [Clause])
+orderByInf vs cs = let alwaysInf = getInf cs in
+                       (selectInf alwaysInf vs,
+                        map deInf (map (selectExp alwaysInf) cs))
+  where
+    getInf [] = []
+    getInf [(pats, def)] = infPos 0 pats
+    getInf ((pats, def) : cs) = infPos 0 pats `intersect` getInf cs
+
+    selectExp :: [Int] -> Clause -> Clause
+    selectExp infs (pats, def)
+         = let (notInf, inf) = splitPats 0 infs [] [] pats in
+               (notInf ++ inf, def)
+
+    selectInf :: [Int] -> [a] -> [a]
+    selectInf infs ns = let (notInf, inf) = splitPats 0 infs [] [] ns in
+                            notInf ++ inf
+
+    splitPats i infpos notInf inf [] = (reverse notInf, reverse inf)
+    splitPats i infpos notInf inf (p : ps)
+         | i `elem` infpos = splitPats (i + 1) infpos notInf (p : inf) ps
+         | otherwise = splitPats (i + 1) infpos (p : notInf) inf ps
+
+    infPos i [] = []
+    infPos i (PInferred p : ps) = i : infPos (i + 1) ps
+    infPos i (_ : ps) = infPos (i + 1) ps
+
+    deInf (pats, def) = (map deInfPat pats, def)
+
+    deInfPat (PInferred p) = p
+    deInfPat p = p
+
 match :: [Name] -> [Clause] -> SC -- error case
                             -> CaseBuilder SC
 match [] (([], ret) : xs) err
@@ -490,8 +547,9 @@
          case snd ret of
             Impossible -> return ImpossibleCase
             tm -> return $ STerm tm -- run out of arguments
-match vs cs err = do let ps = partition cs
-                     mixture vs ps err
+match vs cs err = do let (vs', de_inf) = orderByInf vs cs
+                         ps = partition de_inf
+                     mixture vs' ps err
 
 mixture :: [Name] -> [Partition] -> SC -> CaseBuilder SC
 mixture vs [] err = return err
diff --git a/src/Idris/Core/Constraints.hs b/src/Idris/Core/Constraints.hs
--- a/src/Idris/Core/Constraints.hs
+++ b/src/Idris/Core/Constraints.hs
@@ -7,12 +7,12 @@
 -}
 module Idris.Core.Constraints ( ucheck ) where
 
-import Idris.Core.TT ( TC(..), UExp(..), UConstraint(..), FC(..),
-                       ConstraintFC(..), Err'(..) )
+import Idris.Core.TT (ConstraintFC(..), Err'(..), FC(..), TC(..),
+                      UConstraint(..), UExp(..))
 
 import Control.Applicative
 import Control.Monad.State.Strict
-import Data.List ( partition )
+import Data.List (partition)
 import qualified Data.Map.Strict as M
 import qualified Data.Set as S
 import Debug.Trace
diff --git a/src/Idris/Core/DeepSeq.hs b/src/Idris/Core/DeepSeq.hs
--- a/src/Idris/Core/DeepSeq.hs
+++ b/src/Idris/Core/DeepSeq.hs
@@ -10,9 +10,9 @@
 
 module Idris.Core.DeepSeq where
 
-import Idris.Core.TT
 import Idris.Core.CaseTree
 import Idris.Core.Evaluate
+import Idris.Core.TT
 
 import Control.DeepSeq
 
diff --git a/src/Idris/Core/Elaborate.hs b/src/Idris/Core/Elaborate.hs
--- a/src/Idris/Core/Elaborate.hs
+++ b/src/Idris/Core/Elaborate.hs
@@ -10,29 +10,30 @@
 primitives.
 -}
 
-{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, PatternGuards #-}
+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, PatternGuards #-}
 module Idris.Core.Elaborate (
     module Idris.Core.Elaborate
   , module Idris.Core.ProofState
   ) where
 
+import Idris.Core.DeepSeq
+import Idris.Core.Evaluate
 import Idris.Core.ProofState
-import Idris.Core.ProofTerm(bound_in, getProofTerm, mkProofTerm, bound_in_term,
-                            refocus)
+import Idris.Core.ProofTerm (bound_in, bound_in_term, getProofTerm, mkProofTerm,
+                             refocus)
 import Idris.Core.TT
-import Idris.Core.Evaluate
 import Idris.Core.Typecheck
 import Idris.Core.Unify
-import Idris.Core.DeepSeq
+import Idris.Core.WHNF
 
+import Util.Pretty hiding (fill)
+
 import Control.DeepSeq
 import Control.Monad.State.Strict
 import Data.Char
 import Data.List
 import Debug.Trace
 
-import Util.Pretty hiding (fill)
-
 data ElabState aux = ES (ProofState, aux) String (Maybe (ElabState aux))
   deriving Show
 
@@ -422,9 +423,12 @@
 simplify :: Elab' aux ()
 simplify = processTactic' Simplify
 
-hnf_compute :: Elab' aux ()
-hnf_compute = processTactic' HNF_Compute
+whnf_compute :: Elab' aux ()
+whnf_compute = processTactic' WHNF_Compute
 
+whnf_compute_args :: Elab' aux ()
+whnf_compute_args = processTactic' WHNF_ComputeArgs
+
 eval_in :: Raw -> Elab' aux ()
 eval_in t = processTactic' (EvalIn t)
 
@@ -575,7 +579,7 @@
        -- Count arguments to check if we need to normalise the type
        let usety = if argsOK (finalise ty) imps
                       then finalise ty
-                      else normalise ctxt env (finalise ty)
+                      else whnfArgs ctxt env (finalise ty)
        claims <- -- trace (show (fn, imps, ty, map fst env, normalise ctxt env (finalise ty))) $
                  mkClaims usety imps [] (map fst env)
        ES (p, a) s prev <- get
@@ -697,7 +701,7 @@
     do ty <- get_type (Var n)
        ctxt <- get_context
        env <- get_env
-       claims <- doClaims (hnf ctxt env ty) args []
+       claims <- doClaims (normalise ctxt env ty) args []
        prep_fill n (map fst claims)
        let eclaims = sortBy (\ (_, x) (_,y) -> priOrder x y) claims
        elabClaims [] False claims
@@ -745,7 +749,7 @@
             = do g <- goal
                  ctxt <- get_context
                  env <- get_env
-                 case (normalise ctxt env g) of
+                 case (whnf ctxt env g) of
                     Bind _ (Pi _ _ _) _ -> return ()
                     _ -> do a <- getNameFrom (sMN 0 "__pargTy")
                             b <- getNameFrom (sMN 0 "__pretTy")
@@ -820,7 +824,7 @@
        focus s; attack;
        ctxt <- get_context
        env <- get_env
-       case normalise ctxt env fty of
+       case whnf ctxt env fty of
             -- if f gives a function type, unify our argument type with
             -- f's expected argument type
             Bind _ (Pi _ argty _) _ -> unifyGoal (forget argty)
diff --git a/src/Idris/Core/Evaluate.hs b/src/Idris/Core/Evaluate.hs
--- a/src/Idris/Core/Evaluate.hs
+++ b/src/Idris/Core/Evaluate.hs
@@ -5,13 +5,14 @@
 License     : BSD3
 Maintainer  : The Idris Community.
 -}
-{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, BangPatterns,
-             PatternGuards, DeriveGeneric #-}
+{-# LANGUAGE BangPatterns, DeriveGeneric, FlexibleInstances,
+             MultiParamTypeClasses, PatternGuards #-}
 {-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
 
 module Idris.Core.Evaluate(normalise, normaliseTrace, normaliseC,
                 normaliseAll, normaliseBlocking, toValue, quoteTerm,
-                rt_simplify, simplify, specialise, hnf, convEq, convEq',
+                rt_simplify, simplify, inlineSmall,
+                specialise, unfold, convEq, convEq',
                 Def(..), CaseInfo(..), CaseDefs(..),
                 Accessibility(..), Injectivity, Totality(..), PReason(..), MetaInformation(..),
                 Context, initContext, ctxtAlist, next_tvar,
@@ -19,24 +20,24 @@
                 addDatatype, addCasedef, simplifyCasedef, addOperator,
                 lookupNames, lookupTyName, lookupTyNameExact, lookupTy, lookupTyExact,
                 lookupP, lookupP_all, lookupDef, lookupNameDef, lookupDefExact, lookupDefAcc, lookupDefAccExact, lookupVal,
-                mapDefCtxt,
+                mapDefCtxt, tcReducible,
                 lookupTotal, lookupTotalExact, lookupInjectiveExact,
-                lookupNameTotal, lookupMetaInformation, lookupTyEnv, isTCDict, 
+                lookupNameTotal, lookupMetaInformation, lookupTyEnv, isTCDict,
                 isCanonical, isDConName, canBeDConName, isTConName, isConName, isFnName,
                 Value(..), Quote(..), initEval, uniqueNameCtxt, uniqueBindersCtxt, definitions,
                 isUniverse) where
 
-import Debug.Trace
+import Idris.Core.CaseTree
+import Idris.Core.TT
+
 import Control.Applicative hiding (Const)
-import Control.Monad.State -- not Strict!
-import qualified Data.Binary as B
+import Control.Monad.State
 import Data.Binary hiding (get, put)
+import qualified Data.Binary as B
 import Data.Maybe (listToMaybe)
+import Debug.Trace
 import GHC.Generics (Generic)
 
-import Idris.Core.TT
-import Idris.Core.CaseTree
-
 data EvalState = ES { limited :: [(Name, Int)],
                       nexthole :: Int,
                       blocking :: Bool }
@@ -45,10 +46,10 @@
 type Eval a = State EvalState a
 
 data EvalOpt = Spec
-             | HNF
-             | Simplify
+             | Simplify Bool -- ^ whether to expand lets or not
              | AtREPL
              | RunTT
+             | Unfold
   deriving (Show, Eq)
 
 initEval = ES [] 0 False
@@ -131,10 +132,7 @@
          (tm, limited st)
 
 -- | Like normalise, but we only reduce functions that are marked as okay to
--- inline (and probably shouldn't reduce lets?)
--- 20130908: now only used to reduce for totality checking. Inlining should
--- be done elsewhere.
-
+-- inline, and lets 
 simplify :: Context -> Env -> TT Name -> TT Name
 simplify ctxt env t
    = evalState (do val <- eval False ctxt [(sUN "lazy", 0),
@@ -146,9 +144,18 @@
                                            (sUN "prim__syntactic_eq", 0),
                                            (sUN "fork", 0)]
                                  (map finalEntry env) (finalise t)
-                                 [Simplify]
+                                 [Simplify True]
                    quote 0 val) initEval
 
+-- | Like simplify, but we only reduce functions that are marked as okay to
+-- inline, and don't reduce lets 
+inlineSmall :: Context -> Env -> TT Name -> TT Name
+inlineSmall ctxt env t
+   = evalState (do val <- eval False ctxt []
+                                 (map finalEntry env) (finalise t)
+                                 [Simplify False]
+                   quote 0 val) initEval
+
 -- | Simplify for run-time (i.e. basic inlining)
 rt_simplify :: Context -> Env -> TT Name -> TT Name
 rt_simplify ctxt env t
@@ -162,12 +169,19 @@
                                  [RunTT]
                    quote 0 val) initEval
 
--- | Reduce a term to head normal form
-hnf :: Context -> Env -> TT Name -> TT Name
-hnf ctxt env t
-   = evalState (do val <- eval False ctxt []
-                                 (map finalEntry env)
-                                 (finalise t) [HNF]
+-- | Unfold the given names in a term, the given number of times in a stack.
+-- Preserves 'let'.
+-- This is primarily to support inlining of the given names, and can also
+-- help with partial evaluation by allowing a rescursive definition to be
+-- unfolded once only.
+-- Specifically used to unfold definitions using interfaces before going to
+-- the totality checker (otherwise mutually recursive definitions in
+-- implementations will not work...)
+unfold :: Context -> Env -> [(Name, Int)] -> TT Name -> TT Name
+unfold ctxt env ns t
+   = evalState (do val <- eval False ctxt ns
+                               (map finalEntry env) (finalise t)
+                               [Unfold]
                    quote 0 val) initEval
 
 
@@ -187,22 +201,25 @@
 unbindEnv env tm = error "Impossible case occurred: couldn't unbind env."
 
 usable :: Bool -- specialising
+          -> Bool -- unfolding only
           -> Int -- Reduction depth limit (when simplifying/at REPL)
           -> Name -> [(Name, Int)] -> Eval (Bool, [(Name, Int)])
 -- usable _ _ ns@((MN 0 "STOP", _) : _) = return (False, ns)
-usable False depthlimit n [] = return (True, [])
-usable True depthlimit n ns
+usable False uf depthlimit n [] = return (True, [])
+usable True uf depthlimit n ns
   = do ES ls num b <- get
        if b then return (False, ns)
             else case lookup n ls of
                     Just 0 -> return (False, ns)
                     Just i -> return (True, ns)
                     _ -> return (False, ns)
-usable False depthlimit n ns
+usable False uf depthlimit n ns
   = case lookup n ns of
          Just 0 -> return (False, ns)
          Just i -> return $ (True, (n, abs (i-1)) : filter (\ (n', _) -> n/=n') ns)
-         _ -> return $ (True, (n, depthlimit) : filter (\ (n', _) -> n/=n') ns)
+         _ -> return $ if uf 
+                          then (False, ns)
+                          else (True, (n, depthlimit) : filter (\ (n', _) -> n/=n') ns)
 
 
 fnCount :: Int -> Name -> Eval ()
@@ -231,10 +248,11 @@
         [EvalOpt] -> Eval Value
 eval traceon ctxt ntimes genv tm opts = ev ntimes [] True [] tm where
     spec = Spec `elem` opts
-    simpl = Simplify `elem` opts
+    simpl = Simplify True `elem` opts || Simplify False `elem` opts
+    simpl_inline = Simplify False `elem` opts
     runtime = RunTT `elem` opts
     atRepl = AtREPL `elem` opts
-    hnf = HNF `elem` opts
+    unfold = Unfold `elem` opts
 
     -- returns 'True' if the function should block
     -- normal evaluation should return false
@@ -243,33 +261,33 @@
            = if always then False
                        else not (inl || dict) || elem n stk
        | simpl
-           = (not (inl || dict) || elem n stk)
+           = (not inl || elem n stk)
              || (n == sUN "prim__syntactic_eq")
        | otherwise = False
 
-    getCases cd | simpl = cases_totcheck cd
+    getCases cd | simpl = cases_compiletime cd
                 | runtime = cases_runtime cd
                 | otherwise = cases_compiletime cd
 
     ev ntimes stk top env (P _ n ty)
         | Just (Let t v) <- lookup n genv = ev ntimes stk top env v
     ev ntimes_in stk top env (P Ref n ty)
-      | not top && hnf = liftM (VP Ref n) (ev ntimes stk top env ty)
-      | otherwise
          = do let limit = if simpl then 100 else 10000
-              (u, ntimes) <- usable spec limit n ntimes_in
-              let red = u && (tcReducible n ctxt || spec || atRepl || runtime
+              (u, ntimes) <- usable spec unfold limit n ntimes_in
+              let red = u && (tcReducible n ctxt || spec || atRepl 
+                                || runtime || unfold
                                 || sUN "assert_total" `elem` stk)
               if red then
-               do let val = lookupDefAcc n (spec || atRepl || runtime) ctxt
+               do let val = lookupDefAccExact n (spec || unfold || atRepl || runtime) ctxt
                   case val of
-                    [(Function _ tm, Public)] ->
+                    Just (Function _ tm, Public) ->
                            ev ntimes (n:stk) True env tm
-                    [(TyDecl nt ty, _)] -> do vty <- ev ntimes stk True env ty
-                                              return $ VP nt n vty
-                    [(CaseOp ci _ _ _ _ cd, acc)]
-                         | (acc == Public || acc == Hidden || sUN "assert_total" `elem` stk) &&
-                             null (fst (cases_totcheck cd)) -> -- unoptimised version
+                    Just (TyDecl nt ty, _) -> do vty <- ev ntimes stk True env ty
+                                                 return $ VP nt n vty
+                    Just (CaseOp ci _ _ _ _ cd, acc)
+                         | (acc == Public || acc == Hidden) &&
+--                                || sUN "assert_total" `elem` stk) &&
+                             null (fst (cases_compiletime cd)) -> -- unoptimised version
                        let (ns, tree) = getCases cd in
                          if blockSimplify ci n stk
                             then liftM (VP Ref n) (ev ntimes stk top env ty)
@@ -281,12 +299,12 @@
                     _ -> liftM (VP Ref n) (ev ntimes stk top env ty)
                else liftM (VP Ref n) (ev ntimes stk top env ty)
     ev ntimes stk top env (P nt n ty)
-         = liftM (VP nt n) (ev ntimes stk top env ty)
+        = liftM (VP nt n) (ev ntimes stk top env ty)
     ev ntimes stk top env (V i)
-                     | i < length env && i >= 0 = return $ snd (env !! i)
-                     | otherwise      = return $ VV i
+        | i < length env && i >= 0 = return $ snd (env !! i)
+        | otherwise      = return $ VV i
     ev ntimes stk top env (Bind n (Let t v) sc)
-        | not runtime || occurrences n sc < 2
+        | (not (runtime || simpl_inline || unfold)) || occurrences n sc < 2
            = do v' <- ev ntimes stk top env v --(finalise v)
                 sc' <- ev ntimes stk top ((n, v') : env) sc
                 wknV (-1) sc'
@@ -315,7 +333,7 @@
     -- block reduction immediately under codata (and not forced)
     ev ntimes stk top env
               (App _ (App _ (App _ d@(P _ (UN dly) _) l@(P _ (UN lco) _)) t) arg)
-       | dly == txt "Delay" && lco == txt "Infinite" && not simpl
+       | dly == txt "Delay" && lco == txt "Infinite" && not (unfold || simpl)
             = do let (f, _) = unApply arg
                  let ntimes' = case f of
                                     P _ fn _ -> (fn, 0) : ntimes
@@ -329,8 +347,8 @@
                  evApply ntimes' stk top env [l',t',arg'] d'
     -- Treat "assert_total" specially, as long as it's defined!
     ev ntimes stk top env (App _ (App _ (P _ n@(UN at) _) _) arg)
-       | [(CaseOp _ _ _ _ _ _, _)] <- lookupDefAcc n (spec || atRepl || runtime) ctxt,
-         at == txt "assert_total" && not simpl
+       | Just (CaseOp _ _ _ _ _ _, _) <- lookupDefAccExact n (spec || atRepl || runtime) ctxt,
+         at == txt "assert_total" && not (simpl || unfold)
             = ev ntimes (n : stk) top env arg
     ev ntimes stk top env (App _ f a)
            = do f' <- ev ntimes stk False env f
@@ -348,6 +366,7 @@
     ev ntimes stk top env (Constant c) = return $ VConstant c
     ev ntimes stk top env Erased    = return VErased
     ev ntimes stk top env Impossible  = return VImpossible
+    ev ntimes stk top env (Inferred tm) = ev ntimes stk top env tm
     ev ntimes stk top env (TType i)   = return $ VType i
     ev ntimes stk top env (UType u)   = return $ VUType u
 
@@ -357,9 +376,9 @@
           = apply ntimes stk top env f args
 
     reapply ntimes stk top env f@(VP Ref n ty) args
-       = let val = lookupDefAcc n (spec || atRepl || runtime) ctxt in
+       = let val = lookupDefAccExact n (spec || atRepl || runtime) ctxt in
          case val of
-              [(CaseOp ci _ _ _ _ cd, acc)] ->
+              Just (CaseOp ci _ _ _ _ cd, acc) ->
                  let (ns, tree) = getCases cd in
                      do c <- evCase ntimes n (n:stk) top env ns args tree
                         case c of
@@ -377,18 +396,15 @@
               app <- apply ntimes stk top env a' as
               wknV 1 app
     apply ntimes_in stk top env f@(VP Ref n ty) args
-      | not top && hnf = case args of
-                            [] -> return f
-                            _ -> return $ unload env f args
-      | otherwise
          = do let limit = if simpl then 100 else 10000
-              (u, ntimes) <- usable spec limit n ntimes_in
-              let red = u && (tcReducible n ctxt || spec || atRepl || runtime
+              (u, ntimes) <- usable spec unfold limit n ntimes_in
+              let red = u && (tcReducible n ctxt || spec || atRepl 
+                                || unfold || runtime
                                 || sUN "assert_total" `elem` stk)
               if red then
-                 do let val = lookupDefAcc n (spec || atRepl || runtime) ctxt
+                 do let val = lookupDefAccExact n (spec || unfold || atRepl || runtime) ctxt
                     case val of
-                      [(CaseOp ci _ _ _ _ cd, acc)]
+                      Just (CaseOp ci _ _ _ _ cd, acc)
                            | acc == Public || acc == Hidden ->
                            -- unoptimised version
                        let (ns, tree) = getCases cd in
@@ -399,7 +415,7 @@
                                    case c of
                                       (Nothing, _) -> return $ unload env (VP Ref n ty) args
                                       (Just v, rest) -> evApply ntimes stk top env rest v
-                      [(Operator _ i op, _)]  ->
+                      Just (Operator _ i op, _)  ->
                         if (i <= length args)
                            then case op (take i args) of
                               Nothing -> return $ unload env (VP Ref n ty) args
@@ -687,7 +703,7 @@
                                        caseeq ((x,y):ps) xdef ydef
                         _ -> return False
 
-    sameCase :: [(Name, Name)] -> Name -> Name -> [Term] -> [Term] -> 
+    sameCase :: [(Name, Name)] -> Name -> Name -> [Term] -> [Term] ->
                 StateT UCs TC Bool
     sameCase ps x y xargs yargs
           = case (lookupDef x ctxt, lookupDef y ctxt) of
@@ -697,7 +713,7 @@
                   [CaseOp _ _ _ _ _ yd])
                        -> let (xin, xdef) = cases_compiletime xd
                               (yin, ydef) = cases_compiletime yd in
-                            do liftM2 (&&) 
+                            do liftM2 (&&)
                                   (do ok <- zipWithM (ceq ps)
                                               (drop (length xin) xargs)
                                               (drop (length yin) yargs)
@@ -734,9 +750,7 @@
 --                   [Name] SC -- Run time cae definitions
 
 data CaseDefs = CaseDefs {
-                  cases_totcheck :: !([Name], SC),
                   cases_compiletime :: !([Name], SC),
-                  cases_inlined :: !([Name], SC),
                   cases_runtime :: !([Name], SC)
                 }
   deriving Generic
@@ -764,11 +778,8 @@
     show (Operator ty _ _) = "Operator: " ++ show ty
     show (CaseOp (CaseInfo inlc inla inlr) ty atys ps_in ps cd)
       = let (ns, sc) = cases_compiletime cd
-            (ns_t, sc_t) = cases_totcheck cd
             (ns', sc') = cases_runtime cd in
           "Case: " ++ show ty ++ " " ++ show ps ++ "\n" ++
-                                        "TOTALITY CHECK TIME:\n\n" ++
-                                        show ns_t ++ " " ++ show sc_t ++ "\n\n" ++
                                         "COMPILE TIME:\n\n" ++
                                         show ns ++ " " ++ show sc ++ "\n\n" ++
                                         "RUN TIME:\n\n" ++
@@ -928,42 +939,37 @@
               [(Type, Bool)] -> -- argument types, whether canonical
               [Int] ->  -- inaccessible arguments
               [Either Term (Term, Term)] ->
-              [([Name], Term, Term)] -> -- totality
               [([Name], Term, Term)] -> -- compile time
-              [([Name], Term, Term)] -> -- inlined
               [([Name], Term, Term)] -> -- run time
               Type -> Context -> TC Context
 addCasedef n ei ci@(CaseInfo inline alwaysInline tcdict)
            tcase covering reflect asserted argtys inacc
-           ps_in ps_tot ps_inl ps_ct ps_rt ty uctxt
+           ps_in ps_ct ps_rt ty uctxt
     = do let ctxt = definitions uctxt
              access = case lookupDefAcc n False uctxt of
                            [(_, acc)] -> acc
                            _ -> Public
-         totalityTime <- simpleCase tcase covering reflect CompileTime emptyFC inacc argtys ps_tot ei
          compileTime <- simpleCase tcase covering reflect CompileTime emptyFC inacc argtys ps_ct ei
-         inlined <- simpleCase tcase covering reflect CompileTime emptyFC inacc argtys ps_inl ei
          runtime <- simpleCase tcase covering reflect RunTime emptyFC inacc argtys ps_rt ei
-         ctxt' <- case (totalityTime, compileTime, inlined, runtime) of
-                    (CaseDef args_tot sc_tot _,
-                     CaseDef args_ct sc_ct _,
-                     CaseDef args_inl sc_inl _,
+         ctxt' <- case (compileTime, runtime) of
+                    ( CaseDef args_ct sc_ct _,
                      CaseDef args_rt sc_rt _) ->
                        let inl = alwaysInline -- tcdict
                            inlc = (inl || small n args_ct sc_ct) && (not asserted)
                            inlr = inl || small n args_rt sc_rt
-                           cdef = CaseDefs (args_tot, sc_tot)
-                                           (args_ct, sc_ct)
-                                           (args_inl, sc_inl)
+                           cdef = CaseDefs (args_ct, sc_ct)
                                            (args_rt, sc_rt)
                            op = (CaseOp (ci { case_inlinable = inlc })
-                                                ty argtys ps_in ps_tot cdef,
+                                                ty argtys ps_in ps_ct cdef,
                                  False, access, Unchecked, EmptyMI)
                        in return $ addDef n op ctxt
 --                    other -> tfail (Msg $ "Error adding case def: " ++ show other)
          return uctxt { definitions = ctxt' }
 
--- simplify a definition for totality checking
+-- simplify a definition by inlining
+-- (Note: This used to be for totality checking, and now it's actually a
+-- no-op, but I'm keeping it here because I'll be putting it back with some
+-- more carefully controlled inlining at some stage. --- EB)
 simplifyCasedef :: Name -> ErasureInfo -> Context -> TC Context
 simplifyCasedef n ei uctxt
    = do let ctxt = definitions uctxt
@@ -975,7 +981,7 @@
                              pdef = map debind ps_in'
                          CaseDef args sc _ <- simpleCase False (STerm Erased) False CompileTime emptyFC [] atys pdef ei
                          return $ addDef n (CaseOp ci
-                                              ty atys ps_in' ps (cd { cases_totcheck = (args, sc) }),
+                                              ty atys ps_in' ps (cd { cases_compiletime = (args, sc) }),
                                               inj, acc, tot, metainf) ctxt
 
                    _ -> return ctxt
@@ -989,7 +995,7 @@
                                 (vs, x', y')
     debind (Left x)       = let (vs, x') = depat [] x in
                                 (vs, x', Impossible)
-    simpl (Right (x, y)) = Right (x, simplify uctxt [] y)
+    simpl (Right (x, y)) = Right (x, y) -- inline uctxt [] y)
     simpl t = t
 
 addOperator :: Name -> Type -> Int -> ([Value] -> Maybe Value) ->
diff --git a/src/Idris/Core/Execute.hs b/src/Idris/Core/Execute.hs
--- a/src/Idris/Core/Execute.hs
+++ b/src/Idris/Core/Execute.hs
@@ -6,48 +6,43 @@
 Maintainer  : The Idris Community.
 -}
 
-{-# LANGUAGE PatternGuards, ExistentialQuantification, CPP #-}
+{-# LANGUAGE CPP, ExistentialQuantification, PatternGuards #-}
 {-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
 module Idris.Core.Execute (execute) where
 
 import Idris.AbsSyntax
 import Idris.AbsSyntaxTree
-import IRTS.Lang(FDesc(..), FType(..))
-
-import Idris.Primitives(Prim(..), primitives)
-
-import Idris.Core.TT
-import Idris.Core.Evaluate
 import Idris.Core.CaseTree
-
+import Idris.Core.Evaluate
+import Idris.Core.TT
 import Idris.Error
-
-import Debug.Trace
+import Idris.Primitives (Prim(..), primitives)
+import IRTS.Lang (FDesc(..), FType(..))
 
 import Util.DynamicLinker
 import Util.System
 
 import Control.Applicative hiding (Const)
 import Control.Exception
+import Control.Monad hiding (forM)
 import Control.Monad.Trans
-import Control.Monad.Trans.State.Strict
 import Control.Monad.Trans.Except (ExceptT, runExceptT, throwE)
-import Control.Monad hiding (forM)
-import Data.Maybe
+import Control.Monad.Trans.State.Strict
 import Data.Bits
-import Data.Traversable (forM)
-import Data.Time.Clock.POSIX (getPOSIXTime)
 import qualified Data.Map as M
+import Data.Maybe
+import Data.Time.Clock.POSIX (getPOSIXTime)
+import Data.Traversable (forM)
+import Debug.Trace
+import System.IO
 
 #ifdef IDRIS_FFI
-import Foreign.LibFFI
 import Foreign.C.String
+import Foreign.LibFFI
 import Foreign.Marshal.Alloc (free)
 import Foreign.Ptr
 #endif
 
-import System.IO
-
 #ifndef IDRIS_FFI
 execute :: Term -> Idris Term
 execute tm = fail "libffi not supported, rebuild Idris with -f FFI"
@@ -180,9 +175,9 @@
          [Function _ tm] -> doExec env ctxt tm
          [TyDecl _ _] -> return (EP Ref n EErased) -- abstract def
          [Operator tp arity op] -> return (EP Ref n EErased) -- will be special-cased later
-         [CaseOp _ _ _ _ _ (CaseDefs _ ([], STerm tm) _ _)] -> -- nullary fun
+         [CaseOp _ _ _ _ _ (CaseDefs ([], STerm tm) _)] -> -- nullary fun
              doExec env ctxt tm
-         [CaseOp _ _ _ _ _ (CaseDefs _ (ns, sc) _ _)] -> return (EP Ref n EErased)
+         [CaseOp _ _ _ _ _ (CaseDefs (ns, sc) _)] -> return (EP Ref n EErased)
          [] -> execFail . Msg $ "Could not find " ++ show n ++ " in definitions."
          other | length other > 1 -> execFail . Msg $ "Multiple definitions found for " ++ show n
                | otherwise        -> execFail . Msg . take 500 $ "got to " ++ show other ++ " lookup up " ++ show n
@@ -217,6 +212,7 @@
                               doExec env ctxt ((x:xs) !! i)
 doExec env ctxt Erased = return EErased
 doExec env ctxt Impossible = fail "Tried to execute an impossible case"
+doExec env ctxt (Inferred t) = doExec env ctxt t
 doExec env ctxt (TType u) = return (EType u)
 doExec env ctxt (UType u) = return (EUType u)
 
@@ -275,10 +271,10 @@
                                            execApp env ctxt r (drop arity args)
                       _ -> return (mkEApp f args)
                else return (mkEApp f args)
-         [CaseOp _ _ _ _ _ (CaseDefs _ ([], STerm tm) _ _)] -> -- nullary fun
+         [CaseOp _ _ _ _ _ (CaseDefs ([], STerm tm) _)] -> -- nullary fun
              do rhs <- doExec env ctxt tm
                 execApp env ctxt rhs args
-         [CaseOp _ _ _ _ _ (CaseDefs _ (ns, sc) _ _)] ->
+         [CaseOp _ _ _ _ _ (CaseDefs (ns, sc) _)] ->
              do res <- execCase env ctxt ns sc args
                 return $ fromMaybe (mkEApp f args) res
          thing -> return $ mkEApp f args
@@ -402,6 +398,12 @@
                       "The argument to isNull should be a pointer or file handle or string, but it was " ++
                       show ptr ++
                       ". Are all cases covered?"
+
+    | Just (FFun "idris_disableBuffering" _ _) <- foreignFromTT arity ty fn xs
+       = do execIO $ hSetBuffering stdin NoBuffering
+            execIO $ hSetBuffering stdout NoBuffering
+            execApp env ctxt ioUnit (drop arity xs)
+
 
 -- Right now, there's no way to send command-line arguments to the executor,
 -- so just return 0.
diff --git a/src/Idris/Core/ProofState.hs b/src/Idris/Core/ProofState.hs
--- a/src/Idris/Core/ProofState.hs
+++ b/src/Idris/Core/ProofState.hs
@@ -10,7 +10,7 @@
 evaluation/checking inside the proof system, etc.
 -}
 
-{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, PatternGuards #-}
+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, PatternGuards #-}
 module Idris.Core.ProofState(
     ProofState(..), newProof, envAtFocus, goalAtFocus
   , Tactic(..), Goal(..), processTactic, nowElaboratingPS
@@ -18,20 +18,21 @@
   , keepGiven, getProvenance
   ) where
 
-import Idris.Core.Typecheck
 import Idris.Core.Evaluate
+import Idris.Core.ProofTerm
 import Idris.Core.TT
+import Idris.Core.Typecheck
 import Idris.Core.Unify
-import Idris.Core.ProofTerm
+import Idris.Core.WHNF
 
-import Control.Monad.State.Strict
+import Util.Pretty hiding (fill)
+
 import Control.Applicative hiding (empty)
 import Control.Arrow ((***))
+import Control.Monad.State.Strict
 import Data.List
 import Debug.Trace
 
-import Util.Pretty hiding (fill)
-
 data ProofState = PS { thname            :: Name,
                        holes             :: [Name], -- ^ holes still to be solved
                        usedns            :: [Name], -- ^ used names, don't use again
@@ -81,7 +82,8 @@
             | Compute
             | ComputeLet Name
             | Simplify
-            | HNF_Compute
+            | WHNF_Compute
+            | WHNF_ComputeArgs
             | EvalIn Raw
             | CheckIn Raw
             | Intro (Maybe Name)
@@ -651,7 +653,7 @@
                   Nothing -> x
        let t' = case t of
                     x@(Bind y (Pi _ s _) _) -> x
-                    _ -> hnf ctxt env t
+                    _ -> normalise ctxt env t
        (tyv, tyt) <- lift $ check ctxt env ty
 --        ns <- lift $ unify ctxt env tyv t'
        case t' of
@@ -668,7 +670,7 @@
 intro mn ctxt env (Bind x (Hole t) (P _ x' _)) | x == x' =
     do let t' = case t of
                     x@(Bind y (Pi _ s _) _) -> x
-                    _ -> hnf ctxt env t
+                    _ -> normalise ctxt env t
        case t' of
            Bind y (Pi _ s _) t ->
                let n = case mn of
@@ -825,7 +827,7 @@
 patbind n ctxt env (Bind x (Hole t) (P _ x' _)) | x == x' =
     do let t' = case t of
                     x@(Bind y (PVTy s) t) -> x
-                    _ -> hnf ctxt env t
+                    _ -> normalise ctxt env t
        case t' of
            Bind y (PVTy s) t -> let t' = updsubst y (P Bound n s) t in
                                     return $ Bind n (PVar s) (Bind x (Hole t') (P Bound x t'))
@@ -837,13 +839,18 @@
     do return $ Bind x (Hole (normalise ctxt env ty)) sc
 compute ctxt env t = return t
 
-hnf_compute :: RunTactic
-hnf_compute ctxt env (Bind x (Hole ty) sc) =
-    do let ty' = hnf ctxt env ty in
---          trace ("HNF " ++ show (ty, ty')) $
+whnf_compute :: RunTactic
+whnf_compute ctxt env (Bind x (Hole ty) sc) =
+    do let ty' = whnf ctxt env ty in
            return $ Bind x (Hole ty') sc
-hnf_compute ctxt env t = return t
+whnf_compute ctxt env t = return t
 
+whnf_compute_args :: RunTactic
+whnf_compute_args ctxt env (Bind x (Hole ty) sc) =
+    do let ty' = whnfArgs ctxt env ty in
+           return $ Bind x (Hole ty') sc
+whnf_compute_args ctxt env t = return t
+
 -- reduce let bindings only
 simplify :: RunTactic
 simplify ctxt env (Bind x (Hole ty) sc) =
@@ -1131,7 +1138,8 @@
          mktac (StartUnify n)    = start_unify n
          mktac Compute           = compute
          mktac Simplify          = Idris.Core.ProofState.simplify
-         mktac HNF_Compute       = hnf_compute
+         mktac WHNF_Compute      = whnf_compute
+         mktac WHNF_ComputeArgs  = whnf_compute_args
          mktac (Intro n)         = intro n
          mktac (IntroTy ty n)    = introTy ty n
          mktac (Forall n i t)    = forall n i t
diff --git a/src/Idris/Core/ProofTerm.hs b/src/Idris/Core/ProofTerm.hs
--- a/src/Idris/Core/ProofTerm.hs
+++ b/src/Idris/Core/ProofTerm.hs
@@ -6,7 +6,7 @@
 Maintainer  : The Idris Community.
 -}
 
-{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, PatternGuards #-}
+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, PatternGuards #-}
 module Idris.Core.ProofTerm(
     ProofTerm, Goal(..), mkProofTerm, getProofTerm
   , resetProofTerm
@@ -16,9 +16,9 @@
   , goal, atHole
   ) where
 
-import Idris.Core.Typecheck
 import Idris.Core.Evaluate
 import Idris.Core.TT
+import Idris.Core.Typecheck
 
 import Control.Monad.State.Strict
 import Data.List
diff --git a/src/Idris/Core/TT.hs b/src/Idris/Core/TT.hs
--- a/src/Idris/Core/TT.hs
+++ b/src/Idris/Core/TT.hs
@@ -22,8 +22,8 @@
    * We have a simple collection of tactics which we use to elaborate source
      programs with implicit syntax into fully explicit terms.
 -}
-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, DeriveFunctor,
-             DeriveDataTypeable, DeriveGeneric, PatternGuards #-}
+{-# LANGUAGE DeriveDataTypeable, DeriveFunctor, DeriveGeneric,
+             FunctionalDependencies, MultiParamTypeClasses, PatternGuards #-}
 {-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
 module Idris.Core.TT(
     AppStatus(..), ArithTy(..), Binder(..), Const(..), Ctxt(..)
@@ -38,7 +38,7 @@
   , bindingOf, bindTyArgs, caseName, constDocs, constIsType, deleteDefExact
   , discard, emptyContext, emptyFC, explicitNames, fc_end, fc_fname
   , fc_start, fcIn, fileFC, finalise, fmapMB, forget, forgetEnv
-  , freeNames, getArgTys, getRetTy, implicitable, instantiate, internalNS
+  , freeNames, getArgTys, getRetTy, substRetTy, implicitable, instantiate, internalNS
   , intTyName, isInjective, isTypeConst, lookupCtxt
   , lookupCtxtExact, lookupCtxtName, mapCtxt, mkApp, nativeTyWidth
   , nextName, noOccurrence, nsroot, occurrences
@@ -51,40 +51,39 @@
   , uniqueNameFrom, uniqueNameSet, unList, updateDef, vToP, weakenTm
   ) where
 
+import Util.Pretty hiding (Str)
+
 -- Work around AMP without CPP
-import Prelude (Eq(..), Show(..), Ord(..), Functor(..), Monad(..), String, Int,
-                Integer, Ordering(..), Maybe(..), Num(..), Bool(..), Enum(..),
-                Read(..), FilePath, Double, (&&), (||), ($), (.), div, error, flip,
-                fst, snd, not, mod, read, otherwise)
+import Prelude (Bool(..), Double, Enum(..), Eq(..), FilePath, Functor(..), Int,
+                Integer, Maybe(..), Monad(..), Num(..), Ord(..), Ordering(..),
+                Read(..), Show(..), String, div, error, flip, fst, mod, not,
+                otherwise, read, snd, ($), (&&), (.), (||))
 
-import Control.Applicative (Applicative (..), Alternative)
-import qualified Control.Applicative as A (Alternative (..))
+import Control.Applicative (Alternative, Applicative(..))
+import qualified Control.Applicative as A (Alternative(..))
 import Control.DeepSeq (($!!))
 import Control.Monad.State.Strict
-import Control.Monad.Trans.Except (Except (..))
-import Debug.Trace
-import qualified Data.Map.Strict as Map
+import Control.Monad.Trans.Except (Except(..))
+import Data.Binary hiding (get, put)
+import qualified Data.Binary as B
 import Data.Char
 import Data.Data (Data)
-import Data.Monoid (mconcat)
-import Numeric (showIntAtBase)
-import qualified Data.Text as T
+import Data.Foldable (Foldable)
 import Data.List hiding (group, insert)
-import Data.Set(Set, member, fromList, insert)
+import qualified Data.Map.Strict as Map
 import Data.Maybe (listToMaybe)
-import Data.Foldable (Foldable)
+import Data.Monoid (mconcat)
+import Data.Set (Set, fromList, insert, member)
+import qualified Data.Text as T
 import Data.Traversable (Traversable)
 import Data.Typeable (Typeable)
 import Data.Vector.Unboxed (Vector)
 import qualified Data.Vector.Unboxed as V
-import qualified Data.Binary as B
-import Data.Binary hiding (get, put)
+import Debug.Trace
 import Foreign.Storable (sizeOf)
 import GHC.Generics (Generic)
-
-import Numeric.IEEE (IEEE (identicalIEEE))
-
-import Util.Pretty hiding (Str)
+import Numeric (showIntAtBase)
+import Numeric.IEEE (IEEE(identicalIEEE))
 
 data Option = TTypeInTType
             | CheckConv
@@ -235,7 +234,7 @@
                      | TermPart Term
                      | RawPart Raw
                      | SubReport [ErrorReportPart]
-                       deriving (Show, Eq, Data, Generic, Typeable)
+                       deriving (Show, Eq, Ord, Data, Generic, Typeable)
 
 
 data Provenance = ExpectedType
@@ -243,7 +242,7 @@
                 | InferredVal
                 | GivenVal
                 | SourceTerm Term
-  deriving (Show, Eq, Data, Generic, Typeable)
+  deriving (Show, Eq, Ord, Data, Generic, Typeable)
 {-!
 deriving instance Binary Err
 !-}
@@ -308,7 +307,7 @@
           | RunningElabScript (Err' t) -- ^ The error occurred during a top-level elaboration script
           | ElabScriptStaging Name
           | FancyMsg [ErrorReportPart]
-  deriving (Eq, Functor, Data, Generic, Typeable)
+  deriving (Eq, Ord, Functor, Data, Generic, Typeable)
 
 type Err = Err' Term
 
@@ -821,7 +820,7 @@
          | RType
          | RUType Universe
          | RConstant Const
-  deriving (Show, Eq, Data, Generic, Typeable)
+  deriving (Show, Eq, Ord, Data, Generic, Typeable)
 
 instance Sized Raw where
   size (Var name) = 1
@@ -941,7 +940,7 @@
   size _ = 1
 
 instance Show UExp where
-    show (UVar ns x) 
+    show (UVar ns x)
        | x < 26 = ns ++ "." ++ [toEnum (x + fromEnum 'a')]
        | otherwise = ns ++ "." ++ toEnum ((x `mod` 26) + fromEnum 'a') : show (x `div` 26)
     show (UVal x) = show x
@@ -1009,6 +1008,9 @@
                              -- (-1) is a special case for 'subtract one from BI'
           | Erased -- ^ an erased term
           | Impossible -- ^ special case for totality checking
+          | Inferred (TT n) -- ^ For building case trees when coverage checkimg only.
+                            -- Marks a term as being inferred by the machine, rather than
+                            -- given by the programmer
           | TType UExp -- ^ the type of types at some level
           | UType Universe -- ^ Uniqueness type universe (disjoint from TType)
   deriving (Ord, Functor, Data, Generic, Typeable)
@@ -1056,6 +1058,7 @@
   size (TType u) = 1 + size u
   size (Proj a _) = 1 + size a
   size Impossible = 1
+  size (Inferred t) = size t
   size (UType u) = 1 + size u
 
 instance Pretty a o => Pretty (TT a) o where
@@ -1289,7 +1292,7 @@
   st (Bind x b sc) = Bind x (fmap st b) (st sc)
   st t = t
 
-  eqAlpha as (P _ x _) (P _ y _) 
+  eqAlpha as (P _ x _) (P _ y _)
        = x == y || (x, y) `elem` as || (y, x) `elem` as
   eqAlpha as (V x) (V y) = x == y
   eqAlpha as (Bind x xb xs) (Bind y yb ys)
@@ -1301,7 +1304,7 @@
        = eqAlpha as xt yt && eqAlpha as xv yv
   eqAlphaB as (Guess xt xv) (Guess yt yv)
        = eqAlpha as xt yt && eqAlpha as xv yv
-  eqAlphaB as bx by = eqAlpha as (binderTy bx) (binderTy by) 
+  eqAlphaB as bx by = eqAlpha as (binderTy bx) (binderTy by)
 
 -- | Return number of occurrences of V 0 or bound name i the term
 occurrences :: Eq n => n -> TT n -> Int
@@ -1380,6 +1383,7 @@
 termSmallerThan x (Constant c) = True
 termSmallerThan x Erased = True
 termSmallerThan x Impossible = True
+termSmallerThan x (Inferred t) = termSmallerThan x t
 termSmallerThan x (TType u) = True
 termSmallerThan x (UType u) = True
 
@@ -1422,6 +1426,7 @@
 safeForgetEnv env Erased    = Just $ RConstant Forgot
 safeForgetEnv env (Proj tm i) = error "Don't know how to forget a projection"
 safeForgetEnv env Impossible = error "Don't know how to forget Impossible"
+safeForgetEnv env (Inferred t) = safeForgetEnv env t
 
 -- | Introduce a 'Bind' into the given term for each element of the
 -- given list of (name, binder) pairs.
@@ -1450,6 +1455,14 @@
 getRetTy (Bind n (Pi _ _ _) sc)   = getRetTy sc
 getRetTy sc = sc
 
+-- | As getRetTy but substitutes names for de Bruijn indices
+substRetTy :: TT n -> TT n
+substRetTy (Bind n (PVar ty) sc) = substRetTy (substV (P Ref n ty) sc)
+substRetTy (Bind n (PVTy ty) sc) = substRetTy (substV (P Ref n ty) sc)
+substRetTy (Bind n (Pi _ ty _) sc) = substRetTy (substV (P Ref n ty) sc)
+substRetTy sc = sc
+   
+
 uniqueNameFrom :: [Name] -> [Name] -> Name
 uniqueNameFrom []           hs = uniqueName (nextName (sUN "x")) hs
 uniqueNameFrom (s : supply) hs
@@ -1576,6 +1589,7 @@
     prettySe p env Erased debug = text "[_]"
     prettySe p env (TType i) debug = text "Type" <+> (text . show $ i)
     prettySe p env Impossible debug = text "Impossible"
+    prettySe p env (Inferred tm) debug = text "<" <+> prettySe p env tm debug <+> text ">"
     prettySe p env (UType u) debug = text (show u)
 
     -- Render a `Binder` and its name
@@ -1621,6 +1635,7 @@
     se p env (Constant c) = show c
     se p env Erased = "[__]"
     se p env Impossible = "[impossible]"
+    se p env (Inferred t) = "<" ++ se p env t ++ ">"
     se p env (TType i) = "Type " ++ show i
     se p env (UType u) = show u
 
@@ -1729,6 +1744,7 @@
       text "!" <> text (show i)
     pp p bound Erased = text "<<<erased>>>"
     pp p bound Impossible = text "<<<impossible>>>"
+    pp p bound (Inferred t) = text "<" <+> pp p bound t <+> text ">"
     pp p bound (TType ue) = annotate (AnnType "Type" "The type of types") $
                             text "Type"
     pp p bound (UType u) = text (show u)
diff --git a/src/Idris/Core/Typecheck.hs b/src/Idris/Core/Typecheck.hs
--- a/src/Idris/Core/Typecheck.hs
+++ b/src/Idris/Core/Typecheck.hs
@@ -6,17 +6,17 @@
 Maintainer  : The Idris Community.
 -}
 
-{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, DeriveFunctor,
+{-# LANGUAGE DeriveFunctor, FlexibleInstances, MultiParamTypeClasses,
              PatternGuards #-}
 
 module Idris.Core.Typecheck where
 
+import Idris.Core.Evaluate
+import Idris.Core.TT
+
 import Control.Monad.State
-import Debug.Trace
 import qualified Data.Vector.Unboxed as V (length)
-
-import Idris.Core.TT
-import Idris.Core.Evaluate
+import Debug.Trace
 
 -- To check conversion, normalise each term wrt the current environment.
 -- Since we haven't converted everything to de Bruijn indices yet, we'll have to
@@ -83,7 +83,7 @@
 check :: Context -> Env -> Raw -> TC (Term, Type)
 check ctxt env tm
      -- Holes allowed, so constraint namespace doesn't matter
-     = evalStateT (check' True [] ctxt env tm) (0, []) 
+     = evalStateT (check' True [] ctxt env tm) (0, [])
 
 check' :: Bool -> String -> Context -> Env -> Raw -> StateT UCs TC (Term, Type)
 check' holes tcns ctxt env top = chk (TType (UVar tcns (-5))) Nothing env top where
@@ -116,7 +116,7 @@
            let fty' = case uniqueBinders (map fst env) (finalise fty) of
                         ty@(Bind x (Pi i s k) t) -> ty
                         _ -> uniqueBinders (map fst env)
-                                 $ case hnf ctxt env fty of
+                                 $ case normalise ctxt env fty of
                                      ty@(Bind x (Pi i s k) t) -> ty
                                      _ -> normalise ctxt env fty
            case fty' of
@@ -138,7 +138,7 @@
            let fty' = case uniqueBinders (map fst env) (finalise fty) of
                         ty@(Bind x (Pi i s k) t) -> ty
                         _ -> uniqueBinders (map fst env)
-                                 $ case hnf ctxt env fty of
+                                 $ case normalise ctxt env fty of
                                      ty@(Bind x (Pi i s k) t) -> ty
                                      _ -> normalise ctxt env fty
            (av, aty) <- chk u Nothing env a
@@ -343,7 +343,7 @@
                      StateT [(Name, (UniqueUse, Universe))] TC ()
     chkBinderName env n b
        = do let rawty = forgetEnv (map fst env) (binderTy b)
-            (_, kind) <- lift $ check ctxt env rawty 
+            (_, kind) <- lift $ check ctxt env rawty
             case kind of
                  UType UniqueType -> do ns <- get
                                         if n `elem` borrowed
diff --git a/src/Idris/Core/Unify.hs b/src/Idris/Core/Unify.hs
--- a/src/Idris/Core/Unify.hs
+++ b/src/Idris/Core/Unify.hs
@@ -19,13 +19,13 @@
   , unrecoverable
   ) where
 
-import Idris.Core.TT
 import Idris.Core.Evaluate
+import Idris.Core.TT
 
 import Control.Monad
 import Control.Monad.State.Strict
-import Data.Maybe
 import Data.List
+import Data.Maybe
 import Debug.Trace
 
 -- terms which need to be injective, with the things we're trying to unify
diff --git a/src/Idris/Core/WHNF.hs b/src/Idris/Core/WHNF.hs
--- a/src/Idris/Core/WHNF.hs
+++ b/src/Idris/Core/WHNF.hs
@@ -8,18 +8,19 @@
 
 {-# LANGUAGE PatternGuards #-}
 {-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
-module Idris.Core.WHNF(whnf, WEnv) where
+module Idris.Core.WHNF(whnf, whnfArgs, WEnv) where
 
-import Idris.Core.TT
 import Idris.Core.CaseTree
 import Idris.Core.Evaluate hiding (quote)
 import qualified Idris.Core.Evaluate as Evaluate
+import Idris.Core.TT
 
 import Debug.Trace
 
 -- | A stack entry consists of a term and the environment it is to be
 -- evaluated in (i.e. it's a thunk)
 type StackEntry = (Term, WEnv)
+
 data WEnv = WEnv Int -- number of free variables
                  [(Term, WEnv)]
   deriving Show
@@ -34,10 +35,11 @@
 -- environment it was encountered in, so that when we quote back to a term
 -- we get the substitutions right.
 
-data WHNF = WDCon Int Int Bool Name (Type, WEnv) -- ^ data constructor
+data WHNF = WDCon Int Int Bool Name (Term, WEnv) -- ^ data constructor
           | WTCon Int Int Name (Type, WEnv) -- ^ type constructor
-          | WPRef Name (Type, WEnv) -- ^irreducible global (e.g. a postulate)
-          | WBind Name (Binder Term) (Term, WEnv)
+          | WPRef Name (Term, WEnv) -- ^irreducible global (e.g. a postulate)
+          | WV Int
+          | WBind Name (Binder (Term, WEnv)) (Term, WEnv)
           | WApp WHNF (Term, WEnv)
           | WConstant Const
           | WProj WHNF Int
@@ -46,24 +48,56 @@
           | WErased
           | WImpossible
 
--- | Reduce a *closed* term to weak head normal form.
-whnf :: Context -> Term -> Term
-whnf ctxt tm = quote (do_whnf ctxt (WEnv 0 []) tm)
+-- NOTE: These aren't yet ready to be used in practice - there's still a
+-- bug or two in the handling of de Bruijn indices.
 
-do_whnf :: Context -> WEnv -> Term -> WHNF
-do_whnf ctxt env tm = eval env [] tm
+-- | Reduce a term to weak head normal form.
+whnf :: Context -> Env -> Term -> Term
+-- whnf ctxt env tm = let res = whnf' ctxt env tm in
+--                        trace (show tm ++ "\n==>\n" ++ show res ++ "\n") res
+whnf ctxt env tm = 
+   inlineSmall ctxt env $ -- reduce small things in body. This is primarily
+                          -- to get rid of any noisy "assert_smaller/assert_total"
+                          -- and evaluate any simple operators, which makes things
+                          -- easier to read.
+     whnf' ctxt env tm
+whnf' ctxt env tm = 
+     quote (do_whnf ctxt (map finalEntry env) (finalise tm))
+
+-- | Reduce a type so that all arguments are expanded
+whnfArgs :: Context -> Env -> Term -> Term
+whnfArgs ctxt env tm = inlineSmall ctxt env $ finalise (whnfArgs' ctxt env tm)
+whnfArgs' ctxt env tm
+    = case whnf' ctxt env tm of
+           -- The assumption is that de Bruijn indices refer to local things
+           -- (so not in the external environment) so we need to instantiate
+           -- the name
+           Bind n b@(Pi _ ty _) sc -> 
+                    Bind n b (whnfArgs' ctxt ((n,b):env) 
+                             (subst n (P Bound n ty) sc))
+           res -> tm
+
+finalEntry :: (Name, Binder (TT Name)) -> (Name, Binder (TT Name))
+finalEntry (n, b) = (n, fmap finalise b)
+
+do_whnf :: Context -> Env -> Term -> WHNF
+do_whnf ctxt genv tm = eval (WEnv 0 []) [] tm
   where
     eval :: WEnv -> Stack -> Term -> WHNF
     eval wenv@(WEnv d env) stk (V i)
          | i < length env = let (tm, env') = env !! i in
                                 eval env' stk tm
-         | otherwise = error "Can't happen: WHNF scope error"
+         | otherwise = WV i
     eval wenv@(WEnv d env) stk (Bind n (Let t v) sc)
          = eval (WEnv d ((v, wenv) : env)) stk sc
-    eval (WEnv d env) [] (Bind n b sc) = WBind n b (sc, WEnv (d + 1) env)
-    eval (WEnv d env) ((tm, tenv) : stk) (Bind n b sc)
+    eval (WEnv d env) ((tm, tenv) : stk) (Bind n b@(Lam _) sc)
          = eval (WEnv d ((tm, tenv) : env)) stk sc
+    eval wenv@(WEnv d env) stk (Bind n b sc) -- stk must be empty if well typed
+         =let n' = uniqueName n (map fst genv) in
+              WBind n' (fmap (\t -> (t, wenv)) b) (sc, WEnv (d + 1) env)
 
+    eval env stk (P nt n ty) 
+         | Just (Let t v) <- lookup n genv = eval env stk v
     eval env stk (P nt n ty) = apply env nt n ty stk
     eval env stk (App _ f a) = eval env ((a, env) : stk) f
     eval env stk (Constant c) = unload (WConstant c) stk
@@ -73,30 +107,34 @@
 
     eval env stk Erased = unload WErased stk
     eval env stk Impossible = unload WImpossible stk
+    eval env stk (Inferred tm) = eval env stk tm
     eval env stk (TType u) = unload (WType u) stk
     eval env stk (UType u) = unload (WUType u) stk
 
     apply :: WEnv -> NameType -> Name -> Type -> Stack -> WHNF
-    apply env nt n ty stk
+    apply env nt n ty stk 
           = let wp = case nt of
                           DCon t a u -> WDCon t a u n (ty, env)
                           TCon t a -> WTCon t a n (ty, env)
                           Ref -> WPRef n (ty, env)
                           _ -> WPRef n (ty, env)
                         in
-            case lookupDefExact n ctxt of
-                 Just (CaseOp ci _ _ _ _ cd) ->
-                      let (ns, tree) = cases_compiletime cd in
-                          case evalCase env ns tree stk of
-                               Just w -> w
-                               Nothing -> unload wp stk
-                 Just (Operator _ i op) ->
+            if not (tcReducible n ctxt)
+               then unload wp stk
+               else case lookupDefAccExact n False ctxt of
+                         Just (CaseOp ci _ _ _ _ cd, acc) 
+                             | acc == Public || acc == Hidden ->
+                          let (ns, tree) = cases_compiletime cd in
+                              case evalCase env ns tree stk of
+                                   Just w -> w
+                                   Nothing -> unload wp stk
+                         Just (Operator _ i op, acc) ->
                           if i <= length stk
                              then case runOp env op (take i stk) (drop i stk) of
                                   Just v -> v
                                   Nothing -> unload wp stk
                              else unload wp stk
-                 _ -> unload wp stk
+                         _ -> unload wp stk
 
     unload :: WHNF -> Stack -> WHNF
     unload f [] = f
@@ -112,6 +150,8 @@
                   -- aren't run on constants are themselves pretty ugly
                   -- (it's prim__believe_me and prim__syntacticEq, for
                   -- example) so let's not worry too much...
+                  -- We will need to deal with believe_me before dropping this
+                  -- into the type checker, though.
                   Just val -> Just $ eval env rest (quoteTerm val)
                   _ -> Nothing
 
@@ -189,7 +229,9 @@
 quote (WDCon t a u n (ty, env)) = P (DCon t a u) n (quoteEnv env ty)
 quote (WTCon t a n (ty, env)) = P (TCon t a) n (quoteEnv env ty)
 quote (WPRef n (ty, env)) = P Ref n (quoteEnv env ty)
-quote (WBind n ty (sc, env)) = Bind n ty (quoteEnv env sc)
+quote (WV i) = V i
+quote (WBind n b (sc, env)) = Bind n (fmap (\ (t, env) -> quoteEnv env t) b) 
+                                     (quoteEnv env sc)
 quote (WApp f (a, env)) = App Complete (quote f) (quoteEnv env a)
 quote (WConstant c) = Constant c
 quote (WProj t i) = Proj (quote t) i
@@ -201,10 +243,13 @@
 quoteEnv :: WEnv -> Term -> Term
 quoteEnv (WEnv d ws) tm = qe' d ws tm
   where
+    -- d is number of free variables in the external environment
+    -- (all bound in the scope of 'ws')
     qe' d ts (V i)
-        | i < d = V i
-        | otherwise = let (tm, env) = ts !! (i - d) in
-                          quoteEnv env tm
+        | (i - d) < length ts && (i - d) >= 0
+              = let (tm, env) = ts !! (i - d) in
+                    quoteEnv env tm
+        | otherwise = V i
     qe' d ts (Bind n b sc)
         = Bind n (fmap (qe' d ts) b) (qe' (d + 1) ts sc)
     qe' d ts (App c f a)
diff --git a/src/Idris/Coverage.hs b/src/Idris/Coverage.hs
--- a/src/Idris/Coverage.hs
+++ b/src/Idris/Coverage.hs
@@ -1,921 +1,375 @@
 {-|
 Module      : Idris.Coverage
-Description : The coverage and totality checkers for Idris are in this module.
-Copyright   :
-License     : BSD3
-Maintainer  : The Idris Community.
--}
-{-# LANGUAGE PatternGuards #-}
-module Idris.Coverage where
-
-import Idris.Core.TT
-import Idris.Core.Evaluate
-import Idris.Core.CaseTree
-
-import Idris.AbsSyntax
-import Idris.Delaborate
-import Idris.Error
-import Idris.Output (iWarn, iputStrLn)
-
-import Data.Char
-import Data.List
-import Data.Either
-import Data.Maybe
-import Debug.Trace
-
-import Control.Monad.State.Strict
-
--- | Generate a pattern from an 'impossible' LHS.
---
--- We need this to eliminate the pattern clauses which have been
--- provided explicitly from new clause generation.
-mkPatTm :: PTerm -> Idris Term
-mkPatTm t = do i <- getIState
-               let timp = addImpl' True [] [] [] i t
-               evalStateT (toTT (mapPT deNS timp)) 0
-  where
-    toTT (PRef _ _ n) = do i <- lift getIState
-                           case lookupNameDef n (tt_ctxt i) of
-                                [(n', TyDecl nt _)] -> return $ P nt n' Erased
-                                _ -> return $ P Ref n Erased
-    toTT (PApp _ t args) = do t' <- toTT t
-                              args' <- mapM (toTT . getTm) args
-                              return $ mkApp t' args'
-    toTT (PDPair _ _ _ l _ r) = do l' <- toTT l
-                                   r' <- toTT r
-                                   return $ mkApp (P Ref sigmaCon Erased) [Erased, Erased, l', r']
-    toTT (PPair _ _ _ l r) = do l' <- toTT l
-                                r' <- toTT r
-                                return $ mkApp (P Ref pairCon Erased) [Erased, Erased, l', r']
-    -- For alternatives, pick the first and drop the namespaces. It doesn't
-    -- really matter which is taken since matching will ignore the namespace.
-    toTT (PAlternative _ _ (a : as)) = toTT a
-    toTT _ = do v <- get
-                put (v + 1)
-                return (P Bound (sMN v "imp") Erased)
-
-    deNS (PRef f hl (NS n _)) = PRef f hl n
-    deNS t = t
-
--- | Given a list of LHSs, generate a extra clauses which cover the remaining
--- cases. The ones which haven't been provided are marked 'absurd' so
--- that the checker will make sure they can't happen.
---
--- This will only work after the given clauses have been typechecked and the
--- names are fully explicit!
-genClauses :: FC -> Name -> [Term] -> [PTerm] -> Idris [PTerm]
-genClauses fc n xs given
-   = do i <- getIState
-        let lhs_tms = map (\x -> flattenArgs $ delab' i x True True) xs
-        -- if a placeholder was given, don't bother generating cases for it
-        let lhs_tms' = zipWith mergePlaceholders lhs_tms
-                          (map (stripUnmatchable i) (map flattenArgs given))
-        let lhss = map pUnApply lhs_tms'
-        nty <- case lookupTyExact n (tt_ctxt i) of
-                    Just t -> return (normalise (tt_ctxt i) [] t)
-                    _ -> fail "Can't happen - genClauses, lookupTyExact"
-
-        let argss = transpose lhss
-        let all_args = map (genAll i) (zip (genPH i nty) argss)
-        logCoverage 5 $ "COVERAGE of " ++ show n
-        logCoverage 5 $ "using type " ++ show nty
-        logCoverage 5 $ "non-concrete args " ++ show (genPH i nty)
-
-        logCoverage 5 $ show (lhs_tms, lhss)
-        logCoverage 5 $ "Args are: " ++ show argss
-        logCoverage 5 $ show (map length argss) ++ "\nAll args:\n" ++ show (map length all_args)
-        logCoverage 10 $ "All args are: " ++ show all_args
-        logCoverage 3 $ "Original: \n" ++
-             showSep "\n" (map (\t -> showTmImpls (delab' i t True True)) xs)
-        -- add an infinite supply of explicit arguments to update the possible
-        -- cases for (the return type may be variadic, or function type, so
-        -- there may be more case splitting that the idris_implicits record
-        -- suggests)
-        let parg = case lookupCtxt n (idris_implicits i) of
-                        (p : _) ->
-                          p ++ repeat (PExp 0 [] (sMN 0 "gcarg") Placeholder)
-                        _       -> repeat (pexp Placeholder)
-        let tryclauses = mkClauses parg all_args
-        logCoverage 3 $ show (length tryclauses) ++ " initially to check"
-        logCoverage 2 $ showSep "\n" (map (showTm i) tryclauses)
-        let new = filter (noMatch i) (nub tryclauses)
-        logCoverage 2 $ show (length new) ++ " clauses to check for impossibility"
-        logCoverage 4 $ "New clauses: \n" ++ showSep "\n" (map (showTm i) new)
---           ++ " from:\n" ++ showSep "\n" (map (showImp True) tryclauses)
-        return new
---         return (map (\t -> PClause n t [] PImpossible []) new)
-  where getLHS i term
-            | (f, args) <- unApply term = map (\t -> delab' i t True True) args
-            | otherwise = []
-
-        -- if an argument has a non-concrete type (i.e. it's a function
-        -- that calculates something from a previous argument) we'll also
-        -- need to generate a placeholder pattern for it since it could be
-        -- anything based on earlier values
-        genPH :: IState -> Type -> [Bool]
-        genPH ist (Bind n (Pi _ ty _) sc) = notConcrete ist ty : genPH ist sc
-        genPH ist ty = []
-
-        notConcrete ist t | (P _ n _, args) <- unApply t,
-                           not (isConName n (tt_ctxt ist)) = True
-        notConcrete _ _ = False
-
-        pUnApply (PApp _ f args) = map getTm args
-        pUnApply _ = []
-
-        flattenArgs (PApp fc (PApp _ f as) as')
-             = flattenArgs (PApp fc f (as ++ as'))
-        flattenArgs t = t
-
-        -- Return whether the given clause matches none of the input clauses
-        -- (xs)
-        noMatch i tm = all (\x -> case matchClause i (stripUnmatchable i (delab' i x True True)) tm of
-                                       Right ms -> False
-                                       Left miss -> True) xs
-
-
-        mergePlaceholders :: PTerm -> PTerm -> PTerm
-        mergePlaceholders x Placeholder = Placeholder
-        mergePlaceholders (PApp fc f args) (PApp fc' f' args')
-            = PApp fc' f' (zipWith mergePArg args args')
-           where mergePArg x y = let xtm = mergePlaceholders (getTm x) (getTm y) in
-                                     x { getTm = xtm}
-        mergePlaceholders x _ = x
-
-        mkClauses :: [PArg] -> [[PTerm]] -> [PTerm]
-        mkClauses parg args
-            | all (== [Placeholder]) args = []
-        mkClauses parg args
-            = do args' <- mkArg args
-                 let tm = PApp fc (PRef fc [] n) (zipWith upd args' parg)
-                 return tm
-          where
-            mkArg :: [[PTerm]] -> [[PTerm]]
-            mkArg [] = return []
-            mkArg (a : as) = do a' <- a
-                                as' <- mkArg as
-                                return (a':as')
-
--- | Does this error result rule out a case as valid when coverage checking?
-validCoverageCase :: Context -> Err -> Bool
-validCoverageCase ctxt (CantUnify _ (topx, _) (topy, _) e _ _)
-    = let topx' = normalise ctxt [] topx
-          topy' = normalise ctxt [] topy in
-          not (sameFam topx' topy' || not (validCoverageCase ctxt e))
-  where sameFam topx topy
-            = case (unApply topx, unApply topy) of
-                   ((P _ x _, _), (P _ y _, _)) -> x == y
-                   _ -> False
-validCoverageCase ctxt (InfiniteUnify _ _ _) = False
-validCoverageCase ctxt (CantConvert _ _ _) = False
-validCoverageCase ctxt (At _ e) = validCoverageCase ctxt e
-validCoverageCase ctxt (Elaborating _ _ _ e) = validCoverageCase ctxt e
-validCoverageCase ctxt (ElaboratingArg _ _ _ e) = validCoverageCase ctxt e
-validCoverageCase ctxt _ = True
-
--- | Check whether an error is recoverable in the sense needed for
--- coverage checking.
-recoverableCoverage :: Context -> Err -> Bool
-recoverableCoverage ctxt (CantUnify r (topx, _) (topy, _) e _ _)
-    = let topx' = normalise ctxt [] topx
-          topy' = normalise ctxt [] topy in
-          r || checkRec topx' topy'
-  where -- different notion of recoverable than in unification, since we
-        -- have no metavars -- just looking to see if a constructor is failing
-        -- to unify with a function that may be reduced later
-        checkRec (App _ f a) p@(P _ _ _) = checkRec f p
-        checkRec p@(P _ _ _) (App _ f a) = checkRec p f
-        checkRec fa@(App _ _ _) fa'@(App _ _ _)
-            | (f, as) <- unApply fa,
-              (f', as') <- unApply fa'
-                 = if (length as /= length as')
-                      then checkRec f f'
-                      else checkRec f f' && and (zipWith checkRec as as')
-        checkRec (P xt x _) (P yt y _) = x == y || ntRec xt yt
-        checkRec _ _ = False
-
-        ntRec x y | Ref <- x = True
-                  | Ref <- y = True
-                  | (Bound, Bound) <- (x, y) = True
-                  | otherwise = False -- name is different, unrecoverable
-recoverableCoverage ctxt (At _ e) = recoverableCoverage ctxt e
-recoverableCoverage ctxt (Elaborating _ _ _ e) = recoverableCoverage ctxt e
-recoverableCoverage ctxt (ElaboratingArg _ _ _ e) = recoverableCoverage ctxt e
-recoverableCoverage _ _ = False
-
-genAll :: IState -> (Bool, [PTerm]) -> [PTerm]
-genAll i (addPH, args)
-   = case filter (/=Placeholder) $ fnub $ mergePHs $ fnub (concatMap otherPats (fnub args)) of
-          [] -> [Placeholder]
-          xs -> ph xs
-  where
-    ph ts = if addPH then Placeholder : ts else ts
-
-    -- Merge patterns with placeholders in other patterns, to ensure we've
-    -- covered all possible generated cases
-    -- e.g. if we have (True, _) (False, _) (_, True) (_, False) 
-    -- we should merge these to get (True, True), (False, False)
-    -- (False, True) and (True, False)
-    mergePHs :: [PTerm] -> [PTerm]
-    mergePHs xs = mergePHs' xs xs
-
-    mergePHs' [] all = []
-    mergePHs' (x : xs) all = mergePH x all ++ mergePHs' xs all
-
-    mergePH :: PTerm -> [PTerm] -> [PTerm]
-    mergePH tm [] = []
-    mergePH tm (x : xs) 
-          | Just merged <- mergePTerm tm x = merged : mergePH tm xs
-          | otherwise = mergePH tm xs
-
-    mergePTerm :: PTerm -> PTerm -> Maybe PTerm
-    mergePTerm x Placeholder = Just x
-    mergePTerm Placeholder x = Just x
-    mergePTerm tm@(PRef fc1 hl1 n1) (PRef fc2 hl2 n2)
-          | n1 == n2 = Just tm
-    mergePTerm (PPair fc1 hl1 p1 x1 y1) (PPair fc2 hl2 p2 x2 y2)
-          = do x <- mergePTerm x1 x2
-               y <- mergePTerm y1 y2
-               Just (PPair fc1 hl1 p1 x y)
-    mergePTerm (PDPair fc1 hl1 p1 x1 t1 y1) (PDPair fc2 hl2 p2 x2 t2 y2)
-          = do x <- mergePTerm x1 x2
-               y <- mergePTerm y1 y2
-               t <- mergePTerm t1 t2
-               Just (PDPair fc1 hl1 p1 x t y)
-    mergePTerm (PApp fc1 f1 args1) (PApp fc2 f2 args2)
-          = do fm <- mergePTerm f1 f2
-               margs <- mergeArgs args1 args2
-               Just (PApp fc1 fm margs)
-      where
-        mergeArgs [] [] = Just []
-        mergeArgs (a : as) (b : bs)
-                  = do ma_in <- mergePTerm (getTm a) (getTm b)
-                       let ma = a { getTm = ma_in }
-                       mas <- mergeArgs as bs
-                       Just (ma : mas)
-        mergeArgs _ _ = Nothing
-    mergePTerm x y | x == y = Just x
-                   | otherwise = Nothing
-
-    -- for every constant in a term (at any level) take next one to make sure
-    -- that constants which are not explicitly handled are covered
-    nextConst (PConstant fc c) = PConstant NoFC (nc' c)
-    nextConst o = o
-
-    nc' (I c) = I (c + 1)
-    nc' (BI c) = BI (c + 1)
-    nc' (Fl c) = Fl (c + 1)
-    nc' (B8 c) = B8 (c + 1)
-    nc' (B16 c) = B16 (c + 1)
-    nc' (B32 c) = B32 (c + 1)
-    nc' (B64 c) = B64 (c + 1)
-    nc' (Ch c) = Ch (chr $ ord c + 1)
-    nc' (Str c) = Str (c ++ "'")
-    nc' o = o
-
-    otherPats :: PTerm -> [PTerm]
-    otherPats o@(PRef fc hl n) = ph $ ops fc n [] o
-    otherPats o@(PApp _ (PRef fc hl n) xs) = ph $ ops fc n xs o
-    otherPats o@(PPair fc hls _ l r)
-        = ph $ ops fc pairCon
-                ([pimp (sUN "A") Placeholder True,
-                  pimp (sUN "B") Placeholder True] ++
-                 [pexp l, pexp r]) o
-    otherPats o@(PDPair fc hls p t _ v)
-        = ph $ ops fc sigmaCon
-                ([pimp (sUN "a") Placeholder True,
-                  pimp (sUN "P") Placeholder True] ++
-                 [pexp t,pexp v]) o
-    otherPats o@(PConstant _ c) = ph [o, nextConst o]
-    otherPats arg = return Placeholder
-
-    ops fc n xs o
-        | (TyDecl c@(DCon _ arity _) ty : _) <- lookupDef n (tt_ctxt i)
-            = do xs' <- mapM otherPats (map getExpTm xs)
-                 let p = resugar (PApp fc (PRef fc [] n) (zipWith upd xs' xs))
-                 let tyn = getTy n (tt_ctxt i)
-                 case lookupCtxt tyn (idris_datatypes i) of
-                         (TI ns _ _ _ _ : _) -> p : map (mkPat fc) (ns \\ [n])
-                         _ -> [p]
-    ops fc n arg o = return Placeholder
-
-    getExpTm (PImp _ True _ _ _) = Placeholder -- machine inferred, no point!
-    getExpTm t = getTm t
-
-    -- put it back to its original form
-    resugar (PApp _ (PRef fc hl n) [_,_,t,v])
-      | n == sigmaCon
-        = PDPair fc [] TypeOrTerm (getTm t) Placeholder (getTm v)
-    resugar (PApp _ (PRef fc hl n) [_,_,l,r])
-      | n == pairCon
-        = PPair fc [] IsTerm (getTm l) (getTm r)
-    resugar t = t
-
-    dropForce force (x : xs) i | i `elem` force
-        = upd Placeholder x : dropForce force xs (i + 1)
-    dropForce force (x : xs) i = x : dropForce force xs (i + 1)
-    dropForce _ [] _ = []
-
-
-    getTy n ctxt = case lookupTy n ctxt of
-                          (t : _) -> case unApply (getRetTy t) of
-                                        (P _ tyn _, _) -> tyn
-                                        x -> error $ "Can't happen getTy 1 " ++ show (n, x)
-                          _ -> error "Can't happen getTy 2"
-
-    mkPat fc x = case lookupCtxt x (idris_implicits i) of
-                      (pargs : _)
-                         -> PApp fc (PRef fc [] x) (map (upd Placeholder) pargs)
-                      _ -> error "Can't happen - genAll"
-
-    fnub :: [PTerm] -> [PTerm]
-    fnub xs = fnub' [] xs
-
-    fnub' :: [PTerm] -> [PTerm] -> [PTerm]
-    fnub' acc (x : xs) | x `qelem` acc = fnub' acc (filter (not.(quickEq x)) xs)
-                       | otherwise = fnub' (x : acc) xs
-    fnub' acc [] = acc
-
-    -- quick check for constructor equality
-    quickEq :: PTerm -> PTerm -> Bool
-    quickEq (PConstant _ n) (PConstant _ n') = n == n'
-    quickEq (PRef _ _ n) (PRef _ _ n') = n == n'
-    quickEq (PPair _ _ _ l r) (PPair _ _ _ l' r') = quickEq l l' && quickEq r r'
-    quickEq (PApp _ t as) (PApp _ t' as')
-        | length as == length as'
-           = quickEq t t' && and (zipWith quickEq (map getTm as) (map getTm as'))
-    quickEq Placeholder Placeholder = True
-    quickEq x y = False
-
-    qelem :: PTerm -> [PTerm] -> Bool
-    qelem x [] = False
-    qelem x (y : ys) | x `quickEq` y = True
-                     | otherwise = qelem x ys
-
-
-upd :: t -> PArg' t -> PArg' t
-upd p' p = p { getTm = p' }
-
--- | Check whether function and all descendants cover all cases
--- (partial is okay, as long as it's due to recursion)
-checkAllCovering :: FC -> [Name] -> Name -> Name -> Idris ()
-checkAllCovering fc done top n | not (n `elem` done)
-   = do i <- get
-        case lookupTotal n (tt_ctxt i) of
-             [tot@(Partial NotCovering)] ->
-                    do let msg = show top ++ " is " ++ show tot ++ " due to " ++ show n
-                       putIState i { idris_totcheckfail = (fc, msg) : idris_totcheckfail i }
-                       addIBC (IBCTotCheckErr fc msg)
-             [Partial _] ->
-                case lookupCtxt n (idris_callgraph i) of
-                     [cg] -> mapM_ (checkAllCovering fc (n : done) top)
-                                   (calls cg)
-                     _ -> return ()
-             x -> return () -- stop if total
-checkAllCovering _ _ _ _ = return ()
-
--- | Check if, in a given group of type declarations mut_ns, the
--- constructor cn : ty is strictly positive, and update the context
--- accordingly
-checkPositive :: [Name]       -- ^ the group of type declarations
-              -> (Name, Type) -- ^ the constructor
-              -> Idris Totality
-checkPositive mut_ns (cn, ty')
-    = do i <- getIState
-         let ty = delazy' True (normalise (tt_ctxt i) [] ty')
-         let p = cp i ty
-         let tot = if p then Total (args ty) else Partial NotPositive
-         let ctxt' = setTotal cn tot (tt_ctxt i)
-         putIState (i { tt_ctxt = ctxt' })
-         logCoverage 5 $ "Constructor " ++ show cn ++ " is " ++ show tot ++ " with " ++ show mut_ns
-         addIBC (IBCTotal cn tot)
-         return tot
-  where
-    args t = [0..length (getArgTys t)-1]
-
-    cp i (Bind n (Pi _ aty _) sc)
-         = posArg i aty && cp i sc
-    cp i t | (P _ n' _ , args) <- unApply t,
-             n' `elem` mut_ns = all noRec args
-    cp i _ = True
-
-    posArg ist (Bind _ (Pi _ nty _) sc) = noRec nty && posArg ist sc
-    posArg ist t = posParams ist t
-
-    noRec arg = all (\x -> x `notElem` mut_ns) (allTTNames arg)
-
-    -- If the type appears recursively in a parameter argument, that's
-    -- fine, otherwise if it appears in an argument it's not fine.
-    posParams ist t | (P _ n _, args) <- unApply t
-       = case lookupCtxtExact n (idris_datatypes ist) of
-              Just ti -> checkParamsOK (param_pos ti) 0 args
-              Nothing -> and (map (posParams ist) args)
-    posParams ist t = noRec t
-
-    checkParamsOK ppos i [] = True
-    checkParamsOK ppos i (p : ps)
-          | i `elem` ppos = checkParamsOK ppos (i + 1) ps
-          | otherwise = noRec p && checkParamsOK ppos (i + 1) ps
-
--- | Calculate the totality of a function from its patterns.  Either
--- follow the size change graph (if inductive) or check for
--- productivity (if coinductive)
-calcTotality :: FC -> Name -> [([Name], Term, Term)] -> Idris Totality
-calcTotality fc n pats
-    = do i <- getIState
-         let opts = case lookupCtxt n (idris_flags i) of
-                            [fs] -> fs
-                            _ -> []
-         case mapMaybe (checkLHS i) (map (\ (_, l, r) -> l) pats) of
-            (failure : _) -> return failure
-            _ -> checkSizeChange n
-  where
-    checkLHS i (P _ fn _)
-        = case lookupTotalExact fn (tt_ctxt i) of
-               Just (Partial _) -> return (Partial (Other [fn]))
-               _ -> Nothing
-    checkLHS i (App _ f a) = mplus (checkLHS i f) (checkLHS i a)
-    checkLHS _ _ = Nothing
-
-checkTotality :: [Name] -> FC -> Name -> Idris Totality
-checkTotality path fc n
-    | n `elem` path = return (Partial (Mutual (n : path)))
-    | otherwise = do
-        t <- getTotality n
-        i <- getIState
-        ctxt' <- do ctxt <- getContext
-                    tclift $ simplifyCasedef n (getErasureInfo i) ctxt
-        setContext ctxt'
-        ctxt <- getContext
-        i <- getIState
-        let opts = case lookupCtxt n (idris_flags i) of
-                            [fs] -> fs
-                            _ -> []
-        t' <- case t of
-                Unchecked ->
-                    case lookupDef n ctxt of
-                        [CaseOp _ _ _ _ pats _] ->
-                            do t' <- if AssertTotal `elem` opts
-                                        then return $ Total []
-                                        else calcTotality fc n pats
-                               logCoverage 2 $ "Set to " ++ show t'
-                               setTotality n t'
-                               addIBC (IBCTotal n t')
-                               return t'
-                        [TyDecl (DCon _ _ _) ty] ->
-                            case unApply (getRetTy ty) of
-                              (P _ tyn _, _) -> do
-                                 let ms = case lookupCtxt tyn (idris_datatypes i) of
-                                       [TI _ _ _ _ xs@(_:_)] -> xs
-                                       ts -> [tyn]
-                                 checkPositive ms (n, ty)
-                              _-> return $ Total []
-                        _ -> return $ Total []
-                x -> return x
-        case t' of
-            Total _ -> return t'
-            Productive -> return t'
-            e -> do w <- cmdOptType WarnPartial
-                    if TotalFn `elem` opts
-                       then do totalityError t'; return t'
-                       else do when (w && not (PartialFn `elem` opts)) $
-                                   warnPartial n t'
-                               return t'
-  where
-    totalityError t = do i <- getIState
-                         let msg = show n ++ " is " ++ show t
-                         putIState i { idris_totcheckfail = (fc, msg) : idris_totcheckfail i}
-                         addIBC (IBCTotCheckErr fc msg)
-
-    warnPartial n t
-       = do i <- getIState
-            case lookupDef n (tt_ctxt i) of
-               [x] -> do
-                  iWarn fc . pprintErr i . Msg $ "Warning - " ++ show n ++ " is " ++ show t
---                                ++ "\n" ++ show x
---                   let cg = lookupCtxtName Nothing n (idris_callgraph i)
---                   iputStrLn (show cg)
-
-
-checkDeclTotality :: (FC, Name) -> Idris Totality
-checkDeclTotality (fc, n)
-    = do logCoverage 2 $ "Checking " ++ show n ++ " for totality"
-         i <- getIState
-         let opts = case lookupCtxtExact n (idris_flags i) of
-                              Just fs -> fs
-                              _ -> []
-         when (CoveringFn `elem` opts) $ checkAllCovering fc [] n n
-         t <- checkTotality [] fc n
-         return t
-
--- If the name calls something which is partial, set it as partial
-verifyTotality :: (FC, Name) -> Idris ()
-verifyTotality (fc, n)
-    = do logCoverage 2 $ "Checking " ++ show n ++ "'s descendents are total"
-         ist <- getIState
-         case lookupTotalExact n (tt_ctxt ist) of
-              Just (Total _) -> do
-                 let ns = getNames (tt_ctxt ist)
-
-                 case getPartial ist [] ns of
-                      Nothing -> return ()
-                      Just bad -> do let t' = Partial (Other bad)
-                                     logCoverage 2 $ "Set to " ++ show t'
-                                     setTotality n t'
-                                     addIBC (IBCTotal n t')
-              _ -> return ()
-  where
-    getNames ctxt = case lookupDefExact n ctxt of
-                         Just (CaseOp  _ _ _ _ _ defs)
-                           -> let (top, def) = cases_compiletime defs in
-                                  map fst (findCalls' True def top)
-                         _ -> []
-
-    getPartial ist [] [] = Nothing
-    getPartial ist bad [] = Just bad
-    getPartial ist bad (n : ns)
-        = case lookupTotalExact n (tt_ctxt ist) of
-               Just (Partial _) -> getPartial ist (n : bad) ns
-               _ -> getPartial ist bad ns
-
--- | Calculate the size change graph for this definition
---
--- SCG for a function f consists of a list of:
---    (g, [(a1, sizechange1), (a2, sizechange2), ..., (an, sizechangen)])
---
--- where g is a function called
--- a1 ... an are the arguments of f in positions 1..n of g
--- sizechange1 ... sizechange2 is how their size has changed wrt the input
--- to f
---    Nothing, if the argument is unrelated to the input
-buildSCG :: (FC, Name) -> Idris ()
-buildSCG (_, n) = do
-   ist <- getIState
-   case lookupCtxt n (idris_callgraph ist) of
-       [cg] -> case lookupDefExact n (tt_ctxt ist) of
-           Just (CaseOp _ _ _ pats _ cd) ->
-             let (args, sc) = cases_totcheck cd in
-               do logCoverage 2 $ "Building SCG for " ++ show n ++ " from\n"
-                                ++ show pats ++ "\n" ++ show sc
-                  let newscg = buildSCG' ist n (rights pats) args
-                  logCoverage 5 $ "SCG is: " ++ show newscg
-                  addToCG n ( cg { scg = newscg } )
-           _ -> return () -- CG comes from a type declaration only
-       [] -> logCoverage 5 $ "Could not build SCG for " ++ show n ++ "\n"
-       x -> error $ "buildSCG: " ++ show (n, x)
-
-delazy = delazy' False -- not lazy codata
-delazy' all t@(App _ f a)
-     | (P _ (UN l) _, [_, _, arg]) <- unApply t,
-       l == txt "Force" = delazy' all arg
-     | (P _ (UN l) _, [P _ (UN lty) _, _, arg]) <- unApply t,
-       l == txt "Delay" && (all || lty /= txt "Infinite") = delazy arg
-     | (P _ (UN l) _, [P _ (UN lty) _, arg]) <- unApply t,
-       l == txt "Delayed" && (all || lty /= txt "Infinite") = delazy' all arg
-delazy' all (App s f a) = App s (delazy' all f) (delazy' all a)
-delazy' all (Bind n b sc) = Bind n (fmap (delazy' all) b) (delazy' all sc)
-delazy' all t = t
-
-data Guardedness = Toplevel | Unguarded | Guarded | Delayed
-  deriving Show
-
-buildSCG' :: IState -> Name -> [(Term, Term)] -> [Name] -> [SCGEntry]
-buildSCG' ist topfn pats args = nub $ concatMap scgPat pats where
-  scgPat (lhs, rhs) = let lhs' = delazy lhs
-                          rhs' = delazy rhs
-                          (f, pargs) = unApply (dePat lhs') in
-                            findCalls [] Toplevel (dePat rhs') (patvars lhs')
-                                      (zip pargs [0..])
-
-  -- Under a delay, calls are excluded from the graph - if it's a call to a
-  -- non-total function we'll find that in the final totality check
-  findCalls cases Delayed ap@(P _ n _) pvs args = []
-  findCalls cases guarded ap@(App _ f a) pvs pargs
-     -- under a call to "assert_total", don't do any checking, just believe
-     -- that it is total.
-     | (P _ (UN at) _, [_, _]) <- unApply ap,
-       at == txt "assert_total" = []
-     -- don't go under calls to functions which are asserted total
-     | (P _ n _, _) <- unApply ap,
-       Just opts <- lookupCtxtExact n (idris_flags ist),
-       AssertTotal `elem` opts = []
-     -- under a guarded call to "Delay Infinite", we are 'Delayed', so don't
-     -- check under guarded constructors.
-     | (P _ (UN del) _, [_,_,arg]) <- unApply ap,
-       Guarded <- guarded,
-       del == txt "Delay"
-           = findCalls cases Delayed arg pvs pargs
-     | (P _ n _, args) <- unApply ap,
-       Delayed <- guarded,
-       isConName n (tt_ctxt ist)
-           = -- Still under a 'Delay' and constructor guarded, so check
-             -- just the arguments to the constructor, remaining Delayed
-             concatMap (\x -> findCalls cases guarded x pvs pargs) args
-     | (P _ ifthenelse _, [_, _, t, e]) <- unApply ap,
-       ifthenelse == sNS (sUN "ifThenElse") ["Bool", "Prelude"]
-       -- Continue look inside if...then...else blocks
-       -- TODO: Consider whether we should do this for user defined ifThenElse
-       -- rather than just the one in the Prelude as a special case
-       = findCalls cases guarded t pvs pargs ++
-         findCalls cases guarded e pvs pargs
-     | (P _ n _, args) <- unApply ap,
-       caseName n && n /= topfn,
-       notPartial (lookupTotalExact n (tt_ctxt ist))
-       -- case block - look inside the block, as long as it was covering
-       -- (i.e. not currently set at Partial) to get a more accurate size
-       -- change result from the top level patterns (also to help pass
-       -- information through from guarded corecursion accurately)
-       = concatMap (\x -> findCalls cases Unguarded x pvs pargs) args ++
-             if n `notElem` cases
-                then findCallsCase (n : cases) guarded n args pvs pargs
-                else []
-     | (P _ n _, args) <- unApply ap,
-       Delayed <- guarded
-       -- Under a delayed recursive call just check the arguments
-           = concatMap (\x -> findCalls cases Unguarded x pvs pargs) args
-     | (P _ n _, args) <- unApply ap
-        -- Ordinary call, not under a delay.
-        -- If n is a constructor, set 'args' as Guarded
-        = let nguarded = case guarded of
-                              Unguarded -> Unguarded
-                              x -> if isConName n (tt_ctxt ist)
-                                      then Guarded
-                                      else Unguarded in
-              mkChange n args pargs ++
-                 concatMap (\x -> findCalls cases nguarded x pvs pargs) args
-    where notPartial (Just (Partial NotCovering)) = False
-          notPartial _ = True
-  findCalls cases guarded (App _ f a) pvs pargs
-        = findCalls cases Unguarded f pvs pargs ++ findCalls cases Unguarded a pvs pargs
-  findCalls cases guarded (Bind n (Let t v) e) pvs pargs
-        = findCalls cases Unguarded t pvs pargs ++
-          findCalls cases Unguarded v pvs pargs ++ findCalls cases guarded e (n : pvs) pargs
-  findCalls cases guarded (Bind n t e) pvs pargs
-        = findCalls cases Unguarded (binderTy t) pvs pargs ++
-          findCalls cases guarded e (n : pvs) pargs
-  findCalls cases guarded (P _ f _ ) pvs pargs
-      | not (f `elem` pvs) = [(f, [])]
-  findCalls _ _ _ _ _ = []
-
-  -- Assumption is that names are preserved in the case block (shadowing
-  -- dealt with by the elaborator) so we can just assume the top level names
-  -- are okay for building the size change
-  findCallsCase cases guarded n args pvs pargs
-      = case lookupDefExact n (tt_ctxt ist) of
-           Just (CaseOp _ _ _ pats _ cd) ->
-                concatMap (fccPat cases pvs pargs args guarded) (rights pats)
-           Nothing -> []
-
-  fccPat cases pvs pargs args g (lhs, rhs)
-      = let lhs' = delazy lhs
-            rhs' = delazy rhs
-            (f, pargs_case) = unApply (dePat lhs')
-            -- pargs is a pair of a term, and the argument position that
-            -- term appears in. If any of the arguments to the case block
-            -- are also on the lhs, we also want those patterns to appear
-            -- in the parg list so that we'll spot patterns which are
-            -- smaller than then
-            newpargs = newPArg args pargs
-            -- Now need to update the rhs of the case with the names in the
-            -- outer definition: In rhs', wherever we see what's in pargs_case,
-            -- replace it with the corresponding thing in pargs
-            csubs = zip pargs_case args
-            newrhs = doCaseSubs csubs (dePat rhs')
-            pargs' = pargs ++ addPArg newpargs pargs_case in
-               findCalls cases g newrhs pvs pargs'
-    where
-      doCaseSubs [] tm = tm
-      doCaseSubs ((x, x') : cs) tm
-           = doCaseSubs (subIn x x' cs) (substTerm x x' tm)
-
-      subIn x x' [] = []
-      subIn x x' ((l, r) : cs)
-          = (substTerm x x' l, substTerm x x' r) : subIn x x' cs
-
-  addPArg (Just (t, i) : ts) (t' : ts') = (t', i) : addPArg ts ts'
-  addPArg (Nothing : ts) (t' : ts') = addPArg ts ts'
-  addPArg _ _ = []
-
-  newPArg :: [Term] -> [(Term, Int)] -> [Maybe (Term, Int)]
-  newPArg (t : ts) pargs = case lookup t pargs of
-                                Just i -> Just (t, i) : newPArg ts pargs
-                                Nothing -> Nothing : newPArg ts pargs
-  newPArg [] pargs = []
-
-  expandToArity n args
-     = case lookupTy n (tt_ctxt ist) of
-            [ty] -> expand 0 (normalise (tt_ctxt ist) [] ty) args
-            _ -> args
-     where expand i (Bind n (Pi _ _ _) sc) (x : xs) = x : expand (i + 1) sc xs
-           expand i (Bind n (Pi _ _ _) sc) [] = Just (i, Same) : expand (i + 1) sc []
-           expand i _ xs = xs
-
-  mkChange n args pargs = [(n, expandToArity n (sizes args))]
-    where
-      sizes [] = []
-      sizes (a : as) = checkSize a pargs : sizes as
-
-      -- find which argument in pargs <a> is smaller than, if any
-      checkSize a ((p, i) : ps)
-          | a == p = Just (i, Same)
-          | (P _ (UN as) _, [_,_,arg,_]) <- unApply a,
-            as == txt "assert_smaller" && arg == p
-                  = Just (i, Smaller)
-          | smaller Nothing a (p, Nothing) = Just (i, Smaller)
-          | otherwise = checkSize a ps
-      checkSize a [] = Nothing
-
-      -- the smaller thing we find must be defined in the same group of mutally
-      -- defined types as <a>, and not be coinductive - so carry the type of
-      -- the constructor we've gone under.
-
-      smaller (Just tyn) a (t, Just tyt)
-         | a == t = isInductive (fst (unApply (getRetTy tyn)))
-                                (fst (unApply (getRetTy tyt)))
-      smaller ty a (ap@(App _ f s), _)
-          | (P (DCon _ _ _) n _, args) <- unApply ap
-               = let tyn = getType n in
-                     any (smaller (ty `mplus` Just tyn) a)
-                         (zip args (map toJust (getArgTys tyn)))
-      -- check higher order recursive arguments
-      smaller ty (App _ f s) a = smaller ty f a
-      smaller _ _ _ = False
-
-      toJust (n, t) = Just t
-
-      getType n = case lookupTyExact n (tt_ctxt ist) of
-                       Just ty -> delazy (normalise (tt_ctxt ist) [] ty) -- must exist
-
-      isInductive (P _ nty _) (P _ nty' _) =
-          let (co, muts) = case lookupCtxt nty (idris_datatypes ist) of
-                                [TI _ x _ _ muts] -> (x, muts)
-                                _ -> (False, []) in
-              (nty == nty' || any (== nty') muts) && not co
-      isInductive _ _ = False
-
-  dePat (Bind x (PVar ty) sc) = dePat (instantiate (P Bound x ty) sc)
-  dePat t = t
-
-  patvars (Bind x (PVar _) sc) = x : patvars sc
-  patvars _ = []
-
-checkSizeChange :: Name -> Idris Totality
-checkSizeChange n = do
-   ist <- getIState
-   case lookupCtxt n (idris_callgraph ist) of
-       [cg] -> do let ms = mkMultiPaths ist [] (scg cg)
-                  logCoverage 5 ("Multipath for " ++ show n ++ ":\n" ++
-                            "from " ++ show (scg cg) ++ "\n" ++
-                            show (length ms) ++ "\n" ++
-                            showSep "\n" (map show ms))
-                  logCoverage 6 (show cg)
-                  -- every multipath must have an infinitely descending
-                  -- thread, then the function terminates
-                  -- also need to checks functions called are all total
-                  -- (Unchecked is okay as we'll spot problems here)
-                  let tot = map (checkMP ist n (getArity ist n)) ms
-                  logCoverage 4 $ "Generated " ++ show (length tot) ++ " paths"
-                  logCoverage 5 $ "Paths for " ++ show n ++ " yield " ++
-                       (showSep "\n" (map show (zip ms tot)))
-                  return (noPartial tot)
-       [] -> do logCoverage 5 $ "No paths for " ++ show n
-                return Unchecked
-  where getArity ist n
-          = case lookupTy n (tt_ctxt ist) of
-                 [ty] -> arity (normalise (tt_ctxt ist) [] ty)
-                 _ -> error "Can't happen: checkSizeChange.getArity"
-
-type MultiPath = [SCGEntry]
-
-mkMultiPaths :: IState -> MultiPath -> [SCGEntry] -> [MultiPath]
-mkMultiPaths ist path [] = [reverse path]
-mkMultiPaths ist path cg = concatMap extend cg
-  where extend (nextf, args)
-           | (nextf, args) `inPath` path = [ reverse ((nextf, args) : path) ]
-           | [Unchecked] <- lookupTotal nextf (tt_ctxt ist)
-               = case lookupCtxt nextf (idris_callgraph ist) of
-                    [ncg] -> mkMultiPaths ist ((nextf, args) : path) (scg ncg)
-                    _ -> [ reverse ((nextf, args) : path) ]
-           | otherwise = [ reverse ((nextf, args) : path) ]
-
-        inPath :: SCGEntry -> [SCGEntry] -> Bool
-        inPath f [] = False
-        inPath f (g : gs) = smallerEq f g || f == g || inPath f gs
-
-        smallerEq :: SCGEntry -> SCGEntry -> Bool
-        smallerEq (f, args) (g, args')
-            = f == g && not (null (filter smallers args))
-                     && filter smallers args == filter smallers args'
-        smallers (Just (_, Smaller)) = True
-        smallers _ = False
-
--- If any route along the multipath leads to infinite descent, we're fine.
--- Try a route beginning with every argument.
---   If we reach a point we've been to before, but with a smaller value,
---   that means there is an infinitely descending path from that argument.
-
-checkMP :: IState -> Name -> Int -> MultiPath -> Totality
-checkMP ist topfn i mp = if i > 0
-                     then let paths = (map (tryPath 0 [] mp) [0..i-1]) in
---                               trace ("Paths " ++ show paths) $
-                               collapse paths
-                     else tryPath 0 [] mp 0
-  where
-    tryPath' d path mp arg
-           = let res = tryPath d path mp arg in
-                 trace (show mp ++ "\n" ++ show arg ++ " " ++ show res) res
-
-    mkBig (e, d) = (e, 10000)
-
-    tryPath :: Int -> [((SCGEntry, Int), Int)] -> MultiPath -> Int -> Totality
-    tryPath desc path [] _ = Total []
---     tryPath desc path ((UN "believe_me", _) : _) arg
---             = Partial BelieveMe
-    -- if we get to a constructor, it's fine as long as it's strictly positive
-    tryPath desc path ((f, _) : es) arg
-        | [TyDecl (DCon _ _ _) _] <- lookupDef f (tt_ctxt ist)
-            = case lookupTotalExact f (tt_ctxt ist) of
-                   Just (Total _) -> Unchecked -- okay so far
-                   Just (Partial _) -> Partial (Other [f])
-                   x -> Unchecked -- An error elsewhere, set as Unchecked to make
-                                  -- some progress
-        | [TyDecl (TCon _ _) _] <- lookupDef f (tt_ctxt ist)
-            = Total []
-    tryPath desc path (e@(f, args) : es) arg
-        | [Total a] <- lookupTotal f (tt_ctxt ist) = Total a
-        | e `elem` es && allNothing args = Partial (Mutual [f])
-    tryPath desc path (e@(f, nextargs) : es) arg
-        | [Total a] <- lookupTotal f (tt_ctxt ist) = Total a
-        | [Partial _] <- lookupTotal f (tt_ctxt ist) = Partial (Other [f])
-        | Just d <- lookup (e, arg) path
-            = if desc - d > 0 -- Now lower than when we were last here
-                   then -- trace ("Descent " ++ show (desc - d) ++ " "
-                        --      ++ show (path, e)) $
-                        Total []
-                   else Partial (Mutual (map (fst . fst . fst) path ++ [f]))
-        | e `elem` map (fst . fst) path
-           && not (f `elem` map fst es)
-              = Partial (Mutual (map (fst . fst . fst) path ++ [f]))
-        | [Unchecked] <- lookupTotal f (tt_ctxt ist) =
-            let argspos = zip nextargs [0..]
-                pathres =
-                  do (a, pos) <- argspos
-                     case a of
-                        Nothing -> -- gone up, but if the
-                                   -- rest definitely terminates without any
-                                   -- cycles (including the path so far, which
-                                   -- we take as inaccessible) the path is fine
-                            return $ tryPath 0 (map mkBig (((e, arg), desc) : path)) es pos
-                        Just (nextarg, sc) ->
-                          if nextarg == arg then
-                            case sc of
-                              Same -> return $ tryPath desc (((e, arg), desc) : path)
-                                                       es pos
-                              Smaller -> return $ tryPath (desc+1)
-                                                          (((e, arg), desc) : path)
-                                                          es
-                                                          pos
-                              _ -> trace ("Shouldn't happen " ++ show e) $
-                                      return (Partial Itself)
-                            else return Unchecked in
---                   trace (show (desc, argspos, path, es, pathres)) $
-                   collapse pathres
-
-        | otherwise = Unchecked
-
-allNothing :: [Maybe a] -> Bool
-allNothing xs = null (collapseNothing (zip xs [0..]))
-
-collapseNothing :: [(Maybe a, b)] -> [(Maybe a, b)]
-collapseNothing ((Nothing, t) : xs)
-   = (Nothing, t) : filter (\ (x, _) -> case x of
-                                             Nothing -> False
-                                             _ -> True) xs
-collapseNothing (x : xs) = x : collapseNothing xs
-collapseNothing [] = []
-
-noPartial :: [Totality] -> Totality
-noPartial (Partial p : xs) = Partial p
-noPartial (_ : xs)         = noPartial xs
-noPartial []               = Total []
-
-collapse :: [Totality] -> Totality
-collapse xs = collapse' Unchecked xs
-collapse' def (Total r : xs)   = Total r
-collapse' def (Unchecked : xs) = collapse' def xs
-collapse' def (d : xs)         = collapse' d xs
--- collapse' Unchecked []         = Total []
-collapse' def []               = def
-
-totalityCheckBlock :: Idris ()
-totalityCheckBlock = do
-         ist <- getIState
-         -- Do totality checking after entire mutual block
-         mapM_ (\n -> do logElab 5 $ "Simplifying " ++ show n
-                         ctxt' <- do ctxt <- getContext
-                                     tclift $ simplifyCasedef n (getErasureInfo ist) ctxt
-                         setContext ctxt')
-                 (map snd (idris_totcheck ist))
-         mapM_ buildSCG (idris_totcheck ist)
-         mapM_ checkDeclTotality (idris_totcheck ist)
-         clear_totcheck
+Description : Clause generation for coverage checking
+Copyright   :
+License     : BSD3
+Maintainer  : The Idris Community.
+-}
+{-# LANGUAGE PatternGuards #-}
+module Idris.Coverage(genClauses, validCoverageCase, recoverableCoverage,
+                      mkPatTm) where
+
+import Idris.AbsSyntax
+import Idris.Core.CaseTree
+import Idris.Core.Evaluate
+import Idris.Core.TT
+import Idris.Delaborate
+import Idris.Error
+import Idris.Output (iWarn, iputStrLn)
+
+import Control.Monad.State.Strict
+import Data.Char
+import Data.Either
+import Data.List
+import Data.Maybe
+import Debug.Trace
+
+-- | Generate a pattern from an 'impossible' LHS.
+--
+-- We need this to eliminate the pattern clauses which have been
+-- provided explicitly from new clause generation.
+mkPatTm :: PTerm -> Idris Term
+mkPatTm t = do i <- getIState
+               let timp = addImpl' True [] [] [] i t
+               evalStateT (toTT (mapPT deNS timp)) 0
+  where
+    toTT (PRef _ _ n) = do i <- lift getIState
+                           case lookupNameDef n (tt_ctxt i) of
+                                [(n', TyDecl nt _)] -> return $ P nt n' Erased
+                                _ -> return $ P Ref n Erased
+    toTT (PApp _ t args) = do t' <- toTT t
+                              args' <- mapM (toTT . getTm) args
+                              return $ mkApp t' args'
+    toTT (PDPair _ _ _ l _ r) = do l' <- toTT l
+                                   r' <- toTT r
+                                   return $ mkApp (P Ref sigmaCon Erased) [Erased, Erased, l', r']
+    toTT (PPair _ _ _ l r) = do l' <- toTT l
+                                r' <- toTT r
+                                return $ mkApp (P Ref pairCon Erased) [Erased, Erased, l', r']
+    -- For alternatives, pick the first and drop the namespaces. It doesn't
+    -- really matter which is taken since matching will ignore the namespace.
+    toTT (PAlternative _ _ (a : as)) = toTT a
+    toTT _ = do v <- get
+                put (v + 1)
+                return (P Bound (sMN v "imp") Erased)
+
+    deNS (PRef f hl (NS n _)) = PRef f hl n
+    deNS t = t
+
+-- | Given a list of LHSs, generate a extra clauses which cover the remaining
+-- cases. The ones which haven't been provided are marked 'absurd' so
+-- that the checker will make sure they can't happen.
+--
+-- This will only work after the given clauses have been typechecked and the
+-- names are fully explicit!
+genClauses :: FC -> Name -> [([Name], Term)] -> -- (Argument names, LHS) 
+              [PTerm] -> Idris [PTerm]
+-- No clauses (only valid via elab reflection). We should probably still do
+-- a check here somehow, e.g. that one of the arguments is an obviously
+-- empty type. In practice, this should only really be used for Void elimination.
+genClauses fc n lhs_tms [] = return [] 
+genClauses fc n lhs_tms given
+   = do i <- getIState
+      
+        let lhs_given = zipWith removePlaceholders lhs_tms 
+                            (map (stripUnmatchable i) (map flattenArgs given))
+        
+        logCoverage 5 $ "Building coverage tree for:\n" ++ showSep "\n" (map show (lhs_given))
+        let givenpos = mergePos (map getGivenPos given)
+
+        (cns, ctree_in) <- 
+                         case simpleCase False (UnmatchedCase "Undefined") False
+                              (CoverageCheck givenpos) emptyFC [] []
+                              lhs_given 
+                              (const []) of
+                           OK (CaseDef cns ctree_in _) ->
+                              return (cns, ctree_in)
+                           Error e -> tclift $ tfail $ At fc e
+            
+        let ctree = trimOverlapping (addMissingCons i ctree_in)
+        let (coveredas, missingas) = mkNewClauses (tt_ctxt i) n cns ctree
+        let covered = map (\t -> delab' i t True True) coveredas
+        let missing = filter (\x -> x `notElem` covered) $
+                          map (\t -> delab' i t True True) missingas
+
+        logCoverage 5 $ "Coverage from case tree for " ++ show n ++ ": " ++ show ctree
+        logCoverage 2 $ show (length missing) ++ " missing clauses for " ++ show n
+        logCoverage 3 $ "Missing clauses:\n" ++ showSep "\n" 
+                              (map showTmImpls missing)
+        logCoverage 10 $ "Covered clauses:\n" ++ showSep "\n" 
+                              (map showTmImpls covered)
+        return missing
+    where
+        flattenArgs (PApp fc (PApp _ f as) as')
+             = flattenArgs (PApp fc f (as ++ as'))
+        flattenArgs t = t
+
+getGivenPos :: PTerm -> [Int]
+getGivenPos (PApp _ _ pargs) = getGiven 0 (map getTm pargs)
+  where
+    getGiven i (Placeholder : tms) = getGiven (i + 1) tms
+    getGiven i (_ : tms) = i : getGiven (i + 1) tms
+    getGiven i [] = []
+getGivenPos _ = []
+
+-- Return a list of Ints which are in every list
+mergePos :: [[Int]] -> [Int]
+mergePos [] = []
+mergePos [x] = x
+mergePos (x : xs) = intersect x (mergePos xs)
+
+removePlaceholders :: ([Name], Term) -> PTerm -> ([Name], Term, Term)
+removePlaceholders (ns, tm) ptm = (ns, rp tm ptm, Erased)
+  where
+    rp Erased Placeholder = Erased
+    rp tm Placeholder = Inferred tm
+    rp tm (PApp _ pf pargs)
+       | (tf, targs) <- unApply tm
+           = let tf' = rp tf pf
+                 targs' = zipWith rp targs (map getTm pargs) in
+                 mkApp tf' targs'
+    rp tm (PPair _ _ _ pl pr)
+       | (tf, [tyl, tyr, tl, tr]) <- unApply tm
+           = let tl' = rp tl pl
+                 tr' = rp tr pr in
+                 mkApp tf [Erased, Erased, tl', tr'] 
+    rp tm (PDPair _ _ _ pl pt pr)
+       | (tf, [tyl, tyr, tl, tr]) <- unApply tm
+           = let tl' = rp tl pl
+                 tr' = rp tr pr in
+                 mkApp tf [Erased, Erased, tl', tr'] 
+    rp tm _ = tm
+
+mkNewClauses :: Context -> Name -> [Name] -> SC -> ([Term], [Term])
+mkNewClauses ctxt fn ns sc 
+     = (map (mkPlApp (P Ref fn Erased)) $
+            mkFromSC True (map (\n -> P Ref n Erased) ns) sc,
+        map (mkPlApp (P Ref fn Erased)) $
+            mkFromSC False (map (\n -> P Ref n Erased) ns) sc)
+  where
+    mkPlApp f args = mkApp f (map erasePs args)
+
+    erasePs ap@(App t f a) 
+        | (f, args) <- unApply ap = mkApp f (map erasePs args)
+    erasePs (P _ n _) | not (isConName n ctxt) = Erased
+    erasePs tm = tm
+
+    mkFromSC cov args sc = evalState (mkFromSC' cov args sc) []
+
+    mkFromSC' :: Bool -> [Term] -> SC -> State [[Term]] [[Term]]
+    mkFromSC' cov args (STerm _) 
+        = if cov then return [args] else return [] -- leaf of provided case
+    mkFromSC' cov args (UnmatchedCase _) 
+        = if cov then return [] else return [args] -- leaf of missing case
+    mkFromSC' cov args ImpossibleCase = return []
+    mkFromSC' cov args (Case _ x alts)
+       = do done <- get
+            if (args `elem` done)
+               then return []
+               else do alts' <- mapM (mkFromAlt cov args x) alts 
+                       put (args : done)
+                       return (concat alts')
+    mkFromSC' cov args _ = return [] -- Should never happen
+
+    mkFromAlt :: Bool -> [Term] -> Name -> CaseAlt -> State [[Term]] [[Term]]
+    mkFromAlt cov args x (ConCase c t conargs sc)
+       = let argrep = mkApp (P (DCon t (length args) False) c Erased)
+                            (map (\n -> P Ref n Erased) conargs)
+             args' = map (subst x argrep) args in
+             mkFromSC' cov args' sc
+    mkFromAlt cov args x (ConstCase c sc)
+       = let argrep = Constant c 
+             args' = map (subst x argrep) args in
+             mkFromSC' cov args' sc
+    mkFromAlt cov args x (DefaultCase sc)
+       = mkFromSC' cov args sc
+    mkFromAlt cov _ _ _ = return []
+
+-- Modify the generated case tree (the case tree builder doesn't have access
+-- to the context, so can't do this itself).
+-- Replaces any missing cases with explicit cases for the missing constructors
+addMissingCons :: IState -> SC -> SC
+addMissingCons ist sc = evalState (addMissingConsSt ist sc) 0
+
+addMissingConsSt :: IState -> SC -> State Int SC
+addMissingConsSt ist (Case t n alts) = liftM (Case t n) (addMissingAlts n alts)
+  where
+    addMissingAlt :: CaseAlt -> State Int CaseAlt
+    addMissingAlt (ConCase n i ns sc) 
+         = liftM (ConCase n i ns) (addMissingConsSt ist sc)
+    addMissingAlt (FnCase n ns sc) 
+         = liftM (FnCase n ns) (addMissingConsSt ist sc)
+    addMissingAlt (ConstCase c sc) 
+         = liftM (ConstCase c) (addMissingConsSt ist sc)
+    addMissingAlt (SucCase n sc) 
+         = liftM (SucCase n) (addMissingConsSt ist sc)
+    addMissingAlt (DefaultCase sc) 
+         = liftM DefaultCase (addMissingConsSt ist sc)
+
+    addMissingAlts argn as 
+--          | any hasDefault as = map addMissingAlt as
+         | cons@(n:_) <- mapMaybe collectCons as,
+           Just tyn <- getConType n,
+           Just ti <- lookupCtxtExact tyn (idris_datatypes ist)
+             -- If we've fallen through on this argument earlier, then the
+             -- things which were matched in other cases earlier can't be missing
+             -- cases now
+             = let missing = con_names ti \\ cons in
+                   do as' <- addCases missing as
+                      mapM addMissingAlt as'
+         | consts@(n:_) <- mapMaybe collectConsts as
+             = let missing = nub (map nextConst consts) \\ consts in
+                   mapM addMissingAlt (addCons missing as)
+    addMissingAlts n as = mapM addMissingAlt as
+
+    addCases missing [] = return []
+    addCases missing (DefaultCase rhs : rest)
+       = do missing' <- mapM (genMissingAlt rhs) missing
+            return (mapMaybe id missing' ++ rest)
+    addCases missing (c : rest) 
+       = liftM (c :) $ addCases missing rest
+
+    addCons missing [] = []
+    addCons missing (DefaultCase rhs : rest)
+       = map (genMissingConAlt rhs) missing ++ rest
+    addCons missing (c : rest) = c : addCons missing rest
+
+    genMissingAlt rhs n
+         | Just (TyDecl (DCon tag arity _) ty) <- lookupDefExact n (tt_ctxt ist)
+             = do name <- get
+                  put (name + arity)
+                  let args = map (name +) [0..arity-1]
+                  return $ Just $ ConCase n tag (map (\i -> sMN i "m") args) rhs
+         | otherwise = return Nothing
+
+    genMissingConAlt rhs n = ConstCase n rhs
+
+    collectCons (ConCase n i args sc) = Just n
+    collectCons _ = Nothing
+
+    collectConsts (ConstCase c sc) = Just c
+    collectConsts _ = Nothing
+
+    hasDefault (DefaultCase (UnmatchedCase _)) = False
+    hasDefault (DefaultCase _) = True
+    hasDefault _ = False
+
+    getConType n = do ty <- lookupTyExact n (tt_ctxt ist)
+                      case unApply (getRetTy (normalise (tt_ctxt ist) [] ty)) of
+                           (P _ tyn _, _) -> Just tyn
+                           _ -> Nothing
+    
+    -- for every constant in a term (at any level) take next one to make sure
+    -- that constants which are not explicitly handled are covered
+    nextConst (I c) = I (c + 1)
+    nextConst (BI c) = BI (c + 1)
+    nextConst (Fl c) = Fl (c + 1)
+    nextConst (B8 c) = B8 (c + 1)
+    nextConst (B16 c) = B16 (c + 1)
+    nextConst (B32 c) = B32 (c + 1)
+    nextConst (B64 c) = B64 (c + 1)
+    nextConst (Ch c) = Ch (chr $ ord c + 1)
+    nextConst (Str c) = Str (c ++ "'")
+    nextConst o = o
+
+addMissingConsSt ist sc = return sc
+
+trimOverlapping :: SC -> SC
+trimOverlapping sc = trim [] [] sc
+  where
+    trim :: [(Name, (Name, [Name]))] -> -- Variable - constructor+args already matched
+            [(Name, [Name])] -> -- Variable - constructors which it can't be
+            SC -> SC
+    trim mustbes nots (Case t vn alts)
+       | Just (c, args) <- lookup vn mustbes
+            = Case t vn (trimAlts mustbes nots vn (substMatch (c, args) alts))
+       | Just cantbe <- lookup vn nots
+            = let alts' = filter (notConMatch cantbe) alts in
+                  Case t vn (trimAlts mustbes nots vn alts')
+       | otherwise = Case t vn (trimAlts mustbes nots vn alts)
+    trim cs nots sc = sc
+
+    trimAlts cs nots vn [] = []
+    trimAlts cs nots vn (ConCase cn t args sc : rest)
+        = ConCase cn t args (trim (addMatch vn (cn, args) cs) nots sc) :
+            trimAlts cs (addCantBe vn cn nots) vn rest
+    trimAlts cs nots vn (FnCase n ns sc : rest)
+        = FnCase n ns (trim cs nots sc) : trimAlts cs nots vn rest
+    trimAlts cs nots vn (ConstCase c sc : rest)
+        = ConstCase c (trim cs nots sc) : trimAlts cs nots vn rest
+    trimAlts cs nots vn (SucCase n sc : rest)
+        = SucCase n (trim cs nots sc) : trimAlts cs nots vn rest
+    trimAlts cs nots vn (DefaultCase sc : rest)
+        = DefaultCase (trim cs nots sc) : trimAlts cs nots vn rest
+
+    isConMatch c (ConCase cn t args sc) = c == cn
+    isConMatch _ _ = False
+
+    substMatch :: (Name, [Name]) -> [CaseAlt] -> [CaseAlt]
+    substMatch ca [] = []
+    substMatch (c,args) (ConCase cn t args' sc : _)
+        | c == cn = [ConCase c t args (substNames (zip args' args) sc)]
+    substMatch ca (_:cs) = substMatch ca cs
+
+    substNames [] sc = sc
+    substNames ((n, n') : ns) sc 
+       = substNames ns (substSC n n' sc)
+
+    notConMatch cs (ConCase cn t args sc) = cn `notElem` cs
+    notConMatch cs _ = True
+
+    addMatch vn cn cs = (vn, cn) : cs
+
+    addCantBe :: Name -> Name -> [(Name, [Name])] -> [(Name, [Name])]
+    addCantBe vn cn [] = [(vn, [cn])]
+    addCantBe vn cn ((n, cbs) : nots)
+          | vn == n = ((n, nub (cn : cbs)) : nots)
+          | otherwise = ((n, cbs) : addCantBe vn cn nots)
+
+-- | Does this error result rule out a case as valid when coverage checking?
+validCoverageCase :: Context -> Err -> Bool
+validCoverageCase ctxt (CantUnify _ (topx, _) (topy, _) e _ _)
+    = let topx' = normalise ctxt [] topx
+          topy' = normalise ctxt [] topy in
+          not (sameFam topx' topy' || not (validCoverageCase ctxt e))
+  where sameFam topx topy
+            = case (unApply topx, unApply topy) of
+                   ((P _ x _, _), (P _ y _, _)) -> x == y
+                   _ -> False
+validCoverageCase ctxt (InfiniteUnify _ _ _) = False
+validCoverageCase ctxt (CantConvert _ _ _) = False
+validCoverageCase ctxt (At _ e) = validCoverageCase ctxt e
+validCoverageCase ctxt (Elaborating _ _ _ e) = validCoverageCase ctxt e
+validCoverageCase ctxt (ElaboratingArg _ _ _ e) = validCoverageCase ctxt e
+validCoverageCase ctxt _ = True
+
+-- | Check whether an error is recoverable in the sense needed for
+-- coverage checking.
+recoverableCoverage :: Context -> Err -> Bool
+recoverableCoverage ctxt (CantUnify r (topx, _) (topy, _) e _ _)
+    = let topx' = normalise ctxt [] topx
+          topy' = normalise ctxt [] topy in
+          checkRec topx' topy'
+  where -- different notion of recoverable than in unification, since we
+        -- have no metavars -- just looking to see if a constructor is failing
+        -- to unify with a function that may be reduced later
+        checkRec (App _ f a) p@(P _ _ _) = checkRec f p
+        checkRec p@(P _ _ _) (App _ f a) = checkRec p f
+        checkRec fa@(App _ _ _) fa'@(App _ _ _)
+            | (f, as) <- unApply fa,
+              (f', as') <- unApply fa'
+                 = if (length as /= length as')
+                      then checkRec f f'
+                      else checkRec f f' && and (zipWith checkRec as as')
+        checkRec (P xt x _) (P yt y _) = x == y || ntRec xt yt
+        checkRec _ _ = False
+
+        ntRec x y | Ref <- x = True
+                  | Ref <- y = True
+                  | (Bound, Bound) <- (x, y) = True
+                  | otherwise = False -- name is different, unrecoverable
+recoverableCoverage ctxt (At _ e) = recoverableCoverage ctxt e
+recoverableCoverage ctxt (Elaborating _ _ _ e) = recoverableCoverage ctxt e
+recoverableCoverage ctxt (ElaboratingArg _ _ _ e) = recoverableCoverage ctxt e
+recoverableCoverage _ _ = False
+
diff --git a/src/Idris/DSL.hs b/src/Idris/DSL.hs
--- a/src/Idris/DSL.hs
+++ b/src/Idris/DSL.hs
@@ -10,14 +10,12 @@
 
 module Idris.DSL where
 
-import Data.Generics.Uniplate.Data (transform)
-
 import Idris.AbsSyntax
-
-import Idris.Core.TT
 import Idris.Core.Evaluate
+import Idris.Core.TT
 
 import Control.Monad.State.Strict
+import Data.Generics.Uniplate.Data (transform)
 import Debug.Trace
 
 debindApp :: SyntaxInfo -> PTerm -> PTerm
diff --git a/src/Idris/DeepSeq.hs b/src/Idris/DeepSeq.hs
--- a/src/Idris/DeepSeq.hs
+++ b/src/Idris/DeepSeq.hs
@@ -12,20 +12,20 @@
   , module Idris.Core.DeepSeq
   ) where
 
-import Idris.Core.DeepSeq
-import Idris.Docstrings
-import Idris.Core.TT
 import Idris.AbsSyntaxTree
 import Idris.Colours
+import Idris.Core.DeepSeq
+import Idris.Core.TT
+import Idris.Docstrings
+import qualified Idris.Docstrings as D
+import IRTS.CodegenCommon (OutputType(..))
 import IRTS.Lang (PrimFn(..))
-import IRTS.CodegenCommon (OutputType (..))
-import Util.DynamicLinker
 
-import Control.DeepSeq
-import Network.Socket(PortNumber)
+import Util.DynamicLinker
 
 import qualified Cheapskate.Types as CT
-import qualified Idris.Docstrings as D
+import Control.DeepSeq
+import Network.Socket (PortNumber)
 
 -- These types don't have Generic instances
 instance NFData CT.Options where
diff --git a/src/Idris/Delaborate.hs b/src/Idris/Delaborate.hs
--- a/src/Idris/Delaborate.hs
+++ b/src/Idris/Delaborate.hs
@@ -13,23 +13,22 @@
   , pprintDelabTy, pprintErr, resugar
   ) where
 
-import Util.Pretty
-
 import Idris.AbsSyntax
-import Idris.Core.TT
 import Idris.Core.Evaluate
-import Idris.Docstrings (overview, renderDocstring, renderDocTerm)
+import Idris.Core.TT
+import Idris.Docstrings (overview, renderDocTerm, renderDocstring)
 import Idris.ErrReverse
 
+import Util.Pretty
+
 import Prelude hiding ((<$>))
 
+import Control.Applicative (Alternative((<|>)))
+import Control.Monad.State
 import Data.Generics.Uniplate.Data (transform)
-import Data.Maybe (mapMaybe)
 import Data.List (intersperse, nub)
+import Data.Maybe (mapMaybe)
 import qualified Data.Text as T
-import Control.Applicative (Alternative((<|>)))
-import Control.Monad.State
-
 import Debug.Trace
 
 bugaddr = "https://github.com/idris-lang/Idris-dev/issues"
@@ -81,10 +80,10 @@
 
 -- | Delaborate a term without resugaring
 delab :: IState -> Term -> PTerm
-delab i tm = delab' i tm False False 
+delab i tm = delab' i tm False False
 
 delabMV :: IState -> Term -> PTerm
-delabMV i tm = delab' i tm False True 
+delabMV i tm = delab' i tm False True
 
 -- | Delaborate a term directly, leaving case applications as they are.
 -- We need this for interactive case splitting, where we need access to the
@@ -112,7 +111,7 @@
 delabTy' ist imps tm fullname mvs docases = de [] imps tm
   where
     un = fileFC "(val)"
-    
+
     -- Special case for spotting applications of case functions
     -- (Normally the scrutinee is let-bound, but hole types get normalised,
     -- so they could appear in this form. The scrutinee is always added as
@@ -123,7 +122,7 @@
           | docases
           , isCaseApp sc
           , (P _ cOp _, args@(_:_)) <- unApply sc
-          , Just caseblock <- delabCase env imps (last args) cOp args 
+          , Just caseblock <- delabCase env imps (last args) cOp args
                  = caseblock
 
     de env _ (App _ f a) = deFn env f [a]
@@ -174,6 +173,7 @@
     de env _ (Proj _ _) = error "Delaboration got run-time-only Proj!"
     de env _ Erased = Placeholder
     de env _ Impossible = Placeholder
+    de env _ (Inferred t) = Placeholder
     de env _ (TType i) = PType un
     de env _ (UType u) = PUniverse un u
 
diff --git a/src/Idris/Directives.hs b/src/Idris/Directives.hs
--- a/src/Idris/Directives.hs
+++ b/src/Idris/Directives.hs
@@ -9,11 +9,10 @@
 
 import Idris.AbsSyntax
 import Idris.ASTUtils
-import Idris.Imports
-import Idris.Output (sendHighlighting)
-
 import Idris.Core.Evaluate
 import Idris.Core.TT
+import Idris.Imports
+import Idris.Output (sendHighlighting)
 
 import Util.DynamicLinker
 
diff --git a/src/Idris/Docs.hs b/src/Idris/Docs.hs
--- a/src/Idris/Docs.hs
+++ b/src/Idris/Docs.hs
@@ -5,7 +5,7 @@
 License     : BSD3
 Maintainer  : The Idris Community.
 -}
-{-# LANGUAGE DeriveFunctor, PatternGuards, MultiWayIf #-}
+{-# LANGUAGE DeriveFunctor, MultiWayIf, PatternGuards #-}
 {-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
 module Idris.Docs (
     pprintDocs
@@ -15,19 +15,20 @@
 
 import Idris.AbsSyntax
 import Idris.AbsSyntaxTree
-import Idris.Delaborate
-import Idris.Core.TT
 import Idris.Core.Evaluate
-import Idris.Docstrings (Docstring, emptyDocstring, noDocs, nullDocstring, renderDocstring, DocTerm, renderDocTerm, overview)
+import Idris.Core.TT
+import Idris.Delaborate
+import Idris.Docstrings (DocTerm, Docstring, emptyDocstring, noDocs,
+                         nullDocstring, overview, renderDocTerm,
+                         renderDocstring)
 
 import Util.Pretty
 
 import Prelude hiding ((<$>))
 
 import Control.Arrow (first)
-
-import Data.Maybe
 import Data.List
+import Data.Maybe
 import qualified Data.Text as T
 
 -- TODO: Only include names with public/export accessibility
@@ -48,6 +49,7 @@
              | InterfaceDoc Name d  -- interface docs
                             [FunDoc' d] -- method docs
                             [(Name, Maybe d)] -- parameters and their docstrings
+                            [PTerm] -- parameter constraints
                             [(Maybe Name, PTerm, (d, [(Name, d)]))] -- implementations: name for named implementations, the constraint term, the docs
                             [PTerm] -- sub interfaces
                             [PTerm] -- super interfaces
@@ -139,13 +141,18 @@
              if null args then text "No constructors."
              else nest 4 (text "Constructors:" <> line <>
                           vsep (map (pprintFDWithoutTotality ist False) args))
-pprintDocs ist (InterfaceDoc n doc meths params implementations sub_interfaces super_interfaces ctor)
+pprintDocs ist (InterfaceDoc n doc meths params constraints implementations sub_interfaces super_interfaces ctor)
            = nest 4 (text "Interface" <+> prettyName True (ppopt_impl ppo) [] n <>
                      if nullDocstring doc
                        then empty
                        else line <> renderDocstring (renderDocTerm (pprintDelab ist) (normaliseAll (tt_ctxt ist) [])) doc)
              <> line <$>
              nest 4 (text "Parameters:" <$> prettyParameters)
+
+             <> (if null constraints
+                 then empty
+                 else line <$> nest 4 (text "Constraints:" <$> prettyConstraints))
+
              <> line <$>
              nest 4 (text "Methods:" <$>
                       vsep (map (pprintFDWithTotality ist False) meths))
@@ -232,6 +239,9 @@
     isSubInterface (PPi _   _            _ _ pt)                                           = isSubInterface pt
     isSubInterface _                                                                       = False
 
+    prettyConstraints =
+      cat (punctuate (comma <> space) (map (pprintPTerm ppo params' [] infixes) constraints))
+
     prettyParameters =
       if any (isJust . snd) params
          then vsep (map (\(nm,md) -> prettyName True False params' nm <+> maybe empty (showDoc ist) md) params)
@@ -335,7 +345,7 @@
                      SN _ -> return Nothing
                      _    -> fmap Just $ docFun ctorN
        return $ InterfaceDoc
-                  n docstr mdocs params
+                  n docstr mdocs params (interface_constraints ci)
                   implementations' (map (\(_,tm,_) -> tm) sub_interfaces) super_interfaces
                   ctorDocs
   where
diff --git a/src/Idris/Docstrings.hs b/src/Idris/Docstrings.hs
--- a/src/Idris/Docstrings.hs
+++ b/src/Idris/Docstrings.hs
@@ -14,24 +14,21 @@
   , renderHtml, annotCode, DocTerm(..), renderDocTerm, checkDocstring
   ) where
 
-import qualified Cheapskate as C
-import qualified Cheapskate.Types as CT
-import Cheapskate.Html (renderDoc)
+import Idris.Core.TT (Err, Name, OutputAnnotation(..), Term, TextFormatting(..))
 
 import Util.Pretty
 
-import Idris.Core.TT (OutputAnnotation(..), TextFormatting(..), Name, Term, Err)
-
 import Prelude hiding ((<$>))
 
-import qualified Data.Text as T
-import qualified Data.Foldable as F
+import qualified Cheapskate as C
+import Cheapskate.Html (renderDoc)
+import qualified Cheapskate.Types as CT
 import Data.Foldable (Foldable)
-import Data.Traversable (Traversable)
+import qualified Data.Foldable as F
 import qualified Data.Sequence as S
-
+import qualified Data.Text as T
+import Data.Traversable (Traversable)
 import GHC.Generics (Generic)
-
 import Text.Blaze.Html (Html)
 
 -- | The various kinds of code samples that can be embedded in docs
diff --git a/src/Idris/Elab/AsPat.hs b/src/Idris/Elab/AsPat.hs
--- a/src/Idris/Elab/AsPat.hs
+++ b/src/Idris/Elab/AsPat.hs
@@ -7,12 +7,11 @@
 -}
 module Idris.Elab.AsPat(desugarAs) where
 
-import Idris.Core.TT
 import Idris.AbsSyntax
+import Idris.Core.TT
 
 import Control.Applicative
 import Control.Monad.State.Strict
-
 import Data.Generics.Uniplate.Data (transformM)
 
 -- | Desugar by changing x@y on lhs to let x = y in ... or rhs
diff --git a/src/Idris/Elab/Clause.hs b/src/Idris/Elab/Clause.hs
--- a/src/Idris/Elab/Clause.hs
+++ b/src/Idris/Elab/Clause.hs
@@ -10,58 +10,54 @@
 
 import Idris.AbsSyntax
 import Idris.ASTUtils
+import Idris.Core.CaseTree
+import Idris.Core.Elaborate hiding (Tactic(..))
+import Idris.Core.Evaluate
+import Idris.Core.Execute
+import Idris.Core.TT
+import Idris.Core.Typecheck
+import Idris.Coverage
+import Idris.DataOpts
+import Idris.DeepSeq
+import Idris.Delaborate
+import Idris.Docstrings hiding (Unchecked)
 import Idris.DSL
+import Idris.Elab.AsPat
+import Idris.Elab.Term
+import Idris.Elab.Transform
+import Idris.Elab.Type
+import Idris.Elab.Utils
 import Idris.Error
-import Idris.Delaborate
 import Idris.Imports
-import Idris.Elab.Term
-import Idris.Coverage
-import Idris.DataOpts
-import Idris.Providers
-import Idris.Primitives
 import Idris.Inliner
+import Idris.Output (iRenderResult, iWarn, iputStrLn, pshow, sendHighlighting)
 import Idris.PartialEval
+import Idris.Primitives
+import Idris.Providers
+import Idris.Termination
 import Idris.Transforms
-import Idris.DeepSeq
-import Idris.Output (iputStrLn, pshow, iWarn, iRenderResult, sendHighlighting)
 import IRTS.Lang
 
-import Idris.Elab.AsPat
-import Idris.Elab.Type
-import Idris.Elab.Transform
-import Idris.Elab.Utils
-
-import Idris.Core.TT
-import Idris.Core.Elaborate hiding (Tactic(..))
-import Idris.Core.Evaluate
-import Idris.Core.Execute
-import Idris.Core.Typecheck
-import Idris.Core.CaseTree
-
-import Idris.Docstrings hiding (Unchecked)
 import Util.Pretty hiding ((<$>))
+import Util.Pretty (pretty, text)
 
 import Prelude hiding (id, (.))
-import Control.Category
 
 import Control.Applicative hiding (Const)
+import Control.Category
 import Control.DeepSeq
 import Control.Monad
-import Control.Monad.State.Strict as State
 import qualified Control.Monad.State.Lazy as LState
+import Control.Monad.State.Strict as State
+import Data.Char (isLetter, toLower)
 import Data.List
-import Data.Maybe
-import Data.Word
-
-import Debug.Trace
-
+import Data.List.Split (splitOn)
 import qualified Data.Map as Map
+import Data.Maybe
 import qualified Data.Set as S
 import qualified Data.Text as T
-import Data.Char(isLetter, toLower)
-import Data.List.Split (splitOn)
-
-import Util.Pretty(pretty, text)
+import Data.Word
+import Debug.Trace
 import Numeric
 
 -- | Elaborate a collection of left-hand and right-hand pairs - that is, a
@@ -91,11 +87,16 @@
            cs_elab <- mapM (elabClause info opts)
                            (zip [0..] cs)
            ctxt <- getContext
-           -- pats_raw is the version we'll work with at compile time:
-           -- no simplification or PE
+           -- pats_raw is the basic type checked version, no PE or forcing
+           let optinfo = idris_optimisation ist
            let (pats_in, cs_full) = unzip cs_elab
            let pats_raw = map (simple_lhs ctxt) pats_in
+           -- We'll apply forcing to the left hand side here, so that we don't
+           -- do any unnecessary case splits
+           let pats_forced = map (force_lhs optinfo) pats_raw
+
            logElab 3 $ "Elaborated patterns:\n" ++ show pats_raw
+           logElab 5 $ "Forced patterns:\n" ++ show pats_forced
 
            solveDeferred fc n
 
@@ -114,9 +115,10 @@
            -- If the definition is specialisable, this reduces the
            -- RHS
            pe_tm <- doPartialEval ist tpats
+
            let pats_pe = if petrans
-                            then map (simple_lhs ctxt) pe_tm
-                            else pats_raw
+                            then map (force_lhs optinfo . simple_lhs ctxt) pe_tm
+                            else pats_forced
 
            let tcase = opt_typecase (idris_options ist)
 
@@ -143,11 +145,19 @@
 
            -- addCaseDef builds case trees from <pdef> and <pdef'>
 
-           -- pdef is the compile-time pattern definition.
-           -- This will get further inlined to help with totality checking.
-           let pdef = map (\(ns, lhs, rhs) -> (map fst ns, lhs, rhs)) $ map debind pats_raw
+           -- pdef is the compile-time pattern definition, after forcing
+           -- optimisation applied to LHS
+           let pdef = map (\(ns, lhs, rhs) -> (map fst ns, lhs, rhs)) $ 
+                          map debind pats_forced
+           -- pdef_cov is the pattern definition without forcing, which
+           -- we feed to the coverage checker (we need to know what the
+           -- programmer wrote before forcing erasure)
+           let pdef_cov
+                    = map (\(ns, lhs, rhs) -> (map fst ns, lhs, rhs)) $ 
+                          map debind pats_raw
            -- pdef_pe is the one which will get further optimised
-           -- for run-time, and, partially evaluated
+           -- for run-time, with no forcing optimisation of the LHS because
+           -- the affects erasure. Also, it's partially evaluated
            let pdef_pe = map debind pats_transformed
 
            logElab 5 $ "Initial typechecked patterns:\n" ++ show pats_raw
@@ -176,13 +186,15 @@
            pmissing <-
                    if cov && not (hasDefault pats_raw)
                       then do -- Generate clauses from the given possible cases
-                              missing <- genClauses fc n (map getLHS pdef) cs_full
+                              missing <- genClauses fc n 
+                                                 (map (\ (ns,tm,_) -> (ns, tm)) pdef)
+                                                 cs_full
                               -- missing <- genMissing n scargs sc
-                              missing' <- filterM (checkPossible info fc True n) missing
+                              missing' <- checkPossibles info fc True n missing
                               -- Filter out the ones which match one of the
                               -- given cases (including impossible ones)
                               let clhs = map getLHS pdef
-                              logElab 2 $ "Must be unreachable:\n" ++
+                              logElab 2 $ "Must be unreachable (" ++ show (length missing') ++ "):\n" ++
                                           showSep "\n" (map showTmImpls missing') ++
                                          "\nAgainst: " ++
                                           showSep "\n" (map (\t -> showTmImpls (delab ist t)) (map getLHS pdef))
@@ -191,7 +203,7 @@
                               -- unification may force a variable to take a
                               -- particular form, rather than force a case
                               -- to be impossible.
-                              return (filter (noMatch ist clhs) missing')
+                              return missing' -- (filter (noMatch ist clhs) missing')
                       else return []
            let pcover = null pmissing
 
@@ -233,6 +245,7 @@
            putIState (ist { idris_patdefs = addDef n (force pdef_pe, force pmissing)
                                                 (idris_patdefs ist) })
            let caseInfo = CaseInfo (inlinable opts) (inlinable opts) (dictionary opts)
+
            case lookupTyExact n ctxt of
                Just ty ->
                    do ctxt' <- do ctxt <- getContext
@@ -243,10 +256,8 @@
                                                    (AssertTotal `elem` opts)
                                                    atys
                                                    inacc
-                                                   pats_pe
+                                                   pats_forced
                                                    pdef
-                                                   pdef -- compile time
-                                                   pdef_inl -- inlined
                                                    pdef' ty
                                                    ctxt
                       setContext ctxt'
@@ -282,6 +293,19 @@
            -- all called functions, and fail if any of them are also
            -- 'Partial NotCovering'
            when (CoveringFn `elem` opts) $ checkAllCovering fc [] n n
+           -- Add the 'AllGuarded' flag if it's guaranteed that every
+           -- 'Inf' argument will be guarded by constructors in the result
+           -- (allows productivity check to go under this function)
+           checkIfGuarded n
+           -- If this has %static arguments, cache the names of functions
+           -- it calls for partial evaluation later
+           ist <- getIState
+           let statics = case lookupCtxtExact n (idris_statics ist) of
+                              Just ns -> ns
+                              Nothing -> []
+           when (or statics) $ do getAllNames n
+                                  return ()
+
   where
     noMatch i cs tm = all (\x -> case trim_matchClause i (delab' i x True True) tm of
                                       Right _ -> False
@@ -323,9 +347,13 @@
 
     -- Simplify the left hand side of a definition, to remove any lets
     -- that may have arisen during elaboration
-    simple_lhs ctxt (Right (x, y)) = Right (Idris.Core.Evaluate.simplify ctxt [] x, y)
+    simple_lhs ctxt (Right (x, y)) 
+        = Right (Idris.Core.Evaluate.simplify ctxt [] x, y)
     simple_lhs ctxt t = t
 
+    force_lhs opts (Right (x, y)) = Right (forceWith opts x, y)
+    force_lhs opts t = t
+
     simple_rt ctxt (p, x, y) = (p, x, force (uniqueBinders p
                                                 (rt_simplify ctxt [] y)))
 
@@ -348,6 +376,28 @@
                                 Just t -> return t
                                 Nothing -> ierror (At fc (Msg "No specialisation achieved"))
 
+forceWith :: Ctxt OptInfo -> Term -> Term
+forceWith opts lhs = -- trace (show lhs ++ "\n==>\n" ++ show (force lhs) ++ "\n----") $
+                      force lhs
+  where
+    -- If there's forced arguments, erase them
+    force ap@(App _ _ _)
+       | (fn@(P _ c _), args) <- unApply ap,
+         Just copt <- lookupCtxtExact c opts
+            = let args' = eraseArg 0 (forceable copt) args in
+                  mkApp fn (map force args')
+    force (App t f a)
+       = App t (force f) (force a)
+    -- We might have pat bindings, so go under them
+    force (Bind n b sc) = Bind n b (force sc)
+    -- Everything else, leave it alone
+    force t = t
+
+    eraseArg i fs (n : ns) | i `elem` fs = Erased : eraseArg (i + 1) fs ns
+                           | otherwise = n : eraseArg (i + 1) fs ns
+    eraseArg i _ [] = []
+
+
 -- | Find 'static' applications in a term and partially evaluate them.
 -- Return any new transformation rules
 elabPE :: ElabInfo -> FC -> Name -> Term -> Idris [(Term, Term)]
@@ -376,8 +426,8 @@
     mkSpecialised specapp_in = do
         ist <- getIState
         ctxt <- getContext
-        let (specTy, specapp) = getSpecTy ist specapp_in
-        let (n, newnm, specdecl) = getSpecClause ist specapp
+        (specTy, specapp) <- getSpecTy ist specapp_in
+        let (n, newnm, specdecl) = getSpecClause ist specapp specTy
         let lhs = pe_app specdecl
         let rhs = pe_def specdecl
         let undef = case lookupDefExact newnm ctxt of
@@ -404,21 +454,22 @@
                 let opts = [Specialise ((if pe_simple specdecl
                                             then map (\x -> (x, Nothing)) cgns'
                                             else []) ++
-                                         (n, Just maxred) : specnames ++ 
+                                         (n, Just maxred) : specnames ++
                                              concat descs)]
                 logElab 3 $ "Specialising application: " ++ show specapp
-                              ++ " in " ++ show caller ++
-                              " with " ++ show opts
+                              ++ "\n in \n" ++ show caller ++
+                              "\n with \n" ++ show opts
+                              ++ "\nCalling: " ++ show cgns
                 logElab 3 $ "New name: " ++ show newnm
                 logElab 3 $ "PE definition type : " ++ (show specTy)
                             ++ "\n" ++ show opts
-                logElab 5 $ "PE definition " ++ show newnm ++ ":\n" ++
+                logElab 2 $ "PE definition " ++ show newnm ++ ":\n" ++
                              showSep "\n"
                                 (map (\ (lhs, rhs) ->
                                   (showTmImpls lhs ++ " = " ++
                                    showTmImpls rhs)) (pe_clauses specdecl))
 
-                logElab 2 $ show n ++ " transformation rule: " ++
+                logElab 5 $ show n ++ " transformation rule: " ++
                            showTmImpls rhs ++ " ==> " ++ showTmImpls lhs
 
                 elabType info defaultSyntax emptyDocstring [] fc opts newnm NoFC specTy
@@ -434,16 +485,18 @@
           -- if it doesn't work, just don't specialise. Could happen for lots
           -- of valid reasons (e.g. local variables in scope which can't be
           -- lifted out).
-          (\e -> do logElab 3 $ "Couldn't specialise: " ++ (pshow ist e)
+          (\e -> do logElab 5 $ "Couldn't specialise: " ++ (pshow ist e)
                     return [])
 
     hiddenToPH (PHidden _) = Placeholder
     hiddenToPH x = x
 
-    specName simpl (ImplicitS, tm)
+    specName simpl (ImplicitS _, tm)
         | (P Ref n _, _) <- unApply tm = Just (n, Just (if simpl then 1 else 0))
     specName simpl (ExplicitS, tm)
         | (P Ref n _, _) <- unApply tm = Just (n, Just (if simpl then 1 else 0))
+    specName simpl (ConstraintS, tm) 
+        | (P Ref n _, _) <- unApply tm = Just (n, Just (if simpl then 1 else 0))
     specName simpl _ = Nothing
 
     -- get the descendants of the name 'n' which are marked %static
@@ -454,7 +507,7 @@
                           i <- getIState
                           let statics = filter (staticFn i) ns
                           return (map (\n -> (n, Nothing)) statics)
-        
+
     staticFn :: IState -> Name -> Bool
     staticFn i n =  case lookupCtxt n (idris_flags i) of
                             [opts] -> elem StaticFn opts
@@ -464,7 +517,7 @@
                            Just s -> not (or s)
                            _ -> True
 
-    concreteArg ist (ImplicitS, tm) = concreteTm ist tm
+    concreteArg ist (ImplicitS _, tm) = concreteTm ist tm
     concreteArg ist (ExplicitS, tm) = concreteTm ist tm
     concreteArg ist _ = True
 
@@ -484,18 +537,18 @@
               [ty] -> let (specty_in, args') = specType args (explicitNames ty)
                           specty = normalise (tt_ctxt ist) [] (finalise specty_in)
                           t = mkPE_TyDecl ist args' (explicitNames specty) in
-                          (t, (n, args'))
+                          return (t, (n, args'))
 --                             (normalise (tt_ctxt ist) [] (specType args ty))
-              _ -> error "Can't happen (getSpecTy)"
+              _ -> ifail $ "Ambiguous name " ++ show n ++ " (getSpecTy)"
 
     -- get the clause of a specialised application
-    getSpecClause ist (n, args)
+    getSpecClause ist (n, args) specTy
        = let newnm = sUN ("PE_" ++ show (nsroot n) ++ "_" ++
                                qhash 5381 (showSep "_" (map showArg args))) in
                                -- UN (show n ++ show (map snd args)) in
-             (n, newnm, mkPE_TermDecl ist newnm n args)
+             (n, newnm, mkPE_TermDecl ist newnm n specTy args)
       where showArg (ExplicitS, n) = qshow n
-            showArg (ImplicitS, n) = qshow n
+            showArg (ImplicitS _, n) = qshow n
             showArg _ = ""
 
             qshow (Bind _ _ _) = "fn"
@@ -511,14 +564,18 @@
             qhash hash (x:xs) = qhash (hash * 33 + fromIntegral(fromEnum x)) xs
 
 -- | Checks if the clause is a possible left hand side.
-checkPossible :: ElabInfo -> FC -> Bool -> Name -> PTerm -> Idris Bool
+-- NOTE: A lot of this is repeated for reflected definitions in Idris.Elab.Term
+-- One day, these should be merged, but until then remember that if you edit
+-- this you might need to edit the other version...
+checkPossible :: ElabInfo -> FC -> Bool -> Name -> PTerm -> Idris (Maybe PTerm)
 checkPossible info fc tcgen fname lhs_in
    = do ctxt <- getContext
         i <- getIState
         let lhs = addImplPat i lhs_in
+        logElab 10 $ "Trying missing case: " ++ showTmImpls lhs
         -- if the LHS type checks, it is possible
         case elaborate (constraintNS info) ctxt (idris_datatypes i) (idris_name i) (sMN 0 "patLHS") infP initEState
-                            (erun fc (buildTC i info ELHS [] fname
+                            (erun fc (buildTC i info EImpossible [] fname
                                                 (allNamesIn lhs_in)
                                                 (infTerm lhs))) of
             OK (ElabResult lhs' _ _ ctxt' newDecls highlights newGName, _) ->
@@ -526,15 +583,63 @@
                   processTacticDecls info newDecls
                   sendHighlighting highlights
                   updateIState $ \i -> i { idris_name = newGName }
-                  let lhs_tm = orderPats (getInferTerm lhs')
-                  case recheck (constraintNS info) ctxt' [] (forget lhs_tm) lhs_tm of
-                       OK _ -> return True
-                       err -> return False
+                  let lhs_tm = normalise ctxt [] (orderPats (getInferTerm lhs'))
+                  let emptyPat = hasEmptyPat ctxt (idris_datatypes i) lhs_tm
+                  if emptyPat then 
+                     do logElab 10 $ "Empty type in pattern "
+                        return Nothing
+                    else
+                      case recheck (constraintNS info) ctxt' [] (forget lhs_tm) lhs_tm of
+                           OK (tm, _, _) -> 
+                                    do logElab 10 $ "Valid " ++ show tm ++ "\n"
+                                                 ++ " from " ++ show lhs
+                                       return (Just (delab' i tm True True))
+                           err -> do logElab 10 $ "Conversion failure"
+                                     return Nothing
             -- if it's a recoverable error, the case may become possible
-            Error err -> if tcgen then return (recoverableCoverage ctxt err)
-                                  else return (validCoverageCase ctxt err ||
+            Error err -> do logLvl 10 $ "Impossible case " ++ (pshow i err)
+                            -- tcgen means that it was generated by genClauses,
+                            -- so only looking for an error. Otherwise, it
+                            -- needs to be the right kind of error (a type mismatch
+                            -- in the same family).
+                            if tcgen then returnTm i err (recoverableCoverage ctxt err)
+                                  else returnTm i err (validCoverageCase ctxt err ||
                                                  recoverableCoverage ctxt err)
+  where returnTm i err True = do logLvl 10 $ "Possibly resolvable error on " ++ 
+                                    pshow i (fmap (normalise (tt_ctxt i) []) err)
+                                              ++ " on " ++ showTmImpls lhs_in
+                                 return $ Just lhs_in
+        returnTm i err False = return $ Nothing
 
+-- Filter out the terms which are not well type left hand sides. Whenever we
+-- eliminate one, also eliminate later ones which match it without checking,
+-- because they're obviously going to have the same result
+checkPossibles :: ElabInfo -> FC -> Bool -> Name -> [PTerm] -> Idris [PTerm]
+checkPossibles info fc tcgen fname (lhs : rest)
+   = do ok <- checkPossible info fc tcgen fname lhs
+        i <- getIState
+        -- Hypothesis: any we can remove will be within the next few, because
+        -- leftmost patterns tend to change less
+        -- Since the match could take a while if there's a lot of cases to
+        -- check, just remove from the next batch
+        let rest' = filter (\x -> not (qmatch x lhs)) (take 200 rest) ++ drop 200 rest
+        restpos <- checkPossibles info fc tcgen fname rest'
+        case ok of 
+             Nothing -> return restpos 
+             Just lhstm -> return (lhstm : restpos)
+  where
+    qmatch _ Placeholder = True
+    qmatch (PApp _ f args) (PApp _ f' args')
+       | length args == length args'
+            = qmatch f f' && and (zipWith qmatch (map getTm args)
+                                                 (map getTm args'))
+    qmatch (PRef _ _ n) (PRef _ _ n') = n == n'
+    qmatch (PPair _ _ _ l r) (PPair _ _ _ l' r') = qmatch l l' && qmatch r r' 
+    qmatch (PDPair _ _ _ l t r) (PDPair _ _ _ l' t' r') 
+          = qmatch l l' && qmatch t t' && qmatch r r' 
+    qmatch x y = x == y
+checkPossibles _ _ _ _ [] = return []
+
 findUnique :: Context -> Env -> Term -> [Name]
 findUnique ctxt env (Bind n b sc)
    = let rawTy = forgetEnv (map fst env) (binderTy b)
@@ -547,6 +652,34 @@
                  else findUnique ctxt ((n, b) : env) sc
 findUnique _ _ _ = []
 
+getUnfolds (UnfoldIface n ns : _) = Just (n, ns)
+getUnfolds (_ : xs) = getUnfolds xs
+getUnfolds [] = Nothing
+
+-- Unfold the given name, interface methdods, and any function which uses it as
+-- an argument directly. This is specifically for finding applications of
+-- interface dictionaries and inlining them both for totality checking and for
+-- a small performance gain.
+getNamesToUnfold :: Name -> [Name] -> Term -> [Name]
+getNamesToUnfold iname ms tm = nub $ iname : getNames Nothing tm ++ ms
+  where
+    getNames under fn@(App _ _ _)
+        | (f, args) <- unApply fn
+             = let under' = case f of
+                                 P _ fn _ -> Just fn
+                                 _ -> Nothing 
+                              in
+                   getNames under f ++ concatMap (getNames under') args
+    getNames (Just under) (P _ ref _)
+        = if ref == iname then [under] else []
+    getNames under (Bind n (Let t v) sc) 
+        = getNames Nothing t ++
+          getNames Nothing v ++
+          getNames Nothing sc
+    getNames under (Bind n b sc) = getNames Nothing (binderTy b) ++
+                                   getNames Nothing sc
+    getNames _ _ = []
+
 -- | Return the elaborated LHS/RHS, and the original LHS with implicits added
 elabClause :: ElabInfo -> FnOpts -> (Int, PClause) ->
               Idris (Either Term (Term, Term), PTerm)
@@ -556,12 +689,12 @@
         let lhs = addImpl [] i lhs_in
         b <- checkPossible info fc tcgen fname lhs_in
         case b of
-            True -> tclift $ tfail (At fc
-                                (Msg $ show lhs_in ++ " is a valid case"))
-            False -> do ptm <- mkPatTm lhs_in
-                        logElab 5 $ "Elaborated impossible case " ++ showTmImpls lhs ++
-                                    "\n" ++ show ptm
-                        return (Left ptm, lhs)
+            Just _ -> tclift $ tfail (At fc
+                                 (Msg $ show lhs_in ++ " is a valid case"))
+            Nothing -> do ptm <- mkPatTm lhs_in
+                          logElab 5 $ "Elaborated impossible case " ++ showTmImpls lhs ++
+                                      "\n" ++ show ptm
+                          return (Left ptm, lhs)
 elabClause info opts (cnum, PClause fc fname lhs_in_as withs rhs_in_as whereblock)
    = do let tcgen = Dictionary `elem` opts
         push_estack fname False
@@ -630,7 +763,7 @@
                                then recheckC_borrowing False (PEGenerated `notElem` opts)
                                                        [] (constraintNS info) fc id [] lhs_tm
                                else return (lhs_tm, lhs_ty)
-        let clhs = Idris.Core.Evaluate.simplify ctxt [] clhs_c
+        let clhs = normalise ctxt [] clhs_c
         let borrowed = borrowedNames [] clhs
 
         -- These are the names we're not allowed to use on the RHS, because
@@ -685,7 +818,7 @@
         logElab 2 $ "RHS: " ++ show (map fst newargs_all) ++ " " ++ showTmImpls rhs
         ctxt <- getContext -- new context with where block added
         logElab 5 "STARTING CHECK"
-        ((rhs', defer, holes, is, probs, ctxt', newDecls, highlights, newGName), _) <-
+        ((rhsElab, defer, holes, is, probs, ctxt', newDecls, highlights, newGName), _) <-
            tclift $ elaborate (constraintNS info) ctxt (idris_datatypes i) (idris_name i) (sMN 0 "patRHS") clhsty initEState
                     (do pbinds ist lhs_tm
                         -- proof search can use explicitly written names
@@ -714,7 +847,19 @@
         when inf $ addTyInfConstraints fc (map (\(x,y,_,_,_,_,_) -> (x,y)) probs)
 
         logElab 5 "DONE CHECK"
-        logElab 4 $ "---> " ++ show rhs'
+        logElab 3 $ "---> " ++ show rhsElab
+        ctxt <- getContext
+        
+        let rhs' = case getUnfolds opts of
+                        Just (n, ms) -> 
+                           let ns = getNamesToUnfold n ms rhsElab in
+                               unfold ctxt [] (map (\n -> (n, 1)) ns) rhsElab
+                        _ -> rhsElab
+        
+        logElab 5 $ "----- " ++ show (getUnfolds opts) ++
+                    "\nUnfolded " ++ show rhsElab ++ "\n" ++
+                    "to " ++ show rhs'
+
         when (not (null defer)) $ logElab 1 $ "DEFERRED " ++
                     show (map (\ (n, (_,_,t,_)) -> (n, t)) defer)
 
@@ -767,14 +912,17 @@
             Error e -> ierror (At fc (CantUnify False (clhsty, Nothing) (crhsty, Nothing) e [] 0))
         i <- getIState
         checkInferred fc (delab' i crhs True True) rhs
-        -- if the function is declared '%error_reverse', or its type,
+        -- if the function is declared '%error_reverse',
         -- then we'll try running it in reverse to improve error messages
+        -- Also if the type is '%error_reverse' and the LHS is smaller than
+        -- the RHS
         let (ret_fam, _) = unApply (getRetTy crhsty)
         rev <- case ret_fam of
                     P _ rfamn _ ->
                         case lookupCtxt rfamn (idris_datatypes i) of
                              [TI _ _ dopts _ _] ->
-                                 return (DataErrRev `elem` dopts)
+                                 return (DataErrRev `elem` dopts &&
+                                         size clhs <= size crhs)
                              _ -> return False
                     _ -> return False
 
@@ -872,13 +1020,15 @@
         let ret_ty = getRetTy (explicitNames (normalise ctxt [] lhs_ty))
         let static_names = getStaticNames i lhs_tm
         logElab 5 (show lhs_tm ++ "\n" ++ show static_names)
-        (clhs, clhsty) <- recheckC (constraintNS info) fc id [] lhs_tm
+        (clhs_c, clhsty) <- recheckC (constraintNS info) fc id [] lhs_tm
+        let clhs = normalise ctxt [] clhs_c
+
         logElab 5 ("Checked " ++ show clhs)
         let bargs = getPBtys (explicitNames (normalise ctxt [] lhs_tm))
         let wval = rhs_trans info $ addImplBound i (map fst bargs) wval_in
         logElab 5 ("Checking " ++ showTmImpls wval)
         -- Elaborate wval in this context
-        ((wval', defer, is, ctxt', newDecls, highlights, newGName), _) <-
+        ((wvalElab, defer, is, ctxt', newDecls, highlights, newGName), _) <-
             tclift $ elaborate (constraintNS info) ctxt (idris_datatypes i) (idris_name i) (sMN 0 "withRHS")
                         (bindTyArgs PVTy bargs infP) initEState
                         (do pbinds i lhs_tm
@@ -900,8 +1050,19 @@
         let def'' = map (\(n, (i, top, t, ns)) -> (n, (i, top, t, ns, False, True))) def'
         addDeferred def''
         mapM_ (elabCaseBlock info opts) is
+
+        let wval' = case getUnfolds opts of
+                        Just (n, ms) -> 
+                           let ns = getNamesToUnfold n ms wvalElab in
+                             unfold ctxt [] (map (\n -> (n, 1)) ns) wvalElab
+                        _ -> wvalElab
+        
         logElab 5 ("Checked wval " ++ show wval')
+        logElab 5 $ "----- " ++ show (getUnfolds opts) ++
+                    "\nUnfolded wval " ++ show wvalElab ++ "\n" ++
+                    "to " ++ show wval'
 
+
         ctxt <- getContext
         (cwval, cwvalty) <- recheckC (constraintNS info) fc id [] (getInferTerm wval')
         let cwvaltyN = explicitNames (normalise ctxt [] cwvalty)
@@ -971,9 +1132,13 @@
         wb <- mapM (mkAuxC mpn wname lhs (map fst bargs_pre) (map fst bargs_post))
                        withblock
         logElab 3 ("with block " ++ show wb)
-        -- propagate totality assertion to the new definitions
-        setFlags wname [Inlinable]
-        when (AssertTotal `elem` opts) $ setFlags wname [Inlinable, AssertTotal]
+        -- propagate totality assertion and unfold flags to the new definitions
+        let uflags = case getUnfolds opts of
+                          Just (n, ns) -> [UnfoldIface n ns]
+                          _ -> []
+        setFlags wname ([Inlinable] ++ uflags)
+        when (AssertTotal `elem` opts) $ 
+           setFlags wname ([Inlinable, AssertTotal] ++ uflags)
         i <- getIState
         let rhstrans' = updateWithTerm i mpn wname lhs (map fst bargs_pre) (map fst (bargs_post))
                              . rhs_trans info
@@ -993,7 +1158,7 @@
         logElab 5 ("New RHS " ++ showTmImpls rhs)
         ctxt <- getContext -- New context with block added
         i <- getIState
-        ((rhs', defer, is, ctxt', newDecls, highlights, newGName), _) <-
+        ((rhsElab, defer, is, ctxt', newDecls, highlights, newGName), _) <-
            tclift $ elaborate (constraintNS info) ctxt (idris_datatypes i) (idris_name i) (sMN 0 "wpatRHS") clhsty initEState
                     (do pbinds i lhs_tm
                         setNextName
@@ -1003,9 +1168,22 @@
                         tt <- get_term
                         return (tt, d, is, ctxt', newDecls, highlights, newGName))
         setContext ctxt'
+        
         processTacticDecls info newDecls
         sendHighlighting highlights
         updateIState $ \i -> i { idris_name = newGName }
+        
+        ctxt <- getContext
+        let rhs' = case getUnfolds opts of
+                        Just (n, ms) -> 
+                           let ns = getNamesToUnfold n ms rhsElab in
+                             unfold ctxt [] (map (\n -> (n, 1)) ns) rhsElab
+                        _ -> rhsElab
+        
+        logElab 5 $ "----- " ++ show (getUnfolds opts) ++
+                    "\nUnfolded with RHS " ++ show rhsElab ++ "\n" ++
+                    "to " ++ show rhs'
+
 
         def' <- checkDef info fc iderr True defer
         let def'' = map (\(n, (i, top, t, ns)) -> (n, (i, top, t, ns, False, True))) def'
diff --git a/src/Idris/Elab/Data.hs b/src/Idris/Elab/Data.hs
--- a/src/Idris/Elab/Data.hs
+++ b/src/Idris/Elab/Data.hs
@@ -10,53 +10,49 @@
 
 import Idris.AbsSyntax
 import Idris.ASTUtils
-import Idris.DSL
-import Idris.Error
-import Idris.Delaborate
-import Idris.Imports
-import Idris.Elab.Term
+import Idris.Core.CaseTree
+import Idris.Core.Elaborate hiding (Tactic(..))
+import Idris.Core.Evaluate
+import Idris.Core.Execute
+import Idris.Core.TT
+import Idris.Core.Typecheck
 import Idris.Coverage
 import Idris.DataOpts
-import Idris.Providers
-import Idris.Primitives
-import Idris.Inliner
-import Idris.PartialEval
 import Idris.DeepSeq
-import Idris.Output (iputStrLn, pshow, iWarn, sendHighlighting)
-import IRTS.Lang
-
+import Idris.Delaborate
+import Idris.Docstrings
+import Idris.DSL
+import Idris.Elab.Rewrite
+import Idris.Elab.Term
 import Idris.Elab.Type
 import Idris.Elab.Utils
-import Idris.Elab.Rewrite
 import Idris.Elab.Value
-
-import Idris.Core.TT
-import Idris.Core.Elaborate hiding (Tactic(..))
-import Idris.Core.Evaluate
-import Idris.Core.Execute
-import Idris.Core.Typecheck
-import Idris.Core.CaseTree
+import Idris.Error
+import Idris.Imports
+import Idris.Inliner
+import Idris.Output (iWarn, iputStrLn, pshow, sendHighlighting)
+import Idris.PartialEval
+import Idris.Primitives
+import Idris.Providers
+import IRTS.Lang
 
-import Idris.Docstrings
+import Util.Pretty
 
 import Prelude hiding (id, (.))
-import Control.Category
 
 import Control.Applicative hiding (Const)
+import Control.Category
 import Control.DeepSeq
 import Control.Monad
 import Control.Monad.State.Strict as State
+import Data.Char (isLetter, toLower)
 import Data.List
-import Data.Maybe
-import Debug.Trace
-
+import Data.List.Split (splitOn)
 import qualified Data.Map as Map
+import Data.Maybe
 import qualified Data.Set as S
 import qualified Data.Text as T
-import Data.Char(isLetter, toLower)
-import Data.List.Split (splitOn)
-
-import Util.Pretty
+import Debug.Trace
 
 warnLC :: FC -> Name -> Idris ()
 warnLC fc n
@@ -193,9 +189,13 @@
 
          -- Check that the constructor type is, in fact, a part of the family being defined
          tyIs n cty'
+         let force = if tn == sUN "Delayed" 
+                        then [] -- TMP HACK! Totality checker needs this info
+                        else forceArgs ctxt cty'
 
          logElab 5 $ show fc ++ ":Constructor " ++ show n ++ " elaborated : " ++ show t
          logElab 5 $ "Inaccessible args: " ++ show inacc
+         logElab 5 $ "Forceable args: " ++ show force
          logElab 2 $ "---> " ++ show n ++ " : " ++ show cty
 
          -- Add to the context (this is temporary, so that later constructors
@@ -210,6 +210,7 @@
          addDocStr n doc' argDocs'
          addIBC (IBCDoc n)
          fputState (opt_inaccessible . ist_optimisation n) inacc
+         fputState (opt_forceable . ist_optimisation n) force
          addIBC (IBCOpt n)
          return (n, cty)
   where
@@ -259,6 +260,47 @@
         = tclift $ tfail (At fc (UniqueKindError AllTypes n))
     checkUniqueKind _ _ = return ()
 
+forceArgs :: Context -> Type -> [Int]
+forceArgs ctxt ty = forceFrom 0 ty
+  where
+    -- for each argument, substitute in MN pos "FF"
+    -- then when we look at the return type, if we see MN pos name
+    -- constructor guarded, then 'pos' is a forceable position
+    forceFrom :: Int -> Type -> [Int]
+    forceFrom i (Bind n (Pi _ _ _) sc)
+       = forceFrom (i + 1) (substV (P Ref (sMN i "FF") Erased) sc)
+    forceFrom i sc 
+        -- Go under the top level type application
+        -- We risk affecting erasure of more complex indices, so we'll only
+        -- mark something forced if *everything* which appears in an index
+        -- is forceable
+        -- (FIXME: Actually the real risk is if we erase something a programmer
+        -- definitely wants, which is particularly the case with 'views'.
+        -- So perhaps we need a way of marking that in the source?)
+        | (P _ ty _, args) <- unApply sc
+             = if null (concatMap (findNonForcePos True) args)
+                  then nub (concatMap findForcePos args)
+                  else []
+    forceFrom i sc = []
+
+    findForcePos (P _ (MN i ff) _)
+        | ff == txt "FF" = [i]
+    -- Only look under constructors in applications
+    findForcePos ap@(App _ f a)
+        | (P _ con _, args) <- unApply ap,
+          isDConName con ctxt 
+            = nub $ concatMap findForcePos args
+    findForcePos _ = []
+
+    findNonForcePos fok (P _ (MN i ff) _)
+        | ff == txt "FF" = if fok then [] else [i]
+    -- Look under non-constructors in applications for things which can't
+    -- be forced 
+    findNonForcePos fok ap@(App _ f a)
+        | (P _ con _, args) <- unApply ap
+            = nub $ concatMap (findNonForcePos (fok && isConName con ctxt)) args
+    findNonForcePos _ _ = []
+
 addParamConstraints :: FC -> [Int] -> Type -> [(Name, Type)] -> Idris ()
 addParamConstraints fc ps cty cons
    = case getRetTy cty of
@@ -289,7 +331,7 @@
                                                     then ULE avar cvar
                                                     else ULT avar cvar
                                        addConstraints fc (tv, [con])
-                                       addIBC (IBCConstraint fc con) 
+                                       addIBC (IBCConstraint fc con)
                   _ -> return ()
         constraintTy t = return ()
 
diff --git a/src/Idris/Elab/Implementation.hs b/src/Idris/Elab/Implementation.hs
--- a/src/Idris/Elab/Implementation.hs
+++ b/src/Idris/Elab/Implementation.hs
@@ -10,52 +10,49 @@
 
 import Idris.AbsSyntax
 import Idris.ASTUtils
+import Idris.Core.CaseTree
+import Idris.Core.Elaborate hiding (Tactic(..))
+import Idris.Core.Evaluate
+import Idris.Core.Execute
+import Idris.Core.TT
+import Idris.Core.Typecheck
+import Idris.Coverage
+import Idris.DataOpts
+import Idris.DeepSeq
+import Idris.Delaborate
+import Idris.Docstrings
 import Idris.DSL
+import Idris.Elab.Data
+import Idris.Elab.Term
+import Idris.Elab.Type
+import Idris.Elab.Utils
 import Idris.Error
-import Idris.Delaborate
 import Idris.Imports
-import Idris.Coverage
-import Idris.DataOpts
-import Idris.Providers
-import Idris.Primitives
 import Idris.Inliner
+import Idris.Output (iWarn, iputStrLn, pshow, sendHighlighting)
 import Idris.PartialEval
-import Idris.DeepSeq
-import Idris.Output (iputStrLn, pshow, iWarn, sendHighlighting)
+import Idris.Primitives
+import Idris.Providers
 import IRTS.Lang
 
-import Idris.Elab.Type
-import Idris.Elab.Data
-import Idris.Elab.Utils
-import Idris.Elab.Term
-
-import Idris.Core.TT
-import Idris.Core.Elaborate hiding (Tactic(..))
-import Idris.Core.Evaluate
-import Idris.Core.Execute
-import Idris.Core.Typecheck
-import Idris.Core.CaseTree
-
-import Idris.Docstrings
+import Util.Pretty (pretty, text)
 
 import Prelude hiding (id, (.))
-import Control.Category
 
 import Control.Applicative hiding (Const)
+import Control.Category
 import Control.DeepSeq
 import Control.Monad
 import Control.Monad.State.Strict as State
+import Data.Char (isLetter, toLower)
 import Data.List
-import Data.Maybe
-import Debug.Trace
-
+import Data.List.Split (splitOn)
 import qualified Data.Map as Map
+import Data.Maybe
 import qualified Data.Set as S
 import qualified Data.Text as T
-import Data.Char(isLetter, toLower)
-import Data.List.Split (splitOn)
+import Debug.Trace
 
-import Util.Pretty(pretty, text)
 
 elabImplementation :: ElabInfo
                    -> SyntaxInfo
@@ -96,10 +93,12 @@
          -- if the implementation type matches any of the implementations we have already,
          -- and it's not a named implementation, then it's overlapping, so report an error
          case expn of
-            Nothing -> do mapM_ (maybe (return ()) overlapping . findOverlapping ist (interface_determiners ci) (delab ist nty))
+            Nothing 
+               | OverlappingDictionary `notElem` opts ->
+                       do mapM_ (maybe (return ()) overlapping . findOverlapping ist (interface_determiners ci) (delab ist nty))
                                 (map fst $ interface_implementations ci)
                           addImplementation intImpl True n iname
-            Just _ -> addImplementation intImpl False n iname
+            _ -> addImplementation intImpl False n iname
     when (what /= ETypes && (not (null ds && not emptyinterface))) $ do
          -- Add the parent implementation names to the privileged set
          oldOpen <- addOpenImpl parents
@@ -130,11 +129,17 @@
                 = case lookupTyExact iname (tt_ctxt ist) of
                               Just ty -> (map (\n -> (n, getTypeIn ist n ty)) headVars, ty)
                               _ -> (zip headVars (repeat Placeholder), Erased)
-         logElab 3 $ "Head var types " ++ show headVarTypes ++ " from " ++ show ty
 
+         let impps = getImpParams ist (interface_impparams ci) 
+                          (snd (unApply (substRetTy ty)))
+         let iimpps = zip (interface_impparams ci) impps
+
+         logElab 5 $ "ImpPS: " ++ show impps ++ " --- " ++ show iimpps
+         logElab 5 $ "Head var types " ++ show headVarTypes ++ " from " ++ show ty
+
          let all_meths = map (nsroot . fst) (interface_methods ci)
          let mtys = map (\ (n, (inj, op, t)) ->
-                   let t_in = substMatchesShadow ips pnames t
+                   let t_in = substMatchesShadow (iimpps ++ ips) pnames t
                        mnamemap =
                           map (\n -> (n, PApp fc (PRef fc [] (decorate ns iname n))
                                               (map (toImp fc) headVars)))
@@ -143,11 +148,14 @@
                        (decorate ns iname n,
                            op, coninsert cs pextra t', t'))
               (interface_methods ci)
-         logElab 3 (show (mtys, ips))
+
+         logElab 5 (show (mtys, (iimpps ++ ips)))
          logElab 5 ("Before defaults: " ++ show ds ++ "\n" ++ show (map fst (interface_methods ci)))
          let ds_defs = insertDefaults ist iname (interface_defaults ci) ns ds
          logElab 3 ("After defaults: " ++ show ds_defs ++ "\n")
-         let ds' = reorderDefs (map fst (interface_methods ci)) ds_defs
+
+         let ds' = map (addUnfold iname (map fst (interface_methods ci))) $
+                    reorderDefs (map fst (interface_methods ci)) ds_defs
          logElab 1 ("Reordered: " ++ show ds' ++ "\n")
 
          mapM_ (warnMissing ds' ns iname) (map fst (interface_methods ci))
@@ -195,6 +203,7 @@
 
          let wbVals' = map (addParams prop_params) wbVals
 
+         logElab 5 ("Elaborating method bodies: " ++ show wbVals')
          mapM_ (rec_elabDecl info EAll info) wbVals'
 
          mapM_ (checkInjectiveDef fc (interface_methods ci)) (zip ds' wbVals')
@@ -208,10 +217,18 @@
          addIBC (IBCImplementation intImpl (isNothing expn) n iname)
 
   where
+    getImpParams ist = zipWith (\n tm -> delab ist tm)
+
     intImpl = case ps of
                 [PConstant NoFC (AType (ATInt ITNative))] -> True
                 _ -> False
 
+    addUnfold iname ms (PTy doc docs syn fc opts n fc' tm)
+       = PTy doc docs syn fc (UnfoldIface iname ms : opts) n fc' tm
+    addUnfold iname ms (PClauses fc opts n cs)
+       = PClauses fc (UnfoldIface iname ms : opts) n cs
+    addUnfold iname ms dec = dec
+
     mkiname n' ns ps' expn' =
         case expn' of
           Nothing -> case ns of
@@ -257,6 +274,8 @@
 
     findOverlapping i dets t n
      | SN (ParentN _ _) <- n = Nothing
+     | Just opts <- lookupCtxtExact n (idris_flags i),
+       OverlappingDictionary `elem` opts = Nothing
      | otherwise
         = case lookupTy n (tt_ctxt i) of
             [t'] -> let tret = getRetType t
@@ -475,7 +494,7 @@
     clookup n [] = Nothing
     clookup n ((n', d) : ds) | nsroot n == nsroot n' = Just d
                              | otherwise = Nothing
-checkInjectiveDef fc ns _ = return()
+checkInjectiveDef fc ns _ = return ()
 
 checkInjectiveArgs :: FC -> Name -> [Int] -> Maybe Type -> Idris ()
 checkInjectiveArgs fc n ds Nothing = return ()
diff --git a/src/Idris/Elab/Interface.hs b/src/Idris/Elab/Interface.hs
--- a/src/Idris/Elab/Interface.hs
+++ b/src/Idris/Elab/Interface.hs
@@ -11,53 +11,50 @@
 
 import Idris.AbsSyntax
 import Idris.ASTUtils
+import Idris.Core.CaseTree
+import Idris.Core.Elaborate hiding (Tactic(..))
+import Idris.Core.Evaluate
+import Idris.Core.Execute
+import Idris.Core.TT
+import Idris.Core.Typecheck
+import Idris.Coverage
+import Idris.DataOpts
+import Idris.DeepSeq
+import Idris.Delaborate
+import Idris.Docstrings
 import Idris.DSL
+import Idris.Elab.Data
+import Idris.Elab.Term
+import Idris.Elab.Type
+import Idris.Elab.Utils
 import Idris.Error
-import Idris.Delaborate
 import Idris.Imports
-import Idris.Elab.Term
-import Idris.Coverage
-import Idris.DataOpts
-import Idris.Providers
-import Idris.Primitives
 import Idris.Inliner
+import Idris.Output (iWarn, iputStrLn, pshow, sendHighlighting)
 import Idris.PartialEval
-import Idris.DeepSeq
-import Idris.Output (iputStrLn, pshow, iWarn, sendHighlighting)
+import Idris.Primitives
+import Idris.Providers
 import IRTS.Lang
 
-import Idris.Elab.Type
-import Idris.Elab.Data
-import Idris.Elab.Utils
-
-import Idris.Core.TT
-import Idris.Core.Elaborate hiding (Tactic(..))
-import Idris.Core.Evaluate
-import Idris.Core.Execute
-import Idris.Core.Typecheck
-import Idris.Core.CaseTree
-
-import Idris.Docstrings
+import Util.Pretty (pretty, text)
 
 import Prelude hiding (id, (.))
-import Control.Category
 
 import Control.Applicative hiding (Const)
+import Control.Category
 import Control.DeepSeq
 import Control.Monad
 import Control.Monad.State.Strict as State
+import Data.Char (isLetter, toLower)
+import Data.Generics.Uniplate.Data (transform)
 import Data.List
-import Data.Maybe
-import Debug.Trace
-
+import Data.List.Split (splitOn)
 import qualified Data.Map as Map
+import Data.Maybe
 import qualified Data.Set as S
 import qualified Data.Text as T
-import Data.Char(isLetter, toLower)
-import Data.List.Split (splitOn)
-import Data.Generics.Uniplate.Data (transform)
+import Debug.Trace
 
-import Util.Pretty(pretty, text)
 
 data MArgTy = IA Name | EA Name | CA deriving Show
 
@@ -65,10 +62,10 @@
               -> SyntaxInfo
               -> Docstring (Either Err PTerm)
               -> FC
-              -> [(Name, PTerm)]
+              -> [(Name, PTerm)] -- ^ Superclass constraints
               -> Name
               -> FC
-              -> [(Name, FC, PTerm)]
+              -> [(Name, FC, PTerm)] -- ^ Parameters
               -> [(Name, Docstring (Either Err PTerm))]
               -> [(Name, FC)]                 -- ^ determining params
               -> [PDecl]                      -- ^ interface body
@@ -77,7 +74,6 @@
               -> Idris ()
 elabInterface info syn_in doc fc constraints tn tnfc ps pDocs fds ds mcn cd
     = do let cn = fromMaybe (SN (ImplementationCtorN tn)) (fst <$> mcn)
-         let tty = pibind (map (\(n, _, ty) -> (n, ty)) ps) (PType fc)
          let constraint = PApp fc (PRef fc [] tn)
                                   (map (pexp . PRef fc []) (map (\(n, _, _) -> n) ps))
 
@@ -85,7 +81,21 @@
               syn_in { using = addToUsing (using syn_in)
                                  [(pn, pt) | (pn, _, pt) <- ps]
                      }
+         
+         -- Calculate implicit parameters
+         ist <- getIState
+         let impps_ns = nub $ map (\n -> (n, emptyFC, Placeholder)) $
+                            concatMap (implicitNamesIn [] ist) 
+                                      (map (\ (_,_,x) -> x) ps)
+         let impps = filter (\ (n, _, _) -> 
+                               n `notElem` (map (\ (n, _, _) -> n) ps)) impps_ns
 
+         let tty = impbind (map (\(n, _, ty) -> (n, ty)) impps) $ 
+                     pibind (map (\(n, _, ty) -> (n, ty)) ps) (PType fc)
+
+         logElab 5 $ "Implicit parameters are " ++ show impps
+         logElab 5 $ "Interface type is " ++ showTmImpls tty
+
          -- build data declaration
          let mdecls = filter tydecl ds -- method declarations
          let idecls = filter impldecl ds -- default super interface implementation declarations
@@ -98,7 +108,7 @@
          mapM_ (checkConstraintName (map (\(x, _, _) -> x) ps)) constraintNames
 
          logElab 2 $ "Building methods " ++ show mnames
-         ims <- mapM (tdecl mnames) mdecls
+         ims <- mapM (tdecl impps mnames) mdecls
          defs <- mapM (defdecl (map (\ (x,y,z) -> z) ims) constraint)
                       (filter clause ds)
          let (methods, imethods)
@@ -106,20 +116,24 @@
          let defaults = map (\ (x, (y, z)) -> (x,y)) defs
 
          -- build implementation constructor type
-         let cty = impbind [(pn, pt) | (pn, _, pt) <- ps] $ conbind constraints
+         let cty = impbind [(pn, pt) | (pn, _, pt) <- impps ++ ps] $ conbind constraints
                       $ pibind (map (\ (n, ty) -> (nsroot n, ty)) methods)
                                constraint
 
          let cons = [(cd, pDocs ++ mapMaybe memberDocs ds, cn, NoFC, cty, fc, [])]
          let ddecl = PDatadecl tn NoFC tty cons
 
-         logElab 5 $ "Interface data " ++ show (showDImp verbosePPOption ddecl)
+         logElab 5 $ "Interface " ++ show (showDImp verbosePPOption ddecl)
 
          -- Elaborate the data declaration
          elabData info (syn { no_imp = no_imp syn ++ mnames,
                               imp_methods = mnames }) doc pDocs fc [] ddecl
          dets <- findDets cn (map fst fds)
-         addInterface tn (CI cn (map nodoc imethods) defaults idecls (map (\(n, _, _) -> n) ps) [] dets)
+         addInterface tn (CI cn (map nodoc imethods) defaults idecls 
+                              (map (\(n, _, _) -> n) impps)
+                              (map (\(n, _, _) -> n) ps) 
+                              (map snd constraints)
+                              [] dets)
 
          -- for each constraint, build a top level function to chase it
          cfns <- mapM (cfun cn constraint syn (map fst imethods)) constraints
@@ -191,14 +205,14 @@
     getMName (PTy _ _ _ _ _ n nfc _) = nsroot n
     getMName (PData _ _ _ _ _ (PLaterdecl n nfc _)) = nsroot n
 
-    tdecl allmeths (PTy doc _ syn _ o n nfc t)
-           = do t' <- implicit' info syn (map (\(n, _, _) -> n) ps ++ allmeths) n t
+    tdecl impps allmeths (PTy doc _ syn _ o n nfc t)
+           = do t' <- implicit' info syn (map (\(n, _, _) -> n) (impps ++ ps) ++ allmeths) n t
                 logElab 2 $ "Method " ++ show n ++ " : " ++ showTmImpls t'
                 return ( (n, (toExp (map (\(pn, _, _) -> pn) ps) Exp t')),
                          (n, (False, nfc, doc, o, (toExp (map (\(pn, _, _) -> pn) ps)
                                               (\ l s p -> Imp l s p Nothing True) t'))),
                          (n, (nfc, syn, o, t) ) )
-    tdecl allmeths (PData doc _ syn _ _ (PLaterdecl n nfc t))
+    tdecl impps allmeths (PData doc _ syn _ _ (PLaterdecl n nfc t))
            = do let o = []
                 t' <- implicit' info syn (map (\(n, _, _) -> n) ps ++ allmeths) n t
                 logElab 2 $ "Data method " ++ show n ++ " : " ++ showTmImpls t'
@@ -206,9 +220,9 @@
                          (n, (True, nfc, doc, o, (toExp (map (\(pn, _, _) -> pn) ps)
                                               (\ l s p -> Imp l s p Nothing True) t'))),
                          (n, (nfc, syn, o, t) ) )
-    tdecl allmeths (PData doc _ syn _ _ _)
+    tdecl impps allmeths (PData doc _ syn _ _ _)
          = ierror $ At fc (Msg "Data definitions not allowed in an interface declaration")
-    tdecl _ _ = ierror $ At fc (Msg "Not allowed in an interface declaration")
+    tdecl _ _ _ = ierror $ At fc (Msg "Not allowed in an interface declaration")
 
     -- Create default definitions
     defdecl mtys c d@(PClauses fc opts n cs) =
diff --git a/src/Idris/Elab/Provider.hs b/src/Idris/Elab/Provider.hs
--- a/src/Idris/Elab/Provider.hs
+++ b/src/Idris/Elab/Provider.hs
@@ -10,53 +10,49 @@
 
 import Idris.AbsSyntax
 import Idris.ASTUtils
+import Idris.Core.CaseTree
+import Idris.Core.Elaborate hiding (Tactic(..))
+import Idris.Core.Evaluate
+import Idris.Core.Execute
+import Idris.Core.TT
+import Idris.Core.Typecheck
+import Idris.Coverage
+import Idris.DataOpts
+import Idris.DeepSeq
+import Idris.Delaborate
+import Idris.Docstrings
 import Idris.DSL
+import Idris.Elab.Clause
+import Idris.Elab.Term
+import Idris.Elab.Type
+import Idris.Elab.Utils
+import Idris.Elab.Value
 import Idris.Error
-import Idris.Delaborate
 import Idris.Imports
-import Idris.Coverage
-import Idris.DataOpts
-import Idris.Providers
-import Idris.Primitives
 import Idris.Inliner
+import Idris.Output (iWarn, iputStrLn, pshow)
 import Idris.PartialEval
-import Idris.DeepSeq
-import Idris.Output (iputStrLn, pshow, iWarn)
+import Idris.Primitives
+import Idris.Providers
 import IRTS.Lang
 
-import Idris.Elab.Type
-import Idris.Elab.Clause
-import Idris.Elab.Value
-import Idris.Elab.Utils
-import Idris.Elab.Term
-
-import Idris.Core.TT
-import Idris.Core.Elaborate hiding (Tactic(..))
-import Idris.Core.Evaluate
-import Idris.Core.Execute
-import Idris.Core.Typecheck
-import Idris.Core.CaseTree
-
-import Idris.Docstrings
+import Util.Pretty (pretty, text)
 
 import Prelude hiding (id, (.))
-import Control.Category
 
 import Control.Applicative hiding (Const)
+import Control.Category
 import Control.DeepSeq
 import Control.Monad
 import Control.Monad.State.Strict as State
+import Data.Char (isLetter, toLower)
 import Data.List
-import Data.Maybe
-import Debug.Trace
-
+import Data.List.Split (splitOn)
 import qualified Data.Map as Map
+import Data.Maybe
 import qualified Data.Set as S
 import qualified Data.Text as T
-import Data.Char(isLetter, toLower)
-import Data.List.Split (splitOn)
-
-import Util.Pretty(pretty, text)
+import Debug.Trace
 
 -- | Elaborate a type provider
 elabProvider :: Docstring (Either Err PTerm) -> ElabInfo -> SyntaxInfo -> FC -> FC -> ProvideWhat -> Name -> Idris ()
diff --git a/src/Idris/Elab/Quasiquote.hs b/src/Idris/Elab/Quasiquote.hs
--- a/src/Idris/Elab/Quasiquote.hs
+++ b/src/Idris/Elab/Quasiquote.hs
@@ -7,9 +7,9 @@
 -}
 module Idris.Elab.Quasiquote (extractUnquotes) where
 
+import Idris.AbsSyntax
 import Idris.Core.Elaborate hiding (Tactic(..))
 import Idris.Core.TT
-import Idris.AbsSyntax
 
 
 extract1 :: Int -> (PTerm -> a) -> PTerm -> Elab' aux (a, [(Name, PTerm)])
diff --git a/src/Idris/Elab/Record.hs b/src/Idris/Elab/Record.hs
--- a/src/Idris/Elab/Record.hs
+++ b/src/Idris/Elab/Record.hs
@@ -5,39 +5,35 @@
 License     : BSD3
 Maintainer  : The Idris Community.
 -}
-{-# LANGUAGE PatternGuards, ViewPatterns #-}
+{-# LANGUAGE PatternGuards #-}
 module Idris.Elab.Record(elabRecord) where
 
 import Idris.AbsSyntax
+import Idris.Core.Evaluate
+import Idris.Core.TT
+import Idris.Coverage
+import Idris.DataOpts
+import Idris.DeepSeq
+import Idris.Delaborate
 import Idris.Docstrings
+import Idris.Elab.Data
+import Idris.Elab.Data
+import Idris.Elab.Term
+import Idris.Elab.Type
+import Idris.Elab.Utils
 import Idris.Error
-import Idris.Delaborate
 import Idris.Imports
-import Idris.Elab.Term
-import Idris.Coverage
-import Idris.DataOpts
-import Idris.Providers
-import Idris.Primitives
 import Idris.Inliner
+import Idris.Output (iWarn, iputStrLn, pshow, sendHighlighting)
+import Idris.Parser.Expr (tryFullExpr)
 import Idris.PartialEval
-import Idris.DeepSeq
-import Idris.Output (iputStrLn, pshow, iWarn, sendHighlighting)
+import Idris.Primitives
+import Idris.Providers
 import IRTS.Lang
 
-import Idris.Parser.Expr (tryFullExpr)
-
-import Idris.Elab.Type
-import Idris.Elab.Data
-import Idris.Elab.Utils
-
-import Idris.Core.TT
-import Idris.Core.Evaluate
-
-import Idris.Elab.Data
-
-import Data.Maybe
-import Data.List
 import Control.Monad
+import Data.List
+import Data.Maybe
 
 -- | Elaborate a record declaration
 elabRecord :: ElabInfo
@@ -271,7 +267,7 @@
 
     -- | Elaborate the projection functions.
     elabProj :: Name -> [Name] -> [(Name, Name, Plicity, PTerm, Docstring (Either Err PTerm), Int)] -> Idris ()
-    elabProj cn paramnames fs 
+    elabProj cn paramnames fs
                    = let phArgs = map (uncurry placeholderArg) [(p, n) | (n, _, p, _, _, _) <- fs]
                          elab = \(n, n', p, t, doc, i) ->
                               -- Use projections in types
@@ -283,7 +279,7 @@
 
     -- | Elaborate the update functions.
     elabUp :: Name -> [Name] -> [(Name, Name, Plicity, PTerm, Docstring (Either Err PTerm), Int)] -> Idris ()
-    elabUp cn paramnames fs 
+    elabUp cn paramnames fs
                  = let args = map (uncurry asPRefArg) [(p, n) | (n, _, p, _, _, _) <- fs]
                        elab = \(n, n', p, t, doc, i) -> elabUpdate info n paramnames n' p t doc rsyn fc target cn args fieldNames i (optionalSetter n)
                    in mapM_ elab fs
diff --git a/src/Idris/Elab/Rewrite.hs b/src/Idris/Elab/Rewrite.hs
--- a/src/Idris/Elab/Rewrite.hs
+++ b/src/Idris/Elab/Rewrite.hs
@@ -5,23 +5,22 @@
 License     : BSD3
 Maintainer  : The Idris Community.
 -}
-{-# LANGUAGE PatternGuards, ViewPatterns #-}
+{-# LANGUAGE PatternGuards #-}
 {-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
 module Idris.Elab.Rewrite(elabRewrite, elabRewriteLemma) where
 
 import Idris.AbsSyntax
 import Idris.AbsSyntaxTree
-import Idris.Delaborate
-import Idris.Error
-import Idris.Core.TT
 import Idris.Core.Elaborate
 import Idris.Core.Evaluate
+import Idris.Core.TT
+import Idris.Delaborate
 import Idris.Docstrings
+import Idris.Error
 
 import Control.Monad
 import Control.Monad.State.Strict
 import Data.List
-
 import Debug.Trace
 
 elabRewrite :: (PTerm -> ElabD ()) -> IState ->
diff --git a/src/Idris/Elab/RunElab.hs b/src/Idris/Elab/RunElab.hs
--- a/src/Idris/Elab/RunElab.hs
+++ b/src/Idris/Elab/RunElab.hs
@@ -7,19 +7,16 @@
 -}
 module Idris.Elab.RunElab (elabRunElab) where
 
-import Idris.Elab.Term
-import Idris.Elab.Value (elabVal)
-
 import Idris.AbsSyntax
-import Idris.Error
-
-import Idris.Core.Elaborate hiding (Tactic (..))
+import Idris.Core.Elaborate hiding (Tactic(..))
 import Idris.Core.Evaluate
 import Idris.Core.Execute
 import Idris.Core.TT
 import Idris.Core.Typecheck
-
-import Idris.Output (iputStrLn, pshow, iWarn, sendHighlighting)
+import Idris.Elab.Term
+import Idris.Elab.Value (elabVal)
+import Idris.Error
+import Idris.Output (iWarn, iputStrLn, pshow, sendHighlighting)
 
 elabScriptTy :: Type
 elabScriptTy = App Complete (P Ref (sNS (sUN "Elab") ["Elab", "Reflection", "Language"]) Erased)
diff --git a/src/Idris/Elab/Term.hs b/src/Idris/Elab/Term.hs
--- a/src/Idris/Elab/Term.hs
+++ b/src/Idris/Elab/Term.hs
@@ -11,26 +11,27 @@
 
 import Idris.AbsSyntax
 import Idris.AbsSyntaxTree
-import Idris.DSL
-import Idris.Delaborate
-import Idris.Error
-import Idris.ProofSearch
-import Idris.Output (pshow)
-
 import Idris.Core.CaseTree (SC, SC'(STerm), findCalls, findUsedArgs)
 import Idris.Core.Elaborate hiding (Tactic(..))
-import Idris.Core.TT
 import Idris.Core.Evaluate
-import Idris.Core.Unify
 import Idris.Core.ProofTerm (getProofTerm)
-import Idris.Core.Typecheck (check, recheck, converts, isType)
-import Idris.Core.WHNF (whnf)
-import Idris.Coverage (buildSCG, checkDeclTotality, checkPositive, genClauses, recoverableCoverage, validCoverageCase)
-import Idris.ErrReverse (errReverse)
+import Idris.Core.TT
+import Idris.Core.Typecheck (check, converts, isType, recheck)
+import Idris.Core.Unify
+import Idris.Core.WHNF (whnf,whnfArgs)
+import Idris.Coverage (genClauses, recoverableCoverage, validCoverageCase)
+import Idris.Delaborate
+import Idris.DSL
 import Idris.Elab.Quasiquote (extractUnquotes)
-import Idris.Elab.Utils
 import Idris.Elab.Rewrite
+import Idris.Elab.Utils
+import Idris.Error
+import Idris.ErrReverse (errReverse)
+import Idris.Output (pshow)
+import Idris.ProofSearch
 import Idris.Reflection
+import Idris.Termination(buildSCG, checkDeclTotality, checkPositive)
+
 import qualified Util.Pretty as U
 
 import Control.Applicative ((<$>))
@@ -39,13 +40,12 @@
 import Data.Foldable (for_)
 import Data.List
 import qualified Data.Map as M
-import Data.Maybe (mapMaybe, fromMaybe, catMaybes, maybeToList)
+import Data.Maybe (catMaybes, fromMaybe, mapMaybe, maybeToList)
 import qualified Data.Set as S
 import qualified Data.Text as T
-
 import Debug.Trace
 
-data ElabMode = ETyDecl | ETransLHS | ELHS | ERHS
+data ElabMode = ETyDecl | ETransLHS | ELHS | EImpossible | ERHS
   deriving Eq
 
 
@@ -143,7 +143,7 @@
          if log /= ""
             then trace log $ return (ElabResult tm ds (map snd is) ctxt impls highlights g_nextname)
             else return (ElabResult tm ds (map snd is) ctxt impls highlights g_nextname)
-  where pattern = emode == ELHS
+  where pattern = emode == ELHS || emode == EImpossible
         tydecl = emode == ETyDecl
 
         mkPat = do hs <- get_holes
@@ -189,7 +189,7 @@
          if (log /= "")
             then trace log $ return (ElabResult tm ds (map snd is) ctxt impls highlights g_nextname)
             else return (ElabResult tm ds (map snd is) ctxt impls highlights g_nextname)
-  where pattern = emode == ELHS
+  where pattern = emode == ELHS || emode == EImpossible
 
 -- | return whether arguments of the given constructor name can be
 -- matched on. If they're polymorphic, no, unless the type has beed
@@ -245,7 +245,7 @@
 elab ist info emode opts fn tm
     = do let loglvl = opt_logLevel (idris_options ist)
          when (loglvl > 5) $ unifyLog True
-         compute -- expand type synonyms, etc
+         whnf_compute_args -- expand type synonyms, etc
          let fc = maybe "(unknown)"
          elabE initElabCtxt (elabFC info) tm -- (in argument, guarded, in type, in qquote)
          est <- getAux
@@ -259,9 +259,11 @@
                   mkPat
                   update_term liftPats)
   where
-    pattern = emode == ELHS
+    pattern = emode == ELHS || emode == EImpossible
+    eimpossible = emode == EImpossible
     intransform = emode == ETransLHS
     bindfree = emode == ETyDecl || emode == ELHS || emode == ETransLHS
+               || emode == EImpossible
     autoimpls = opt_autoimpls (idris_options ist)
 
     get_delayed_elab est =
@@ -332,13 +334,13 @@
                               pexp ct]))
 
     forceErr orig env (CantUnify _ (t,_) (t',_) _ _ _)
-       | (P _ (UN ht) _, _) <- unApply (normalise (tt_ctxt ist) env t),
+       | (P _ (UN ht) _, _) <- unApply (whnf (tt_ctxt ist) env t),
             ht == txt "Delayed" = notDelay orig
     forceErr orig env (CantUnify _ (t,_) (t',_) _ _ _)
-       | (P _ (UN ht) _, _) <- unApply (normalise (tt_ctxt ist) env t'),
+       | (P _ (UN ht) _, _) <- unApply (whnf (tt_ctxt ist) env t'),
             ht == txt "Delayed" = notDelay orig
     forceErr orig env (InfiniteUnify _ t _)
-       | (P _ (UN ht) _, _) <- unApply (normalise (tt_ctxt ist) env t),
+       | (P _ (UN ht) _, _) <- unApply (whnf (tt_ctxt ist) env t),
             ht == txt "Delayed" = notDelay orig
     forceErr orig env (Elaborating _ _ _ t) = forceErr orig env t
     forceErr orig env (ElaboratingArg _ _ _ t) = forceErr orig env t
@@ -387,7 +389,7 @@
                           highlightSource fc' (AnnConst c)
     elab' ina fc (PQuote r)     = do fill r; solve
     elab' ina _ (PTrue fc _)   =
-       do hnf_compute
+       do whnf_compute
           g <- goal
           case g of
             TType _ -> elab' ina (Just fc) (PRef fc [] unitTy)
@@ -421,7 +423,7 @@
                     pexp l, pexp r]))
 
     elab' ina _ (PPair fc hls _ l r)
-        = do hnf_compute
+        = do whnf_compute
              g <- goal
              let (tc, _) = unApply g
              case g of
@@ -444,7 +446,7 @@
                 IsType -> asType
                 IsTerm -> asValue
                 TypeOrTerm ->
-                   do hnf_compute
+                   do whnf_compute
                       g <- goal
                       case g of
                          TType _ -> asType
@@ -498,11 +500,13 @@
               showHd x = getNameFrom (sMN 0 "_") -- We probably should do something better than this here
 
               doPrune as =
-                  do compute
+                  do compute -- to get 'Delayed' if it's there
                      ty <- goal
-                     let (tc, _) = unApply (unDelay ty)
+                     ctxt <- get_context
                      env <- get_env
-                     return $ pruneByType env tc (unDelay ty) ist as
+                     let ty' = unDelay ty
+                     let (tc, _) = unApply ty'
+                     return $ pruneByType eimpossible env tc ty' ist as
 
               unDelay t | (P _ (UN l) _, [_, arg]) <- unApply t,
                           l == txt "Delayed" = unDelay arg
@@ -532,7 +536,7 @@
                          (trySeq' deferr xs) True
     elab' ina fc (PAlternative ms TryImplicit (orig : alts)) = do
         env <- get_env
-        compute
+        whnf_compute
         ty <- goal
         let doelab = elab' ina fc orig
         tryCatch doelab
@@ -564,7 +568,7 @@
         recoverableErr _ = True
 
         pruneAlts (CantUnify _ (inc, _) (outc, _) _ _ _) alts env
-            = case unApply (normalise (tt_ctxt ist) env inc) of
+            = case unApply (whnf (tt_ctxt ist) env inc) of
                    (P (TCon _ _) n _, _) -> filter (hasArg n env) alts
                    (Constant _, _) -> alts
                    _ -> filter isLend alts -- special case hack for 'Borrowed'
@@ -656,7 +660,7 @@
                do fty <- get_type (Var n) -- check for implicits
                   ctxt <- get_context
                   env <- get_env
-                  let a' = insertScopedImps fc (normalise ctxt env fty) []
+                  let a' = insertScopedImps fc (whnfArgs ctxt env fty) []
                   if null a'
                      then erun fc $
                             do apply (Var n) []
@@ -840,7 +844,7 @@
             let dataCon = isDConName f ctxt
             annot <- findHighlight f
             mapM_ checkKnownImplicit args_in
-            let args = insertScopedImps fc (normalise ctxt env fty) args_in
+            let args = insertScopedImps fc (whnfArgs ctxt env fty) args_in
             let unmatchableArgs = if pattern
                                      then getUnmatchable (tt_ctxt ist) f
                                      else []
@@ -878,7 +882,7 @@
                     ns <- apply (Var f) (map isph args)
 --                    trace ("ns is " ++ show ns) $ return ()
                     -- mark any interface arguments as injective
---                     when (not pattern) $ 
+--                     when (not pattern) $
                     mapM_ checkIfInjective (map snd ns)
                     unifyProblems -- try again with the new information,
                                   -- to help with disambiguation
@@ -902,7 +906,7 @@
                                          return []
                                       Just rguess -> do
                                          gty <- get_type rguess
-                                         let ty_n = normalise ctxt env gty
+                                         let ty_n = whnf ctxt env gty
                                          return $ getReqImps ty_n
                               else return []
                     -- Now we find out how many implicits we needed at the
@@ -916,7 +920,7 @@
                                  ivs' <- get_implementations
                                  -- Attempt to resolve any interfaces which have 'complete' types,
                                  -- i.e. no holes in them
-                                 when (not pattern || (e_inarg ina && not tcgen)) $ 
+                                 when (not pattern || (e_inarg ina && not tcgen)) $
                                     mapM_ (\n -> do focus n
                                                     g <- goal
                                                     env <- get_env
@@ -959,7 +963,7 @@
                 case lookup n env of
                      Nothing -> return ()
                      Just b ->
-                       case unApply (normalise (tt_ctxt ist) env (binderTy b)) of
+                       case unApply (whnf (tt_ctxt ist) env (binderTy b)) of
                             (P _ c _, args) ->
                                 case lookupCtxtExact c (idris_interfaces ist) of
                                    Nothing -> return ()
@@ -969,7 +973,7 @@
                                            ulog <- getUnifyLog
                                            probs <- get_probs
                                            inj <- get_inj
-                                           traceWhen ulog ("Injective now " ++ show args ++ "\nAll: " ++ show inj 
+                                           traceWhen ulog ("Injective now " ++ show args ++ "\nAll: " ++ show inj
                                                             ++ "\nProblems: " ++ qshow probs) $
                                              unifyProblems
                                            probs <- get_probs
@@ -1421,7 +1425,7 @@
     insertLazy ina t@(PApp _ (PRef _ _ (UN l)) _) | l == txt "Delay" = return t
     insertLazy ina t@(PApp _ (PRef _ _ (UN l)) _) | l == txt "Force" = return t
     insertLazy ina (PCoerced t) = return t
-    -- Don't add a delay to top level pattern variables, since they 
+    -- Don't add a delay to top level pattern variables, since they
     -- can be forced on the rhs if needed
     insertLazy ina t@(PPatvar _ _) | pattern && not (e_guarded ina) = return t
     insertLazy ina t =
@@ -1625,11 +1629,11 @@
 
 -- Rule out alternatives that don't return the same type as the head of the goal
 -- (If there are none left as a result, do nothing)
-pruneByType :: Env -> Term -> -- head of the goal
+pruneByType :: Bool -> Env -> Term -> -- head of the goal
                Type -> -- goal
                IState -> [PTerm] -> [PTerm]
 -- if an alternative has a locally bound name at the head, take it
-pruneByType env t goalty c as
+pruneByType imp env t goalty c as
    | Just a <- locallyBound as = [a]
   where
     locallyBound [] = Nothing
@@ -1645,7 +1649,7 @@
     getName _ = Nothing
 
 -- 'n' is the name at the head of the goal type
-pruneByType env (P _ n _) goalty ist as
+pruneByType imp env (P _ n _) goalty ist as
 -- if the goal type is polymorphic, keep everything
    | Nothing <- lookupTyExact n ctxt = as
 -- if the goal type is a ?metavariable, keep everything
@@ -1677,12 +1681,13 @@
                Just ty -> case unApply (getRetTy ty) of
                             (P _ ctyn _, _) | isTConName ctyn ctxt && not (ctyn == f)
                                      -> False
-                            _ -> let ty' = normalise ctxt [] ty in
---                                    trace ("Trying " ++ show (getRetTy ty') ++ " for " ++ show goalty) $
+                            _ -> let ty' = whnf ctxt [] ty in
+--                                    trace ("Trying " ++ show f' ++ " : " ++ show (getRetTy ty') ++ " for " ++ show goalty
+--                                       ++ "\nMATCH: " ++ show (pat, matching (getRetTy ty') goalty)) $
                                      case unApply (getRetTy ty') of
                                           (V _, _) ->
                                               isPlausible ist var env n ty
-                                          _ -> matching (getRetTy ty') goalty
+                                          _ -> matchingTypes imp (getRetTy ty') goalty
                                                  || isCoercion (getRetTy ty') goalty
 -- May be useful to keep for debugging purposes for a bit:
 --                                                let res = matching (getRetTy ty') goalty in
@@ -1690,9 +1695,12 @@
 --                                                     ("Rejecting " ++ show (getRetTy ty', goalty)) res
                _ -> False
 
+    matchingTypes True = matchingHead
+    matchingTypes False = matching
+
     -- If the goal is a constructor, it must match the suggested function type
     matching (P _ ctyn _) (P _ n' _)
-         | isTConName n' ctxt = ctyn == n'
+         | isTConName n' ctxt && isTConName ctyn ctxt = ctyn == n'
          | otherwise = True
     -- Variables match anything
     matching (V _) _ = True
@@ -1703,14 +1711,28 @@
     matching (Bind n _ sc) _ = True
     matching _ (Bind n _ sc) = True
     -- If we hit a function name, it's a plausible match
-    matching (App _ (P _ f _) _) _ | not (isConName f ctxt) = True
-    matching _ (App _ (P _ f _) _) | not (isConName f ctxt) = True
-    -- Otherwise, match the rest of the structure
-    matching (App _ f a) (App _ f' a') = matching f f' && matching a a'
+    matching apl@(App _ _ _) apr@(App _ _ _)
+         | (P _ fl _, argsl) <- unApply apl,
+           (P _ fr _, argsr) <- unApply apr
+       = fl == fr && and (zipWith matching argsl argsr)
+           || (not (isConName fl ctxt && isConName fr ctxt))
+    -- If the application structures aren't easily comparable, it's a
+    -- plausible match
+    matching (App _ f a) (App _ f' a') = True
     matching (TType _) (TType _) = True
     matching (UType _) (UType _) = True
     matching l r = l == r
 
+    -- In impossible-case mode, only look at the heads (this is to account for
+    -- the non type-directed case with 'impossible' - we'd be ruling out
+    -- too much and wouldn't find the mismatch we're looking for)
+    matchingHead apl@(App _ _ _) apr@(App _ _ _)
+         | (P _ fl _, argsl) <- unApply apl,
+           (P _ fr _, argsr) <- unApply apr,
+           isConName fl ctxt && isConName fr ctxt
+       = fl == fr 
+    matchingHead _ _ = True
+
     -- Return whether there is a possible coercion between the return type
     -- of an alternative and the goal type
     isCoercion rty gty | (P _ r _, _) <- unApply rty
@@ -1735,7 +1757,7 @@
                        _ -> False
 
 
-pruneByType _ t _ _ as = as
+pruneByType _ _ t _ _ as = as
 
 -- Could the name feasibly be the return type?
 -- If there is an interface constraint on the return type, and no implementation
@@ -1941,8 +1963,6 @@
                              clauses'
                              clauses'''
                              clauses'''
-                             clauses'''
-                             clauses'''
                              ty
                              ctxt
          set_context ctxt'
@@ -2254,7 +2274,7 @@
       = do ~[tm] <- tacTmArgs 1 tac args
            tm' <- reifyTT tm
            ctxt <- get_context
-           fmap fst . checkClosed . reflect $ whnf ctxt tm'
+           fmap fst . checkClosed . reflect $ whnf ctxt [] tm'
       | n == tacN "Prim__Converts"
       = do ~[env, tm1, tm2] <- tacTmArgs 3 tac args
            env' <- reifyEnv env
@@ -2634,7 +2654,7 @@
                           (value, _) <- get_type_val (Var letn)
                           ctxt <- get_context
                           env <- get_env
-                          let value' = hnf ctxt env value
+                          let value' = normalise ctxt env value
                           runTac autoSolve ist perhapsFC fn (Exact $ PQuote (reflect value'))
     runT (Fill v) = do attack -- let x = fill x in ...
                        tyn <- getNameFrom (sMN 0 "letty")
@@ -2828,15 +2848,16 @@
     RClausesInstrs n cs ->
       do logElab 3 $ "Pattern-matching definition from tactics: " ++ show n
          solveDeferred emptyFC n
-         let lhss = map (\(_, lhs, _) -> lhs) cs
+         let lhss = map (\(ns, lhs, _) -> (map fst ns, lhs)) cs
          let fc = fileFC "elab_reflected"
          pmissing <-
            do ist <- getIState
               possible <- genClauses fc n lhss
-                                     (map (\lhs ->
+                                     (map (\ (ns, lhs) ->
                                         delab' ist lhs True True) lhss)
               missing <- filterM (checkPossible n) possible
-              return (filter (noMatch ist lhss) missing)
+              let undef = filter (noMatch ist (map snd lhss)) missing
+              return undef
          let tot = if null pmissing
                       then Unchecked -- still need to check recursive calls
                       else Partial NotCovering -- missing cases implies not total
@@ -2873,16 +2894,16 @@
   where
     -- TODO: see if the code duplication with Idris.Elab.Clause can be
     -- reduced or eliminated.
+    -- These are always cases generated by genClauses
     checkPossible :: Name -> PTerm -> Idris Bool
     checkPossible fname lhs_in =
        do ctxt <- getContext
           ist <- getIState
           let lhs = addImplPat ist lhs_in
           let fc = fileFC "elab_reflected_totality"
-          let tcgen = False -- TODO: later we may support dictionary generation
           case elaborate (constraintNS info) ctxt (idris_datatypes ist) (idris_name ist) (sMN 0 "refPatLHS") infP initEState
-                (erun fc (buildTC ist info ELHS [] fname (allNamesIn lhs_in)
-                                                         (infTerm lhs))) of
+                (erun fc (buildTC ist info EImpossible [] fname (allNamesIn lhs_in)
+                                                                (infTerm lhs))) of
             OK (ElabResult lhs' _ _ _ _ _ name', _) ->
               do -- not recursively calling here, because we don't
                  -- want to run infinitely many times
@@ -2892,9 +2913,7 @@
                       OK _ -> return True
                       err -> return False
             -- if it's a recoverable error, the case may become possible
-            Error err -> if tcgen then return (recoverableCoverage ctxt err)
-                                  else return (validCoverageCase ctxt err ||
-                                                 recoverableCoverage ctxt err)
+            Error err -> return (recoverableCoverage ctxt err)
 
 
     -- TODO: Attempt to reduce/eliminate code duplication with Idris.Elab.Clause
diff --git a/src/Idris/Elab/Transform.hs b/src/Idris/Elab/Transform.hs
--- a/src/Idris/Elab/Transform.hs
+++ b/src/Idris/Elab/Transform.hs
@@ -10,50 +10,46 @@
 
 import Idris.AbsSyntax
 import Idris.ASTUtils
+import Idris.Core.CaseTree
+import Idris.Core.Elaborate hiding (Tactic(..))
+import Idris.Core.Evaluate
+import Idris.Core.Execute
+import Idris.Core.TT
+import Idris.Core.Typecheck
+import Idris.Coverage
+import Idris.DataOpts
+import Idris.DeepSeq
+import Idris.Delaborate
+import Idris.Docstrings
 import Idris.DSL
+import Idris.Elab.Term
+import Idris.Elab.Utils
 import Idris.Error
-import Idris.Delaborate
 import Idris.Imports
-import Idris.Coverage
-import Idris.DataOpts
-import Idris.Providers
-import Idris.Primitives
 import Idris.Inliner
+import Idris.Output (iWarn, iputStrLn, pshow, sendHighlighting)
 import Idris.PartialEval
-import Idris.DeepSeq
-import Idris.Output (iputStrLn, pshow, iWarn, sendHighlighting)
+import Idris.Primitives
+import Idris.Providers
 import IRTS.Lang
 
-import Idris.Elab.Utils
-import Idris.Elab.Term
-
-import Idris.Core.TT
-import Idris.Core.Elaborate hiding (Tactic(..))
-import Idris.Core.Evaluate
-import Idris.Core.Execute
-import Idris.Core.Typecheck
-import Idris.Core.CaseTree
-
-import Idris.Docstrings
+import Util.Pretty (pretty, text)
 
 import Prelude hiding (id, (.))
-import Control.Category
 
 import Control.Applicative hiding (Const)
+import Control.Category
 import Control.DeepSeq
 import Control.Monad
 import Control.Monad.State.Strict as State
+import Data.Char (isLetter, toLower)
 import Data.List
-import Data.Maybe
-import Debug.Trace
-
+import Data.List.Split (splitOn)
 import qualified Data.Map as Map
+import Data.Maybe
 import qualified Data.Set as S
 import qualified Data.Text as T
-import Data.Char(isLetter, toLower)
-import Data.List.Split (splitOn)
-
-import Util.Pretty(pretty, text)
+import Debug.Trace
 
 elabTransform :: ElabInfo -> FC -> Bool -> PTerm -> PTerm -> Idris (Term, Term)
 elabTransform info fc safe lhs_in@(PApp _ (PRef _ _ tf) _) rhs_in
diff --git a/src/Idris/Elab/Type.hs b/src/Idris/Elab/Type.hs
--- a/src/Idris/Elab/Type.hs
+++ b/src/Idris/Elab/Type.hs
@@ -13,53 +13,48 @@
 
 import Idris.AbsSyntax
 import Idris.ASTUtils
+import Idris.Core.CaseTree
+import Idris.Core.Elaborate hiding (Tactic(..))
+import Idris.Core.Evaluate
+import Idris.Core.Execute
+import Idris.Core.TT
+import Idris.Core.Typecheck
+import Idris.Coverage
+import Idris.DataOpts
+import Idris.DeepSeq
+import Idris.Delaborate
+import Idris.Docstrings (Docstring)
 import Idris.DSL
+import Idris.Elab.Term
+import Idris.Elab.Utils
+import Idris.Elab.Value
 import Idris.Error
-import Idris.Delaborate
 import Idris.Imports
-import Idris.Elab.Term
-import Idris.Coverage
-import Idris.DataOpts
-import Idris.Providers
-import Idris.Primitives
 import Idris.Inliner
+import Idris.Output (iWarn, iputStrLn, pshow, sendHighlighting)
 import Idris.PartialEval
-import Idris.DeepSeq
-import Idris.Output (iputStrLn, pshow, iWarn, sendHighlighting)
+import Idris.Primitives
+import Idris.Providers
 import IRTS.Lang
 
-import Idris.Elab.Utils
-import Idris.Elab.Value
-
-import Idris.Core.TT
-import Idris.Core.Elaborate hiding (Tactic(..))
-import Idris.Core.Evaluate
-import Idris.Core.Execute
-import Idris.Core.Typecheck
-import Idris.Core.CaseTree
-
-import Idris.Docstrings (Docstring)
+import Util.Pretty (pretty, text)
 
 import Prelude hiding (id, (.))
-import Control.Category
 
 import Control.Applicative hiding (Const)
+import Control.Category
 import Control.DeepSeq
 import Control.Monad
 import Control.Monad.State.Strict as State
+import Data.Char (isLetter, toLower)
 import Data.List
-import Data.Maybe
-import Debug.Trace
-
-import qualified Data.Traversable as Traversable
-
+import Data.List.Split (splitOn)
 import qualified Data.Map as Map
+import Data.Maybe
 import qualified Data.Set as S
 import qualified Data.Text as T
-import Data.Char(isLetter, toLower)
-import Data.List.Split (splitOn)
-
-import Util.Pretty(pretty, text)
+import qualified Data.Traversable as Traversable
+import Debug.Trace
 
 buildType :: ElabInfo
           -> SyntaxInfo
@@ -215,7 +210,7 @@
                                          return (n, d')) argDocs
          addDocStr n doc' argDocs'
          addIBC (IBCDoc n)
-         addIBC (IBCFlags n opts')
+         addIBC (IBCFlags n)
          fputState (opt_inaccessible . ist_optimisation n) inacc
          addIBC (IBCOpt n)
          when (Implicit `elem` opts') $ do addCoercion n
diff --git a/src/Idris/Elab/Utils.hs b/src/Idris/Elab/Utils.hs
--- a/src/Idris/Elab/Utils.hs
+++ b/src/Idris/Elab/Utils.hs
@@ -9,35 +9,32 @@
 module Idris.Elab.Utils where
 
 import Idris.AbsSyntax
-import Idris.Error
+import Idris.Core.Elaborate hiding (Tactic(..))
+import Idris.Core.Evaluate
+import Idris.Core.TT
+import Idris.Core.Typecheck
 import Idris.DeepSeq
 import Idris.Delaborate
 import Idris.Docstrings
+import Idris.Error
 import Idris.Output
 
-import Idris.Core.TT
-import Idris.Core.Elaborate hiding (Tactic(..))
-import Idris.Core.Evaluate
-import Idris.Core.Typecheck
-
 import Util.Pretty
 
 import Control.Applicative hiding (Const)
-import Control.Monad.State
 import Control.Monad
+import Control.Monad.State
 import Data.List
+import qualified Data.Map as Map
 import Data.Maybe
 import qualified Data.Traversable as Traversable
-
 import Debug.Trace
 
-import qualified Data.Map as Map
-
 recheckC = recheckC_borrowing False True []
 
 recheckC_borrowing uniq_check addConstrs bs tcns fc mkerr env t
     = do -- t' <- applyOpts (forget t) (doesn't work, or speed things up...)
-         
+
          ctxt <- getContext
          t' <- case safeForget t of
                     Just ft -> return ft
@@ -47,7 +44,7 @@
                                    OK x -> return x
          logElab 6 $ "CONSTRAINTS ADDED: " ++ show (tm, ty, cs)
          tit <- typeInType
-         when (not tit && addConstrs) $ 
+         when (not tit && addConstrs) $
                            do addConstraints fc cs
                               mapM_ (\c -> addIBC (IBCConstraint fc c)) (snd cs)
          mapM_ (checkDeprecated fc) (allTTNames tm)
@@ -441,7 +438,7 @@
     let opt = idris_optimisation ist
     case lookupCtxt n opt of
         [oi] -> putIState ist { idris_optimisation = addDef n oi { detaggable = True } opt }
-        _    -> putIState ist { idris_optimisation = addDef n (Optimise [] True) opt }
+        _    -> putIState ist { idris_optimisation = addDef n (Optimise [] True []) opt }
 
 displayWarnings :: EState -> Idris ()
 displayWarnings est
@@ -545,4 +542,32 @@
                              return (App s f' a')
     getPats t = return t
 
+isEmpty :: Context -> Ctxt TypeInfo -> Type -> Bool
+isEmpty ctxt tyctxt ty
+    | (P _ tyname _, args) <- unApply (getRetTy ty),
+      Just tyinfo <- lookupCtxtExact tyname tyctxt
+      -- Compare all the constructor types against the type we need
+      -- If they *all* have an argument position where some constructor
+      -- clases with the needed type, then the type we're looking for must
+      -- be empty
+         = let neededty = getRetTy ty
+               contys = mapMaybe getConType (con_names tyinfo) in
+                 all (findClash neededty) contys
+  where
+    getConType n = do t <- lookupTyExact n ctxt
+                      return (getRetTy (normalise ctxt [] t))
 
+    findClash l r
+       | (P _ n _, _) <- unApply l,
+         (P _ n' _, _) <- unApply r,
+         isConName n ctxt && isConName n' ctxt, n /= n' 
+           = True
+    findClash (App _ f a) (App _ f' a') = findClash f f' || findClash a a'
+    findClash l r = False
+
+isEmpty ctxt tyinfo ty = False
+
+hasEmptyPat :: Context -> Ctxt TypeInfo -> Term -> Bool
+hasEmptyPat ctxt tyctxt (Bind n (PVar ty) sc)
+    = isEmpty ctxt tyctxt ty || hasEmptyPat ctxt tyctxt sc
+hasEmptyPat ctxt tyctxt _ = False
diff --git a/src/Idris/Elab/Value.hs b/src/Idris/Elab/Value.hs
--- a/src/Idris/Elab/Value.hs
+++ b/src/Idris/Elab/Value.hs
@@ -14,51 +14,47 @@
 
 import Idris.AbsSyntax
 import Idris.ASTUtils
+import Idris.Core.CaseTree
+import Idris.Core.Elaborate hiding (Tactic(..))
+import Idris.Core.Evaluate hiding (Unchecked)
+import Idris.Core.Execute
+import Idris.Core.TT
+import Idris.Core.Typecheck
+import Idris.Coverage
+import Idris.DataOpts
+import Idris.DeepSeq
+import Idris.Delaborate
+import Idris.Docstrings
 import Idris.DSL
+import Idris.Elab.Term
+import Idris.Elab.Utils
 import Idris.Error
-import Idris.Delaborate
 import Idris.Imports
-import Idris.Coverage
-import Idris.DataOpts
-import Idris.Providers
-import Idris.Primitives
 import Idris.Inliner
+import Idris.Output (iWarn, iputStrLn, pshow, sendHighlighting)
 import Idris.PartialEval
-import Idris.DeepSeq
-import Idris.Output (iputStrLn, pshow, iWarn, sendHighlighting)
+import Idris.Primitives
+import Idris.Providers
 import IRTS.Lang
 
-import Idris.Elab.Utils
-import Idris.Elab.Term
-
-import Idris.Core.TT
-import Idris.Core.Elaborate hiding (Tactic(..))
-import Idris.Core.Evaluate hiding (Unchecked)
-import Idris.Core.Execute
-import Idris.Core.Typecheck
-import Idris.Core.CaseTree
-
-import Idris.Docstrings
+import Util.Pretty (pretty, text)
 
 import Prelude hiding (id, (.))
-import Control.Category
 
 import Control.Applicative hiding (Const)
+import Control.Category
 import Control.DeepSeq
 import Control.Monad
 import Control.Monad.State.Strict as State
+import Data.Char (isLetter, toLower)
 import Data.List
-import Data.Maybe
-import qualified Data.Traversable as Traversable
-import Debug.Trace
-
+import Data.List.Split (splitOn)
 import qualified Data.Map as Map
+import Data.Maybe
 import qualified Data.Set as S
 import qualified Data.Text as T
-import Data.Char(isLetter, toLower)
-import Data.List.Split (splitOn)
-
-import Util.Pretty(pretty, text)
+import qualified Data.Traversable as Traversable
+import Debug.Trace
 
 -- | Elaborate a value, returning any new bindings created (this will only
 -- happen if elaborating as a pattern clause)
diff --git a/src/Idris/ElabDecls.hs b/src/Idris/ElabDecls.hs
--- a/src/Idris/ElabDecls.hs
+++ b/src/Idris/ElabDecls.hs
@@ -6,69 +6,65 @@
 Maintainer  : The Idris Community.
 -}
 
-{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, DeriveFunctor,
+{-# LANGUAGE DeriveFunctor, FlexibleInstances, MultiParamTypeClasses,
              PatternGuards #-}
 
 module Idris.ElabDecls where
 
 import Idris.AbsSyntax
 import Idris.ASTUtils
-import Idris.DSL
-import Idris.Error
-import Idris.Delaborate
-import Idris.Directives
-import Idris.Imports
-import Idris.Elab.Term
+import Idris.Core.CaseTree
+import Idris.Core.Elaborate hiding (Tactic(..))
+import Idris.Core.Evaluate
+import Idris.Core.Execute
+import Idris.Core.TT
+import Idris.Core.Typecheck
 import Idris.Coverage
 import Idris.DataOpts
-import Idris.Providers
-import Idris.Primitives
-import Idris.Inliner
-import Idris.PartialEval
 import Idris.DeepSeq
-import Idris.Output (iputStrLn, pshow, iWarn, sendHighlighting)
-import IRTS.Lang
-
-import Idris.Elab.Utils
-import Idris.Elab.Type
+import Idris.Delaborate
+import Idris.Directives
+import Idris.Docstrings hiding (Unchecked)
+import Idris.DSL
 import Idris.Elab.Clause
 import Idris.Elab.Data
-import Idris.Elab.Record
-import Idris.Elab.Interface
 import Idris.Elab.Implementation
+import Idris.Elab.Interface
 import Idris.Elab.Provider
+import Idris.Elab.Record
 import Idris.Elab.RunElab
+import Idris.Elab.Term
 import Idris.Elab.Transform
+import Idris.Elab.Type
+import Idris.Elab.Utils
 import Idris.Elab.Value
-
-import Idris.Core.TT
-import Idris.Core.Elaborate hiding (Tactic(..))
-import Idris.Core.Evaluate
-import Idris.Core.Execute
-import Idris.Core.Typecheck
-import Idris.Core.CaseTree
+import Idris.Error
+import Idris.Imports
+import Idris.Inliner
+import Idris.Output (iWarn, iputStrLn, pshow, sendHighlighting)
+import Idris.PartialEval
+import Idris.Primitives
+import Idris.Providers
+import Idris.Termination
+import IRTS.Lang
 
-import Idris.Docstrings hiding (Unchecked)
+import Util.Pretty (pretty, text)
 
 import Prelude hiding (id, (.))
-import Control.Category
 
 import Control.Applicative hiding (Const)
+import Control.Category
 import Control.DeepSeq
 import Control.Monad
 import Control.Monad.State.Strict as State
+import Data.Char (isLetter, toLower)
 import Data.List
-import Data.Maybe
-import Debug.Trace
-
+import Data.List.Split (splitOn)
 import qualified Data.Map as Map
+import Data.Maybe
 import qualified Data.Set as S
 import qualified Data.Text as T
-import Data.Char(isLetter, toLower)
-import Data.List.Split (splitOn)
-
-import Util.Pretty(pretty, text)
-
+import Debug.Trace
 
 -- | Top level elaborator info, supporting recursive elaboration
 recinfo :: FC -> ElabInfo
@@ -87,7 +83,7 @@
 elabPrims = do i <- getIState
                let cs_in = idris_constraints i
                let mkdec opt decl docs argdocs =
-                       PData docs argdocs defaultSyntax (fileFC "builtin") 
+                       PData docs argdocs defaultSyntax (fileFC "builtin")
                              opt decl
                elabDecl' EAll (recinfo primfc) (mkdec inferOpts inferDecl emptyDocstring [])
                -- We don't want the constraints generated by 'Infer' since
diff --git a/src/Idris/Erasure.hs b/src/Idris/Erasure.hs
--- a/src/Idris/Erasure.hs
+++ b/src/Idris/Erasure.hs
@@ -12,32 +12,31 @@
 import Idris.AbsSyntax
 import Idris.ASTUtils
 import Idris.Core.CaseTree
-import Idris.Core.TT
 import Idris.Core.Evaluate
-import Idris.Primitives
+import Idris.Core.TT
 import Idris.Error
-
-import Debug.Trace
-import System.IO.Unsafe
+import Idris.Primitives
 
-import Control.Category
 import Prelude hiding (id, (.))
 
-import Control.Arrow
 import Control.Applicative
+import Control.Arrow
+import Control.Category
 import Control.Monad.State
-import Data.Maybe
-import Data.List
-import qualified Data.Set as S
-import qualified Data.IntSet as IS
-import qualified Data.Map as M
+import Data.IntMap (IntMap)
 import qualified Data.IntMap as IM
-import Data.Set (Set)
 import Data.IntSet (IntSet)
+import qualified Data.IntSet as IS
+import Data.List
 import Data.Map (Map)
-import Data.IntMap (IntMap)
+import qualified Data.Map as M
+import Data.Maybe
+import Data.Set (Set)
+import qualified Data.Set as S
 import Data.Text (pack)
 import qualified Data.Text as T
+import Debug.Trace
+import System.IO.Unsafe
 
 -- | UseMap maps names to the set of used (reachable) argument
 -- positions.
@@ -135,7 +134,7 @@
 
     checkAccessibility :: Ctxt OptInfo -> (Name, IntMap (Set Reason)) -> Idris ()
     checkAccessibility opt (n, reachable)
-        | Just (Optimise inaccessible dt) <- lookupCtxtExact n opt
+        | Just (Optimise inaccessible dt force) <- lookupCtxtExact n opt
         , eargs@(_:_) <- [fmt n (S.toList rs) | (i,n) <- inaccessible, rs <- maybeToList $ IM.lookup i reachable]
         = warn $ show n ++ ": inaccessible arguments reachable:\n  " ++ intercalate "\n  " eargs
 
@@ -498,9 +497,18 @@
         Nothing -> error $ "Erasure/getArity: definition not found for " ++ show n
 
     -- convert applications of lambdas to lets
-    -- Note that this transformation preserves de bruijn numbering
+    -- note that this transformation preserves de bruijn numbering
     lamToLet :: Term -> Term
-    lamToLet (App _ (Bind n (Lam ty) tm) val) = Bind n (Let ty val) tm
+    lamToLet tm = lamToLet' args f
+      where
+        (f, args) = unApply tm
+
+    lamToLet' :: [Term] -> Term -> Term
+    lamToLet' (v:vs) (Bind n (Lam ty) tm) = Bind n (Let ty v) $ lamToLet' vs tm
+    lamToLet'    []  tm = tm
+    lamToLet'    vs  tm = error $
+        "Erasure.hs:lamToLet': unexpected input: "
+            ++ "vs = " ++ show vs ++ ", tm = " ++ show tm
 
     -- split "\x_i -> T(x_i)" into [x_i] and T
     unfoldLams :: Term -> ([Name], Term)
diff --git a/src/Idris/Error.hs b/src/Idris/Error.hs
--- a/src/Idris/Error.hs
+++ b/src/Idris/Error.hs
@@ -10,28 +10,28 @@
 
 module Idris.Error where
 
-import Prelude hiding (catch)
 import Idris.AbsSyntax
-import Idris.Delaborate
-
+import Idris.Core.Constraints
 import Idris.Core.Evaluate (ctxtAlist)
 import Idris.Core.TT
 import Idris.Core.Typecheck
-import Idris.Core.Constraints
+import Idris.Delaborate
 import Idris.Output
 
-import System.Console.Haskeline
-import System.Console.Haskeline.MonadException
+import Prelude hiding (catch)
+
 import Control.Monad (when)
 import Control.Monad.State.Strict
-import System.IO.Error(isUserError, ioeGetErrorString)
 import Data.Char
+import qualified Data.Foldable as Foldable
 import Data.List (intercalate, isPrefixOf)
-import qualified Data.Text as T
 import qualified Data.Set as S
-import Data.Typeable
+import qualified Data.Text as T
 import qualified Data.Traversable as Traversable
-import qualified Data.Foldable as Foldable
+import Data.Typeable
+import System.Console.Haskeline
+import System.Console.Haskeline.MonadException
+import System.IO.Error (ioeGetErrorString, isUserError)
 
 iucheck :: Idris ()
 iucheck = do tit <- typeInType
diff --git a/src/Idris/IBC.hs b/src/Idris/IBC.hs
--- a/src/Idris/IBC.hs
+++ b/src/Idris/IBC.hs
@@ -12,44 +12,42 @@
                   writeIBC, writePkgIndex,
                   hasValidIBCVersion, IBCPhase(..)) where
 
-import Idris.Core.Evaluate
-import Idris.Core.TT
+import Idris.AbsSyntax
 import Idris.Core.Binary
 import Idris.Core.CaseTree
-import Idris.AbsSyntax
-import Idris.Imports
-import Idris.Error
+import Idris.Core.Evaluate
+import Idris.Core.TT
 import Idris.DeepSeq
 import Idris.Delaborate
-import qualified Idris.Docstrings as D
 import Idris.Docstrings (Docstring)
+import qualified Idris.Docstrings as D
+import Idris.Error
+import Idris.Imports
 import Idris.Output
 import IRTS.System (getIdrisLibDir)
+
 import Paths_idris
 
 import qualified Cheapskate.Types as CT
-
+import Codec.Archive.Zip
+import Control.DeepSeq
+import Control.Monad
+import Control.Monad.State.Strict hiding (get, put)
+import qualified Control.Monad.State.Strict as ST
 import Data.Binary
+import Data.ByteString.Lazy as B hiding (elem, length, map)
 import Data.Functor
-import Data.Vector.Binary
 import Data.List as L
 import Data.Maybe (catMaybes)
-import Data.ByteString.Lazy as B hiding (length, elem, map)
-import qualified Data.Text as T
 import qualified Data.Set as S
-
-import Control.Monad
-import Control.DeepSeq
-import Control.Monad.State.Strict hiding (get, put)
-import qualified Control.Monad.State.Strict as ST
-import System.FilePath
-import System.Directory
-import Codec.Archive.Zip
-
+import qualified Data.Text as T
+import Data.Vector.Binary
 import Debug.Trace
+import System.Directory
+import System.FilePath
 
 ibcVersion :: Word16
-ibcVersion = 149
+ibcVersion = 155
 
 -- | When IBC is being loaded - we'll load different things (and omit
 -- different structures/definitions) depending on which phase we're in.
@@ -315,7 +313,10 @@
                         _ -> ifail "IBC write failed"
 ibc i (IBCCoercion n) f = return f { ibc_coercions = n : ibc_coercions f }
 ibc i (IBCAccess n a) f = return f { ibc_access = (n,a) : ibc_access f }
-ibc i (IBCFlags n a) f = return f { ibc_flags = (n,a) : ibc_flags f }
+ibc i (IBCFlags n) f 
+    = case lookupCtxtExact n (idris_flags i) of
+           Just a -> return f { ibc_flags = (n,a): ibc_flags f }
+           _ -> ifail "IBC write failed"
 ibc i (IBCFnInfo n a) f = return f { ibc_fninfo = (n,a) : ibc_fninfo f }
 ibc i (IBCTotal n a) f = return f { ibc_total = (n,a) : ibc_total f }
 ibc i (IBCInjective n a) f = return f { ibc_injective = (n,a) : ibc_injective f }
@@ -553,7 +554,7 @@
         -- Don't lose implementations from previous IBCs, which
         -- could have loaded in any order
         let is = case lookupCtxtExact n (idris_interfaces i) of
-                    Just (CI _ _ _ _ _ ins _) -> ins
+                    Just ci -> interface_implementations ci
                     _ -> []
         let c' = c { interface_implementations = interface_implementations c ++ is }
         putIState (i { idris_interfaces = addDef n c' (idris_interfaces i) })) cs
@@ -659,10 +660,10 @@
             r' <- update r
             return $ Right (l', r')
 
-        updateCD (CaseDefs (ts, t) (cs, c) (is, i) (rs, r)) = do
+        updateCD (CaseDefs (cs, c) (rs, r)) = do
             c' <- updateSC c
             r' <- updateSC r
-            return $ CaseDefs (cs, c') (cs, c') (cs, c') (rs, r')
+            return $ CaseDefs (cs, c') (rs, r')
 
         updateSC (Case t n alts) = do
             alts' <- mapM updateAlt alts
@@ -942,14 +943,16 @@
                    _ -> error "Corrupted binary data for SizeChange"
 
 instance Binary CGInfo where
-        put (CGInfo x1 x2 x3)
+        put (CGInfo x1 x2 x3 x4)
           = do put x1
 --                put x3 -- Already used SCG info for totality check
-               put x3
+               put x2
+               put x4
         get
           = do x1 <- get
+               x2 <- get
                x3 <- get
-               return (CGInfo x1 [] x3)
+               return (CGInfo x1 x2 [] x3)
 
 instance Binary CaseType where
         put x = case x of
@@ -1038,14 +1041,13 @@
                    _ -> error "Corrupted binary data for CaseAlt"
 
 instance Binary CaseDefs where
-        put (CaseDefs x1 x2 x3 x4)
-          = do -- don't need totality checked or inlined versions
+        put (CaseDefs x1 x2)
+          = do put x1
                put x2
-               put x4
         get
-          = do x2 <- get
-               x4 <- get
-               return (CaseDefs x2 x2 x2 x4)
+          = do x1 <- get
+               x2 <- get
+               return (CaseDefs x1 x2)
 
 instance Binary CaseInfo where
         put x@(CaseInfo x1 x2 x3) = do put x1
@@ -1210,7 +1212,7 @@
                 AssertTotal -> putWord8 3
                 Specialise x -> do putWord8 4
                                    put x
-                Coinductive -> putWord8 5
+                AllGuarded -> putWord8 5
                 PartialFn -> putWord8 6
                 Implicit -> putWord8 7
                 Reflection -> putWord8 8
@@ -1224,6 +1226,10 @@
                 AutoHint -> putWord8 15
                 PEGenerated -> putWord8 16
                 StaticFn -> putWord8 17
+                OverlappingDictionary -> putWord8 18
+                UnfoldIface x ns -> do putWord8 19
+                                       put x
+                                       put ns
         get
           = do i <- getWord8
                case i of
@@ -1233,7 +1239,7 @@
                    3 -> return AssertTotal
                    4 -> do x <- get
                            return (Specialise x)
-                   5 -> return Coinductive
+                   5 -> return AllGuarded
                    6 -> return PartialFn
                    7 -> return Implicit
                    8 -> return Reflection
@@ -1247,6 +1253,10 @@
                    15 -> return AutoHint
                    16 -> return PEGenerated
                    17 -> return StaticFn
+                   18 -> return OverlappingDictionary
+                   19 -> do x <- get
+                            ns <- get
+                            return (UnfoldIface x ns)
                    _ -> error "Corrupted binary data for FnOpt"
 
 instance Binary Fixity where
@@ -2354,13 +2364,15 @@
 
 
 instance Binary InterfaceInfo where
-        put (CI x1 x2 x3 x4 x5 _ x6)
+        put (CI x1 x2 x3 x4 x5 x6 x7 _ x8)
           = do put x1
                put x2
                put x3
                put x4
                put x5
                put x6
+               put x7
+               put x8
         get
           = do x1 <- get
                x2 <- get
@@ -2368,7 +2380,9 @@
                x4 <- get
                x5 <- get
                x6 <- get
-               return (CI x1 x2 x3 x4 x5 [] x6)
+               x7 <- get
+               x8 <- get
+               return (CI x1 x2 x3 x4 x5 x6 x7 [] x8)
 
 instance Binary RecordInfo where
         put (RI x1 x2 x3)
@@ -2382,13 +2396,15 @@
                return (RI x1 x2 x3)
 
 instance Binary OptInfo where
-        put (Optimise x1 x2)
+        put (Optimise x1 x2 x3)
           = do put x1
                put x2
+               put x3
         get
           = do x1 <- get
                x2 <- get
-               return (Optimise x1 x2)
+               x3 <- get
+               return (Optimise x1 x2 x3)
 
 instance Binary FnInfo where
         put (FnInfo x1)
diff --git a/src/Idris/IdeMode.hs b/src/Idris/IdeMode.hs
--- a/src/Idris/IdeMode.hs
+++ b/src/Idris/IdeMode.hs
@@ -11,23 +11,22 @@
 
 module Idris.IdeMode(parseMessage, convSExp, WhatDocs(..), IdeModeCommand(..), sexpToCommand, toSExp, SExp(..), SExpable, Opt(..), ideModeEpoch, getLen, getNChar, sExpToString) where
 
-import Text.Printf
-import Numeric
-import Data.List
-import Data.Maybe (isJust)
+import Idris.Core.Binary
+import Idris.Core.TT
+
+import Control.Applicative hiding (Const)
 import qualified Data.Binary as Binary
 import qualified Data.ByteString.Base64 as Base64
 import qualified Data.ByteString.Lazy as Lazy
 import qualified Data.ByteString.UTF8 as UTF8
+import Data.List
+import Data.Maybe (isJust)
 import qualified Data.Text as T
+import Numeric
+import System.IO
+import Text.Printf
 import Text.Trifecta hiding (Err)
 import Text.Trifecta.Delta
-import System.IO
-
-import Idris.Core.TT
-import Idris.Core.Binary
-
-import Control.Applicative hiding (Const)
 
 getNChar :: Handle -> Int -> String -> IO (String)
 getNChar _ 0 s = return (reverse s)
diff --git a/src/Idris/IdrisDoc.hs b/src/Idris/IdrisDoc.hs
--- a/src/Idris/IdrisDoc.hs
+++ b/src/Idris/IdrisDoc.hs
@@ -5,57 +5,50 @@
 License     : BSD3
 Maintainer  : The Idris Community.
 -}
-{-# LANGUAGE PatternGuards #-}
-{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE OverloadedStrings, PatternGuards #-}
 {-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
 module Idris.IdrisDoc (generateDocs) where
 
-import Idris.Core.TT (Name (..), sUN, SpecialName (..), OutputAnnotation (..),
-                      TextFormatting (..), txt, str, nsroot, constIsType, toAlist)
-import Idris.Core.Evaluate (ctxtAlist, Def (..), lookupDefAcc,
-                            Accessibility (..), isDConName, isFnName,
-                            isTConName)
-import Idris.Parser.Helpers (opChars)
 import Idris.AbsSyntax
+import Idris.Core.Evaluate (Accessibility(..), Def(..), ctxtAlist, isDConName,
+                            isFnName, isTConName, lookupDefAcc)
+import Idris.Core.TT (Name(..), OutputAnnotation(..), SpecialName(..),
+                      TextFormatting(..), constIsType, nsroot, sUN, str,
+                      toAlist, txt)
 import Idris.Docs
 import Idris.Docstrings (nullDocstring)
 import qualified Idris.Docstrings as Docstrings
-
+import Idris.Parser.Helpers (opChars)
 import IRTS.System (getDataFileName)
 
 import Control.Applicative ((<|>))
 import Control.Monad (forM_)
 import Control.Monad.Trans.Except
 import Control.Monad.Trans.State.Strict
-
-import Data.Maybe
-
 import qualified Data.ByteString as BS
 import qualified Data.ByteString.Lazy as BS2
-import qualified Data.Text.Encoding as E
 import qualified Data.List as L
 import qualified Data.List.Split as LS
 import qualified Data.Map as M hiding ((!))
+import Data.Maybe
 import Data.Monoid (mempty)
 import qualified Data.Ord (compare)
 import qualified Data.Set as S
 import qualified Data.Text as T
-
+import qualified Data.Text.Encoding as E
+import System.Directory
+import System.FilePath
 import System.IO
 import System.IO.Error
-import System.FilePath
-import System.Directory
-
-import Text.PrettyPrint.Annotated.Leijen (displayDecorated, renderCompact)
-
-import Text.Blaze (toValue, contents)
-import Text.Blaze.Internal (MarkupM (Empty))
-import Text.Blaze.Html5 ((!), toHtml, preEscapedToHtml)
+import Text.Blaze (contents, toValue)
+import qualified Text.Blaze.Html.Renderer.String as R
+import Text.Blaze.Html.Renderer.Utf8 (renderHtml)
+import Text.Blaze.Html5 (preEscapedToHtml, toHtml, (!))
 import qualified Text.Blaze.Html5 as H
 import Text.Blaze.Html5.Attributes as A
-import Text.Blaze.Html.Renderer.Utf8 (renderHtml)
-import qualified Text.Blaze.Html.Renderer.String as R
+import Text.Blaze.Internal (MarkupM(Empty))
 import Text.Blaze.Renderer.String (renderMarkup)
+import Text.PrettyPrint.Annotated.Leijen (displayDecorated, renderCompact)
 
 -- ---------------------------------------------------------------- [ Public ]
 
@@ -174,7 +167,7 @@
   in  filter ((flip S.notMember children) . (\(n, _, _) -> n)) list
 
   where names (Just (DataDoc _ fds))                  = map (\(FD n _ _ _ _) -> n) fds
-        names (Just (InterfaceDoc _ _ fds _ _ _ _ c)) = map (\(FD n _ _ _ _) -> n) fds ++ map (\(FD n _ _ _ _) -> n) (maybeToList c)
+        names (Just (InterfaceDoc _ _ fds _ _ _ _ _ c)) = map (\(FD n _ _ _ _) -> n) fds ++ map (\(FD n _ _ _ _) -> n) (maybeToList c)
         names _                                       = []
 
 -- | Whether a Name names something which should be documented
@@ -222,14 +215,14 @@
       names  = concatMap (extractPTermNames) ts
   in  S.map getNs $ S.fromList names
 
-  where getFunDocs (FunDoc f)                      = [f]
-        getFunDocs (DataDoc f fs)                  = f:fs
-        getFunDocs (InterfaceDoc _ _ fs _ _ _ _ _) = fs
-        getFunDocs (RecordDoc _ _ f fs _)          = f:fs
-        getFunDocs (NamedImplementationDoc _ fd)         = [fd]
-        getFunDocs (ModDoc _ _)                    = []
-        types (FD _ _ args t _)                    = t:(map second args)
-        second (_, x, _, _)                        = x
+  where getFunDocs (FunDoc f)                        = [f]
+        getFunDocs (DataDoc f fs)                    = f:fs
+        getFunDocs (InterfaceDoc _ _ fs _ _ _ _ _ _) = fs
+        getFunDocs (RecordDoc _ _ f fs _)            = f:fs
+        getFunDocs (NamedImplementationDoc _ fd)     = [fd]
+        getFunDocs (ModDoc _ _)                      = []
+        types (FD _ _ args t _)                      = t:(map second args)
+        second (_, x, _, _)                          = x
 
 
 -- | Returns an NsDict of containing all known namespaces and their contents
@@ -583,7 +576,7 @@
                -> H.Html -- ^ Resulting HTML
 createOtherDoc ist (FunDoc fd)                = createFunDoc ist fd
 
-createOtherDoc ist (InterfaceDoc n docstring fds _ _ _ _ c) = do
+createOtherDoc ist (InterfaceDoc n docstring fds _ _ _ _ _ c) = do
   H.dt ! (A.id $ toValue $ show n) $ do
     H.span ! class_ "word" $ do "interface"; nbsp
     H.span ! class_ "name type"
diff --git a/src/Idris/Imports.hs b/src/Idris/Imports.hs
--- a/src/Idris/Imports.hs
+++ b/src/Idris/Imports.hs
@@ -10,19 +10,16 @@
   , ibcPathNoFallback, installedPackages, pkgIndex
   ) where
 
-import Control.Applicative ((<$>))
-import Data.List (isSuffixOf)
-
 import Idris.AbsSyntax
-import Idris.Error
-
 import Idris.Core.TT
-
+import Idris.Error
 import IRTS.System (getIdrisLibDir)
 
-import System.FilePath
-import System.Directory
+import Control.Applicative ((<$>))
 import Control.Monad.State.Strict
+import Data.List (isSuffixOf)
+import System.Directory
+import System.FilePath
 
 data IFileType = IDR FilePath | LIDR FilePath | IBC FilePath IFileType
     deriving (Show, Eq)
diff --git a/src/Idris/Info.hs b/src/Idris/Info.hs
--- a/src/Idris/Info.hs
+++ b/src/Idris/Info.hs
@@ -6,7 +6,11 @@
 Maintainer  : The Idris Community.
 -}
 module Idris.Info
-  ( getIdrisLibDir
+  ( getIdrisDataDir
+  , getIdrisCRTSDir
+  , getIdrisJSRTSDir
+  , getIdrisLibDir
+  , getIdrisDocDir
   , getIdrisFlagsLib
   , getIdrisFlagsInc
   , getIdrisFlagsEnv
@@ -20,18 +24,27 @@
   , getIdrisLoggingCategories
   ) where
 
-import System.FilePath
-import System.Directory
-import Data.Version
-
-import Idris.Imports (installedPackages)
 import Idris.AbsSyntax (loggingCatsStr)
-
+import Idris.Imports (installedPackages)
 import qualified IRTS.System as S
 
+import Paths_idris
 import Version_idris (gitHash)
 
-import Paths_idris
+import Data.Version
+import System.Directory
+import System.FilePath
+getIdrisDataDir :: IO String
+getIdrisDataDir = S.getIdrisDataDir
+
+getIdrisCRTSDir :: IO String
+getIdrisCRTSDir = S.getIdrisCRTSDir
+
+getIdrisJSRTSDir :: IO String
+getIdrisJSRTSDir = S.getIdrisJSRTSDir
+
+getIdrisDocDir :: IO String
+getIdrisDocDir = S.getIdrisDocDir
 
 getIdrisLibDir :: IO String
 getIdrisLibDir = S.getIdrisLibDir
diff --git a/src/Idris/Info/Show.hs b/src/Idris/Info/Show.hs
--- a/src/Idris/Info/Show.hs
+++ b/src/Idris/Info/Show.hs
@@ -1,9 +1,29 @@
 module Idris.Info.Show where
 
+import Idris.Info
+
 import System.Exit
 
-import Idris.Info
+showIdrisCRTSDir :: IO ()
+showIdrisCRTSDir = do
+  ldir <- getIdrisCRTSDir
+  putStrLn ldir
 
+showExitIdrisCRTSDir :: IO ()
+showExitIdrisCRTSDir = do
+  showIdrisCRTSDir
+  exitSuccess
+
+showIdrisJSRTSDir :: IO ()
+showIdrisJSRTSDir = do
+  ldir <- getIdrisJSRTSDir
+  putStrLn ldir
+
+showExitIdrisJSRTSDir :: IO ()
+showExitIdrisJSRTSDir = do
+  showIdrisJSRTSDir
+  exitSuccess
+
 showIdrisFlagsLibs :: IO ()
 showIdrisFlagsLibs = do
   libFlags <- getIdrisFlagsLib
@@ -14,6 +34,16 @@
   showIdrisFlagsLibs
   exitSuccess
 
+showIdrisDataDir :: IO ()
+showIdrisDataDir = do
+  ldir <- getIdrisDataDir
+  putStrLn ldir
+
+showExitIdrisDataDir :: IO ()
+showExitIdrisDataDir = do
+  showIdrisDataDir
+  exitSuccess
+
 showIdrisLibDir :: IO ()
 showIdrisLibDir = do
   ldir <- getIdrisLibDir
@@ -24,6 +54,16 @@
   showIdrisLibDir
   exitSuccess
 
+showIdrisDocDir :: IO ()
+showIdrisDocDir = do
+  ldir <- getIdrisDocDir
+  putStrLn ldir
+
+showExitIdrisDocDir :: IO ()
+showExitIdrisDocDir = do
+  showIdrisDocDir
+  exitSuccess
+
 showIdrisFlagsInc :: IO ()
 showIdrisFlagsInc = do
   incFlags <- getIdrisFlagsInc
@@ -68,8 +108,16 @@
   putStrLn "Paths:"
   ldir <- getIdrisLibDir
   udir <- getIdrisUserDataDir
+  ddir <- getIdrisDocDir
+  idir <- getIdrisDataDir
+  crdir <- getIdrisCRTSDir
+  jrdir <- getIdrisJSRTSDir
+  putStrLn $ unwords ["-", "Data Dir:", idir]
   putStrLn $ unwords ["-", "Library Dir:", ldir]
+  putStrLn $ unwords ["-", "C RTS Dir:", crdir]
+  putStrLn $ unwords ["-", "JS RTS Dir:", jrdir]
   putStrLn $ unwords ["-", "User Dir:",    udir]
+  putStrLn $ unwords ["-", "Documentation Dir:", ddir]
 
   putStrLn "Flags:"
   lflag <- getIdrisFlagsLib
diff --git a/src/Idris/Inliner.hs b/src/Idris/Inliner.hs
--- a/src/Idris/Inliner.hs
+++ b/src/Idris/Inliner.hs
@@ -9,8 +9,8 @@
 
 module Idris.Inliner(inlineDef, inlineTerm) where
 
-import Idris.Core.TT
 import Idris.AbsSyntax
+import Idris.Core.TT
 
 inlineDef :: IState -> [([Name], Term, Term)] -> [([Name], Term, Term)]
 inlineDef ist ds = map (\ (ns, lhs, rhs) -> (ns, lhs, inlineTerm ist rhs)) ds
diff --git a/src/Idris/Interactive.hs b/src/Idris/Interactive.hs
--- a/src/Idris/Interactive.hs
+++ b/src/Idris/Interactive.hs
@@ -14,30 +14,29 @@
   , makeLemma
   ) where
 
-import Idris.Core.TT
-import Idris.Core.Evaluate
-import Idris.CaseSplit
 import Idris.AbsSyntax
+import Idris.CaseSplit
+import Idris.Core.Evaluate
+import Idris.Core.TT
+import Idris.Delaborate
+import Idris.Elab.Term
+import Idris.Elab.Value
 import Idris.ElabDecls
 import Idris.Error
 import Idris.ErrReverse
-import Idris.Delaborate
-import Idris.Output
 import Idris.IdeMode hiding (IdeModeCommand(..))
-import Idris.Elab.Value
-import Idris.Elab.Term
+import Idris.Output
 
 import Util.Pretty
 import Util.System
 
-import System.FilePath
-import System.Directory
-import System.IO
 import Data.Char
-import Data.Maybe (fromMaybe)
 import Data.List (isSuffixOf)
-
+import Data.Maybe (fromMaybe)
 import Debug.Trace
+import System.Directory
+import System.FilePath
+import System.IO
 
 caseSplitAt :: FilePath -> Bool -> Int -> Name -> Idris ()
 caseSplitAt fn updatefile l n
diff --git a/src/Idris/Main.hs b/src/Idris/Main.hs
--- a/src/Idris/Main.hs
+++ b/src/Idris/Main.hs
@@ -13,52 +13,47 @@
   ) where
 
 import Idris.AbsSyntax
-import Idris.ModeCommon
-import Idris.REPL.Parser
+import Idris.Core.Execute (execute)
+import Idris.Core.TT
+import Idris.Elab.Term
+import Idris.Elab.Value
+import Idris.ElabDecls
 import Idris.Error
 import Idris.IBC
-import Idris.Parser hiding (indent)
+import Idris.Info
+import Idris.ModeCommon
 import Idris.Output
-
-import Idris.REPL.Commands
+import Idris.Parser hiding (indent)
 import Idris.REPL
-
-import Idris.ElabDecls
-import Idris.Elab.Value
-import Idris.Elab.Term
-import Idris.Info
+import Idris.REPL.Commands
+import Idris.REPL.Parser
+import IRTS.CodegenCommon
 
 import Util.System
 
-import Idris.Core.Execute (execute)
-import Idris.Core.TT
-
-import IRTS.CodegenCommon
+import Prelude hiding (id, (.), (<$>))
 
 import Control.Category
-import Prelude hiding ((<$>), (.), id)
-
-import Text.Trifecta.Result(Result(..), ErrInfo(..))
-
-import System.Console.Haskeline as H
-import System.FilePath
-import System.Exit
-import System.Directory
-import System.IO
+import Control.DeepSeq
 import Control.Monad
+import Control.Monad.Trans (lift)
 import Control.Monad.Trans.Except (runExceptT)
 import Control.Monad.Trans.State.Strict (execStateT)
-import Control.Monad.Trans ( lift )
 import Data.Maybe
-import Control.DeepSeq
-
-
+import System.Console.Haskeline as H
+import System.Directory
+import System.Exit
+import System.FilePath
+import System.IO
+import Text.Trifecta.Result (ErrInfo(..), Result(..))
 
 -- | How to run Idris programs.
 runMain :: Idris () -> IO ()
 runMain prog = do res <- runExceptT $ execStateT prog idrisInit
                   case res of
-                       Left err -> putStrLn $ "Uncaught error: " ++ show err
+                       Left err -> do
+                         putStrLn $ "Uncaught error: " ++ show err
+                         exitFailure
                        Right _ -> return ()
 
 
diff --git a/src/Idris/ModeCommon.hs b/src/Idris/ModeCommon.hs
--- a/src/Idris/ModeCommon.hs
+++ b/src/Idris/ModeCommon.hs
@@ -6,32 +6,29 @@
 -}
 module Idris.ModeCommon where
 
-
 import Idris.AbsSyntax
+import Idris.Chaser
+import Idris.Core.TT
+import Idris.Delaborate
 import Idris.Erasure
 import Idris.Error
 import Idris.IBC
-import Idris.Delaborate
-import Idris.Parser hiding (indent)
-import Idris.Chaser
 import Idris.Imports
-import Idris.Output
 import Idris.Info
-import Idris.Core.TT
-
+import Idris.Output
+import Idris.Parser hiding (indent)
 import IRTS.Exports
 
-import Control.Category
-import Prelude hiding ((<$>), (.), id)
+import Prelude hiding (id, (.), (<$>))
 
-import System.Directory
+import Control.Category
+import Control.DeepSeq
 import Control.Monad
 import Control.Monad.Trans.State.Strict (get)
-import Network.Socket (PortNumber)
-import Data.Maybe
 import Data.List hiding (group)
-import Control.DeepSeq
-
+import Data.Maybe
+import Network.Socket (PortNumber)
+import System.Directory
 
 defaultPort :: PortNumber
 defaultPort = fromIntegral 4294
diff --git a/src/Idris/Output.hs b/src/Idris/Output.hs
--- a/src/Idris/Output.hs
+++ b/src/Idris/Output.hs
@@ -10,11 +10,10 @@
 
 module Idris.Output where
 
-import Idris.Core.TT
-import Idris.Core.Evaluate (isDConName, isTConName, isFnName, normaliseAll)
-
 import Idris.AbsSyntax
-import Idris.Colours (hStartColourise, hEndColourise)
+import Idris.Colours (hEndColourise, hStartColourise)
+import Idris.Core.Evaluate (isDConName, isFnName, isTConName, normaliseAll)
+import Idris.Core.TT
 import Idris.Delaborate
 import Idris.Docstrings
 import Idris.IdeMode
@@ -23,18 +22,16 @@
 import Util.ScreenSize (getScreenWidth)
 import Util.System (isATTY)
 
-import Control.Monad.Trans.Except (ExceptT (ExceptT), runExceptT)
-
-import System.Console.Haskeline.MonadException
-  (MonadException (controlIO), RunIO (RunIO))
-import System.IO (stdout, Handle, hPutStrLn, hPutStr)
-import System.FilePath (replaceExtension)
-
 import Prelude hiding ((<$>))
 
+import Control.Monad.Trans.Except (ExceptT(ExceptT), runExceptT)
 import Data.Char (isAlpha)
-import Data.List (nub, intersperse)
+import Data.List (intersperse, nub)
 import Data.Maybe (fromMaybe)
+import System.Console.Haskeline.MonadException (MonadException(controlIO),
+                                                RunIO(RunIO))
+import System.FilePath (replaceExtension)
+import System.IO (Handle, hPutStr, hPutStrLn, stdout)
 
 instance MonadException m => MonadException (ExceptT Err m) where
     controlIO f = ExceptT $ controlIO $ \(RunIO run) -> let
diff --git a/src/Idris/Package.hs b/src/Idris/Package.hs
--- a/src/Idris/Package.hs
+++ b/src/Idris/Package.hs
@@ -8,42 +8,38 @@
 {-# LANGUAGE CPP #-}
 module Idris.Package where
 
-import System.Process
-import System.Directory
-import System.Exit
-import System.IO
-import System.FilePath ((</>), addTrailingPathSeparator, takeFileName,
-                        takeDirectory, normalise, addExtension, hasExtension)
-import System.Directory (createDirectoryIfMissing, copyFile)
-
-import Util.System
-
-import Control.Monad
-import Control.Monad.Trans.State.Strict (execStateT)
-import Control.Monad.Trans.Except (runExceptT)
-
-import Data.List
-import Data.List.Split(splitOn)
-import Data.Maybe(fromMaybe)
-import Data.Either(partitionEithers)
-
-import Idris.Core.TT
-import Idris.REPL
-import Idris.Parser (loadModule)
-import Idris.Output (pshow)
 import Idris.AbsSyntax
-import Idris.IdrisDoc
+import Idris.Core.TT
+import Idris.Error (ifail)
 import Idris.IBC
-import Idris.Output
+import Idris.IdrisDoc
 import Idris.Imports
-import Idris.Error (ifail)
-import Idris.Main (idrisMain, idris)
-
+import Idris.Main (idris, idrisMain)
+import Idris.Output (pshow)
+import Idris.Output
 import Idris.Package.Common
 import Idris.Package.Parser
-
+import Idris.Parser (loadModule)
+import Idris.REPL
 import IRTS.System
 
+import Util.System
+
+import Control.Monad
+import Control.Monad.Trans.Except (runExceptT)
+import Control.Monad.Trans.State.Strict (execStateT)
+import Data.Either (partitionEithers)
+import Data.List
+import Data.List.Split (splitOn)
+import Data.Maybe (fromMaybe)
+import System.Directory
+import System.Directory (copyFile, createDirectoryIfMissing)
+import System.Exit
+import System.FilePath (addExtension, addTrailingPathSeparator, hasExtension,
+                        normalise, takeDirectory, takeFileName, (</>))
+import System.IO
+import System.Process
+
 -- To build a package:
 -- * read the package description
 -- * check all the library dependencies exist
@@ -149,6 +145,7 @@
     case mergeOptions copts (idris_opts pkgdesc) of
       Left emsg  -> ifail emsg
       Right opts -> do
+  
         putIState orig
         dir <- runIO getCurrentDirectory
         runIO $ setCurrentDirectory $ dir </> sourcedir pkgdesc
@@ -190,10 +187,10 @@
 --
 -- Issue number #1572 on the issue tracker
 --       https://github.com/idris-lang/Idris-dev/issues/1572
-documentPkg :: [Opt]    -- ^ Command line options.
-            -> FilePath -- ^ Path to ipkg file.
+documentPkg :: [Opt]           -- ^ Command line options.
+            -> (Bool,FilePath) -- ^ (Should we install?, Path to ipkg file).
             -> IO ()
-documentPkg copts fp = do
+documentPkg copts (install,fp) = do
   pkgdesc        <- parseDesc fp
   cd             <- getCurrentDirectory
   let pkgDir      = cd </> takeDirectory fp
@@ -223,7 +220,13 @@
           putStrLn $ pshow idrisInit err
           exitWith (ExitFailure 1)
         Right ist -> do
-          docRes <- generateDocs ist mods outputDir
+          iDocDir   <- getIdrisDocDir
+          pkgDocDir <- makeAbsolute (iDocDir </> pkgname pkgdesc)
+          let out_dir = if install then pkgDocDir else outputDir
+          when install $ do
+              putStrLn $ unwords ["Attempting to install IdrisDocs for", pkgname pkgdesc, "in:", out_dir]
+
+          docRes <- generateDocs ist mods out_dir
           case docRes of
             Right _  -> return ()
             Left msg -> do
@@ -235,42 +238,44 @@
 -- | Build a package with a sythesized main function that runs the tests
 testPkg :: [Opt]     -- ^ Command line options.
         -> FilePath  -- ^ Path to ipkg file.
-        -> IO ()
+        -> IO ExitCode
 testPkg copts fp = do
   pkgdesc <- parseDesc fp
   ok <- mapM (testLib True (pkgname pkgdesc)) (libdeps pkgdesc)
-  when (and ok) $ do
-    m_ist <- inPkgDir pkgdesc $ do
-      make (makefile pkgdesc)
-      -- Get a temporary file to save the tests' source in
-      (tmpn, tmph) <- tempfile ".idr"
-      hPutStrLn tmph $
-          "module Test_______\n" ++
-          concat ["import " ++ show m ++ "\n" | m <- modules pkgdesc]
-              ++ "namespace Main\n"
-              ++ "  main : IO ()\n"
-              ++ "  main = do "
-              ++ concat [ show t ++ "\n            "
-                        | t <- idris_tests pkgdesc]
-      hClose tmph
-      (tmpn', tmph') <- tempfile ""
-      hClose tmph'
-      let popts = (Filename tmpn : NoREPL : Verbose : Output tmpn' : idris_opts pkgdesc)
-      case mergeOptions copts popts of
-        Left emsg -> do
-          putStrLn emsg
-          exitWith (ExitFailure 1)
-        Right opts -> do
-          m_ist <- idris opts
-          rawSystem tmpn' []
-          return m_ist
-    case m_ist of
-      Nothing  -> exitWith (ExitFailure 1)
-      Just ist -> do
-        -- Quit with error code if problem building
-        case errSpan ist of
-          Just _ -> exitWith (ExitFailure 1)
-          _      -> return ()
+  if and ok
+    then do
+      (m_ist, exitCode) <- inPkgDir pkgdesc $ do
+        make (makefile pkgdesc)
+        -- Get a temporary file to save the tests' source in
+        (tmpn, tmph) <- tempfile ".idr"
+        hPutStrLn tmph $
+            "module Test_______\n" ++
+            concat ["import " ++ show m ++ "\n" | m <- modules pkgdesc]
+                ++ "namespace Main\n"
+                ++ "  main : IO ()\n"
+                ++ "  main = do "
+                ++ concat [ show t ++ "\n            "
+                          | t <- idris_tests pkgdesc]
+        hClose tmph
+        (tmpn', tmph') <- tempfile ""
+        hClose tmph'
+        let popts = (Filename tmpn : NoREPL : Verbose : Output tmpn' : idris_opts pkgdesc)
+        case mergeOptions copts popts of
+          Left emsg -> do
+            putStrLn emsg
+            exitWith (ExitFailure 1)
+          Right opts -> do
+            m_ist    <- idris opts
+            exitCode <- rawSystem tmpn' []
+            return (m_ist, exitCode)
+      case m_ist of
+        Nothing  -> exitWith (ExitFailure 1)
+        Just ist -> do
+          -- Quit with error code if problem building
+          case errSpan ist of
+            Just _ -> exitWith (ExitFailure 1)
+            _      -> return exitCode
+    else return (ExitFailure 1)
 
 --  ----------------------------------------------------------- [ Installation ]
 
@@ -279,7 +284,7 @@
            -> PkgDesc   -- ^ iPKG file.
            -> IO ()
 installPkg altdests pkgdesc = inPkgDir pkgdesc $ do
-  d <- getTargetDir
+  d <- getIdrisLibDir
   let destdir = case altdests of
                   []     -> d
                   (d':_) -> d'
@@ -302,11 +307,11 @@
 
 testLib :: Bool -> String -> String -> IO Bool
 testLib warn p f
-    = do d <- getDataDir
+    = do d <- getIdrisCRTSDir
          gcc <- getCC
          (tmpf, tmph) <- tempfile ""
          hClose tmph
-         let libtest = d </> "rts" </> "libtest.c"
+         let libtest = d </> "libtest.c"
          e <- rawSystem gcc [libtest, "-l" ++ f, "-o", tmpf]
          case e of
             ExitSuccess -> return True
@@ -416,14 +421,15 @@
     normaliseOpts = filter filtOpt
 
     filtOpt :: Opt -> Bool
-    filtOpt (PkgBuild   _) = False
-    filtOpt (PkgInstall _) = False
-    filtOpt (PkgClean   _) = False
-    filtOpt (PkgCheck   _) = False
-    filtOpt (PkgREPL    _) = False
-    filtOpt (PkgMkDoc   _) = False
-    filtOpt (PkgTest    _) = False
-    filtOpt _              = True
+    filtOpt (PkgBuild        _) = False
+    filtOpt (PkgInstall      _) = False
+    filtOpt (PkgClean        _) = False
+    filtOpt (PkgCheck        _) = False
+    filtOpt (PkgREPL         _) = False
+    filtOpt (PkgDocBuild     _) = False
+    filtOpt (PkgDocInstall   _) = False
+    filtOpt (PkgTest         _) = False
+    filtOpt _                   = True
 
     chkOpt :: Opt -> Either String Opt
     chkOpt o@(OLogging _)     = Right o
diff --git a/src/Idris/Package/Common.hs b/src/Idris/Package/Common.hs
--- a/src/Idris/Package/Common.hs
+++ b/src/Idris/Package/Common.hs
@@ -6,9 +6,8 @@
 -}
 module Idris.Package.Common where
 
-import Idris.Core.TT (Name)
-
 import Idris.AbsSyntaxTree (Opt(..))
+import Idris.Core.TT (Name)
 
 -- | Description of an Idris package.
 data PkgDesc = PkgDesc {
diff --git a/src/Idris/Package/Parser.hs b/src/Idris/Package/Parser.hs
--- a/src/Idris/Package/Parser.hs
+++ b/src/Idris/Package/Parser.hs
@@ -11,23 +11,23 @@
 #endif
 module Idris.Package.Parser where
 
-import Text.Trifecta hiding (span, charLiteral, natural, symbol, char, string, whiteSpace)
-import qualified Text.PrettyPrint.ANSI.Leijen as PP
-import Idris.Core.TT
-import Idris.REPL
 import Idris.AbsSyntaxTree
-import Idris.Parser.Helpers hiding (stringLiteral)
 import Idris.CmdOptions
-
+import Idris.Core.TT
 import Idris.Package.Common
+import Idris.Parser.Helpers hiding (stringLiteral)
+import Idris.REPL
 
-import Control.Monad.State.Strict
+import Util.System
+
 import Control.Applicative
-import System.FilePath (takeFileName, isValid)
-import Data.Maybe (isNothing, fromJust)
+import Control.Monad.State.Strict
 import Data.List (union)
-
-import Util.System
+import Data.Maybe (fromJust, isNothing)
+import System.FilePath (isValid, takeFileName)
+import qualified Text.PrettyPrint.ANSI.Leijen as PP
+import Text.Trifecta hiding (char, charLiteral, natural, span, string, symbol,
+                      whiteSpace)
 
 type PParser = StateT PkgDesc IdrisInnerParser
 
diff --git a/src/Idris/Parser.hs b/src/Idris/Parser.hs
--- a/src/Idris/Parser.hs
+++ b/src/Idris/Parser.hs
@@ -5,7 +5,7 @@
 License     : BSD3
 Maintainer  : The Idris Community.
 -}
-{-# LANGUAGE GeneralizedNewtypeDeriving, ConstraintKinds, PatternGuards #-}
+{-# LANGUAGE ConstraintKinds, GeneralizedNewtypeDeriving, PatternGuards #-}
 {-# OPTIONS_GHC -O0 #-}
 module Idris.Parser(module Idris.Parser,
                     module Idris.Parser.Expr,
@@ -13,74 +13,67 @@
                     module Idris.Parser.Helpers,
                     module Idris.Parser.Ops) where
 
-import Prelude hiding (pi)
-
-import qualified System.Directory as Dir (makeAbsolute)
-
-import Text.Trifecta.Delta
-import Text.Trifecta hiding (span, stringLiteral, charLiteral, natural, symbol, char, string, whiteSpace, Err)
-import Text.Parser.LookAhead
-import Text.Parser.Expression
-import qualified Text.Parser.Token as Tok
-import qualified Text.Parser.Char as Chr
-import qualified Text.Parser.Token.Highlight as Hi
-
-import Text.PrettyPrint.ANSI.Leijen (Doc, plain)
-import qualified Text.PrettyPrint.ANSI.Leijen as ANSI
-
 import Idris.AbsSyntax hiding (namespace, params)
-import Idris.DSL
-import Idris.Imports
+import Idris.Core.Evaluate
+import Idris.Core.TT
+import Idris.Coverage
 import Idris.Delaborate
-import Idris.Error
-import Idris.Elab.Value
+import Idris.Docstrings hiding (Unchecked)
+import Idris.DSL
 import Idris.Elab.Term
+import Idris.Elab.Value
 import Idris.ElabDecls
-import Idris.Coverage
+import Idris.Error
 import Idris.IBC
-import Idris.Unlit
-import Idris.Providers
+import Idris.Imports
 import Idris.Output
-
+import Idris.Parser.Data
+import Idris.Parser.Expr
 import Idris.Parser.Helpers
 import Idris.Parser.Ops
-import Idris.Parser.Expr
-import Idris.Parser.Data
-
-import Idris.Docstrings hiding (Unchecked)
-
-import Paths_idris
+import Idris.Providers
+import Idris.Termination
+import Idris.Unlit
 
 import Util.DynamicLinker
-import Util.System (readSource, writeSource)
 import qualified Util.Pretty as P
+import Util.System (readSource, writeSource)
 
-import Idris.Core.TT
-import Idris.Core.Evaluate
+import Paths_idris
 
+import Prelude hiding (pi)
+
 import Control.Applicative hiding (Const)
 import Control.Monad
 import Control.Monad.State.Strict
-
-import Data.Function
-import Data.Maybe
-import qualified Data.List.Split as Spl
-import Data.List
-import Data.Monoid
+import qualified Data.ByteString.UTF8 as UTF8
 import Data.Char
-import Data.Ord
 import Data.Foldable (asum)
+import Data.Function
 import Data.Generics.Uniplate.Data (descendM)
-import qualified Data.Map as M
 import qualified Data.HashSet as HS
-import qualified Data.Text as T
-import qualified Data.ByteString.UTF8 as UTF8
+import Data.List
+import qualified Data.List.Split as Spl
+import qualified Data.Map as M
+import Data.Maybe
+import Data.Monoid
+import Data.Ord
 import qualified Data.Set as S
-
+import qualified Data.Text as T
 import Debug.Trace
-
+import qualified System.Directory as Dir (makeAbsolute)
 import System.FilePath
 import System.IO
+import qualified Text.Parser.Char as Chr
+import Text.Parser.Expression
+import Text.Parser.LookAhead
+import qualified Text.Parser.Token as Tok
+import qualified Text.Parser.Token.Highlight as Hi
+import Text.PrettyPrint.ANSI.Leijen (Doc, plain)
+import qualified Text.PrettyPrint.ANSI.Leijen as ANSI
+import Text.Trifecta hiding (Err, char, charLiteral, natural, span, string,
+                      stringLiteral, symbol, whiteSpace)
+import Text.Trifecta.Delta
 
 {-
 @
@@ -699,6 +692,8 @@
                     return Reflection
         <|> do try (lchar '%' *> reserved "hint");
                     return AutoHint
+        <|> do try (lchar '%' *> reserved "overlapping");
+                    return OverlappingDictionary
         <|> do lchar '%'; reserved "specialise";
                lchar '['; ns <- sepBy nameTimes (lchar ','); lchar ']';
                return $ Specialise ns
diff --git a/src/Idris/Parser/Data.hs b/src/Idris/Parser/Data.hs
--- a/src/Idris/Parser/Data.hs
+++ b/src/Idris/Parser/Data.hs
@@ -5,46 +5,40 @@
 License     : BSD3
 Maintainer  : The Idris Community.
 -}
-{-# LANGUAGE GeneralizedNewtypeDeriving, ConstraintKinds, PatternGuards #-}
+{-# LANGUAGE ConstraintKinds, GeneralizedNewtypeDeriving, PatternGuards #-}
 module Idris.Parser.Data where
 
-import Prelude hiding (pi)
-
-import Text.Trifecta.Delta
-import Text.Trifecta hiding ( span, stringLiteral, charLiteral, natural
-                            , symbol, char, string, whiteSpace, Err)
-
-import           Text.Parser.LookAhead
-import           Text.Parser.Expression
-import qualified Text.Parser.Token as Tok
-import qualified Text.Parser.Char as Chr
-import qualified Text.Parser.Token.Highlight as Hi
-
 import Idris.AbsSyntax
+import Idris.Core.Evaluate
+import Idris.Core.TT
+import Idris.Docstrings
+import Idris.DSL
+import Idris.Parser.Expr
 import Idris.Parser.Helpers
 import Idris.Parser.Ops
-import Idris.Parser.Expr
-import Idris.DSL
 
-import Idris.Core.TT
-import Idris.Core.Evaluate
-
-import Idris.Docstrings
+import Prelude hiding (pi)
 
 import Control.Applicative
 import Control.Monad
 import Control.Monad.State.Strict
-
-import           Data.Maybe
-import qualified Data.List.Split as Spl
-import           Data.List
-import           Data.Monoid
-import           Data.Char
+import qualified Data.ByteString.UTF8 as UTF8
+import Data.Char
 import qualified Data.HashSet as HS
+import Data.List
+import qualified Data.List.Split as Spl
+import Data.Maybe
+import Data.Monoid
 import qualified Data.Text as T
-import qualified Data.ByteString.UTF8 as UTF8
-
 import Debug.Trace
+import qualified Text.Parser.Char as Chr
+import Text.Parser.Expression
+import Text.Parser.LookAhead
+import qualified Text.Parser.Token as Tok
+import qualified Text.Parser.Token.Highlight as Hi
+import Text.Trifecta hiding (Err, char, charLiteral, natural, span, string,
+                      stringLiteral, symbol, whiteSpace)
+import Text.Trifecta.Delta
 
 {- | Parses a record type declaration
 Record ::=
diff --git a/src/Idris/Parser/Expr.hs b/src/Idris/Parser/Expr.hs
--- a/src/Idris/Parser/Expr.hs
+++ b/src/Idris/Parser/Expr.hs
@@ -9,6 +9,12 @@
 {-# LANGUAGE PatternGuards, TupleSections                #-}
 module Idris.Parser.Expr where
 
+import Idris.AbsSyntax
+import Idris.Parser.Helpers
+import Idris.Parser.Ops
+import Idris.DSL
+import Idris.Core.TT
+
 import Prelude hiding (pi)
 
 import Text.Trifecta.Delta
@@ -18,18 +24,9 @@
 import qualified Text.Parser.Token as Tok
 import qualified Text.Parser.Char as Chr
 import qualified Text.Parser.Token.Highlight as Hi
-
-import Idris.AbsSyntax
-import Idris.Parser.Helpers
-import Idris.Parser.Ops
-import Idris.DSL
-
-import Idris.Core.TT
-
 import Control.Applicative
 import Control.Monad
 import Control.Monad.State.Strict
-
 import Data.Function (on)
 import Data.Maybe
 import qualified Data.List.Split as Spl
@@ -39,7 +36,6 @@
 import qualified Data.HashSet as HS
 import qualified Data.Text as T
 import qualified Data.ByteString.UTF8 as UTF8
-
 import Debug.Trace
 
 -- | Allow implicit type declarations
diff --git a/src/Idris/Parser/Helpers.hs b/src/Idris/Parser/Helpers.hs
--- a/src/Idris/Parser/Helpers.hs
+++ b/src/Idris/Parser/Helpers.hs
@@ -5,50 +5,46 @@
 License     : BSD3
 Maintainer  : The Idris Community.
 -}
-{-# LANGUAGE CPP, GeneralizedNewtypeDeriving, ConstraintKinds #-}
-{-# LANGUAGE PatternGuards, StandaloneDeriving                 #-}
+{-# LANGUAGE CPP, ConstraintKinds, GeneralizedNewtypeDeriving, PatternGuards,
+             StandaloneDeriving #-}
 #if !(MIN_VERSION_base(4,8,0))
 {-# LANGUAGE OverlappingInstances #-}
 #endif
 module Idris.Parser.Helpers where
 
-import Prelude hiding (pi)
-
-import Text.Trifecta.Delta
-import Text.Trifecta hiding (span, stringLiteral, charLiteral, natural, symbol, char, string, whiteSpace, Err)
-import Text.Parser.LookAhead
-import Text.Parser.Expression
-import qualified Text.Parser.Token as Tok
-import qualified Text.Parser.Char as Chr
-import qualified Text.Parser.Token.Highlight as Hi
-
 import Idris.AbsSyntax
-
-import Idris.Core.TT
 import Idris.Core.Evaluate
+import Idris.Core.TT
 import Idris.Delaborate (pprintErr)
 import Idris.Docstrings
 import Idris.Output (iWarn)
 
 import qualified Util.Pretty as Pretty (text)
 
+import Prelude hiding (pi)
+
 import Control.Applicative
 import Control.Monad
 import Control.Monad.State.Strict
-
-import Data.Maybe
-import qualified Data.List.Split as Spl
-import Data.List
-import Data.Monoid
+import qualified Data.ByteString.UTF8 as UTF8
 import Data.Char
-import qualified Data.Map as M
 import qualified Data.HashSet as HS
+import Data.List
+import qualified Data.List.Split as Spl
+import qualified Data.Map as M
+import Data.Maybe
+import Data.Monoid
 import qualified Data.Text as T
-import qualified Data.ByteString.UTF8 as UTF8
-
-import System.FilePath
-
 import Debug.Trace
+import System.FilePath
+import qualified Text.Parser.Char as Chr
+import Text.Parser.Expression
+import Text.Parser.LookAhead
+import qualified Text.Parser.Token as Tok
+import qualified Text.Parser.Token.Highlight as Hi
+import Text.Trifecta hiding (Err, char, charLiteral, natural, span, string,
+                      stringLiteral, symbol, whiteSpace)
+import Text.Trifecta.Delta
 
 -- | Idris parser with state used during parsing
 type IdrisParser = StateT IState IdrisInnerParser
diff --git a/src/Idris/Parser/Ops.hs b/src/Idris/Parser/Ops.hs
--- a/src/Idris/Parser/Ops.hs
+++ b/src/Idris/Parser/Ops.hs
@@ -5,38 +5,35 @@
 License     : BSD3
 Maintainer  : The Idris Community.
 -}
-{-# LANGUAGE GeneralizedNewtypeDeriving, ConstraintKinds, PatternGuards #-}
+{-# LANGUAGE ConstraintKinds, GeneralizedNewtypeDeriving, PatternGuards #-}
 module Idris.Parser.Ops where
 
-import Prelude hiding (pi)
-
-import Text.Trifecta.Delta
-import Text.Trifecta hiding (span, stringLiteral, charLiteral, natural, symbol, char, string, whiteSpace)
-import Text.Parser.LookAhead
-import Text.Parser.Expression
-import qualified Text.Parser.Token as Tok
-import qualified Text.Parser.Char as Chr
-import qualified Text.Parser.Token.Highlight as Hi
-
 import Idris.AbsSyntax
+import Idris.Core.TT
 import Idris.Parser.Helpers
 
-import Idris.Core.TT
+import Prelude hiding (pi)
 
 import Control.Applicative
 import Control.Monad
 import Control.Monad.State.Strict
-
-import Data.Maybe
-import qualified Data.List.Split as Spl
-import Data.List
-import Data.Monoid
+import qualified Data.ByteString.UTF8 as UTF8
 import Data.Char
 import qualified Data.HashSet as HS
+import Data.List
+import qualified Data.List.Split as Spl
+import Data.Maybe
+import Data.Monoid
 import qualified Data.Text as T
-import qualified Data.ByteString.UTF8 as UTF8
-
 import Debug.Trace
+import qualified Text.Parser.Char as Chr
+import Text.Parser.Expression
+import Text.Parser.LookAhead
+import qualified Text.Parser.Token as Tok
+import qualified Text.Parser.Token.Highlight as Hi
+import Text.Trifecta hiding (char, charLiteral, natural, span, string,
+                      stringLiteral, symbol, whiteSpace)
+import Text.Trifecta.Delta
 
 -- | Creates table for fixity declarations to build expression parser
 -- using pre-build and user-defined operator/fixity declarations
diff --git a/src/Idris/PartialEval.hs b/src/Idris/PartialEval.hs
--- a/src/Idris/PartialEval.hs
+++ b/src/Idris/PartialEval.hs
@@ -14,23 +14,24 @@
   ) where
 
 import Idris.AbsSyntax
-import Idris.Delaborate
-
-import Idris.Core.TT
 import Idris.Core.CaseTree
 import Idris.Core.Evaluate
+import Idris.Core.TT
+import Idris.Delaborate
 
-import Control.Monad.State
 import Control.Applicative
+import Control.Monad.State
 import Data.Maybe
 import Debug.Trace
 
 -- | Data type representing binding-time annotations for partial evaluation of arguments
-data PEArgType = ImplicitS -- ^ Implicit static argument
-               | ImplicitD -- ^ Implicit dynamic argument
-               | ExplicitS -- ^ Explicit static argument
-               | ExplicitD -- ^ Explicit dynamic argument
-               | UnifiedD  -- ^ Erasable dynamic argument (found under unification)
+data PEArgType = ImplicitS Name -- ^ Implicit static argument
+               | ImplicitD Name -- ^ Implicit dynamic argument
+               | ConstraintS    -- ^ Implementation constraint
+               | ConstraintD    -- ^ Implementation constraint
+               | ExplicitS      -- ^ Explicit static argument
+               | ExplicitD      -- ^ Explicit dynamic argument
+               | UnifiedD       -- ^ Erasable dynamic argument (found under unification)
   deriving (Eq, Show)
 
 -- | A partially evaluated function. pe_app captures the lhs of the
@@ -98,8 +99,10 @@
     -- of expecting it as a function argument
     st ((ExplicitS, v) : xs) (Bind n (Pi _ t _) sc)
          = Bind n (Let t v) (st xs sc)
-    st ((ImplicitS, v) : xs) (Bind n (Pi _ t _) sc)
+    st ((ImplicitS _, v) : xs) (Bind n (Pi _ t _) sc)
          = Bind n (Let t v) (st xs sc)
+    st ((ConstraintS, v) : xs) (Bind n (Pi _ t _) sc)
+         = Bind n (Let t v) (st xs sc)
     -- Erase argument from function type
     st ((UnifiedD, _) : xs) (Bind n (Pi _ t _) sc)
          = st xs sc
@@ -110,7 +113,7 @@
 
     -- Erase implicit dynamic argument if existing argument shares it value,
     -- by substituting the value of previous argument
-    unifyEq (imp@(ImplicitD, v) : xs) (Bind n (Pi i t k) sc)
+    unifyEq (imp@(ImplicitD _, v) : xs) (Bind n (Pi i t k) sc)
          = do amap <- get
               case lookup imp amap of
                    Just n' ->
@@ -140,11 +143,12 @@
   where
     mkty ((ExplicitD, v) : xs) (Bind n (Pi _ t k) sc)
        = PPi expl n NoFC (delab ist (generaliseIn t)) (mkty xs sc)
-    mkty ((ImplicitD, v) : xs) (Bind n (Pi _ t k) sc)
+    mkty ((ConstraintD, v) : xs) (Bind n (Pi _ t k) sc)
          | concreteInterface ist t = mkty xs sc
          | interfaceConstraint ist t
              = PPi constraint n NoFC (delab ist (generaliseIn t)) (mkty xs sc)
-         | otherwise = PPi impl n NoFC (delab ist (generaliseIn t)) (mkty xs sc)
+    mkty ((ImplicitD _, v) : xs) (Bind n (Pi _ t k) sc)
+         = PPi impl n NoFC (delab ist (generaliseIn t)) (mkty xs sc)
 
     mkty (_ : xs) t
        = mkty xs t
@@ -201,7 +205,8 @@
                          (_, args) -> dynArgs ns args
         dynArgs _ [] = True -- can definitely reduce from here
         -- if Static, doesn't matter what the argument is
-        dynArgs ((ImplicitS, _) : ns) (a : as) = dynArgs ns as
+        dynArgs ((ImplicitS _, _) : ns) (a : as) = dynArgs ns as
+        dynArgs ((ConstraintS, _) : ns) (a : as) = dynArgs ns as
         dynArgs ((ExplicitS, _) : ns) (a : as) = dynArgs ns as
         -- if Dynamic, it had better be a variable or we'll need to
         -- do some more work
@@ -210,7 +215,7 @@
         dynArgs _ _ = False -- and now we'll get stuck
 
 mkNewPats ist d ns newname sname lhs rhs =
-    PEDecl lhs rhs (map mkClause d) False
+           PEDecl lhs rhs (map mkClause d) False
   where
     mkClause :: (Term, Term) -> (PTerm, PTerm)
     mkClause (oldlhs, oldrhs)
@@ -222,25 +227,37 @@
                      (lhs, rhs)
 
     mkLHSargs _ [] _ = []
-    -- dynamics don't appear if they're implicit
+    -- dynamics don't appear on the LHS if they're implicit
     mkLHSargs sub ((ExplicitD, t) : ns) (a : as)
          = pexp (delab ist (substNames sub a)) : mkLHSargs sub ns as
-    mkLHSargs sub ((ImplicitD, _) : ns) (a : as)
-         = mkLHSargs sub ns as
+    mkLHSargs sub ((ImplicitD n, t) : ns) (a : as)
+         = pimp n (delab ist (substNames sub a)) True : mkLHSargs sub ns as
+    mkLHSargs sub ((ConstraintD, t) : ns) (a : as)
+         = pconst (delab ist (substNames sub a)) : mkLHSargs sub ns as
     mkLHSargs sub ((UnifiedD, _) : ns) (a : as)
          = mkLHSargs sub ns as
     -- statics get dropped in any case
-    mkLHSargs sub ((ImplicitS, t) : ns) (a : as)
+    mkLHSargs sub ((ImplicitS _, t) : ns) (a : as)
          = mkLHSargs (extend a t sub) ns as
     mkLHSargs sub ((ExplicitS, t) : ns) (a : as)
          = mkLHSargs (extend a t sub) ns as
+    mkLHSargs sub ((ConstraintS, t) : ns) (a : as)
+         = mkLHSargs (extend a t sub) ns as
     mkLHSargs sub _ [] = [] -- no more LHS
 
     extend (P _ n _) t sub = (n, t) : sub
     extend _ _ sub = sub
 
+    --- 'as' are the LHS arguments
     mkRHSargs ((ExplicitS, t) : ns) as = pexp (delab ist t) : mkRHSargs ns as
     mkRHSargs ((ExplicitD, t) : ns) (a : as) = a : mkRHSargs ns as
+    -- Keep the implicits on the RHS, in case they got matched on
+    mkRHSargs ((ImplicitD n, t) : ns) (a : as) = a : mkRHSargs ns as
+    mkRHSargs ((ImplicitS n, t) : ns) as -- Dropped from LHS
+          = pimp n (delab ist t) True : mkRHSargs ns as
+    mkRHSargs ((ConstraintD, t) : ns) (a : as) = a : mkRHSargs ns as
+    mkRHSargs ((ConstraintS, t) : ns) as -- Dropped from LHS
+          = pconst (delab ist t) : mkRHSargs ns as
     mkRHSargs (_ : ns) as = mkRHSargs ns as
     mkRHSargs _ _ = []
 
@@ -255,12 +272,26 @@
 mkPE_TermDecl :: IState
               -> Name
               -> Name
+              -> PTerm -- ^ Type of specialised function
               -> [(PEArgType, Term)]
               -> PEDecl
-mkPE_TermDecl ist newname sname ns
-    = let lhs = PApp emptyFC (PRef emptyFC [] newname) (map pexp (mkp ns))
-          rhs = eraseImps $ delab ist (mkApp (P Ref sname Erased) (map snd ns))
-          patdef = lookupCtxtExact sname (idris_patdefs ist)
+mkPE_TermDecl ist newname sname specty ns
+      {- We need to erase the *dynamic* arguments 
+         where their *name* appears in the *type* of a later argument
+         in specty.
+         i.e. if a later dynamic argument depends on an earlier dynamic
+         argument, we should infer the earlier one.
+         Then we need to erase names from the LHS which no longer appear
+         on the RHS.
+         -}
+    = let deps = getDepNames (eraseRet specty)
+          lhs = eraseDeps deps $ 
+                  PApp emptyFC (PRef emptyFC [] newname) (mkp ns)
+          rhs = eraseDeps deps $
+                  delab ist (mkApp (P Ref sname Erased) (map snd ns))
+          patdef = -- trace (showTmImpls specty ++ "\n" ++ showTmImpls lhs ++ "\n"
+                   --      ++ showTmImpls rhs) $ 
+                   lookupCtxtExact sname (idris_patdefs ist)
           newpats = case patdef of
                          Nothing -> PEDecl lhs rhs [(lhs, rhs)] True
                          Just d -> mkNewPats ist (getPats d) ns
@@ -269,17 +300,28 @@
 
   getPats (ps, _) = map (\(_, lhs, rhs) -> (lhs, rhs)) ps
 
+  eraseRet (PPi p n fc ty sc) = PPi p n fc ty (eraseRet sc)
+  eraseRet _ = Placeholder
+
+  -- Get names used in later arguments; assume we've called eraseRet so there's
+  -- no names going to appear in return type
+  getDepNames (PPi _ n _ _ sc) 
+        | n `elem` allNamesIn sc = n : getDepNames sc
+        | otherwise = getDepNames sc
+  getDepNames tm = []
+
   mkp [] = []
-  mkp ((ExplicitD, tm) : tms) = delab ist tm : mkp tms
+  mkp ((ExplicitD, tm) : tms) = pexp (delab ist tm) : mkp tms
+  mkp ((ImplicitD n, tm) : tms) = pimp n (delab ist tm) True : mkp tms
   mkp (_ : tms) = mkp tms
 
-  eraseImps tm = mapPT deImp tm
+  eraseDeps ns tm = mapPT (deImp ns) tm
 
-  deImp (PApp fc t as) = PApp fc t (map deImpArg as)
-  deImp t = t
+  deImp ns (PApp fc t as) = PApp fc t (map (deImpArg ns) as)
+  deImp ns t = t
 
-  deImpArg a@(PImp _ _ _ _ _) = a { getTm = Placeholder }
-  deImpArg a = a
+  deImpArg ns a | pname a `elem` ns = a { getTm = Placeholder }
+                | otherwise = a
 
 -- | Get specialised applications for a given function
 getSpecApps :: IState
@@ -291,14 +333,22 @@
 --     staticArg env True _ tm@(P _ n _) _ | n `elem` env = Just (True, tm)
 --     staticArg env True _ tm@(App f a) _ | (P _ n _, args) <- unApply tm,
 --                                            n `elem` env = Just (True, tm)
-    staticArg env x imp tm n
-         | x && imparg imp = (ImplicitS, tm)
-         | x = (ExplicitS, tm)
-         | imparg imp = (ImplicitD, tm)
+    staticArg env True imp tm n
+         | Just n <- imparg imp = (ImplicitS n, tm)
+         | constrarg imp = (ConstraintS, tm)
+         | otherwise = (ExplicitS, tm)
+    
+    staticArg env False imp tm n
+         | Just nm <- imparg imp = (ImplicitD nm, (P Ref (sUN (show n ++ "arg")) Erased))
+         | constrarg imp = (ConstraintD, tm)
          | otherwise = (ExplicitD, (P Ref (sUN (show n ++ "arg")) Erased))
 
-    imparg (PExp _ _ _ _) = False
-    imparg _ = True
+    imparg (PExp _ _ _ _) = Nothing
+    imparg (PConstraint _ _ _ _) = Nothing
+    imparg arg = Just (pname arg)
+
+    constrarg (PConstraint _ _ _ _) = True
+    constrarg arg = False
 
     buildApp env [] [] _ _ = []
     buildApp env (s:ss) (i:is) (a:as) (n:ns)
diff --git a/src/Idris/Primitives.hs b/src/Idris/Primitives.hs
--- a/src/Idris/Primitives.hs
+++ b/src/Idris/Primitives.hs
@@ -5,23 +5,21 @@
 License     : BSD3
 Maintainer  : The Idris Community.
 -}
-{-# LANGUAGE RankNTypes, ScopedTypeVariables, PatternGuards #-}
+{-# LANGUAGE PatternGuards, RankNTypes, ScopedTypeVariables #-}
 
 module Idris.Primitives(primitives, Prim(..)) where
 
 import Idris.AbsSyntax
-
+import Idris.Core.Evaluate
+import Idris.Core.TT
 import IRTS.Lang
 
-import Idris.Core.TT
-import Idris.Core.Evaluate
 import Data.Bits
-import Data.Word
-import Data.Int
 import Data.Char
 import Data.Function (on)
+import Data.Int
 import qualified Data.Vector.Unboxed as V
-
+import Data.Word
 import Debug.Trace
 
 data Prim = Prim { p_name  :: Name,
diff --git a/src/Idris/ProofSearch.hs b/src/Idris/ProofSearch.hs
--- a/src/Idris/ProofSearch.hs
+++ b/src/Idris/ProofSearch.hs
@@ -15,22 +15,21 @@
   , resolveTC
   ) where
 
+import Idris.AbsSyntax
+import Idris.Core.CaseTree
 import Idris.Core.Elaborate hiding (Tactic(..))
-import Idris.Core.TT
-import Idris.Core.Unify
 import Idris.Core.Evaluate
-import Idris.Core.CaseTree
+import Idris.Core.TT
 import Idris.Core.Typecheck
-
-import Idris.AbsSyntax
+import Idris.Core.Unify
 import Idris.Delaborate
 import Idris.Error
 
 import Control.Applicative ((<$>))
 import Control.Monad
 import Control.Monad.State.Strict
-import qualified Data.Set as S
 import Data.List
+import qualified Data.Set as S
 import Debug.Trace
 
 -- Pass in a term elaborator to avoid a cyclic dependency with ElabTerm
@@ -526,8 +525,8 @@
 findImplementations ist t
     | (P _ n _, _) <- unApply (getRetTy t)
         = case lookupCtxt n (idris_interfaces ist) of
-            [CI _ _ _ _ _ ins _] ->
-              [n | (n, True) <- ins, accessible n]
+            [ci] -> let ins = interface_implementations ci in
+                        [n | (n, True) <- ins, accessible n]
             _ -> []
     | otherwise = []
   where accessible n = case lookupDefAccExact n False (tt_ctxt ist) of
diff --git a/src/Idris/Prover.hs b/src/Idris/Prover.hs
--- a/src/Idris/Prover.hs
+++ b/src/Idris/Prover.hs
@@ -10,45 +10,41 @@
 
 -- Hack for GHC 7.10 and earlier compat without CPP or warnings
 -- This exludes (<$>) as fmap, because wl-pprint uses it for newline
-import Prelude (Eq(..), Show(..),
-                Bool(..), Either(..), Maybe(..), String,
-                (.), ($), (++), (||), (&&),
-                concatMap, id, elem, error, fst, flip, foldl, foldr, init,
-                length, lines, map, not, null, repeat, reverse, tail, zip)
+import Prelude (Bool(..), Either(..), Eq(..), Maybe(..), Show(..), String,
+                concatMap, elem, error, flip, foldl, foldr, fst, id, init,
+                length, lines, map, not, null, repeat, reverse, tail, zip, ($),
+                (&&), (++), (.), (||))
 
+import Idris.AbsSyntax
+import Idris.AbsSyntaxTree
+import Idris.Completion
+import Idris.Core.CaseTree
 import Idris.Core.Elaborate hiding (Tactic(..))
-import Idris.Core.TT
 import Idris.Core.Evaluate
-import Idris.Core.CaseTree
+import Idris.Core.TT
 import Idris.Core.Typecheck
-
+import Idris.DataOpts
+import Idris.Delaborate
+import Idris.Docs (getDocs, pprintConstDocs, pprintDocs)
+import Idris.Elab.Term
 import Idris.Elab.Utils
 import Idris.Elab.Value
-import Idris.Elab.Term
-
-import Idris.AbsSyntax
-import Idris.AbsSyntaxTree
-import Idris.Delaborate
-import Idris.Docs (getDocs, pprintDocs, pprintConstDocs)
 import Idris.ElabDecls
-import Idris.Parser hiding (params)
 import Idris.Error
-import Idris.DataOpts
-import Idris.Completion
 import qualified Idris.IdeMode as IdeMode
 import Idris.Output
+import Idris.Parser hiding (params)
 import Idris.TypeSearch (searchByType)
 
-import Text.Trifecta.Result(Result(..), ErrInfo(..))
+import Util.Pretty
 
-import System.IO (Handle, stdin, stdout, hPutStrLn)
-import System.Console.Haskeline
-import System.Console.Haskeline.History
-import Control.Monad.State.Strict
 import Control.DeepSeq
-
-import Util.Pretty
+import Control.Monad.State.Strict
 import Debug.Trace
+import System.Console.Haskeline
+import System.Console.Haskeline.History
+import System.IO (Handle, hPutStrLn, stdin, stdout)
+import Text.Trifecta.Result (ErrInfo(..), Result(..))
 
 -- | Launch the proof shell
 prover :: ElabInfo -> Bool -> Bool -> Name -> Idris ()
@@ -124,8 +120,6 @@
                      tclift $ addCasedef n ei (CaseInfo True True False) False (STerm Erased) True False
                                 [] []  -- argtys, inaccArgs
                                 [Right (P Ref n ty, ptm)]
-                                [([], P Ref n ty, ptm)]
-                                [([], P Ref n ty, ptm)]
                                 [([], P Ref n ty, ptm)]
                                 [([], P Ref n ty, ptm')] ty
                                 ctxt
diff --git a/src/Idris/Providers.hs b/src/Idris/Providers.hs
--- a/src/Idris/Providers.hs
+++ b/src/Idris/Providers.hs
@@ -5,17 +5,17 @@
 License     : BSD3
 Maintainer  : The Idris Community.
 -}
-{-# LANGUAGE PatternGuards, DeriveFunctor #-}
+{-# LANGUAGE DeriveFunctor, PatternGuards #-}
 module Idris.Providers (
     providerTy
   , getProvided
   , Provided(..)
   ) where
 
-import Idris.Core.TT
-import Idris.Core.Evaluate
 import Idris.AbsSyntax
 import Idris.AbsSyntaxTree
+import Idris.Core.Evaluate
+import Idris.Core.TT
 import Idris.Error
 
 -- | Wrap a type provider in the type of type providers
diff --git a/src/Idris/REPL.hs b/src/Idris/REPL.hs
--- a/src/Idris/REPL.hs
+++ b/src/Idris/REPL.hs
@@ -4,8 +4,8 @@
 License     : BSD3
 Maintainer  : The Idris Community.
 -}
-{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, DeriveFunctor,
-             PatternGuards, CPP #-}
+{-# LANGUAGE CPP, DeriveFunctor, FlexibleInstances, MultiParamTypeClasses,
+             PatternGuards #-}
 module Idris.REPL
   ( idemodeStart
   , startServer
@@ -17,97 +17,85 @@
   ) where
 
 import Idris.AbsSyntax
-import Idris.ASTUtils
 import Idris.Apropos (apropos, aproposModules)
-import Idris.REPL.Parser
+import Idris.ASTUtils
+import Idris.Colours hiding (colourise)
+import Idris.Completion
+import Idris.Core.Constraints
+import Idris.Core.Evaluate
+import Idris.Core.Execute (execute)
+import Idris.Core.TT
+import Idris.Core.Unify
+import Idris.Core.WHNF
+import Idris.Coverage
+import Idris.Delaborate
+import Idris.Docs hiding (Doc)
+import Idris.Docstrings (overview, renderDocTerm, renderDocstring)
+import Idris.Elab.Clause
+import Idris.Elab.Term
+import Idris.Elab.Value
+import Idris.ElabDecls
 import Idris.Error
-import Idris.IBC
 import Idris.ErrReverse
-import Idris.Delaborate
-import Idris.Docstrings (overview, renderDocstring, renderDocTerm)
 import Idris.Help
-import Idris.IdrisDoc
-import Idris.Prover
-import Idris.Parser hiding (indent)
-import Idris.Coverage
-import Idris.Docs hiding (Doc)
-import Idris.Completion
+import Idris.IBC
 import qualified Idris.IdeMode as IdeMode
-import Idris.Colours hiding (colourise)
+import Idris.IdrisDoc
+import Idris.Info
 import Idris.Inliner
-import Idris.Output
 import Idris.Interactive
-import Idris.WhoCalls
-import Idris.TypeSearch (searchByType)
-
+import Idris.ModeCommon
+import Idris.Output
+import Idris.Parser hiding (indent)
+import Idris.Prover
 import Idris.REPL.Browse (namesInNS, namespacesInNS)
 import Idris.REPL.Commands
-
-import Idris.ElabDecls
-import Idris.Elab.Clause
-import Idris.Elab.Value
-import Idris.Elab.Term
-import Idris.ModeCommon
-import Idris.Info
+import Idris.REPL.Parser
+import Idris.Termination
+import Idris.TypeSearch (searchByType)
+import Idris.WhoCalls
+import IRTS.Compiler
 
-import Version_idris (gitHash)
-import Util.System
 import Util.DynamicLinker
 import Util.Net (listenOnLocalhost, listenOnLocalhostAnyPort)
 import Util.Pretty hiding ((</>))
+import Util.System
 
-import Idris.Core.Evaluate
-import Idris.Core.Execute (execute)
-import Idris.Core.TT
-import Idris.Core.Unify
-import Idris.Core.WHNF
-import Idris.Core.Constraints
+import Version_idris (gitHash)
 
-import IRTS.Compiler
+import Prelude hiding (id, (.), (<$>))
 
 import Control.Category
+import Control.Concurrent
+import Control.Concurrent.Async (race)
+import Control.Concurrent.MVar
+import Control.DeepSeq
 import qualified Control.Exception as X
-import Prelude hiding ((<$>), (.), id)
-import Data.List.Split (splitOn)
-import qualified Data.Text as T
-
-import Text.Trifecta.Result(Result(..), ErrInfo(..))
-
-import System.Console.Haskeline as H
-import System.FilePath
-  ( (</>)
-  , (<.>)
-  , splitExtension
-  , addExtension
-  , dropExtension
-  , takeExtension
-  , takeDirectory
-  )
-import System.Exit
-import System.Environment
-import System.Process
-import System.Directory
-import System.IO
 import Control.Monad
+import Control.Monad.Trans (lift)
 import Control.Monad.Trans.Except (ExceptT, runExceptT)
-import Control.Monad.Trans.State.Strict ( StateT, execStateT, evalStateT, get, put )
-import Control.Monad.Trans ( lift )
-import Control.Concurrent.MVar
-import Network
-import Control.Concurrent
-import Data.Maybe
-import Data.List hiding (group)
+import Control.Monad.Trans.State.Strict (StateT, evalStateT, execStateT, get,
+                                         put)
 import Data.Char
+import Data.Either (partitionEithers)
+import Data.List hiding (group)
+import Data.List.Split (splitOn)
+import Data.Maybe
 import qualified Data.Set as S
+import qualified Data.Text as T
 import Data.Version
-import Data.Either (partitionEithers)
-import Control.DeepSeq
-
-import Control.Concurrent.Async (race)
-import System.FSNotify (withManager, watchDir)
+import Network
+import System.Console.Haskeline as H
+import System.Directory
+import System.Environment
+import System.Exit
+import System.FilePath (addExtension, dropExtension, splitExtension,
+                        takeDirectory, takeExtension, (<.>), (</>))
+import System.FSNotify (watchDir, withManager)
 import System.FSNotify.Devel (allEvents, doAllEvents)
-
-
+import System.IO
+import System.Process
+import Text.Trifecta.Result (ErrInfo(..), Result(..))
 
 -- | Run the REPL
 repl :: IState -- ^ The initial state
@@ -1227,8 +1215,10 @@
                     = do (tm, ty) <- elabVal (recinfo (fileFC "toplevel")) ERHS t
                          ctxt <- getContext
                          ist <- getIState
-                         let tm' = whnf ctxt tm
-                         iPrintResult (show (delab ist tm'))
+                         let tm' = whnf ctxt [] tm
+                         let tmArgs' = whnfArgs ctxt [] tm
+                         iPrintResult $ "WHNF: " ++ (show (delab ist tm'))
+                         iPrintResult $ "WHNF args: " ++ (show (delab ist tmArgs'))
 process fn (TestInline t)
                            = do (tm, ty) <- elabVal (recinfo (fileFC "toplevel")) ERHS t
                                 ctxt <- getContext
@@ -1283,7 +1273,7 @@
          case lookupCtxt n (idris_patdefs i) of
            [] -> iPrintError $ "Unknown name " ++ show n
            [(_, tms)] ->
-             iRenderResult (vsep (map (pprintPTerm ppOpts {ppopt_impl = True}
+             iRenderResult (vsep (map (pprintPTerm ppOpts 
                                                    []
                                                    []
                                                    (idris_infixes i))
diff --git a/src/Idris/REPL/Browse.hs b/src/Idris/REPL/Browse.hs
--- a/src/Idris/REPL/Browse.hs
+++ b/src/Idris/REPL/Browse.hs
@@ -10,17 +10,16 @@
 
 module Idris.REPL.Browse (namespacesInNS, namesInNS) where
 
-import Control.Monad (filterM)
+import Idris.AbsSyntax (getContext)
+import Idris.AbsSyntaxTree (Idris)
+import Idris.Core.Evaluate (Accessibility(Hidden, Private), ctxtAlist,
+                            lookupDefAccExact)
+import Idris.Core.TT (Name(..))
 
+import Control.Monad (filterM)
 import Data.List (isSuffixOf, nub)
 import Data.Maybe (mapMaybe)
 import qualified Data.Text as T (unpack)
-
-import Idris.Core.Evaluate (ctxtAlist, Accessibility(Private, Hidden), lookupDefAccExact)
-import Idris.Core.TT (Name(..))
-
-import Idris.AbsSyntaxTree (Idris)
-import Idris.AbsSyntax (getContext)
 
 -- | Find the sub-namespaces of a given namespace. The components
 -- should be in display order rather than the order that they are in
diff --git a/src/Idris/REPL/Commands.hs b/src/Idris/REPL/Commands.hs
--- a/src/Idris/REPL/Commands.hs
+++ b/src/Idris/REPL/Commands.hs
@@ -1,8 +1,8 @@
 module Idris.REPL.Commands where
 
-import Idris.Core.TT
-import Idris.Colours
 import Idris.AbsSyntaxTree
+import Idris.Colours
+import Idris.Core.TT
 
 -- | REPL commands
 data Command = Quit
diff --git a/src/Idris/REPL/Parser.hs b/src/Idris/REPL/Parser.hs
--- a/src/Idris/REPL/Parser.hs
+++ b/src/Idris/REPL/Parser.hs
@@ -11,31 +11,27 @@
   , setOptions
   ) where
 
-import System.FilePath ((</>))
-import System.Console.ANSI (Color(..))
-
-import Idris.Colours
 import Idris.AbsSyntax
+import Idris.Colours
 import Idris.Core.TT
 import Idris.Help
 import qualified Idris.Parser as P
-
 import Idris.REPL.Commands
 
 import Control.Applicative
 import Control.Monad.State.Strict
-
+import qualified Data.ByteString.UTF8 as UTF8
+import Data.Char (isSpace, toLower)
+import Data.List
+import Data.List.Split (splitOn)
+import Debug.Trace
+import System.Console.ANSI (Color(..))
+import System.FilePath ((</>))
+import Text.Parser.Char (anyChar, oneOf)
 import Text.Parser.Combinators
-import Text.Parser.Char(anyChar,oneOf)
-import Text.Trifecta(Result, parseString)
+import Text.Trifecta (Result, parseString)
 import Text.Trifecta.Delta
 
-import Debug.Trace
-import Data.List
-import Data.List.Split(splitOn)
-import Data.Char(isSpace, toLower)
-import qualified Data.ByteString.UTF8 as UTF8
-
 parseCmd :: IState -> String -> String -> Result (Either String Command)
 parseCmd i inputname = P.runparser pCmd i inputname . trim
     where trim = f . f
@@ -214,8 +210,8 @@
 noArgs :: Command -> String -> P.IdrisParser (Either String Command)
 noArgs cmd name = do
     let emptyArgs = do
-        eof
-        return (Right cmd)
+          eof
+          return (Right cmd)
 
     let failure = return (Left $ ":" ++ name ++ " takes no arguments")
 
@@ -229,17 +225,17 @@
 exprArg :: (PTerm -> Command) -> String -> P.IdrisParser (Either String Command)
 exprArg cmd name = do
     let noArg = do
-        eof
-        return $ Left ("Usage is :" ++ name ++ " <expression>")
+          eof
+          return $ Left ("Usage is :" ++ name ++ " <expression>")
 
     let justOperator = do
-        (op, fc) <- P.operatorFC
-        eof
-        return $ Right $ cmd (PRef fc [] (sUN op))
+          (op, fc) <- P.operatorFC
+          eof
+          return $ Right $ cmd (PRef fc [] (sUN op))
 
     let properArg = do
-        t <- P.fullExpr defaultSyntax
-        return $ Right (cmd t)
+          t <- P.fullExpr defaultSyntax
+          return $ Right (cmd t)
     try noArg <|> try justOperator <|> properArg
 
 
@@ -279,10 +275,10 @@
             return $ Left ("Usage is :" ++ name ++ " <option>")
 
     let oneArg = do
-        o <- pOption
-        P.whiteSpace
-        eof
-        return (Right (cmd o))
+          o <- pOption
+          P.whiteSpace
+          eof
+          return (Right (cmd o))
 
     let failure = return $ Left "Unrecognized setting"
 
@@ -304,14 +300,14 @@
 cmd_doc :: String -> P.IdrisParser (Either String Command)
 cmd_doc name = do
     let constant = do
-        c <- fmap fst P.constant
-        eof
-        return $ Right (DocStr (Right c) FullDocs)
+          c <- fmap fst P.constant
+          eof
+          return $ Right (DocStr (Right c) FullDocs)
 
     let pType = do
-        P.reserved "Type"
-        eof
-        return $ Right (DocStr (Left $ P.mkName ("Type", "")) FullDocs)
+          P.reserved "Type"
+          eof
+          return $ Right (DocStr (Left $ P.mkName ("Type", "")) FullDocs)
 
     let fnName = fnNameArg (\n -> DocStr (Left n) FullDocs) name
 
@@ -380,17 +376,17 @@
             bytecodeCodegen <|> viaCodegen
 
     let hasOneArg = do
-        i <- get
-        f <- fst <$> P.identifier
-        eof
-        return $ Right (Compile defaultCodegen f)
+          i <- get
+          f <- fst <$> P.identifier
+          eof
+          return $ Right (Compile defaultCodegen f)
 
     let hasTwoArgs = do
-        i <- get
-        codegen <- codegenOption
-        f <- fst <$> P.identifier
-        eof
-        return $ Right (Compile codegen f)
+          i <- get
+          codegen <- codegenOption
+          f <- fst <$> P.identifier
+          eof
+          return $ Right (Compile codegen f)
 
     let failure = return $ Left $ "Usage is :" ++ name ++ " [<codegen>] <filename>"
     try hasTwoArgs <|> try hasOneArg <|> failure
diff --git a/src/Idris/Reflection.hs b/src/Idris/Reflection.hs
--- a/src/Idris/Reflection.hs
+++ b/src/Idris/Reflection.hs
@@ -6,31 +6,31 @@
 Maintainer  : The Idris Community.
 -}
 
-{-# LANGUAGE PatternGuards, CPP #-}
+{-# LANGUAGE CPP, PatternGuards #-}
 {-# OPTIONS_GHC -fwarn-incomplete-patterns -fwarn-unused-imports #-}
 module Idris.Reflection where
 
-#if __GLASGOW_HASKELL__ < 710
-import Control.Applicative ((<$>), (<*>), pure)
-import Prelude hiding (mapM)
-import Data.Traversable (mapM)
-#endif
-import Control.Monad (liftM, liftM2, liftM4)
-import Control.Monad.State.Strict (lift)
-import Data.Maybe (catMaybes)
-import Data.List ((\\), findIndex)
-import qualified Data.Text as T
-
 import Idris.Core.Elaborate (claim, fill, focus, getNameFrom, initElaborator,
                              movelast, runElab, solve)
-import Idris.Core.Evaluate (Def(TyDecl), initContext, lookupDefExact, lookupTyExact)
+import Idris.Core.Evaluate (Def(TyDecl), initContext, lookupDefExact,
+                            lookupTyExact)
 import Idris.Core.TT
 
-import Idris.AbsSyntaxTree (ArgOpt(..),ElabD, IState(tt_ctxt, idris_implicits,idris_datatypes, idris_patdefs),
-                            PArg'(..), PArg, PTactic, PTactic'(..), PTerm(..), Fixity (..),
+import Idris.AbsSyntaxTree (ArgOpt(..), ElabD, Fixity(..), IState(idris_datatypes, idris_implicits, idris_patdefs, tt_ctxt),
+                            PArg, PArg'(..), PTactic, PTactic'(..), PTerm(..),
                             initEState, pairCon, pairTy)
 import Idris.Delaborate (delab)
 
+#if __GLASGOW_HASKELL__ < 710
+import Control.Applicative (pure, (<$>), (<*>))
+import Data.Traversable (mapM)
+import Prelude hiding (mapM)
+#endif
+import Control.Monad (liftM, liftM2, liftM4)
+import Control.Monad.State.Strict (lift)
+import Data.List (findIndex, (\\))
+import Data.Maybe (catMaybes)
+import qualified Data.Text as T
 
 data RErasure = RErased | RNotErased deriving Show
 
@@ -491,6 +491,9 @@
 reflectTTQuotePattern unq Impossible
   = lift . tfail . InternalMsg $
       "Phase error! The Impossible constructor is for optimization only and should not have been reflected during elaboration."
+reflectTTQuotePattern unq (Inferred t)
+  = lift . tfail . InternalMsg $
+      "Phase error! The Inferred constructor is for coverage checking only and should not have been reflected during elaboration."
 reflectTTQuotePattern unq (TType exp)
   = do ue <- getNameFrom (sMN 0 "uexp")
        claim ue (Var (sNS (sUN "TTUExp") ["Reflection", "Language"]))
@@ -654,6 +657,8 @@
 reflectTTQuote unq Erased = Var (reflm "Erased")
 reflectTTQuote _   Impossible =
   error "Phase error! The Impossible constructor is for optimization only and should not have been reflected during elaboration."
+reflectTTQuote _   (Inferred tm) =
+  error "Phase error! The Inferred constructor is for coverage checking only and should not have been reflected during elaboration."
 
 reflectRawQuote :: [Name] -> Raw -> Raw
 reflectRawQuote unq (Var n)
diff --git a/src/Idris/Termination.hs b/src/Idris/Termination.hs
new file mode 100644
--- /dev/null
+++ b/src/Idris/Termination.hs
@@ -0,0 +1,649 @@
+{-|
+Module      : Idris.Termination
+Description : The termination checker for Idris
+Copyright   :
+License     : BSD3
+Maintainer  : The Idris Community.
+-}
+{-# LANGUAGE PatternGuards #-}
+module Idris.Termination where
+
+import Idris.AbsSyntax
+import Idris.Core.CaseTree
+import Idris.Core.Evaluate
+import Idris.Core.TT
+import Idris.Delaborate
+import Idris.Error
+import Idris.Output (iWarn, iputStrLn)
+
+import Control.Monad.State.Strict
+import Data.Char
+import Data.Either
+import Data.List
+import Data.Maybe
+import Debug.Trace
+
+-- | Check whether function and all descendants cover all cases
+-- (partial is okay, as long as it's due to recursion)
+checkAllCovering :: FC -> [Name] -> Name -> Name -> Idris ()
+checkAllCovering fc done top n | not (n `elem` done)
+   = do i <- get
+        case lookupTotal n (tt_ctxt i) of
+             [tot@(Partial NotCovering)] ->
+                    do let msg = show top ++ " is " ++ show tot ++ " due to " ++ show n
+                       putIState i { idris_totcheckfail = (fc, msg) : idris_totcheckfail i }
+                       addIBC (IBCTotCheckErr fc msg)
+             [Partial _] ->
+                case lookupCtxt n (idris_callgraph i) of
+                     [cg] -> mapM_ (checkAllCovering fc (n : done) top)
+                                   (calls cg)
+                     _ -> return ()
+             x -> return () -- stop if total
+checkAllCovering _ _ _ _ = return ()
+
+-- | Check whether all 'Inf' arguments to the name end up guaranteed to be
+-- guarded by constructors (conservatively... maybe this can do better later).
+-- Essentially, all it does is check that every branch is a constructor application
+-- with no other function applications.
+--
+-- If so, set the 'AllGuarded' flag which can be used by the productivity check
+checkIfGuarded :: Name -> Idris ()
+checkIfGuarded n 
+   = do i <- get
+        let ctxt = tt_ctxt i
+        case lookupDefExact n ctxt of
+             Just (CaseOp _ ty _ _ _ cases) ->
+                  let gnames = fst (cases_compiletime cases) in
+                      if allGuarded gnames i (snd (cases_compiletime cases))
+                         then -- trace (show (n, gnames, ty, cases_compiletime cases)) $
+                              addFnOpt n AllGuarded
+                         else return ()
+             _ -> return ()
+  where
+    guard n ist = isConName n (tt_ctxt ist) || guardFlag n ist
+    guardFlag n ist = case lookupCtxtExact n (idris_flags ist) of
+                           Nothing -> False
+                           Just fs -> AllGuarded `elem` fs
+
+    -- Top level thing always needs to be a constructor application if 
+    -- the delayed things are going to be definitely guarded by this definition
+    allGuarded names i (STerm t) 
+          | (P _ fn _, args) <- unApply t,
+            guard fn i
+            = and (map (guardedTerm names i) args)
+          | otherwise = False
+    allGuarded names i (ProjCase _ alts) = and (map (guardedAlt names i) alts)
+    allGuarded names i (Case _ _ alts) = and (map (guardedAlt names i) alts)
+    allGuarded names i _ = True
+
+    guardedTerm names i (P _ v _) = v `elem` names || guard v i
+    guardedTerm names i (Bind n (Let t v) sc)
+          = guardedTerm names i v && guardedTerm names i sc
+    guardedTerm names i (Bind n b sc) = False
+    guardedTerm names i ap@(App _ _ _)
+          | (P _ fn _, args) <- unApply ap,
+            guard fn i || fn `elem` names
+                = and (map (guardedTerm names i) args)
+    guardedTerm names i (App _ f a) = False
+    guardedTerm names i tm = True
+    
+    guardedAlt names i (ConCase _ _ _ t) = allGuarded names i t
+    guardedAlt names i (FnCase _ _ t) = allGuarded names i t
+    guardedAlt names i (ConstCase _ t) = allGuarded names i t
+    guardedAlt names i (SucCase _ t) = allGuarded names i t
+    guardedAlt names i (DefaultCase t) = allGuarded names i t
+
+-- | Check if, in a given group of type declarations mut_ns, the
+-- constructor cn : ty is strictly positive, and update the context
+-- accordingly
+checkPositive :: [Name]       -- ^ the group of type declarations
+              -> (Name, Type) -- ^ the constructor
+              -> Idris Totality
+checkPositive mut_ns (cn, ty')
+    = do i <- getIState
+         let ty = delazy' True (normalise (tt_ctxt i) [] ty')
+         let p = cp i ty
+         let tot = if p then Total (args ty) else Partial NotPositive
+         let ctxt' = setTotal cn tot (tt_ctxt i)
+         putIState (i { tt_ctxt = ctxt' })
+         logCoverage 5 $ "Constructor " ++ show cn ++ " is " ++ show tot ++ " with " ++ show mut_ns
+         addIBC (IBCTotal cn tot)
+         return tot
+  where
+    args t = [0..length (getArgTys t)-1]
+
+    cp i (Bind n (Pi _ aty _) sc)
+         = posArg i aty && cp i sc
+    cp i t | (P _ n' _ , args) <- unApply t,
+             n' `elem` mut_ns = all noRec args
+    cp i _ = True
+
+    posArg ist (Bind _ (Pi _ nty _) sc) = noRec nty && posArg ist sc
+    posArg ist t = posParams ist t
+
+    noRec arg = all (\x -> x `notElem` mut_ns) (allTTNames arg)
+
+    -- If the type appears recursively in a parameter argument, that's
+    -- fine, otherwise if it appears in an argument it's not fine.
+    posParams ist t | (P _ n _, args) <- unApply t
+       = case lookupCtxtExact n (idris_datatypes ist) of
+              Just ti -> checkParamsOK (param_pos ti) 0 args
+              Nothing -> and (map (posParams ist) args)
+    posParams ist t = noRec t
+
+    checkParamsOK ppos i [] = True
+    checkParamsOK ppos i (p : ps)
+          | i `elem` ppos = checkParamsOK ppos (i + 1) ps
+          | otherwise = noRec p && checkParamsOK ppos (i + 1) ps
+
+-- | Calculate the totality of a function from its patterns.  Either
+-- follow the size change graph (if inductive) or check for
+-- productivity (if coinductive)
+calcTotality :: FC -> Name -> [([Name], Term, Term)] -> Idris Totality
+calcTotality fc n pats
+    = do i <- getIState
+         let opts = case lookupCtxt n (idris_flags i) of
+                            [fs] -> fs
+                            _ -> []
+         case mapMaybe (checkLHS i) (map (\ (_, l, r) -> l) pats) of
+            (failure : _) -> return failure
+            _ -> checkSizeChange n
+  where
+    checkLHS i (P _ fn _)
+        = case lookupTotalExact fn (tt_ctxt i) of
+               Just (Partial _) -> return (Partial (Other [fn]))
+               _ -> Nothing
+    checkLHS i (App _ f a) = mplus (checkLHS i f) (checkLHS i a)
+    checkLHS _ _ = Nothing
+
+checkTotality :: [Name] -> FC -> Name -> Idris Totality
+checkTotality path fc n
+    | n `elem` path = return (Partial (Mutual (n : path)))
+    | otherwise = do
+        t <- getTotality n
+        i <- getIState
+        ctxt' <- do ctxt <- getContext
+                    tclift $ simplifyCasedef n (getErasureInfo i) ctxt
+        setContext ctxt'
+        ctxt <- getContext
+        i <- getIState
+        let opts = case lookupCtxt n (idris_flags i) of
+                            [fs] -> fs
+                            _ -> []
+        t' <- case t of
+                Unchecked ->
+                    case lookupDef n ctxt of
+                        [CaseOp _ _ _ _ pats _] ->
+                            do t' <- if AssertTotal `elem` opts
+                                        then return $ Total []
+                                        else calcTotality fc n pats
+                               logCoverage 2 $ "Set to " ++ show t'
+                               setTotality n t'
+                               addIBC (IBCTotal n t')
+                               return t'
+                        [TyDecl (DCon _ _ _) ty] ->
+                            case unApply (getRetTy ty) of
+                              (P _ tyn _, _) -> do
+                                 let ms = case lookupCtxt tyn (idris_datatypes i) of
+                                       [TI _ _ _ _ xs@(_:_)] -> xs
+                                       ts -> [tyn]
+                                 checkPositive ms (n, ty)
+                              _-> return $ Total []
+                        _ -> return $ Total []
+                x -> return x
+        case t' of
+            Total _ -> return t'
+            Productive -> return t'
+            e -> do w <- cmdOptType WarnPartial
+                    if TotalFn `elem` opts
+                       then do totalityError t'; return t'
+                       else do when (w && not (PartialFn `elem` opts)) $
+                                   warnPartial n t'
+                               return t'
+  where
+    totalityError t = do i <- getIState
+                         let msg = show n ++ " is " ++ show t
+                         putIState i { idris_totcheckfail = (fc, msg) : idris_totcheckfail i}
+                         addIBC (IBCTotCheckErr fc msg)
+
+    warnPartial n t
+       = do i <- getIState
+            case lookupDef n (tt_ctxt i) of
+               [x] -> do
+                  iWarn fc . pprintErr i . Msg $ "Warning - " ++ show n ++ " is " ++ show t
+--                                ++ "\n" ++ show x
+--                   let cg = lookupCtxtName Nothing n (idris_callgraph i)
+--                   iputStrLn (show cg)
+
+
+checkDeclTotality :: (FC, Name) -> Idris Totality
+checkDeclTotality (fc, n)
+    = do logCoverage 2 $ "Checking " ++ show n ++ " for totality"
+         i <- getIState
+         let opts = case lookupCtxtExact n (idris_flags i) of
+                              Just fs -> fs
+                              _ -> []
+         when (CoveringFn `elem` opts) $ checkAllCovering fc [] n n
+         t <- checkTotality [] fc n
+         return t
+
+-- If the name calls something which is partial, set it as partial
+verifyTotality :: (FC, Name) -> Idris ()
+verifyTotality (fc, n)
+    = do logCoverage 2 $ "Checking " ++ show n ++ "'s descendents are total"
+         ist <- getIState
+         case lookupTotalExact n (tt_ctxt ist) of
+              Just (Total _) -> do
+                 let ns = getNames (tt_ctxt ist)
+
+                 case getPartial ist [] ns of
+                      Nothing -> return ()
+                      Just bad -> do let t' = Partial (Other bad)
+                                     logCoverage 2 $ "Set to " ++ show t'
+                                     setTotality n t'
+                                     addIBC (IBCTotal n t')
+              _ -> return ()
+  where
+    getNames ctxt = case lookupDefExact n ctxt of
+                         Just (CaseOp  _ _ _ _ _ defs)
+                           -> let (top, def) = cases_compiletime defs in
+                                  map fst (findCalls' True def top)
+                         _ -> []
+
+    getPartial ist [] [] = Nothing
+    getPartial ist bad [] = Just bad
+    getPartial ist bad (n : ns)
+        = case lookupTotalExact n (tt_ctxt ist) of
+               Just (Partial _) -> getPartial ist (n : bad) ns
+               _ -> getPartial ist bad ns
+
+-- | Calculate the size change graph for this definition
+--
+-- SCG for a function f consists of a list of:
+--    (g, [(a1, sizechange1), (a2, sizechange2), ..., (an, sizechangen)])
+--
+-- where g is a function called
+-- a1 ... an are the arguments of f in positions 1..n of g
+-- sizechange1 ... sizechange2 is how their size has changed wrt the input
+-- to f
+--    Nothing, if the argument is unrelated to the input
+buildSCG :: (FC, Name) -> Idris ()
+buildSCG (_, n) = do
+   ist <- getIState
+   case lookupCtxt n (idris_callgraph ist) of
+       [cg] -> case lookupDefExact n (tt_ctxt ist) of
+           Just (CaseOp _ _ _ pats _ cd) ->
+             let (args, sc) = cases_compiletime cd in
+               do logCoverage 2 $ "Building SCG for " ++ show n ++ " from\n"
+                                ++ show pats ++ "\n" ++ show sc
+                  let newscg = buildSCG' ist n (rights pats) args
+                  logCoverage 5 $ "SCG is: " ++ show newscg
+                  addToCG n ( cg { scg = newscg } )
+           _ -> return () -- CG comes from a type declaration only
+       [] -> logCoverage 5 $ "Could not build SCG for " ++ show n ++ "\n"
+       x -> error $ "buildSCG: " ++ show (n, x)
+
+delazy = delazy' False -- not lazy codata
+delazy' all t@(App _ f a)
+     | (P _ (UN l) _, [_, _, arg]) <- unApply t,
+       l == txt "Force" = delazy' all arg
+     | (P _ (UN l) _, [P _ (UN lty) _, _, arg]) <- unApply t,
+       l == txt "Delay" && (all || lty /= txt "Infinite") = delazy arg
+     | (P _ (UN l) _, [P _ (UN lty) _, arg]) <- unApply t,
+       l == txt "Delayed" && (all || lty /= txt "Infinite") = delazy' all arg
+delazy' all (App s f a) = App s (delazy' all f) (delazy' all a)
+delazy' all (Bind n b sc) = Bind n (fmap (delazy' all) b) (delazy' all sc)
+delazy' all t = t
+
+data Guardedness = Toplevel | Unguarded | Guarded | Delayed
+  deriving Show
+
+buildSCG' :: IState -> Name -> [(Term, Term)] -> [Name] -> [SCGEntry]
+buildSCG' ist topfn pats args = nub $ concatMap scgPat pats where
+  scgPat (lhs, rhs) = let lhs' = delazy lhs
+                          rhs' = delazy rhs
+                          (f, pargs) = unApply (dePat lhs') in
+                            findCalls [] Toplevel (dePat rhs') (patvars lhs')
+                                      (zip pargs [0..])
+
+  -- Under a delay, calls are excluded from the graph - if it's a call to a
+  -- non-total function we'll find that in the final totality check
+  findCalls cases Delayed ap@(P _ n _) pvs args = []
+  findCalls cases guarded ap@(App _ f a) pvs pargs
+     -- under a call to "assert_total", don't do any checking, just believe
+     -- that it is total.
+     | (P _ (UN at) _, [_, _]) <- unApply ap,
+       at == txt "assert_total" = []
+     -- don't go under calls to functions which are asserted total
+     | (P _ n _, _) <- unApply ap,
+       Just opts <- lookupCtxtExact n (idris_flags ist),
+       AssertTotal `elem` opts = []
+     -- under a guarded call to "Delay Infinite", we are 'Delayed', so don't
+     -- check under guarded constructors.
+     | (P _ (UN del) _, [_,_,arg]) <- unApply ap,
+       Guarded <- guarded,
+       del == txt "Delay"
+           = findCalls cases Delayed arg pvs pargs
+     | (P _ n _, args) <- unApply ap,
+       Delayed <- guarded,
+       isConName n (tt_ctxt ist) || allGuarded n ist
+           = -- Still under a 'Delay' and constructor guarded, so check
+             -- just the arguments to the constructor, remaining Delayed
+             concatMap (\x -> findCalls cases guarded x pvs pargs) args
+     | (P _ ifthenelse _, [_, _, t, e]) <- unApply ap,
+       ifthenelse == sNS (sUN "ifThenElse") ["Bool", "Prelude"]
+       -- Continue look inside if...then...else blocks
+       -- TODO: Consider whether we should do this for user defined ifThenElse
+       -- rather than just the one in the Prelude as a special case
+       = findCalls cases guarded t pvs pargs ++
+         findCalls cases guarded e pvs pargs
+     | (P _ n _, args) <- unApply ap,
+       caseName n && n /= topfn,
+       notPartial (lookupTotalExact n (tt_ctxt ist))
+       -- case block - look inside the block, as long as it was covering
+       -- (i.e. not currently set at Partial) to get a more accurate size
+       -- change result from the top level patterns (also to help pass
+       -- information through from guarded corecursion accurately)
+       = concatMap (\x -> findCalls cases Unguarded x pvs pargs) args ++
+             if n `notElem` cases
+                then findCallsCase (n : cases) guarded n args pvs pargs
+                else []
+     | (P _ n _, args) <- unApply ap,
+       Delayed <- guarded
+       -- Under a delayed recursive call just check the arguments
+           = concatMap (\x -> findCalls cases Unguarded x pvs pargs) args
+     | (P _ n _, args) <- unApply ap
+        -- Ordinary call, not under a delay.
+        -- If n is a constructor, set 'args' as Guarded
+        = let nguarded = case guarded of
+                              Unguarded -> Unguarded
+                              x -> if isConName n (tt_ctxt ist)
+                                       || allGuarded n ist
+                                      then Guarded
+                                      else Unguarded in
+              mkChange n args pargs ++
+                 concatMap (\x -> findCalls cases nguarded x pvs pargs) args
+    where notPartial (Just (Partial NotCovering)) = False
+          notPartial _ = True
+  findCalls cases guarded (App _ f a) pvs pargs
+        = findCalls cases Unguarded f pvs pargs ++ findCalls cases Unguarded a pvs pargs
+  findCalls cases guarded (Bind n (Let t v) e) pvs pargs
+        = findCalls cases Unguarded t pvs pargs ++
+          findCalls cases Unguarded v pvs pargs ++ 
+          -- Substitute in the scope since this might reveal some useful
+          -- structure
+          findCalls cases guarded (substV v e) pvs pargs
+  findCalls cases guarded (Bind n t e) pvs pargs
+        = findCalls cases Unguarded (binderTy t) pvs pargs ++
+          findCalls cases guarded e (n : pvs) pargs
+  findCalls cases guarded (P _ f _ ) pvs pargs
+      | not (f `elem` pvs) = [(f, [])]
+  findCalls _ _ _ _ _ = []
+
+  -- Assumption is that names are preserved in the case block (shadowing
+  -- dealt with by the elaborator) so we can just assume the top level names
+  -- are okay for building the size change
+  findCallsCase cases guarded n args pvs pargs
+      = case lookupDefExact n (tt_ctxt ist) of
+           Just (CaseOp _ _ _ pats _ cd) ->
+                concatMap (fccPat cases pvs pargs args guarded) (rights pats)
+           Nothing -> []
+
+  fccPat cases pvs pargs args g (lhs, rhs)
+      = let lhs' = delazy lhs
+            rhs' = delazy rhs
+            (f, pargs_case) = unApply (dePat lhs')
+            -- pargs is a pair of a term, and the argument position that
+            -- term appears in. If any of the arguments to the case block
+            -- are also on the lhs, we also want those patterns to appear
+            -- in the parg list so that we'll spot patterns which are
+            -- smaller than then
+            newpargs = newPArg args pargs
+            -- Now need to update the rhs of the case with the names in the
+            -- outer definition: In rhs', wherever we see what's in pargs_case,
+            -- replace it with the corresponding thing in pargs
+            csubs = zip pargs_case args
+            newrhs = doCaseSubs csubs (dePat rhs')
+            pargs' = pargs ++ addPArg newpargs pargs_case in
+               findCalls cases g newrhs pvs pargs'
+    where
+      doCaseSubs [] tm = tm
+      doCaseSubs ((x, x') : cs) tm
+           = doCaseSubs (subIn x x' cs) (substTerm x x' tm)
+
+      subIn x x' [] = []
+      subIn x x' ((l, r) : cs)
+          = (substTerm x x' l, substTerm x x' r) : subIn x x' cs
+
+  addPArg (Just (t, i) : ts) (t' : ts') = (t', i) : addPArg ts ts'
+  addPArg (Nothing : ts) (t' : ts') = addPArg ts ts'
+  addPArg _ _ = []
+
+  newPArg :: [Term] -> [(Term, Int)] -> [Maybe (Term, Int)]
+  newPArg (t : ts) pargs = case lookup t pargs of
+                                Just i -> Just (t, i) : newPArg ts pargs
+                                Nothing -> Nothing : newPArg ts pargs
+  newPArg [] pargs = []
+
+  expandToArity n args
+     = case lookupTy n (tt_ctxt ist) of
+            [ty] -> expand 0 (normalise (tt_ctxt ist) [] ty) args
+            _ -> args
+     where expand i (Bind n (Pi _ _ _) sc) (x : xs) = x : expand (i + 1) sc xs
+           expand i (Bind n (Pi _ _ _) sc) [] = Just (i, Same) : expand (i + 1) sc []
+           expand i _ xs = xs
+
+  mkChange n args pargs = [(n, expandToArity n (sizes args))]
+    where
+      sizes [] = []
+      sizes (a : as) = checkSize a pargs : sizes as
+
+      -- find which argument in pargs <a> is smaller than, if any
+      checkSize a ((p, i) : ps)
+          | a == p = Just (i, Same)
+          | (P _ (UN as) _, [_,_,arg,_]) <- unApply a,
+            as == txt "assert_smaller" && arg == p
+                  = Just (i, Smaller)
+          | smaller Nothing a (p, Nothing) = Just (i, Smaller)
+          | otherwise = checkSize a ps
+      checkSize a [] = Nothing
+
+      -- the smaller thing we find must be defined in the same group of mutally
+      -- defined types as <a>, and not be coinductive - so carry the type of
+      -- the constructor we've gone under.
+
+      smaller (Just tyn) a (t, Just tyt)
+         | a == t = isInductive (fst (unApply (getRetTy tyn)))
+                                (fst (unApply (getRetTy tyt)))
+      smaller ty a (ap@(App _ f s), _)
+          | (P (DCon _ _ _) n _, args) <- unApply ap
+               = let tyn = getType n in
+                     any (smaller (ty `mplus` Just tyn) a)
+                         (zip args (map toJust (getArgTys tyn)))
+      -- check higher order recursive arguments
+      smaller ty (App _ f s) a = smaller ty f a
+      smaller _ _ _ = False
+
+      toJust (n, t) = Just t
+
+      getType n = case lookupTyExact n (tt_ctxt ist) of
+                       Just ty -> delazy (normalise (tt_ctxt ist) [] ty) -- must exist
+
+      isInductive (P _ nty _) (P _ nty' _) =
+          let (co, muts) = case lookupCtxt nty (idris_datatypes ist) of
+                                [TI _ x _ _ muts] -> (x, muts)
+                                _ -> (False, []) in
+              (nty == nty' || any (== nty') muts) && not co
+      isInductive _ _ = False
+
+  dePat (Bind x (PVar ty) sc) = dePat (instantiate (P Bound x ty) sc)
+  dePat t = t
+
+  patvars (Bind x (PVar _) sc) = x : patvars sc
+  patvars _ = []
+
+  allGuarded n ist = case lookupCtxtExact n (idris_flags ist) of
+                          Nothing -> False
+                          Just fs -> AllGuarded `elem` fs
+
+checkSizeChange :: Name -> Idris Totality
+checkSizeChange n = do
+   ist <- getIState
+   case lookupCtxt n (idris_callgraph ist) of
+       [cg] -> do let ms = mkMultiPaths ist [] (scg cg)
+                  logCoverage 5 ("Multipath for " ++ show n ++ ":\n" ++
+                            "from " ++ show (scg cg) ++ "\n" ++
+                            show (length ms) ++ "\n" ++
+                            showSep "\n" (map show ms))
+                  logCoverage 6 (show cg)
+                  -- every multipath must have an infinitely descending
+                  -- thread, then the function terminates
+                  -- also need to checks functions called are all total
+                  -- (Unchecked is okay as we'll spot problems here)
+                  let tot = map (checkMP ist n (getArity ist n)) ms
+                  logCoverage 4 $ "Generated " ++ show (length tot) ++ " paths"
+                  logCoverage 5 $ "Paths for " ++ show n ++ " yield " ++
+                       (showSep "\n" (map show (zip ms tot)))
+                  return (noPartial tot)
+       [] -> do logCoverage 5 $ "No paths for " ++ show n
+                return Unchecked
+  where getArity ist n
+          = case lookupTy n (tt_ctxt ist) of
+                 [ty] -> arity (normalise (tt_ctxt ist) [] ty)
+                 _ -> error "Can't happen: checkSizeChange.getArity"
+
+type MultiPath = [SCGEntry]
+
+mkMultiPaths :: IState -> MultiPath -> [SCGEntry] -> [MultiPath]
+mkMultiPaths ist path [] = [reverse path]
+mkMultiPaths ist path cg = concatMap extend cg
+  where extend (nextf, args)
+           | (nextf, args) `inPath` path = [ reverse ((nextf, args) : path) ]
+           | [Unchecked] <- lookupTotal nextf (tt_ctxt ist)
+               = case lookupCtxt nextf (idris_callgraph ist) of
+                    [ncg] -> mkMultiPaths ist ((nextf, args) : path) (scg ncg)
+                    _ -> [ reverse ((nextf, args) : path) ]
+           | otherwise = [ reverse ((nextf, args) : path) ]
+
+        inPath :: SCGEntry -> [SCGEntry] -> Bool
+        inPath f [] = False
+        inPath f (g : gs) = smallerEq f g || f == g || inPath f gs
+
+        smallerEq :: SCGEntry -> SCGEntry -> Bool
+        smallerEq (f, args) (g, args')
+            = f == g && not (null (filter smallers args))
+                     && filter smallers args == filter smallers args'
+        smallers (Just (_, Smaller)) = True
+        smallers _ = False
+
+-- If any route along the multipath leads to infinite descent, we're fine.
+-- Try a route beginning with every argument.
+--   If we reach a point we've been to before, but with a smaller value,
+--   that means there is an infinitely descending path from that argument.
+
+checkMP :: IState -> Name -> Int -> MultiPath -> Totality
+checkMP ist topfn i mp = if i > 0
+                     then let paths = (map (tryPath 0 [] mp) [0..i-1]) in
+--                               trace ("Paths " ++ show paths) $
+                               collapse paths
+                     else tryPath 0 [] mp 0
+  where
+    tryPath' d path mp arg
+           = let res = tryPath d path mp arg in
+                 trace (show mp ++ "\n" ++ show arg ++ " " ++ show res) res
+
+    mkBig (e, d) = (e, 10000)
+
+    tryPath :: Int -> [((SCGEntry, Int), Int)] -> MultiPath -> Int -> Totality
+    tryPath desc path [] _ = Total []
+--     tryPath desc path ((UN "believe_me", _) : _) arg
+--             = Partial BelieveMe
+    -- if we get to a constructor, it's fine as long as it's strictly positive
+    tryPath desc path ((f, _) : es) arg
+        | [TyDecl (DCon _ _ _) _] <- lookupDef f (tt_ctxt ist)
+            = case lookupTotalExact f (tt_ctxt ist) of
+                   Just (Total _) -> Unchecked -- okay so far
+                   Just (Partial _) -> Partial (Other [f])
+                   x -> Unchecked -- An error elsewhere, set as Unchecked to make
+                                  -- some progress
+        | [TyDecl (TCon _ _) _] <- lookupDef f (tt_ctxt ist)
+            = Total []
+    tryPath desc path (e@(f, args) : es) arg
+        | [Total a] <- lookupTotal f (tt_ctxt ist) = Total a
+        | e `elem` es && allNothing args = Partial (Mutual [f])
+    tryPath desc path (e@(f, nextargs) : es) arg
+        | [Total a] <- lookupTotal f (tt_ctxt ist) = Total a
+        | [Partial _] <- lookupTotal f (tt_ctxt ist) = Partial (Other [f])
+        | Just d <- lookup (e, arg) path
+            = if desc - d > 0 -- Now lower than when we were last here
+                   then -- trace ("Descent " ++ show (desc - d) ++ " "
+                        --      ++ show (path, e)) $
+                        Total []
+                   else Partial (Mutual (map (fst . fst . fst) path ++ [f]))
+        | e `elem` map (fst . fst) path
+           && not (f `elem` map fst es)
+              = Partial (Mutual (map (fst . fst . fst) path ++ [f]))
+        | [Unchecked] <- lookupTotal f (tt_ctxt ist) =
+            let argspos = zip nextargs [0..]
+                pathres =
+                  do (a, pos) <- argspos
+                     case a of
+                        Nothing -> -- gone up, but if the
+                                   -- rest definitely terminates without any
+                                   -- cycles (including the path so far, which
+                                   -- we take as inaccessible) the path is fine
+                            return $ tryPath 0 (map mkBig (((e, arg), desc) : path)) es pos
+                        Just (nextarg, sc) ->
+                          if nextarg == arg then
+                            case sc of
+                              Same -> return $ tryPath desc (((e, arg), desc) : path)
+                                                       es pos
+                              Smaller -> return $ tryPath (desc+1)
+                                                          (((e, arg), desc) : path)
+                                                          es
+                                                          pos
+                              _ -> trace ("Shouldn't happen " ++ show e) $
+                                      return (Partial Itself)
+                            else return Unchecked in
+--                   trace (show (desc, argspos, path, es, pathres)) $
+                   collapse pathres
+
+        | otherwise = Unchecked
+
+allNothing :: [Maybe a] -> Bool
+allNothing xs = null (collapseNothing (zip xs [0..]))
+
+collapseNothing :: [(Maybe a, b)] -> [(Maybe a, b)]
+collapseNothing ((Nothing, t) : xs)
+   = (Nothing, t) : filter (\ (x, _) -> case x of
+                                             Nothing -> False
+                                             _ -> True) xs
+collapseNothing (x : xs) = x : collapseNothing xs
+collapseNothing [] = []
+
+noPartial :: [Totality] -> Totality
+noPartial (Partial p : xs) = Partial p
+noPartial (_ : xs)         = noPartial xs
+noPartial []               = Total []
+
+collapse :: [Totality] -> Totality
+collapse xs = collapse' Unchecked xs
+collapse' def (Total r : xs)   = Total r
+collapse' def (Unchecked : xs) = collapse' def xs
+collapse' def (d : xs)         = collapse' d xs
+-- collapse' Unchecked []         = Total []
+collapse' def []               = def
+
+totalityCheckBlock :: Idris ()
+totalityCheckBlock = do
+         ist <- getIState
+         -- Do totality checking after entire mutual block
+         mapM_ (\n -> do logElab 5 $ "Simplifying " ++ show n
+                         ctxt' <- do ctxt <- getContext
+                                     tclift $ simplifyCasedef n (getErasureInfo ist) ctxt
+                         setContext ctxt')
+                 (map snd (idris_totcheck ist))
+         mapM_ buildSCG (idris_totcheck ist)
+         mapM_ checkDeclTotality (idris_totcheck ist)
+         clear_totcheck
+
diff --git a/src/Idris/TypeSearch.hs b/src/Idris/TypeSearch.hs
--- a/src/Idris/TypeSearch.hs
+++ b/src/Idris/TypeSearch.hs
@@ -13,38 +13,41 @@
   , defaultScoreFunction
   ) where
 
-import Control.Applicative (Applicative (..), (<$>), (<*>), (<|>))
-import Control.Arrow       (first, second, (&&&), (***))
-import Control.Monad       (when, guard)
-
-import           Data.List   (find, partition, (\\))
-import           Data.Map    (Map)
-import qualified Data.Map    as M
-import           Data.Maybe  (catMaybes, fromMaybe, isJust, maybeToList, mapMaybe)
-import           Data.Monoid (Monoid (mempty, mappend))
-import           Data.Ord    (comparing)
-import qualified Data.PriorityQueue.FingerTree as Q
-import           Data.Set                           (Set)
-import qualified Data.Set                      as S
-import qualified Data.Text                     as T (pack, isPrefixOf)
-import           Data.Traversable                   (traverse)
-
-import Idris.AbsSyntax     (addUsingConstraints, addImpl, getIState, putIState, implicit, logLvl)
-import Idris.AbsSyntaxTree (interface_implementations, InterfaceInfo, defaultSyntax, eqTy, Idris
-                           , IState (idris_interfaces, idris_docstrings, tt_ctxt, idris_outputmode),
-                           implicitAllowed, OutputMode(..), PTerm, toplevel)
-import Idris.Core.Evaluate (Context (definitions), Def (Function, TyDecl, CaseOp), normaliseC)
-import Idris.Core.TT       hiding (score)
-import Idris.Core.Unify    (match_unify)
-import Idris.Delaborate    (delabTy)
-import Idris.Docstrings    (noDocs, overview)
-import Idris.Elab.Type     (elabType)
-import Idris.Output        (iputStrLn, iRenderOutput, iPrintResult, iRenderError, iRenderResult, prettyDocumentedIst)
+import Idris.AbsSyntax (addImpl, addUsingConstraints, getIState, implicit,
+                        logLvl, putIState)
+import Idris.AbsSyntaxTree (IState(idris_docstrings, idris_interfaces, idris_outputmode, tt_ctxt),
+                            Idris, InterfaceInfo, OutputMode(..), PTerm,
+                            defaultSyntax, eqTy, implicitAllowed,
+                            interface_implementations, toplevel)
+import Idris.Core.Evaluate (Context(definitions), Def(CaseOp, Function, TyDecl),
+                            normaliseC)
+import Idris.Core.TT hiding (score)
+import Idris.Core.Unify (match_unify)
+import Idris.Delaborate (delabTy)
+import Idris.Docstrings (noDocs, overview)
+import Idris.Elab.Type (elabType)
 import Idris.IBC
+import Idris.Output (iPrintResult, iRenderError, iRenderOutput, iRenderResult,
+                     iputStrLn, prettyDocumentedIst)
 
+import Util.Pretty (Doc, annotate, char, text, vsep, (<>))
+
 import Prelude hiding (pred)
 
-import Util.Pretty (text, char, vsep, (<>), Doc, annotate)
+import Control.Applicative (Applicative(..), (<$>), (<*>), (<|>))
+import Control.Arrow (first, second, (&&&), (***))
+import Control.Monad (guard, when)
+import Data.List (find, partition, (\\))
+import Data.Map (Map)
+import qualified Data.Map as M
+import Data.Maybe (catMaybes, fromMaybe, isJust, mapMaybe, maybeToList)
+import Data.Monoid (Monoid(mappend, mempty))
+import Data.Ord (comparing)
+import qualified Data.PriorityQueue.FingerTree as Q
+import Data.Set (Set)
+import qualified Data.Set as S
+import qualified Data.Text as T (isPrefixOf, pack)
+import Data.Traversable (traverse)
 
 searchByType :: [String] -> PTerm -> Idris ()
 searchByType pkgs pterm = do
diff --git a/src/Idris/Unlit.hs b/src/Idris/Unlit.hs
--- a/src/Idris/Unlit.hs
+++ b/src/Idris/Unlit.hs
@@ -8,6 +8,7 @@
 module Idris.Unlit(unlit) where
 
 import Idris.Core.TT
+
 import Data.Char
 
 unlit :: FilePath -> String -> TC String
@@ -18,8 +19,9 @@
 data LineType = Prog | Blank | Comm
 
 ulLine :: String -> (LineType, String)
-ulLine ('>':' ':xs)        = (Prog, xs)
-ulLine ('>':xs)            = (Prog, xs)
+ulLine ('>':' ':xs)        = (Prog, ' ':' ':xs) -- Replace with spaces, otherwise text position numbers will be bogus.
+ulLine ('>':xs)            = (Prog, ' '    :xs) -- The parser can deal with this, because /every/ (code) line is prefixed
+                                                -- with a '>'.
 ulLine xs | all isSpace xs = (Blank, "")
 -- make sure it's not a doc comment
           | otherwise      = (Comm, '-':'-':' ':'>':xs)
@@ -28,7 +30,7 @@
 check f l (a:b:cs) = do chkAdj f l (fst a) (fst b)
                         check f (l+1) (b:cs)
 check f l [x] = return ()
-check f l [] = return ()
+check f l [ ] = return ()
 
 -- Issue #1593 on the issue checker.
 --
diff --git a/src/Idris/WhoCalls.hs b/src/Idris/WhoCalls.hs
--- a/src/Idris/WhoCalls.hs
+++ b/src/Idris/WhoCalls.hs
@@ -8,13 +8,11 @@
 module Idris.WhoCalls (whoCalls, callsWho) where
 
 import Idris.AbsSyntax
-
 import Idris.Core.CaseTree
 import Idris.Core.Evaluate
 import Idris.Core.TT
 
 import Data.List (nub)
-
 
 occurs :: Name -> Term -> Bool
 occurs n (P Bound _ _) = False
diff --git a/src/Util/DynamicLinker.hs b/src/Util/DynamicLinker.hs
--- a/src/Util/DynamicLinker.hs
+++ b/src/Util/DynamicLinker.hs
@@ -5,7 +5,7 @@
 License     : BSD3
 Maintainer  : The Idris Community.
 -}
-{-# LANGUAGE ExistentialQuantification, CPP, ScopedTypeVariables #-}
+{-# LANGUAGE CPP, ExistentialQuantification, ScopedTypeVariables #-}
 module Util.DynamicLinker ( ForeignFun(..)
                           , DynamicLib(..)
                           , tryLoadLib
@@ -14,21 +14,21 @@
 
 #ifdef IDRIS_FFI
 import Foreign.LibFFI
-import Foreign.Ptr (Ptr(), nullPtr, FunPtr, nullFunPtr, castPtrToFunPtr)
+import Foreign.Ptr (FunPtr, Ptr(), castPtrToFunPtr, nullFunPtr, nullPtr)
 import System.Directory
 #ifndef mingw32_HOST_OS
-import Control.Exception (try, IOException, throwIO)
-import Data.Array (Array, inRange, bounds, (!))
+import Control.Exception (IOException, throwIO, try)
+import Data.Array (Array, bounds, inRange, (!))
 import Data.Functor ((<$>))
 import Data.Maybe (catMaybes)
-import System.Posix.DynamicLinker
 import System.FilePath.Posix ((</>))
+import System.Posix.DynamicLinker
 import Text.Regex.TDFA
 #else
-import qualified Control.Exception as Exception (catch, IOException)
+import qualified Control.Exception as Exception (IOException, catch)
+import System.FilePath.Windows ((</>))
 import System.Win32.DLL
 import System.Win32.Types
-import System.FilePath.Windows ((</>))
 type DL = HMODULE
 #endif
 
diff --git a/src/Util/Net.hs b/src/Util/Net.hs
--- a/src/Util/Net.hs
+++ b/src/Util/Net.hs
@@ -7,10 +7,10 @@
 -}
 module Util.Net (listenOnLocalhost, listenOnLocalhostAnyPort) where
 
+import Control.Exception (bracketOnError)
 import Network hiding (socketPort)
-import Network.Socket hiding (sClose)
 import Network.BSD (getProtocolNumber)
-import Control.Exception (bracketOnError)
+import Network.Socket hiding (sClose)
 
 -- Copied from upstream impl of listenOn
 -- bound to localhost interface instead of iNADDR_ANY
diff --git a/src/Util/System.hs b/src/Util/System.hs
--- a/src/Util/System.hs
+++ b/src/Util/System.hs
@@ -22,25 +22,20 @@
 import Control.Monad (when)
 import qualified Data.Text as T
 import qualified Data.Text.IO as TIO
-
 import Foreign.C
-
-import System.Directory (getTemporaryDirectory
-                        , removeFile
-                        , removeDirectoryRecursive
-                        , createDirectoryIfMissing
-                        )
-import System.FilePath ((</>), normalise)
-import System.IO
+import System.Directory (createDirectoryIfMissing, getTemporaryDirectory,
+                         removeDirectoryRecursive, removeFile)
+import System.FilePath (normalise, (</>))
 import System.Info
+import System.IO
 import System.IO.Error
 
 #ifdef FREESTANDING
-import Tools_idris
 import Data.List (intercalate)
-import System.FilePath (isAbsolute, dropFileName, searchPathSeparator)
 import System.Directory (doesDirectoryExist)
-import System.Environment (getEnv, setEnv, getExecutablePath)
+import System.Environment (getEnv, getExecutablePath, setEnv)
+import System.FilePath (dropFileName, isAbsolute, searchPathSeparator)
+import Tools_idris
 #endif
 
 catchIO :: IO a -> (IOError -> IO a) -> IO a
diff --git a/stack-shell.nix b/stack-shell.nix
--- a/stack-shell.nix
+++ b/stack-shell.nix
@@ -2,7 +2,7 @@
 
 let
   # MUST match resolver in stack.yaml
-  resolver = haskell.packages.lts-7_0.ghc;
+  resolver = haskell.packages.lts-7_10.ghc;
 
   native_libs = [
     libffi
diff --git a/stack.yaml b/stack.yaml
--- a/stack.yaml
+++ b/stack.yaml
@@ -1,4 +1,4 @@
-resolver: lts-7.0
+resolver: lts-7.10
 
 packages:
   - location: .
@@ -10,7 +10,7 @@
 
 extra-deps:
   - libffi-0.1
-
+  - safe-0.3.9
 nix:
   enable: false
   shell-file: stack-shell.nix
diff --git a/test/TestData.hs b/test/TestData.hs
--- a/test/TestData.hs
+++ b/test/TestData.hs
@@ -91,7 +91,8 @@
       (  2, ANY  ),
       (  3, ANY  ),
       (  4, ANY  ),
-      (  5, ANY  )]),
+      (  5, ANY  ),
+      (  6, ANY  )]),
   ("dsl",             "DSL",
     [ (  1, ANY  ),
       (  2, C_CG ),
@@ -239,7 +240,8 @@
       ( 48, ANY  ),
       ( 52, C_CG ),
       ( 67, ANY  ),
-      ( 75, ANY  )]),
+      ( 75, ANY  ),
+      ( 76, ANY  )]),
   ("regression",      "Regression",
     [ (  1 , ANY  ),
       (  2 , ANY  )]),
@@ -273,7 +275,9 @@
       ( 14, ANY  ),
       ( 15, ANY  ),
       ( 16, ANY  ),
-      ( 17, ANY  )]),
+      ( 17, ANY  ),
+      ( 18, ANY  ),
+      ( 19, ANY  )]),
   ("tutorial",        "Tutorial examples",
     [ (  1, ANY  ),
       (  2, ANY  ),
diff --git a/test/TestRun.hs b/test/TestRun.hs
--- a/test/TestRun.hs
+++ b/test/TestRun.hs
@@ -1,27 +1,30 @@
+{-# LANGUAGE CPP #-}
 module Main where
 
+import TestData
+
 import Control.Monad
 import Data.Char (isLetter)
-import Data.Typeable
-import Data.Proxy
-import Data.List
 import qualified Data.IntMap as IMap
-
+import Data.List
+#if MIN_VERSION_optparse_applicative(0,13,0)
+import Data.Monoid ((<>))
+#endif
+import Data.Proxy
+import Data.Typeable
+import Options.Applicative
 import System.Directory
 import System.Environment
 import System.Exit
-import System.Process
+import System.FilePath ((</>))
 import System.Info
 import System.IO
-import System.FilePath ((</>))
-import Options.Applicative
+import System.Process
 import Test.Tasty
 import Test.Tasty.Golden
-import Test.Tasty.Runners
-import Test.Tasty.Options
 import Test.Tasty.Ingredients.Rerun
-
-import TestData
+import Test.Tasty.Options
+import Test.Tasty.Runners
 
 --------------------------------------------------------------------- [ Config ]
 
diff --git a/test/basic010/run b/test/basic010/run
--- a/test/basic010/run
+++ b/test/basic010/run
@@ -4,7 +4,7 @@
 
 TIMEOUT=../scripts/timeout
 
-$TIMEOUT 10 "${IDRIS:-idris}" "$@" Main.idr --nocolour --check --warnreach -o basic010
-$TIMEOUT 5  ./basic010
+$TIMEOUT 20 "${IDRIS:-idris}" "$@" Main.idr --nocolour --check --warnreach -o basic010
+$TIMEOUT 20  ./basic010
 
 rm -f -- *.ibc basic010
diff --git a/test/basic013/basic013.idr b/test/basic013/basic013.idr
--- a/test/basic013/basic013.idr
+++ b/test/basic013/basic013.idr
@@ -36,8 +36,41 @@
           printLn [(-9), (-7)..(-1)]
           printLn [17,15..1]
           printLn [19,15..2]
+          printLn [-2,0..4]
+          printLn [1,0..-2]
+          printLn [3,5..3]
+          printLn [2,1..2]
+          printLn [4,1..3]
+          printLn [1,4..2]
+          printLn [3,5..1]
+          printLn [4,1..5]
+          printLn [1,1..2]
+          printLn [2,2..1]
           printLn $ the (List Nat) [1..5]
           printLn $ the (List Nat) [5..1]
-          printLn $ the (List Int) [(-1)..(-5)]
+          printLn $ the (List Nat) [5,4..1]
           printLn $ the (List Nat) [1,3..5]
-
+          printLn $ the (List Nat) [5,3..1]
+          printLn $ the (List Nat) [3,5..3]
+          printLn $ the (List Nat) [2,1..2]
+          printLn $ the (List Nat) [4,1..3]
+          printLn $ the (List Nat) [1,4..2]
+          printLn $ the (List Nat) [3,5..1]
+          printLn $ the (List Nat) [4,1..5]
+          printLn $ the (List Nat) [1,1..2]
+          printLn $ the (List Nat) [2,2..1]
+          printLn $ the (List Int) [(-1)..(-5)]
+          printLn $ the (List Int) [-2,0..4]
+          printLn $ the (List Int) [1,0..-2]
+          printLn $ the (List Int) [3,5..3]
+          printLn $ the (List Int) [2,1..2]
+          printLn $ the (List Int) [4,1..3]
+          printLn $ the (List Int) [1,4..2]
+          printLn $ the (List Int) [3,5..1]
+          printLn $ the (List Int) [4,1..5]
+          printLn $ the (List Int) [1,1..2]
+          printLn $ the (List Int) [2,2..1]
+          printLn ['z'..'x']
+          printLn ['g','e'..'a']
+          printLn ['x'..'z']
+          printLn ['a','c'..'g']
diff --git a/test/basic013/expected b/test/basic013/expected
--- a/test/basic013/expected
+++ b/test/basic013/expected
@@ -17,7 +17,41 @@
 [-9, -7, -5, -3, -1]
 [17, 15, 13, 11, 9, 7, 5, 3, 1]
 [19, 15, 11, 7, 3]
+[-2, 0, 2, 4]
+[1, 0, -1, -2]
+[3]
+[2]
+[4]
+[1]
+[]
+[]
+[]
+[]
 [1, 2, 3, 4, 5]
 [5, 4, 3, 2, 1]
-[-1, -2, -3, -4, -5]
+[5, 4, 3, 2, 1]
 [1, 3, 5]
+[5, 3, 1]
+[3]
+[2]
+[4]
+[1]
+[]
+[]
+[]
+[]
+[-1, -2, -3, -4, -5]
+[-2, 0, 2, 4]
+[1, 0, -1, -2]
+[3]
+[2]
+[4]
+[1]
+[]
+[]
+[]
+[]
+['z', 'y', 'x']
+['g', 'e', 'c', 'a']
+['x', 'y', 'z']
+['a', 'c', 'e', 'g']
diff --git a/test/basic018/expected b/test/basic018/expected
--- a/test/basic018/expected
+++ b/test/basic018/expected
@@ -8,7 +8,7 @@
 Type mismatch between
         42 = 42 (Type of Refl)
 and
-        thing = 42 (Expected type)
+        thing = S (fromIntegerNat 41) (Expected type)
 
 Specifically:
         Type mismatch between
diff --git a/test/delab001/run b/test/delab001/run
--- a/test/delab001/run
+++ b/test/delab001/run
@@ -1,3 +1,3 @@
 #!/usr/bin/env bash
-${IDRIS:-idris} $@ --quiet --nocolor delab001.idr < input
+${IDRIS:-idris} $@ --quiet --port none --nocolor delab001.idr < input
 rm -f *.ibc
diff --git a/test/docs001/run b/test/docs001/run
--- a/test/docs001/run
+++ b/test/docs001/run
@@ -1,3 +1,3 @@
 #!/usr/bin/env bash
-${IDRIS:-idris} $@ --quiet --nocolor docs001.idr < input
+${IDRIS:-idris} $@ --quiet --port none --nocolor docs001.idr < input
 rm *.ibc
diff --git a/test/docs002/run b/test/docs002/run
--- a/test/docs002/run
+++ b/test/docs002/run
@@ -1,3 +1,3 @@
 #!/usr/bin/env bash
-${IDRIS:-idris} $@ --nobanner --nocolor --quiet docs002.idr < input
+${IDRIS:-idris} $@ --nobanner --nocolor --quiet --port none docs002.idr < input
 rm *.ibc
diff --git a/test/docs003/run b/test/docs003/run
--- a/test/docs003/run
+++ b/test/docs003/run
@@ -1,3 +1,3 @@
 #!/usr/bin/env bash
-${IDRIS:-idris} $@ --quiet --nocolor docs003.idr < input
+${IDRIS:-idris} $@ --quiet --port none --nocolor docs003.idr < input
 rm *.ibc
diff --git a/test/docs004/run b/test/docs004/run
--- a/test/docs004/run
+++ b/test/docs004/run
@@ -1,3 +1,3 @@
 #!/usr/bin/env bash
-${IDRIS:-idris} $@ --quiet --nocolor docs004.idr < input
+${IDRIS:-idris} $@ --quiet --port none --nocolor docs004.idr < input
 rm *.ibc
diff --git a/test/docs005/run b/test/docs005/run
--- a/test/docs005/run
+++ b/test/docs005/run
@@ -1,3 +1,3 @@
 #!/usr/bin/env bash
-${IDRIS:-idris} $@ --quiet --nocolor docs005.idr < input
+${IDRIS:-idris} $@ --quiet --port none --nocolor docs005.idr < input
 rm *.ibc
diff --git a/test/docs006/docs006.idr b/test/docs006/docs006.idr
new file mode 100644
--- /dev/null
+++ b/test/docs006/docs006.idr
@@ -0,0 +1,7 @@
+module docs006
+
+||| interface
+||| @ t some parameter
+interface Eq t => Foo t where
+  ||| member of interface
+  m : t
diff --git a/test/docs006/expected b/test/docs006/expected
new file mode 100644
--- /dev/null
+++ b/test/docs006/expected
@@ -0,0 +1,16 @@
+Interface Foo
+    interface
+
+Parameters:
+    t   -- some parameter
+
+Constraints:
+    Eq t
+
+Methods:
+    m : Foo t => t
+        member of interface
+        
+        The function is Total
+Implementations:
+    <no implementations>
diff --git a/test/docs006/input b/test/docs006/input
new file mode 100644
--- /dev/null
+++ b/test/docs006/input
@@ -0,0 +1,1 @@
+:doc Foo
diff --git a/test/docs006/run b/test/docs006/run
new file mode 100644
--- /dev/null
+++ b/test/docs006/run
@@ -0,0 +1,3 @@
+#!/usr/bin/env bash
+${IDRIS:-idris} $@ --quiet --port none --nocolor docs006.idr < input
+rm *.ibc
diff --git a/test/dsl001/expected b/test/dsl001/expected
--- a/test/dsl001/expected
+++ b/test/dsl001/expected
@@ -1,14 +1,14 @@
 24
 12
 testFac : Int
-testFac = PE_interp_f79b3e31 [] (PE_fromInteger_a0377313 4)
+testFac = PE_interp_f79b3e31 [] (PE_fromInteger_d6648df 4)
 PE_interp_f79b3e31 : Env G -> Int -> Int
 PE_interp_f79b3e31 (3arg) = \x =>
-                              ifThenElse (PE_==_a03270d8 x
-                                                         (PE_fromInteger_a0377313 0))
-                                         (Delay (PE_fromInteger_a0377313 1))
-                                         (Delay (PE_*_a725d5d6 (PE_interp_f79b3e31 (x ::
+                              ifThenElse (PE_==_ba2f651f x
+                                                         (PE_fromInteger_d6648df 0))
+                                         (Delay (PE_fromInteger_d6648df 1))
+                                         (Delay (PE_*_ba2f651f (PE_interp_f79b3e31 (x ::
                                                                                     (3arg))
-                                                                                   (PE_-_a71cf640 x
-                                                                                                  (PE_fromInteger_a0377313 1)))
+                                                                                   (PE_-_ba2f651f x
+                                                                                                  (PE_fromInteger_d6648df 1)))
                                                                x))
diff --git a/test/dsl001/run b/test/dsl001/run
--- a/test/dsl001/run
+++ b/test/dsl001/run
@@ -1,5 +1,5 @@
 #!/usr/bin/env bash
 ${IDRIS:-idris} $@ test001.idr -o test001
 ./test001
-${IDRIS:-idris} $@ test001.idr --quiet < input
+${IDRIS:-idris} $@ test001.idr --quiet --port none < input
 rm -f test001 test001.ibc
diff --git a/test/dsl001/test001.idr b/test/dsl001/test001.idr
--- a/test/dsl001/test001.idr
+++ b/test/dsl001/test001.idr
@@ -101,4 +101,3 @@
             printLn test }
 
 
-
diff --git a/test/ffi001/run b/test/ffi001/run
--- a/test/ffi001/run
+++ b/test/ffi001/run
@@ -1,3 +1,3 @@
 #!/usr/bin/env bash
-${IDRIS:-idris} $@ --quiet --nocolour test022.idr --exec main
+${IDRIS:-idris} $@ --quiet --port none --nocolour test022.idr --exec main
 rm -f *.ibc
diff --git a/test/ffi002/run b/test/ffi002/run
--- a/test/ffi002/run
+++ b/test/ffi002/run
@@ -1,3 +1,3 @@
 #!/usr/bin/env bash
-${IDRIS:-idris} $@ --quiet test023.idr -o test023
+${IDRIS:-idris} $@ --quiet --port none test023.idr -o test023
 rm -f test023 *.ibc
diff --git a/test/ffi003/run b/test/ffi003/run
--- a/test/ffi003/run
+++ b/test/ffi003/run
@@ -1,3 +1,3 @@
 #!/usr/bin/env bash
-${IDRIS:-idris} $@ --quiet --nocolour test024.idr --exec main < input
+${IDRIS:-idris} $@ --quiet --port none --nocolour test024.idr --exec main < input
 rm -f *.ibc
diff --git a/test/ffi004/run b/test/ffi004/run
--- a/test/ffi004/run
+++ b/test/ffi004/run
@@ -1,3 +1,3 @@
 #!/usr/bin/env bash
-${IDRIS:-idris} $@ --quiet --nocolour --check test026.idr
+${IDRIS:-idris} $@ --quiet --port none --nocolour --check test026.idr
 rm -f *.ibc
diff --git a/test/idrisdoc009/run b/test/idrisdoc009/run
--- a/test/idrisdoc009/run
+++ b/test/idrisdoc009/run
@@ -1,3 +1,3 @@
 #!/usr/bin/env bash
-${IDRIS:-idris} $@ --nocolour --quiet Test.idr < input
+${IDRIS:-idris} $@ --nocolour --quiet --port none Test.idr < input
 rm -f *.ibc
diff --git a/test/interactive001/run b/test/interactive001/run
--- a/test/interactive001/run
+++ b/test/interactive001/run
@@ -1,3 +1,3 @@
 #!/usr/bin/env bash
-${IDRIS:-idris} $@ --quiet test032.idr < input
+${IDRIS:-idris} $@ --quiet --port none test032.idr < input
 rm -f *.ibc
diff --git a/test/interactive002/run b/test/interactive002/run
--- a/test/interactive002/run
+++ b/test/interactive002/run
@@ -1,3 +1,3 @@
 #!/usr/bin/env bash
-${IDRIS:-idris} $@ --quiet interactive002.idr < input
+${IDRIS:-idris} $@ --quiet --port none interactive002.idr < input
 rm -f *.ibc
diff --git a/test/interactive003/run b/test/interactive003/run
--- a/test/interactive003/run
+++ b/test/interactive003/run
@@ -1,3 +1,3 @@
 #!/usr/bin/env bash
-${IDRIS:-idris} $@ --quiet interactive003.idr < input
+${IDRIS:-idris} $@ --quiet --port none interactive003.idr < input
 rm -f *.ibc
diff --git a/test/interactive004/run b/test/interactive004/run
--- a/test/interactive004/run
+++ b/test/interactive004/run
@@ -1,3 +1,3 @@
 #!/usr/bin/env bash
-${IDRIS:-idris} $@ --quiet interactive004.idr < input
+${IDRIS:-idris} $@ --quiet --port none interactive004.idr < input
 rm -f *.ibc
diff --git a/test/interactive005/run b/test/interactive005/run
--- a/test/interactive005/run
+++ b/test/interactive005/run
@@ -1,5 +1,5 @@
 #!/usr/bin/env bash
-${IDRIS:-idris} $@ --nocolour --quiet interactive005.idr --consolewidth 70 < input
+${IDRIS:-idris} $@ --nocolour --quiet --port none interactive005.idr --consolewidth 70 < input
 rm -f *.ibc
 rm -f hello.bytecode
 rm -f hello
diff --git a/test/interactive006/run b/test/interactive006/run
--- a/test/interactive006/run
+++ b/test/interactive006/run
@@ -1,3 +1,3 @@
 #!/usr/bin/env bash
-${IDRIS:-idris} $@ --quiet --port 5000 interactive006.idr < input
+${IDRIS:-idris} $@ --quiet --port none --port 5000 interactive006.idr < input
 rm -f *.ibc
diff --git a/test/interactive007/run b/test/interactive007/run
--- a/test/interactive007/run
+++ b/test/interactive007/run
@@ -1,2 +1,2 @@
 #!/usr/bin/env bash
-${IDRIS:-idris} $@ -p contrib --nobanner --nocolor < input | perl -pe 's-Data\\Z-Data/Z-g'
+${IDRIS:-idris} $@ -p contrib --nobanner --nocolor --port none < input | perl -pe 's-Data\\Z-Data/Z-g'
diff --git a/test/interactive008/run b/test/interactive008/run
--- a/test/interactive008/run
+++ b/test/interactive008/run
@@ -1,2 +1,2 @@
 #!/usr/bin/env bash
-${IDRIS:-idris} $@ --nobanner --nocolor < input
+${IDRIS:-idris} $@ --nobanner --nocolor --port none < input
diff --git a/test/interactive009/run b/test/interactive009/run
--- a/test/interactive009/run
+++ b/test/interactive009/run
@@ -1,3 +1,3 @@
 #!/usr/bin/env bash
-${IDRIS:-idris} $@ --quiet interactive009.idr < input
+${IDRIS:-idris} $@ --quiet --port none interactive009.idr < input
 rm -f *.ibc
diff --git a/test/interactive010/run b/test/interactive010/run
--- a/test/interactive010/run
+++ b/test/interactive010/run
@@ -1,2 +1,2 @@
 #!/usr/bin/env bash
-${IDRIS:-idris} $@ --quiet --nobanner --nocolor  < input
+${IDRIS:-idris} $@ --quiet --port none --nobanner --nocolor  < input
diff --git a/test/interactive011/run b/test/interactive011/run
--- a/test/interactive011/run
+++ b/test/interactive011/run
@@ -1,3 +1,3 @@
 #!/usr/bin/env bash
-${IDRIS:-idris} $@ --quiet interactive011.idr < input
+${IDRIS:-idris} $@ --quiet --port none interactive011.idr < input
 rm -f *.ibc
diff --git a/test/interactive012/run b/test/interactive012/run
--- a/test/interactive012/run
+++ b/test/interactive012/run
@@ -1,3 +1,3 @@
 #!/usr/bin/env bash
-${IDRIS:-idris} $@ --nocolour --consolewidth 70 --quiet interactive012.idr < input
+${IDRIS:-idris} $@ --nocolour --consolewidth 70 --quiet --port none interactive012.idr < input
 rm -f *.ibc
diff --git a/test/interactive013/run b/test/interactive013/run
--- a/test/interactive013/run
+++ b/test/interactive013/run
@@ -1,3 +1,3 @@
 #!/usr/bin/env bash
-${IDRIS:-idris} $@ --quiet interactive013.idr < input
+${IDRIS:-idris} $@ --quiet --port none interactive013.idr < input
 rm -f *.ibc
diff --git a/test/interfaces001/run b/test/interfaces001/run
--- a/test/interfaces001/run
+++ b/test/interfaces001/run
@@ -1,3 +1,3 @@
 #!/usr/bin/env bash
-${IDRIS:-idris} $@ --quiet --nocolour --consolewidth 70 InterfaceName.idr < input
+${IDRIS:-idris} $@ --quiet --port none --nocolour --consolewidth 70 InterfaceName.idr < input
 rm -f *.ibc
diff --git a/test/interfaces002/interfaces002.idr b/test/interfaces002/interfaces002.idr
--- a/test/interfaces002/interfaces002.idr
+++ b/test/interfaces002/interfaces002.idr
@@ -1,5 +1,7 @@
 import Data.Vect
 
+%default total
+  
 interface ArrayM where
   Array : (n : Nat) -> (a : Type) -> Type
   
diff --git a/test/layout001/run b/test/layout001/run
--- a/test/layout001/run
+++ b/test/layout001/run
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-${IDRIS:-idris} --nobanner --nocolour --quiet <<!
+${IDRIS:-idris} --nobanner --nocolour --quiet --port none <<!
 :load layout001a.idr
 :load layout001b.idr
 :load layout001c.idr
diff --git a/test/primitives002/run b/test/primitives002/run
--- a/test/primitives002/run
+++ b/test/primitives002/run
@@ -48,7 +48,7 @@
 do
     echo ${T%% *} ${T##*#}
     generate_testfile "tmptest.idr" "${T%%#*}"
-    ${IDRIS:-idris} $@ --quiet tmptest.idr -o tmptest || echo "missing primitive in ${CG}"
+    ${IDRIS:-idris} $@ --quiet --port none tmptest.idr -o tmptest || echo "missing primitive in ${CG}"
     ./tmptest <<<"${T##*#}"
     rm tmptest.idr tmptest.ibc tmptest
 done
diff --git a/test/proof001/test029.idr b/test/proof001/test029.idr
--- a/test/proof001/test029.idr
+++ b/test/proof001/test029.idr
@@ -12,9 +12,9 @@
 
 -- Step case
 -- (S k + m = m + S k) <== plus_comm =
-plus_comm (S k) m =
-    rewrite ((k + m = m + k) <== plus_comm) in
-    rewrite ((S (m + k) = m + S k) <== plusSuccRightSucc) in
+plus_comm (S len) m =
+    rewrite ((len + m = m + len) <== plus_comm) in
+    rewrite ((S (m + len) = m + S len) <== plusSuccRightSucc) in
         Refl
 -- QED
 
@@ -29,7 +29,7 @@
 simple.append_lemma_2 = proof {
   intros;
   compute;
-  rewrite (plusSuccRightSucc m k);
+  rewrite (plusSuccRightSucc m len);
   trivial;
 }
 
@@ -39,4 +39,3 @@
   rewrite sym (plusZeroRightNeutral m);
   exact value;
 }
-
diff --git a/test/proof009/run b/test/proof009/run
--- a/test/proof009/run
+++ b/test/proof009/run
@@ -1,3 +1,3 @@
 #!/usr/bin/env bash
-${IDRIS:-idris} $@ --consolewidth 70 --quiet proof009.idr < input
+${IDRIS:-idris} $@ --consolewidth 70 --quiet --port none proof009.idr < input
 rm -f *.ibc
diff --git a/test/quasiquote006/run b/test/quasiquote006/run
--- a/test/quasiquote006/run
+++ b/test/quasiquote006/run
@@ -1,3 +1,3 @@
 #!/usr/bin/env bash
-${IDRIS:-idris} $@ --check --nocolour --quiet --consolewidth 70 quasiquote006.idr
+${IDRIS:-idris} $@ --check --nocolour --quiet --port none --consolewidth 70 quasiquote006.idr
 rm -f *.ibc
diff --git a/test/reg041/run b/test/reg041/run
--- a/test/reg041/run
+++ b/test/reg041/run
@@ -1,5 +1,5 @@
 #!/usr/bin/env bash
-${IDRIS:-idris} $@ --quiet ott.idr -e example
+${IDRIS:-idris} $@ --quiet --port none ott.idr -e example
 ${IDRIS:-idris} $@ showu.idr -o reg040
 ./reg040
 rm -f reg040 *.ibc
diff --git a/test/reg075/run b/test/reg075/run
--- a/test/reg075/run
+++ b/test/reg075/run
@@ -1,3 +1,3 @@
 #!/usr/bin/env bash
-${IDRIS:-idris} $@ --quiet reg075.idr < input
+${IDRIS:-idris} $@ --quiet --port none reg075.idr < input
 rm -f *.ibc
diff --git a/test/reg076/expected b/test/reg076/expected
new file mode 100644
--- /dev/null
+++ b/test/reg076/expected
@@ -0,0 +1,1 @@
+3
diff --git a/test/reg076/input b/test/reg076/input
new file mode 100644
--- /dev/null
+++ b/test/reg076/input
diff --git a/test/reg076/reg076.idr b/test/reg076/reg076.idr
new file mode 100644
--- /dev/null
+++ b/test/reg076/reg076.idr
@@ -0,0 +1,11 @@
+data Op = Add | Mul
+
+binop : Op -> Integer -> Integer -> Integer
+binop Add = (+)
+binop Mul = (*)
+
+doOp : Op -> IO Integer
+doOp op = pure (binop op 1 2)
+
+main : IO ()
+main = doOp Add >>= print
diff --git a/test/reg076/run b/test/reg076/run
new file mode 100644
--- /dev/null
+++ b/test/reg076/run
@@ -0,0 +1,4 @@
+#!/usr/bin/env bash
+${IDRIS:-idris} $@ --port none reg076.idr -o reg076
+./reg076
+rm -f *.ibc reg076
diff --git a/test/regression001/coverage001.idr b/test/regression001/coverage001.idr
new file mode 100644
--- /dev/null
+++ b/test/regression001/coverage001.idr
@@ -0,0 +1,79 @@
+module Data.AVL.Tree
+
+%default total
+%access export
+
+data Balance : Nat -> Nat -> Type where
+  LHeavy   : Balance (S n) n
+  RHeavy   : Balance n     (S n)
+  Balanced : Balance n     n
+
+%name Balance b, bal
+    
+height : Balance n m -> Nat
+height b = S (height' b)
+  where
+    height' : Balance n m -> Nat
+    height' (LHeavy {n}) = S n
+    height' (RHeavy {n}) = S n
+    height' {n} (Balanced {n}) = n
+
+public export
+data Tree : (keyTy : Type) -> (valTy : Type) -> Type
+  where
+    ||| An empty Tree node.
+    Empty : Tree k v
+
+    Node : (key   : k)
+        -> (val   : v)
+        -> (left  : Tree k v)
+        -> (right : Tree k v)
+        -> Tree k v
+
+%name Tree t, tree
+
+public export
+data AVLInvariant : (height : Nat)
+                 -> (tree   : Tree k v)
+                 -> Type
+  where
+    AVLEmpty : AVLInvariant 0 Empty
+
+    AVLNode : (left  : AVLInvariant n l) -> 
+              (right :  AVLInvariant m r) -> 
+              (b : Balance n m) -> 
+              AVLInvariant (height b) (Node k v l r)
+
+%name AVLInvariant inv
+
+public export
+AVLTree : (height : Nat) -> (keyTy : Type) -> (valueTy : Type) -> Type
+AVLTree n k v = Subset (Tree k v) (AVLInvariant n)
+
+-- --------------------------------------------------------------- [ Rotations ]
+private
+data InsertRes : Nat -> (k : Type) -> Type -> Type where
+  Same : AVLTree n k v     -> InsertRes n k v
+  Grew : AVLTree (S n) k v -> InsertRes n k v
+
+%name InsertRes res, r
+
+private
+runInsertRes : InsertRes n k v -> (n : Nat ** AVLTree n k v)
+runInsertRes (Same t) = (_ ** t)
+runInsertRes (Grew t) = (_ ** t)
+
+||| Perform a Left roation.
+private
+rotLeft : k
+       -> v
+       -> AVLTree n k v
+       -> AVLTree (S (S n)) k v
+       -> InsertRes (S (S n)) k v
+-- Impossible because Empty has depth 0 and we know the depth is at least 2 from the type
+rotLeft key val l (Element Empty AVLEmpty) impossible
+rotLeft key val (Element l invl) (Element (Node key' val' rl rr) (AVLNode invrl invrr Balanced)) = ?rl1
+rotLeft key val (Element l invl) (Element (Node key' val' (Node key'' val'' rll rlr) rr) (AVLNode (AVLNode invrll invrlr LHeavy) invrr LHeavy)) = ?rl2
+rotLeft key val (Element l invl) (Element (Node key' val' (Node key'' val'' rll rlr) rr) (AVLNode (AVLNode invrll invrlr RHeavy) invrr LHeavy)) = ?rl3
+rotLeft key val (Element l invl) (Element (Node key' val' (Node key'' val'' rll rlr) rr) (AVLNode (AVLNode invrll invrlr Balanced) invrr LHeavy)) = ?rl4
+rotLeft key val (Element l invl) (Element (Node key' val' rl rr) (AVLNode invrl invrr RHeavy)) = ?rl5
diff --git a/test/regression001/eff001.idr b/test/regression001/eff001.idr
new file mode 100644
--- /dev/null
+++ b/test/regression001/eff001.idr
@@ -0,0 +1,39 @@
+module Test.Random
+
+import Effects
+import Effect.Random
+
+genKVPair : (genA : Eff a [RND])
+         -> (genB : Eff b [RND])
+         -> Eff (Pair a b) [RND]
+genKVPair f g = pure (!f, !g)
+
+genRndListKVUE : (Eq a, Eq b) =>
+                 (seed : Integer)
+              -> (len  : Nat)
+              -> (genA : Eff a [RND])
+              -> (genB : Eff b [RND])
+              -> Eff (List (Pair a b)) [RND]
+genRndListKVUE s l f g = do srand s; pure !(doGen l (genKVPair f g))
+  where
+    genElem : (Eq a, Eq b)
+           => (generator : Eff (Pair a b) [RND])
+           -> (existing  : List (Pair a b))
+           -> Eff (Pair a b) [RND]
+    genElem j xs = do
+      x <- j
+      if elem x xs
+        then genElem j xs
+        else if isJust $ lookup (fst x) xs
+          then genElem j xs
+          else pure x
+
+    doGen : (Eq a, Eq b)
+         => (count     : Nat)
+         -> (generator : Eff (Pair a b) [RND])
+         -> Eff (List (Pair a b)) [RND]
+    doGen Z     j = pure Nil
+    doGen (S n) j = do
+      xs <- doGen n j
+      x  <- genElem j xs
+      pure (x::xs)
diff --git a/test/regression001/reg036.idr b/test/regression001/reg036.idr
--- a/test/regression001/reg036.idr
+++ b/test/regression001/reg036.idr
@@ -5,8 +5,8 @@
   data HV : Vect n Type -> Type where
     MkHV : HVect ts -> HV ts
 
-  showHV : Shows m ts => HV ts -> String
+  showHV : Shows ts => HV ts -> String
   showHV (MkHV v) = show v
 
-  implementation Shows m ts => Show (HV ts) where
+  implementation Shows ts => Show (HV ts) where
     show = showHV
diff --git a/test/regression001/run b/test/regression001/run
--- a/test/regression001/run
+++ b/test/regression001/run
@@ -3,7 +3,11 @@
     reg001.idr reg036.idr reg037.idr reg038.idr reg046.idr \
     reg047a.idr reg053.idr reg057.idr reg058.idr reg058a.idr \
     reg059.idr reg060.idr  reg061.idr reg062.idr reg063.idr \
-    reg064.idr reg065.idr  reg066.idr reg071.idr reg074.idr
+    reg064.idr reg065.idr  reg066.idr reg071.idr reg074.idr \
+    coverage001.idr
+
+${IDRIS:-idris} $@ --check \
+    eff001.idr -p effects
 
 ${IDRIS:-idris} $@ --check --nobuiltins reg047.idr
 
diff --git a/test/regression002/expected b/test/regression002/expected
--- a/test/regression002/expected
+++ b/test/regression002/expected
@@ -6,8 +6,8 @@
 No such variable EvenList
 reg006.idr:17:1:
 RBTree.lookup is possibly not total due to recursive path RBTree.lookup --> RBTree.lookup
-reg007.lidr:8:1:A.n is already defined
-reg007.lidr:12:11-17:When checking right hand side of hurrah with expected type
+reg007.lidr:8:3:A.n is already defined
+reg007.lidr:12:13-19:When checking right hand side of hurrah with expected type
         0 = 1
 
 Type mismatch between
@@ -103,7 +103,7 @@
 When checking an application of constructor Foo.CAny:
         Attempting concrete match on polymorphic argument: Nothing
 reg055a.idr:13:7:When checking left hand side of Foo.apply:
-Can't match on apply (\x => \y => x) a
+Can't match on apply (\x, y => x) a
 reg056.idr:7:7:dodgy n m Refl is a valid case
 reg056.idr:10:6:nonk Refl is a valid case
 reg068.idr:1:6:Main.nat has a name which may be implicitly bound.
diff --git a/test/regression002/run b/test/regression002/run
--- a/test/regression002/run
+++ b/test/regression002/run
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-${IDRIS:-idris} $@ --nobanner --nocolour --quiet <<!
+${IDRIS:-idris} $@ --nobanner --nocolour --quiet --port none <<!
 :load reg003.idr
 :load reg003a.idr
 :load reg006.idr
diff --git a/test/tactics001/Tactics.idr b/test/tactics001/Tactics.idr
--- a/test/tactics001/Tactics.idr
+++ b/test/tactics001/Tactics.idr
@@ -18,14 +18,16 @@
 plusZeroRightNeutralNew : (n : Nat) -> plus n 0 = n
 plusZeroRightNeutralNew Z = Refl
 plusZeroRightNeutralNew (S k) =
-  %runElab (do rewriteWith `(sym $ plusZeroRightNeutralNew ~(Var `{k}))
+  %runElab (do compute
+               rewriteWith `(sym $ plusZeroRightNeutralNew ~(Var `{k}))
                fill $ refl `(Nat : Type) `(S ~(Var `{k}))
                solve)
 
 plusSuccRightSuccNew : (j, k : Nat) -> plus j (S k) = S (plus j k)
 plusSuccRightSuccNew Z k = Refl
 plusSuccRightSuccNew (S j) k =
-  %runElab (do rewriteWith `(sym $ plusSuccRightSuccNew ~(Var `{j}) ~(Var `{k}))
+  %runElab (do compute
+               rewriteWith `(sym $ plusSuccRightSuccNew ~(Var `{j}) ~(Var `{k}))
                fill $ refl `(Nat : Type) `(S (S (plus ~(Var `{j}) ~(Var `{k}))))
                solve)
 
diff --git a/test/totality011/expected b/test/totality011/expected
--- a/test/totality011/expected
+++ b/test/totality011/expected
@@ -1,2 +1,2 @@
-totality011.lidr:22:1:
+totality011.lidr:22:3:
 Main.weCanOnlyGetOlder is not total as there are missing cases
diff --git a/test/totality013/expected b/test/totality013/expected
--- a/test/totality013/expected
+++ b/test/totality013/expected
@@ -1,4 +1,3 @@
 totality013a.idr:5:3:
-Main.foo is possibly not total due to recursive path Main.mtot --> Main.mtot --> Main.mtot --> Main.mtot
-totality013a.idr:9:3:
-Main.mtot is possibly not total due to recursive path Main.mtot --> Main.mtot --> Main.mtot
+Main.foo is possibly not total due to recursive path Main.foo --> Main.mtot --> Main.mtot --> Main.mtot
+totality013a.idr:9:3:Main.mtot is possibly not total due to: Main.foo
diff --git a/test/totality015/totality015.idr b/test/totality015/totality015.idr
--- a/test/totality015/totality015.idr
+++ b/test/totality015/totality015.idr
@@ -12,7 +12,7 @@
      Do : Command a -> (a -> Inf (ConsoleIO b)) -> ConsoleIO b
 
 (>>=) : Command a -> (a -> Inf (ConsoleIO b)) -> ConsoleIO b
-(>>=) = Do
+(>>=) = Do 
 
 data Fuel = Dry | More (Lazy Fuel)
 
diff --git a/test/totality018/expected b/test/totality018/expected
new file mode 100644
--- /dev/null
+++ b/test/totality018/expected
@@ -0,0 +1,1 @@
+totality018.idr:12:1:Main.bar is not total as there are missing cases
diff --git a/test/totality018/run b/test/totality018/run
new file mode 100644
--- /dev/null
+++ b/test/totality018/run
@@ -0,0 +1,3 @@
+#!/usr/bin/env bash
+${IDRIS:-idris} $@ totality018.idr --check
+rm -f *.ibc
diff --git a/test/totality018/totality018.idr b/test/totality018/totality018.idr
new file mode 100644
--- /dev/null
+++ b/test/totality018/totality018.idr
@@ -0,0 +1,15 @@
+import Data.Fin
+
+%default total
+
+foo : Fin 3 -> Nat
+foo FZ = 0
+foo (FS FZ) = 1
+foo (FS (FS FZ)) = 2
+-- testing that there is no need for an extra 'impossible'
+
+bar : Fin 4 -> Nat
+bar FZ = 0
+bar (FS FZ) = 1
+bar (FS (FS FZ)) = 2
+-- should be non-total
diff --git a/test/totality019/expected b/test/totality019/expected
new file mode 100644
--- /dev/null
+++ b/test/totality019/expected
@@ -0,0 +1,2 @@
+totality019.idr:8:1:Main.testCov is not total as there are missing cases
+totality019.idr:12:1:Main.testCov' is not total as there are missing cases
diff --git a/test/totality019/run b/test/totality019/run
new file mode 100644
--- /dev/null
+++ b/test/totality019/run
@@ -0,0 +1,4 @@
+#!/usr/bin/env bash
+${IDRIS:-idris} $@ totality019.idr --check
+${IDRIS:-idris} $@ totality019a.idr --check
+rm -f *.ibc
diff --git a/test/totality019/totality019.idr b/test/totality019/totality019.idr
new file mode 100644
--- /dev/null
+++ b/test/totality019/totality019.idr
@@ -0,0 +1,14 @@
+%default total
+
+MkThing : Bool -> Type
+MkThing True = Nat
+MkThing False = Bool
+
+testCov : (x : Bool) -> MkThing x -> Nat
+testCov False False = ?testCov_rhs_3
+testCov False True = ?testCov_rhs_4
+
+testCov' : (x : Bool ** MkThing x) -> Nat
+testCov' (False ** False) = ?testCov_rhs_3
+testCov' (False ** True) = ?testCov_rhs_4
+
diff --git a/test/totality019/totality019a.idr b/test/totality019/totality019a.idr
new file mode 100644
--- /dev/null
+++ b/test/totality019/totality019a.idr
@@ -0,0 +1,81 @@
+module Test
+
+import Data.Vect
+%default total 
+
+genT : Vect n Type -> Type
+genT [] = Type
+genT (x :: xs) = x -> genT xs
+
+data FunLang: Type where
+  Atom : {dt : Vect n Type} -> genT dt -> FunLang 
+  And  : FunLang -> FunLang -> FunLang
+  Uor  : FunLang -> FunLang -> FunLang
+  Xor  : FunLang -> FunLang -> FunLang  -- d decides on that
+
+data IndexFL : FunLang -> FunLang -> Type where
+  LHere     : IndexFL fl fl
+  LLeftAnd  : IndexFL x rfl -> IndexFL (And x y) rfl
+  LRightAnd : IndexFL y rfl -> IndexFL (And x y) rfl
+  LLeftUor  : IndexFL x rfl -> IndexFL (Uor x y) rfl
+  LRightUor : IndexFL y rfl -> IndexFL (Uor x y) rfl
+  LLeftXor  : IndexFL x rfl -> IndexFL (Xor x y) rfl
+  LRightXor : IndexFL y rfl -> IndexFL (Xor x y) rfl
+
+data SetFL : FunLang -> Type where
+  SEmpty      : SetFL fl
+  SElem      : SetFL fl
+  SLeftAnd   : SetFL x -> SetFL (And x y) 
+  SRightAnd  : SetFL y -> SetFL (And x y) 
+  SBothAnd   : SetFL x -> SetFL y -> SetFL (And x y) 
+  SLeftUor   : SetFL x -> SetFL (Uor x y) 
+  SRightUor : SetFL y -> SetFL (Uor x y) 
+  SBothUor   : SetFL x -> SetFL y -> SetFL (Uor x y) 
+  SLeftXor   : SetFL x -> SetFL (Xor x y) 
+  SRightXor  : SetFL y -> SetFL (Xor x y) 
+  SBothXor   : SetFL x -> SetFL y -> SetFL (Xor x y) 
+
+addIndexFLEmpty : IndexFL fl _ -> SetFL fl
+addIndexFLEmpty LHere = SElem
+addIndexFLEmpty (LLeftAnd z) = SLeftAnd $ addIndexFLEmpty z
+addIndexFLEmpty (LRightAnd z) = SRightAnd $ addIndexFLEmpty z
+addIndexFLEmpty (LLeftUor z) = SLeftUor $ addIndexFLEmpty z
+addIndexFLEmpty (LRightUor z) = SRightUor $ addIndexFLEmpty z
+addIndexFLEmpty (LLeftXor z) = SLeftXor $ addIndexFLEmpty z
+addIndexFLEmpty (LRightXor z) =  SRightXor $ addIndexFLEmpty z
+
+addIndexFL : SetFL fl -> IndexFL fl _ -> SetFL fl
+addIndexFL SEmpty y = addIndexFLEmpty y
+addIndexFL SElem y = SElem
+addIndexFL x LHere = SElem
+addIndexFL (SLeftAnd x) (LLeftAnd w) = SLeftAnd $ addIndexFL x w
+addIndexFL (SLeftAnd SElem) (LRightAnd LHere) = SElem
+addIndexFL (SLeftAnd x) (LRightAnd w) = SBothAnd x (addIndexFLEmpty w)
+addIndexFL (SRightAnd SElem) (LLeftAnd LHere) = SElem
+addIndexFL (SRightAnd x) (LLeftAnd w) = SBothAnd (addIndexFLEmpty w) x
+addIndexFL (SRightAnd x) (LRightAnd w) = SRightAnd $ addIndexFL x w
+addIndexFL (SBothAnd x SElem) (LLeftAnd LHere) = SElem
+addIndexFL (SBothAnd SElem y) (LRightAnd LHere) = SElem
+addIndexFL (SBothAnd x y) (LLeftAnd w) = SBothAnd (addIndexFL x w) y
+addIndexFL (SBothAnd x y) (LRightAnd w) = SBothAnd x (addIndexFL y w)
+addIndexFL (SLeftUor x) (LLeftUor w) = SLeftUor $ addIndexFL x w
+addIndexFL (SLeftUor SElem) (LRightUor LHere) = SElem
+addIndexFL (SLeftUor x) (LRightUor w) = SBothUor x (addIndexFLEmpty w)
+addIndexFL (SRightUor SElem) (LLeftUor LHere) = SElem
+addIndexFL (SRightUor x) (LLeftUor w) = SBothUor (addIndexFLEmpty w) x
+addIndexFL (SRightUor x) (LRightUor w) = SRightUor $ addIndexFL x w
+addIndexFL (SBothUor x SElem) (LLeftUor LHere) = SElem
+addIndexFL (SBothUor SElem y) (LRightUor LHere) = SElem
+addIndexFL (SBothUor x y) (LLeftUor w) = SBothUor (addIndexFL x w) y
+addIndexFL (SBothUor x y) (LRightUor w) = SBothUor x (addIndexFL y w)
+addIndexFL (SLeftXor x) (LLeftXor w) = SLeftXor $ addIndexFL x w
+addIndexFL (SLeftXor SElem) (LRightXor LHere) = SElem
+addIndexFL (SLeftXor x) (LRightXor w) = SBothXor x (addIndexFLEmpty w)
+addIndexFL (SRightXor SElem) (LLeftXor LHere) = SElem
+addIndexFL (SRightXor x) (LLeftXor w) = SBothXor (addIndexFLEmpty w) x
+addIndexFL (SRightXor x) (LRightXor w) = SRightXor $ addIndexFL x w
+addIndexFL (SBothXor x SElem) (LLeftXor LHere) = SElem
+addIndexFL (SBothXor SElem y) (LRightXor LHere) = SElem
+addIndexFL (SBothXor x y) (LLeftXor w) = SBothXor (addIndexFL x w) y
+addIndexFL (SBothXor x y) (LRightXor w) = SBothXor x (addIndexFL y w)
+
diff --git a/test/tutorial006/expected b/test/tutorial006/expected
--- a/test/tutorial006/expected
+++ b/test/tutorial006/expected
@@ -1,18 +1,18 @@
 tutorial006a.idr:5:23-25:
 When checking right hand side of vapp with expected type
-        Vect (S k + m) a
+        Vect (S len + m) a
 
 When checking argument xs to constructor Data.Vect.:::
         Type mismatch between
-                Vect (k + k) a (Type of vapp xs xs)
+                Vect (len + len) a (Type of vapp xs xs)
         and
-                Vect (plus k m) a (Expected type)
+                Vect (plus len m) a (Expected type)
         
         Specifically:
                 Type mismatch between
-                        plus k k
+                        plus len len
                 and
-                        plus k m
+                        plus len m
 tutorial006b.idr:10:10:
 When checking right hand side of with block in Main.parity with expected type
         Parity (S (S (j + j)))
diff --git a/test/unique004/run b/test/unique004/run
--- a/test/unique004/run
+++ b/test/unique004/run
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-${IDRIS:-idris} --nobanner --nocolour --quiet <<!
+${IDRIS:-idris} --nobanner --nocolour --quiet --port none <<!
 :load unique001a.idr
 :load unique001b.idr
 :load unique001c.idr
