diff --git a/.stylish-haskell.yaml b/.stylish-haskell.yaml
new file mode 100644
--- /dev/null
+++ b/.stylish-haskell.yaml
@@ -0,0 +1,154 @@
+# stylish-haskell configuration file
+# ==================================
+
+# The stylish-haskell tool is mainly configured by specifying steps. These steps
+# are a list, so they have an order, and one specific step may appear more than
+# once (if needed). Each file is processed by these steps in the given order.
+steps:
+  # Convert some ASCII sequences to their Unicode equivalents. This is disabled
+  # by default.
+  # - unicode_syntax:
+  #     # In order to make this work, we also need to insert the UnicodeSyntax
+  #     # language pragma. If this flag is set to true, we insert it when it's
+  #     # not already present. You may want to disable it if you configure
+  #     # language extensions using some other method than pragmas. Default:
+  #     # true.
+  #     add_language_pragma: true
+
+  # Import cleanup
+  - imports:
+      # There are different ways we can align names and lists.
+      #
+      # - global: Align the import names and import list throughout the entire
+      #   file.
+      #
+      # - file: Like global, but don't add padding when there are no qualified
+      #   imports in the file.
+      #
+      # - group: Only align the imports per group (a group is formed by adjacent
+      #   import lines).
+      #
+      # - none: Do not perform any alignment.
+      #
+      # Default: global.
+      align: none
+
+      # Folowing options affect only import list alignment.
+      #
+      # List align has following options:
+      #
+      # - after_alias: Import list is aligned with end of import including
+      #   'as' and 'hiding' keywords.
+      #
+      #   > import qualified Data.List      as List (concat, foldl, foldr, head,
+      #   >                                          init, last, length)
+      #
+      # - with_alias: Import list is aligned with start of alias or hiding.
+      #
+      #   > import qualified Data.List      as List (concat, foldl, foldr, head,
+      #   >                                 init, last, length)
+      #
+      # - new_line: Import list starts always on new line.
+      #
+      #   > import qualified Data.List      as List
+      #   >     (concat, foldl, foldr, head, init, last, length)
+      #
+      # Default: after_alias
+      list_align: after_alias
+
+      # Long list align style takes effect when import is too long. This is
+      # determined by 'columns' setting.
+      #
+      # - inline: This option will put as much specs on same line as possible.
+      #
+      # - new_line: Import list will start on new line.
+      #
+      # - new_line_multiline: Import list will start on new line when it's
+      #   short enough to fit to single line. Otherwise it'll be multiline.
+      #
+      # - multiline: One line per import list entry.
+      #   Type with contructor list acts like single import.
+      #
+      #   > import qualified Data.Map as M
+      #   >     ( empty
+      #   >     , singleton
+      #   >     , ...
+      #   >     , delete
+      #   >     )
+      #
+      # Default: inline
+      long_list_align: inline
+
+      # List padding determines indentation of import list on lines after import.
+      # This option affects 'list_align' and 'long_list_align'.
+      list_padding: 4
+
+      # Separate lists option affects formating of import list for type
+      # or class. The only difference is single space between type and list
+      # of constructors, selectors and class functions.
+      #
+      # - true: There is single space between Foldable type and list of it's
+      #   functions.
+      #
+      #   > import Data.Foldable (Foldable (fold, foldl, foldMap))
+      #
+      # - false: There is no space between Foldable type and list of it's
+      #   functions.
+      #
+      #   > import Data.Foldable (Foldable(fold, foldl, foldMap))
+      #
+      # Default: true
+      separate_lists: false
+
+  # Language pragmas
+  - language_pragmas:
+      # We can generate different styles of language pragma lists.
+      #
+      # - vertical: Vertical-spaced language pragmas, one per line.
+      #
+      # - compact: A more compact style.
+      #
+      # - compact_line: Similar to compact, but wrap each line with
+      #   `{-#LANGUAGE #-}'.
+      #
+      # Default: vertical.
+      style: compact
+
+      # Align affects alignment of closing pragma brackets.
+      #
+      # - true: Brackets are aligned in same collumn.
+      #
+      # - false: Brackets are not aligned together. There is only one space
+      #   between actual import and closing bracket.
+      #
+      # Default: true
+      align: true
+
+      # stylish-haskell can detect redundancy of some language pragmas. If this
+      # is set to true, it will remove those redundant pragmas. Default: true.
+      remove_redundant: true
+
+  # Align the types in record declarations
+  # - records: {}
+
+  # Replace tabs by spaces. This is disabled by default.
+  - tabs:
+  #     # Number of spaces to use for each tab. Default: 8, as specified by the
+  #     # Haskell report.
+      spaces: 8
+
+  # Remove trailing whitespace
+  - trailing_whitespace: {}
+
+# A common setting is the number of columns (parts of) code will be wrapped
+# to. Different steps take this into account. Default: 80.
+columns: 80
+
+# Sometimes, language extensions are specified in a cabal file or from the
+# command line instead of using language pragmas in the file. stylish-haskell
+# needs to be aware of these, so it can parse the file correctly.
+#
+# No language extensions are enabled by default.
+# language_extensions:
+  # - TemplateHaskell
+  # - QuasiQuotes
diff --git a/.travis.yml b/.travis.yml
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,6 +8,8 @@
 
 matrix:
   include:
+    - env: CABALVER="1.24" GHCVER="8.0.1" STACKVER="7.14" STYLISH=YES
+      addons: {apt: {packages: [cabal-install-1.24,ghc-8.0.1,hscolour], sources: [hvr-ghc]}}
     - os: osx
       env: CABALVER="1.24" GHCVER="8.0.1" TESTS="test_c"
       compiler: ": #GHC 8.0.1"
@@ -35,11 +37,17 @@
     - env: CABALVER="1.24" GHCVER="8.0.1" TESTS="test_c"
       compiler: ": #GHC 8.0.1"
       addons: {apt: {packages: [cabal-install-1.24,ghc-8.0.1,cppcheck,hscolour], sources: [hvr-ghc]}}
+  allow_failures:
+    - os: osx
+      env: CABALVER="1.24" GHCVER="8.0.1" TESTS="test_c"
+      compiler: ": #GHC 8.0.1"
+  fast-finish: true
 
 cache:
   directories:
     - $HOME/.cabsnap
     - $HOME/.cabal/packages
+    - $HOME/.stack
 
 before_cache:
   - rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log
@@ -56,7 +64,6 @@
   - env
   - if [[ $TRAVIS_OS_NAME == 'osx' ]];
     then
-        brew update;
         brew outdated pkgconfig || brew install pkgconfig;
         brew install ghc cabal-install libffi cppcheck gnu-sed;
         export PATH=$HOME/.cabal/bin:$PATH;
@@ -64,8 +71,11 @@
         export ZCAT=gzcat;
         export PKG_CONFIG_PATH=/usr/local/opt/libffi/lib/pkgconfig:$PKG_CONFIG_PATH;
     fi
+  - if [ -n "$STYLISH" ]; then ./stylize.sh; exit $?; fi
 
 install:
+  - which cabal
+  - which ghc
   - cabal --version
   - echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]"
   - if [ -f $HOME/.cabal/packages/hackage.haskell.org/00-index.tar.gz ];
diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,55 @@
+# New in 0.99.1:
+
+## Language updates
+
+* Language pragmas now required for the less stable existing features, in
+  addition to the existing `TypeProviders` and `ErrorReflection`:
+  + `ElabReflection`, which must be enabled to use `%runElab`
+  + `UniquenessTypes`, which must be enabled to use `UniqueType`
+  + `DSLNotation`, which must be enabled to define a `dsl` block
+  + `FirstClassReflection`, which must be enabled to define a `%reflection`
+    function
+
+* New language extension `LinearTypes`:
+  + This allows adding a /multiplicity/ to a binder which says how often it
+    is allowed to be used; either 0 or 1 (if unstated, multiplicity is "many")
+  + The typing rules follow Conor McBride's paper "I Got Plenty o' Nuttin'"
+  + This is highly experimental, unfinished, not at all polished. and there
+    are still lots of details to sort out. Some features don't quite work
+    properly yet. But it is there to play with for the brave!
+
+## Tool Updates
+
++ Idris' output has been updated to more accurately reflect its
+  progress through the compiler i.e. Type Checking; Totality Checking;
+  IBC Generation; Compiling; and Code Generation. To control the
+  loudness of the reporting three verbosity levels are introduced:
+  `--V0`, `--V1`, and `--V2`. The old aliases of `-V` and `--verbose`
+  persist.
+
++ New REPL command `:!` that runs an external shell command.
+
++ The REPL now colourises output on MinTTY consoles (e.g., Cygwin and MSYS)
+  on Windows, which previously did not occur due to a bug.
+
++ Idris now runs in a UTF-8-compatible codepage on Windows. This fixes many
+  Unicode-rendering issues on Windows (e.g., error messages stating
+  `commitBuffer: invalid argument (invalid character)`).
+
++ Idris now has a `--warnipkg` flag to enable auditing of Idris
+  packages during build time. Currently auditing check's the list of
+  modules specified in the `iPKG` file with those presented in the
+  package directory.
+
+## Library Updates
+
++ Terminating programs has been improved with more appropriate
+  functions (`exitWith`, `exitFailure`, and `exitSuccess`) and a data
+  structure (`ExitCode`) to capture a program's return code.
++ Casting a `String` to an `Int`, `Integer` or a `Double` now ignores leading
+  and trailing whitespace. Previously only leading whitespace was ignored.
++ RTS functions `openFile`, `do_popen`, and `ARGV` are now properly encoded using UTF-8 on Windows.
+
 # New in 0.99:
 
 ## Language updates
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -42,6 +42,7 @@
 Chao-Hong Chen
 Chetan Taralekar
 Chris Allen
+Chris Gibbs
 Christopher Schwaab
 Cliff Harvey
 Cliff L. Biffle
@@ -162,6 +163,7 @@
 Norbert Melzer
 Oskar Wickström
 Ozgur Akgun
+Patrick Hilhorst
 Patrik Jansson
 Paul Koerbitz
 Per Fredelius
@@ -206,6 +208,7 @@
 Trevor Elliott
 uwap
 Vitaly Bragilevsky
+Vyacheslav Shebanov
 xged
 XIE Yuheng
 Yacine Hmito
diff --git a/HLint.hs b/HLint.hs
--- a/HLint.hs
+++ b/HLint.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE TemplateHaskell #-}
 --  --------------------------------------------------------------- [ HLint.hs ]
 -- HLint suggestions we like.
 --
diff --git a/INSTALL.md b/INSTALL.md
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -64,18 +64,28 @@
 cross-platform program for developing Haskell projects, that enhances
 the functionality provided by Cabal. There is experimental support for
 building Idris from source with stack.
+
 This installation has been tested on Ubuntu 16.04.1 LTS, and the current
 NixOS unstable.
 
-To build Idris with stack the following commands are recommended:
+*Important* Stack will not install any external dependencies required
+to build Idris. Before you try stack please ensure you have the
+correct depenencies.
 
+To build Idris with stack use the following command:
+
 * `stack build`
 
-This will install Idris (and related executables) into `./local/bin/`
-on Unix based systems and an appropriate place on Windows. If you
-haven't used stack before this will also setup the related
-infrastructure. For more information about Stack please visit the
-[Stack website](https://github.com/commercialhaskell/stack).
+To install Idris:
+
+* `stack install`
+
+Stack will install Idris (and related executables) into `$HOME/.local/bin/`
+on Unix based systems and an appropriate place on Windows.
+
+Of note: If you haven't used stack before commands will also setup the
+related infrastructure. For more information about Stack please visit
+the [Stack website](https://github.com/commercialhaskell/stack).
 
 On NixOS, please use the following command instead, to make sure
 the required libraries and header files are available:
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-.PHONY: build configure doc install linecount nodefault pinstall lib_clean relib fast test_js test_c test test_clean lib_doc lib_doc_clean user_doc_html user_doc_pdf user_docs
+.PHONY: build configure doc install linecount nodefault pinstall lib_clean relib fast test_js test_c stylize test test_clean lib_doc lib_doc_clean user_doc_html user_doc_pdf user_docs
 
 ARGS=
 TEST-JOBS=
@@ -24,7 +24,10 @@
 build: dist/setup-config
 	$(CABAL) build $(CABALFLAGS)
 
-test: doc test_c
+test: doc test_c stylize
+
+stylize:
+	./stylize.sh
 
 test_c:
 	$(CABAL) test $(ARGS) --test-options \
diff --git a/RELEASE-CHECKS.md b/RELEASE-CHECKS.md
--- a/RELEASE-CHECKS.md
+++ b/RELEASE-CHECKS.md
@@ -37,6 +37,7 @@
 ## Announcements
 
 + [ ] Update website.
+  + [ ] Update web site with SHA256 hash of binary
 + [ ] Email Mailing list.
 + [ ] Make REDDIT post.
 + [ ] Tweet
diff --git a/config.mk b/config.mk
--- a/config.mk
+++ b/config.mk
@@ -1,4 +1,6 @@
-ifneq (, $(findstring MSYS, $(shell uname -a)))
+UNAME_INFO      := $(shell uname -a)
+
+ifeq ($(filter , $(findstring MSYS, $(UNAME_INFO)) $(findstring MINGW, $(UNAME_INFO))),)
 	ifeq (cc,$(CC))
 		# In MSYS2, when using the mingw version of gcc, there is no cc -> gcc
 		# symlink. We can't use ?= here because CC is set implicitly to cc.
diff --git a/docs/conf.py b/docs/conf.py
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -33,7 +33,7 @@
 # ones.
 extensions = [
     'sphinx.ext.todo',
-    'sphinx.ext.pngmath',
+    'sphinx.ext.pngmath', # imgmath is not supported on readthedocs.
     'sphinx.ext.ifconfig',
 ]
 
@@ -51,7 +51,7 @@
 
 # General information about the project.
 project = u'Idris'
-copyright = u'2015, The Idris Community'
+copyright = u'2017, The Idris Community'
 author = u'The Idris Community'
 
 # The version info for the project you're documenting, acts as replacement for
@@ -59,9 +59,9 @@
 # built documents.
 #
 # The short X.Y version.
-version = '0.99'
+version = '0.99.1'
 # The full version, including alpha/beta/rc tags.
-release = '0.99'
+release = '0.99.1'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
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.99
+    / // __  / ___/ / ___/     Version 0.99.1
   _/ // /_/ / /  / (__  )      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.99
+    / // __  / ___/ / ___/     Version 0.99.1
   _/ // /_/ / /  / (__  )      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.99
+   / // __  / ___/ / ___/     Version 0.99.1
  _/ // /_/ / /  / (__  )      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
@@ -1,6 +1,6 @@
-***********************
-Compilation and Logging
-***********************
+************************************
+Compilation, Logging, and Reporting
+************************************
 
 This section provides information about the Idris compilation process, and
 provides details over how you can follow the process through logging.
@@ -41,11 +41,27 @@
 
 Use of this option will still result in the generation of the Idris binary ``.ibc`` files, and is suitable if you do not wish to generate code from one of the supported backends.
 
-Logging Output
-==============
+Reporting Compilation Process
+=============================
 
-The internal operation of Idris is captured using a category based logger.
-Currently, the logging infrastructure has support for the following categories:
+During compilation the reporting of Idris' progress can be controlled
+by setting a verbosity level.
+
++ ``-V``, or alternatively ``--verbose`` and ``--V0``, will report which file Idris is currently type checking.
++ ``--V1`` will additionally report: Parsing, IBC Generation, and Code
+  Generation.
++ ``--V2`` will additionally report: Totality Checking, Universe
+  Checking, and the individual steps prior to code generation.
+
+
+By default Idris' progress reporting is set to quiet-``-q``, or ``--quiet``.
+
+Logging Internal Operation
+===========================
+
+For those that develop on the Idris compiler, the internal operation
+of Idris is captured using a category based logger. Currently, the
+logging infrastructure has support for the following categories:
 
 + Parser
 + Elaborator
diff --git a/docs/reference/documenting.rst b/docs/reference/documenting.rst
--- a/docs/reference/documenting.rst
+++ b/docs/reference/documenting.rst
@@ -61,7 +61,14 @@
     ||| Add some numbers.
     |||
     ||| Addition is really great. This paragraph is not part of the overview.
-    ||| Still the same paragraph. Lists are also nifty:
+    ||| Still the same paragraph. 
+    |||
+    ||| You can even provide examples which are inlined in the documentation:
+    ||| ```idris example
+    ||| add 4 5
+    ||| ```
+    ||| 
+    ||| Lists are also nifty:
     ||| * Really nifty!
     ||| * Yep!
     ||| * The name `add` is a **bold** choice
diff --git a/docs/reference/ffi.rst b/docs/reference/ffi.rst
--- a/docs/reference/ffi.rst
+++ b/docs/reference/ffi.rst
@@ -164,7 +164,7 @@
     myComparer = ...
 
     qsort : Ptr -> Int -> Int -> IO ()
-    test2 data elems elsize = foreign FFI_C "qsort"
+    qsort data elems elsize = foreign FFI_C "qsort"
                     (Ptr -> Int -> Int -> CFnPtr (Ptr -> Ptr -> Int) -> IO ())
                     data elems elsize (MkCFnPtr myComparer)
 
diff --git a/docs/reference/misc.rst b/docs/reference/misc.rst
--- a/docs/reference/misc.rst
+++ b/docs/reference/misc.rst
@@ -273,7 +273,7 @@
 
 
 Existence of an implementation
-========================
+==============================
 
 In order to show that an implementation of some interface is defined for some
 type, one could use the ``%implementation`` keyword:
diff --git a/docs/reference/packages.rst b/docs/reference/packages.rst
--- a/docs/reference/packages.rst
+++ b/docs/reference/packages.rst
@@ -97,7 +97,7 @@
   which must be present for the package to be usable.
 
 + ``objs = <objs>``, which takes a comma separated list of additional
-  files to be installed (object files, headers), perhaps generated 
+  files to be installed (object files, headers), perhaps generated
   by the ``Makefile``.
 
 Testing
@@ -112,6 +112,11 @@
 .. IMPORTANT::
   The modules containing the test functions must also be added to the list of modules.
 
+Comments
+---------
+
+Package files support comments using the standard Idris singleline ``--`` and multiline ``{- -}`` format.
+
 Using Package files
 ===================
 
@@ -127,9 +132,13 @@
 
 + ``idris --mkdoc test.ipkg`` will build HTML documentation for your package in the folder ``test_doc`` in your project's root directory.
 
++ ``idris --installdoc test.ipkg`` will install the packages documentation into Idris' central documentation folder located at ``idris --docdir``.
+
 + ``idris --checkpkg test.ipkg`` will type check all modules in the package only. This differs from build that type checks **and** generates code.
 
 + ``idris --testpkg test.ipkg`` will compile and run any embedded tests you have specified in the ``tests`` parameter.
+
+When building or install packages the commandline flag ``--warnipkg`` will audit the project and warn of any potentiable problems.
 
 Once the test package has been installed, the command line option
 ``--package test`` makes it accessible (abbreviated to ``-p test``).
diff --git a/docs/reference/syntax-guide.rst b/docs/reference/syntax-guide.rst
--- a/docs/reference/syntax-guide.rst
+++ b/docs/reference/syntax-guide.rst
@@ -158,6 +158,76 @@
       Nil  : Vect Z a
       (::) : (x : a) -> (xs : Vect n a) -> Vect (S n) a
 
+The signature of type constructors may use dependent types
+
+.. code:: idris
+
+    data DPair : (a : Type) -> (a -> Type) -> Type where
+      MkDPair : {P : a -> Type} -> (x : a) -> (pf : P x) -> DPair a P
+
+Records
+~~~~~~~
+
+There is a special syntax for data types with one constructors and
+multiple fields.
+
+.. code:: idris
+
+    record A a where
+      constructor MkA
+      foo, bar : a
+      baz : Nat
+
+This defines a constructor as well as getter and setter function for
+each field.
+
+.. code:: idris
+
+    MkA : a -> a -> Nat -> A a
+    foo : A a -> a
+    set_foo : a -> A a -> A a
+
+The types of record fields may depend on the value of other fields
+
+.. code:: idris
+
+    record Collection a where
+      constructor MkCollection
+      size : Nat
+      items : Vect size a
+
+Setter functions are only provided for fields that do not use dependant
+types. In the example above neither ``set_size`` nor ``set_items`` are
+defined.
+
+
+Co-data
+~~~~~~~
+
+Inifinite data structures can be introduced with the ``codata``
+keyword.
+
+.. code:: idris
+
+  codata Stream : Type -> Type where
+    (::) a -> Stream a -> Stream a
+
+This is syntactic sugar for the following, which is usually preferred:
+
+.. code:: idris
+
+  data Stream : Type -> Type where
+    (::) a -> Inf (Stream a) -> Stream a
+
+Every occurence of the the defined type in a constructor argument will be
+wrapped in the ``Inf`` type constructor. This has the effect of delaying the
+evaluation of the second argument when the data constructor is applied.
+An ``Inf`` argument is constructed using ``Delay`` (which Idris will insert
+implicitly) adn evaluated using ``Force`` (again inserted implicitly).
+
+Furthermore, recursive calls under a ``Delay`` must be guarded by a constructor
+to pass the totality checker.
+
 Operators
 ---------
 
diff --git a/docs/tutorial/index.rst b/docs/tutorial/index.rst
--- a/docs/tutorial/index.rst
+++ b/docs/tutorial/index.rst
@@ -24,7 +24,6 @@
    interfaces
    modules
    packages
-   testing
    interp
    views
    theorems
diff --git a/docs/tutorial/interfaces.rst b/docs/tutorial/interfaces.rst
--- a/docs/tutorial/interfaces.rst
+++ b/docs/tutorial/interfaces.rst
@@ -153,6 +153,16 @@
     sortAndShow : (Ord a, Show a) => List a -> String
     sortAndShow xs = show (sort xs)
 
+Note: Interfaces and ``mutual`` blocks
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Idris is strictly "define before use", except in ``mutual`` blocks.
+In a ``mutual`` block, Idris elaborates in two passes: types on the first 
+pass and definitions on the second. When the mutual block contains an
+interface declaration, it elaborates the interface header but none of the
+method types on the first pass, and elaborates the method types and any
+default definitions on the second pass.
+
 Functors and Applicatives
 =========================
 
diff --git a/docs/tutorial/modules.rst b/docs/tutorial/modules.rst
--- a/docs/tutorial/modules.rst
+++ b/docs/tutorial/modules.rst
@@ -299,3 +299,25 @@
 
     *params> show (append _ _ (MkVects _ [1,2,3] [4,5,6]))
     "[1, 2, 3, 4, 5, 6]" : String
+
+
+**********************
+Modules Dependencies Using Atom 
+**********************
+
+If you are using the Atom editor and have a dependency on another package, 
+corresponding to for instance ``import Lightyear`` or ``import Pruviloj``, 
+you need to let Atom know that it should be loaded. The easiest way to 
+accomplish that is with a .ipkg file. The general contents of an ipkg file 
+will be described in the next section of the tutorial, but for now here is 
+a simple recipe for this trivial case. 
+
+- Create a folder myProject. 
+
+- Add a file myProject.ipkg containing just a couple of lines: 
+
+``package myProject`` 
+
+``pkgs = pruviloj, lightyear`` 
+
+- In Atom, use the File menu to Open Folder myProject. 
diff --git a/docs/tutorial/packages.rst b/docs/tutorial/packages.rst
--- a/docs/tutorial/packages.rst
+++ b/docs/tutorial/packages.rst
@@ -31,15 +31,19 @@
 
 
 Other examples of package files can be found in the ``libs`` directory
-of the main Idris repository, and in `third-party libraries <https://github.com/idris-lang/Idris-dev/wiki/Libraries>`_.
-More details including a complete listing of available fields can be found in :ref:`ref-sect-packages`.
+of the main Idris repository, and in `third-party libraries
+<https://github.com/idris-lang/Idris-dev/wiki/Libraries>`_.
 
 
 Using Package files
 ===================
 
-Given an Idris package file ``maths.ipkg`` it can be used with the Idris compiler as follows:
 
+Idris itself is aware about packages, and special commands are
+available to help with, for example, building packages, installing
+packages, and cleaning packages.  For instance, given the ``maths``
+package from earlier we can use Idris as follows:
+
 + ``idris --build maths.ipkg`` will build all modules in the package
 
 + ``idris --install maths.ipkg`` will install the package, making it
@@ -48,20 +52,102 @@
 + ``idris --clean maths.ipkg`` will delete all intermediate code and
   executable files generated when building.
 
-+ ``idris --mkdoc maths.ipkg`` will build HTML documentation for your
-  package in the folder ``maths_doc`` in your project's root
-  directory.
-
-+ ``idris --checkpkg maths.ipkg`` will type check all modules in the
-  package only. This differs from build that type checks **and**
-  generates code.
-
-+ ``idris --testpkg maths.ipkg`` will compile and run any embedded
-  tests you have specified in the ``tests`` parameter. More
-  information about testing is given in the next section.
-
 Once the maths package has been installed, the command line option
 ``--package maths`` makes it accessible (abbreviated to ``-p maths``).
 For example::
 
     idris -p maths Main.idr
+
+
+Testing Idris Packages
+======================
+
+The integrated build system includes a simple testing framework.
+This framework collects functions listed in the ``ipkg`` file under ``tests``.
+All test functions must return ``IO ()``.
+
+
+When you enter ``idris --testpkg yourmodule.ipkg``,
+the build system creates a temporary file in a fresh environment on your machine
+by listing the ``tests`` functions under a single ``main`` function.
+It compiles this temporary file to an executable and then executes it.
+
+
+The tests themselves are responsible for reporting their success or failure.
+Test functions commonly use ``putStrLn`` to report test results.
+The test framework does not impose any standards for reporting and consequently
+does not aggregate test results.
+
+
+For example, lets take the following list of functions that are defined in a module called ``NumOps`` for a sample package ``maths``.
+
+.. name: Math/NumOps.idr
+.. code-block:: idris
+
+    module Maths.NumOps
+
+    %access export -- to make functions under test visible
+
+    double : Num a => a -> a
+    double a = a + a
+
+    triple : Num a => a -> a
+    triple a = a + double a
+
+A simple test module, with a qualified name of ``Test.NumOps`` can be declared as
+
+.. name: Math/TestOps.idr
+.. code-block:: idris
+
+    module Test.NumOps
+
+    import Maths.NumOps
+
+    %access export  -- to make the test functions visible
+
+    assertEq : Eq a => (given : a) -> (expected : a) -> IO ()
+    assertEq g e = if g == e
+        then putStrLn "Test Passed"
+        else putStrLn "Test Failed"
+
+    assertNotEq : Eq a => (given : a) -> (expected : a) -> IO ()
+    assertNotEq g e = if not (g == e)
+        then putStrLn "Test Passed"
+        else putStrLn "Test Failed"
+
+    testDouble : IO ()
+    testDouble = assertEq (double 2) 4
+
+    testTriple : IO ()
+    testTriple = assertNotEq (triple 2) 5
+
+
+The functions ``assertEq`` and ``assertNotEq`` are used to run expected passing, and failing, equality tests.
+The actual tests are ``testDouble`` and ``testTriple``, and are declared in the ``maths.ipkg`` file as follows::
+
+    package maths
+
+    modules = Maths.NumOps
+            , Test.NumOps
+
+    tests = Test.NumOps.testDouble
+          , Test.NumOps.testTriple
+
+
+The testing framework can then be invoked using ``idris --testpkg maths.ipkg``::
+
+    > idris --testpkg maths.ipkg
+    Type checking ./Maths/NumOps.idr
+    Type checking ./Test/NumOps.idr
+    Type checking /var/folders/63/np5g0d5j54x1s0z12rf41wxm0000gp/T/idristests144128232716531729.idr
+    Test Passed
+    Test Passed
+
+Note how both tests have reported success by printing ``Test Passed``
+as we arranged for with the ``assertEq`` and ``assertNoEq`` functions.
+
+More information
+================
+
+More details, including a complete listing of available fields, can be
+found in the reference manual in :ref:`ref-sect-packages`.
diff --git a/docs/tutorial/syntax.rst b/docs/tutorial/syntax.rst
--- a/docs/tutorial/syntax.rst
+++ b/docs/tutorial/syntax.rst
@@ -92,7 +92,7 @@
 
 .. code-block:: idris
 
-    syntax for {x} in [xs] ":" [body] = forLoop xs (\x => body)
+    syntax for {x} "in" [xs] ":" [body] = forLoop xs (\x => body)
 
     main : IO ()
     main = do for x in [1..10]:
diff --git a/docs/tutorial/testing.rst b/docs/tutorial/testing.rst
deleted file mode 100644
--- a/docs/tutorial/testing.rst
+++ /dev/null
@@ -1,85 +0,0 @@
-.. _tut-sect-testing:
-
-**********************
-Testing Idris Packages
-**********************
-
-The integrated build system includes a simple testing framework.
-This framework collects functions listed in the ``ipkg`` file under ``tests``.
-All test functions must return ``IO ()``.
-
-
-When you enter ``idris --testpkg yourmodule.ipkg``,
-the build system creates a temporary file in a fresh environment on your machine
-by listing the ``tests`` functions under a single ``main`` function.
-It compiles this temporary file to an executable and then executes it.
-
-
-The tests themselves are responsible for reporting their success or failure.
-Test functions commonly use ``putStrLn`` to report test results.
-The test framework does not impose any standards for reporting and consequently
-does not aggregate test results.
-
-
-For example, lets take the following list of functions that are defined in a module called ``NumOps`` for a sample package ``maths``.
-
-.. name: Math/NumOps.idr
-.. code-block:: idris
-
-    module Maths.NumOps
-
-    double : Num a => a -> a
-    double a = a + a
-
-    triple : Num a => a -> a
-    triple a = a + double a
-
-A simple test module, with a qualified name of ``Test.NumOps`` can be declared as
-
-.. name: Math/TestOps.idr
-.. code-block:: idris
-
-    module Test.NumOps
-
-    import Maths.NumOps
-
-    assertEq : Eq a => (given : a) -> (expected : a) -> IO ()
-    assertEq g e = if g == e
-        then putStrLn "Test Passed"
-        else putStrLn "Test Failed"
-
-    assertNotEq : Eq a => (given : a) -> (expected : a) -> IO ()
-    assertNotEq g e = if not (g == e)
-        then putStrLn "Test Passed"
-        else putStrLn "Test Failed"
-
-    testDouble : IO ()
-    testDouble = assertEq (double 2) 4
-
-    testTriple : IO ()
-    testTriple = assertNotEq (triple 2) 5
-
-
-The functions ``assertEq`` and ``assertNotEq`` are used to run expected passing, and failing, equality tests.
-The actual tests are ``testDouble`` and ``testTriple``, and are declared in the ``maths.ipkg`` file as follows::
-
-    package maths
-
-    modules = Maths.NumOps
-            , Test.NumOps
-
-    tests = Test.NumOps.testDouble
-          , Test.NumOps.testTriple
-
-
-The testing framework can then be invoked using ``idris --testpkg maths.ipkg``::
-
-    > idris --testpkg maths.ipkg
-    Type checking ./Maths/NumOps.idr
-    Type checking ./Test/NumOps.idr
-    Type checking /var/folders/63/np5g0d5j54x1s0z12rf41wxm0000gp/T/idristests144128232716531729.idr
-    Test Passed
-    Test Passed
-
-Note how both tests have reported success by printing ``Test Passed``
-as we arranged for with the ``assertEq`` and ``assertNoEq`` functions.
diff --git a/docs/tutorial/theorems.rst b/docs/tutorial/theorems.rst
--- a/docs/tutorial/theorems.rst
+++ b/docs/tutorial/theorems.rst
@@ -233,7 +233,7 @@
 argument. The checker works by ensuring that all chains of recursive calls
 eventually lead to one of the arguments decreasing towards a base case, but
 sometimes this is hard to spot. For example, the following definition cannot be
-checked as ``total`` because the checker cannot decide that ``filter (<= x) xs``
+checked as ``total`` because the checker cannot decide that ``filter (< x) xs``
 will always be smaller than ``(x :: xs)``:
 
 .. code-block:: idris
diff --git a/docs/tutorial/typesfuns.rst b/docs/tutorial/typesfuns.rst
--- a/docs/tutorial/typesfuns.rst
+++ b/docs/tutorial/typesfuns.rst
@@ -713,7 +713,7 @@
 
 .. code-block:: idris
 
-    ones :: Stream Nat
+    ones : Stream Nat
     ones = 1 :: ones
 
 It is important to note that codata does not allow the creation of infinite
diff --git a/idris.cabal b/idris.cabal
--- a/idris.cabal
+++ b/idris.cabal
@@ -1,5 +1,5 @@
 Name:           idris
-Version:        0.99
+Version:        0.99.1
 License:        BSD3
 License-file:   LICENSE
 Author:         Edwin Brady
@@ -259,10 +259,11 @@
                 , array >= 0.4.0.1 && < 0.6
                 , base64-bytestring < 1.1
                 , binary >= 0.7 && < 0.9
-                , blaze-html >= 0.6.1.3 && < 0.9
-                , blaze-markup >= 0.5.2.1 && < 0.8
+                , blaze-html >= 0.6.1.3 && < 0.10
+                , blaze-markup >= 0.5.2.1 && < 0.9
                 , bytestring < 0.11
                 , cheapskate < 0.2
+                , code-page >= 0.1 && < 0.2
                 , containers >= 0.5 && < 0.6
                 , deepseq < 1.5
                 , directory >= 1.2.2.0 && < 1.2.3.0 || > 1.2.3.0
@@ -289,7 +290,6 @@
                 , vector < 0.12
                 , vector-binary-instances < 0.3
                 , zip-archive > 0.2.3.5 && < 0.4
-                , safe == 0.3.9
                 , fsnotify >= 0.2 && < 2.2
                 , async < 2.2
 
@@ -302,6 +302,17 @@
   else
      build-depends: process < 1.5
 
+  -- safe 0.3.10 is having issues with cabal 1.20 and ghc 7.6.3, the
+  -- hvr ghc ppa doesn't provide a new enough cabal library. Temporary
+  -- fix until hvr ghc ppa is fixed or we deprecate support for 7.6.3.
+  if impl(ghc < 7.8.4)
+     build-depends: safe == 0.3.9
+  else
+     build-depends: safe >= 0.3.9
+
+  if impl(ghc < 7.8.4)
+     build-depends: tagsoup < 0.14.1
+
   Extensions:     MultiParamTypeClasses
                 , DeriveFoldable
                 , DeriveTraversable
@@ -321,7 +332,8 @@
   if os(darwin)
      build-depends: unix < 2.8
   if os(windows)
-     build-depends: Win32 < 2.4
+     build-depends: mintty >= 0.1 && < 0.2
+                  , Win32 < 2.4
   if flag(FFI)
      build-depends: libffi < 0.2
      cpp-options:   -DIDRIS_FFI
diff --git a/libs/base/Control/Isomorphism.idr b/libs/base/Control/Isomorphism.idr
--- a/libs/base/Control/Isomorphism.idr
+++ b/libs/base/Control/Isomorphism.idr
@@ -2,6 +2,7 @@
 
 import Syntax.PreorderReasoning
 import Data.Fin
+import Control.Category
 
 %default total
 %access public export
@@ -31,6 +32,10 @@
         (\x => (from (from' (to' (to x))))  ={ cong (fromTo' (to x)) }=
                (from (to x))                ={ fromTo x              }=
                x                            QED)
+
+Category Iso where
+  id = isoRefl
+  (.) = flip isoTrans
 
 ||| Isomorphism is symmetric
 isoSym : Iso a b -> Iso b a
diff --git a/libs/base/Data/Bits.idr b/libs/base/Data/Bits.idr
--- a/libs/base/Data/Bits.idr
+++ b/libs/base/Data/Bits.idr
@@ -6,6 +6,9 @@
                -- to improve it! (EB)
 %access export
 
+||| Finds the next exponent of a power of two.
+||| For example `nextPow2 200 = 8`, because 2^8 = 256.
+||| If it is an exact match, it is not rounded up: `nextPow2 256 = 8` because 2^8 = 256.
 public export
 nextPow2 : Nat -> Nat
 nextPow2 Z = Z
@@ -15,10 +18,17 @@
     where
       l2x = log2NZ (S x) SIsNotZ
 
+||| Gets the lowest n for which "8 * 2 ^ n" is larger than or equal to the input.
+||| For example, `nextBytes 10 = 16`.
+||| Like with nextPow2, the result is not rounded up, so `nextBytes 16 = 16`.
 public export
 nextBytes : Nat -> Nat
 nextBytes bits = (nextPow2 (divCeilNZ bits 8 SIsNotZ))
 
+||| An index function to access the Bits* types in order.
+||| machineTy 0 = Bits8, machineTy 1 = Bits16, etc.
+||| Any input that would result in getting a type that is larger than supported
+||| will result in the largest supported type instead (currently 64 bits).
 public export
 machineTy : Nat -> Type
 machineTy Z = Bits8
@@ -26,9 +36,13 @@
 machineTy (S (S Z)) = Bits32
 machineTy (S (S (S _))) = Bits64
 
+||| Finds the number of bits used by `machineTy n`.
+||| For example, bitsUsed 2 = 16
 bitsUsed : Nat -> Nat
 bitsUsed n = 8 * (2 `power` n)
 
+||| Converts a Nat to a machineTy n, with the first argument as an accumulator.
+||| You shouldn't have to call this manually, use natToBits (without ') instead.
 natToBits' : %static {n : Nat} -> machineTy n -> Nat -> machineTy n
 natToBits' a Z = a
 natToBits' {n=n} a x with (n)
@@ -39,6 +53,7 @@
  natToBits' a (S x') | S (S (S _)) = natToBits' {n=3} (prim__addB64 a (prim__truncInt_B64 1)) x'
  natToBits' a _      | _           = assert_unreachable
 
+||| Converts a Nat to a machineTy n.
 natToBits : %static {n : Nat} -> Nat -> machineTy n
 natToBits {n=n} x with (n)
     | Z           = natToBits' {n=0} (prim__truncInt_B8  0) x
@@ -50,25 +65,36 @@
 getPad : %static {n : Nat} -> Nat -> machineTy n
 getPad n = assert_total $ natToBits (minus (bitsUsed (nextBytes n)) n)
 
+||| A "high-level" wrapper to the types defined by `machineTy`.
 public export
 data Bits : Nat -> Type where
+    ||| An bits type that has at least n bits available,
+    ||| up to the maximum supported by `machineTy`.
     MkBits : machineTy (nextBytes n) -> Bits n
 
-pad8 : Nat -> (Bits8 -> Bits8 -> Bits8) -> Bits8 -> Bits8 -> Bits8
+||| Perform a function over Bits8 as if it is carried out on n bits.
+||| (n should be 8 or lower)
+pad8 : (n : Nat) -> (Bits8 -> Bits8 -> Bits8) -> Bits8 -> Bits8 -> Bits8
 pad8 n f x y = prim__lshrB8 (f (prim__shlB8 x pad) (prim__shlB8 y pad)) pad
     where
       pad = getPad {n=0} n
 
-pad16 : Nat -> (Bits16 -> Bits16 -> Bits16) -> Bits16 -> Bits16 -> Bits16
+||| Perform a function over Bits16 as if it is carried out on n bits.
+||| (n should be 16 or lower)
+pad16 : (n: Nat) -> (Bits16 -> Bits16 -> Bits16) -> Bits16 -> Bits16 -> Bits16
 pad16 n f x y = prim__lshrB16 (f (prim__shlB16 x pad) (prim__shlB16 y pad)) pad
     where
       pad = getPad {n=1} n
 
+||| Perform a function over Bits32 as if it is carried out on n bits.
+||| (n should be 32 or lower)
 pad32 : Nat -> (Bits32 -> Bits32 -> Bits32) -> Bits32 -> Bits32 -> Bits32
 pad32 n f x y = prim__lshrB32 (f (prim__shlB32 x pad) (prim__shlB32 y pad)) pad
     where
       pad = getPad {n=2} n
 
+||| Perform a function over Bits64 as if it is carried out on n bits.
+||| (n should be 64 or lower)
 pad64 : Nat -> (Bits64 -> Bits64 -> Bits64) -> Bits64 -> Bits64 -> Bits64
 pad64 n f x y = prim__lshrB64 (f (prim__shlB64 x pad) (prim__shlB64 y pad)) pad
     where
@@ -95,7 +121,7 @@
     where
       pad = getPad {n=3} n
 
--- TODO: This (and all the other functions along these lings) is -- because it is used by things. Do they really need to be
+-- TODO: This (and all the other functions along these lines) is -- because it is used by things. Do they really need to be
 -- public export, or is export good enough?
 shiftLeft' : %static {n : Nat} -> machineTy (nextBytes n) -> machineTy (nextBytes n) -> machineTy (nextBytes n)
 shiftLeft' {n=n} x c with (nextBytes n)
@@ -105,9 +131,11 @@
     | S (S (S _)) = pad64' n prim__shlB64 x c
     | _ = assert_unreachable
 
+||| Binary left shift
 shiftLeft : %static {n : Nat} -> Bits n -> Bits n -> Bits n
 shiftLeft (MkBits x) (MkBits y) = MkBits (shiftLeft' x y)
 
+||| Logical binary right shift
 shiftRightLogical' : %static {n : Nat} -> machineTy n -> machineTy n -> machineTy n
 shiftRightLogical' {n=n} x c with (n)
     | Z = prim__lshrB8 x c
@@ -116,10 +144,12 @@
     | S (S (S _)) = prim__lshrB64 x c
     | _ = assert_unreachable
 
+||| Logical binary right shift
 shiftRightLogical : %static {n : Nat} -> Bits n -> Bits n -> Bits n
 shiftRightLogical {n} (MkBits x) (MkBits y)
     = MkBits {n} (shiftRightLogical' {n=nextBytes n} x y)
 
+||| Arithematic binary right shift
 shiftRightArithmetic' : %static {n : Nat} -> machineTy (nextBytes n) -> machineTy (nextBytes n) -> machineTy (nextBytes n)
 shiftRightArithmetic' {n=n} x c with (nextBytes n)
     | Z = pad8' n prim__ashrB8 x c
@@ -128,9 +158,11 @@
     | S (S (S _)) = pad64' n prim__ashrB64 x c
     | _ = assert_unreachable
 
+||| Arithematic binary right shift
 shiftRightArithmetic : %static {n : Nat} -> Bits n -> Bits n -> Bits n
 shiftRightArithmetic (MkBits x) (MkBits y) = MkBits (shiftRightArithmetic' x y)
 
+||| Binary and
 and' : %static {n : Nat} -> machineTy n -> machineTy n -> machineTy n
 and' {n=n} x y with (n)
     | Z = prim__andB8 x y
@@ -139,9 +171,11 @@
     | S (S (S _)) = prim__andB64 x y
     | _ = assert_unreachable
 
+||| Binary and
 and : %static {n : Nat} -> Bits n -> Bits n -> Bits n
 and {n} (MkBits x) (MkBits y) = MkBits (and' {n=nextBytes n} x y)
 
+||| Binary or
 or' : %static {n : Nat} -> machineTy n -> machineTy n -> machineTy n
 or' {n=n} x y with (n)
     | Z = prim__orB8 x y
@@ -150,9 +184,11 @@
     | S (S (S _)) = prim__orB64 x y
     | _ = assert_unreachable
 
+||| Binary or
 or : %static {n : Nat} -> Bits n -> Bits n -> Bits n
 or {n} (MkBits x) (MkBits y) = MkBits (or' {n=nextBytes n} x y)
 
+||| Binary xor
 xor' : %static {n : Nat} -> machineTy n -> machineTy n -> machineTy n
 xor' {n=n} x y with (n)
     | Z = prim__xorB8 x y
@@ -161,9 +197,11 @@
     | S (S (S _)) = prim__xorB64 x y
     | _ = assert_unreachable
 
+||| Binary xor
 xor : %static {n : Nat} -> Bits n -> Bits n -> Bits n
 xor {n} (MkBits x) (MkBits y) = MkBits {n} (xor' {n=nextBytes n} x y)
 
+||| Overflowing addition
 plus' : machineTy (nextBytes n) -> machineTy (nextBytes n) -> machineTy (nextBytes n)
 plus' {n=n} x y with (nextBytes n)
     | Z = pad8 n prim__addB8 x y
@@ -172,9 +210,11 @@
     | S (S (S _)) = pad64 n prim__addB64 x y
     | _ = assert_unreachable
 
+||| Overflowing addition
 plus : %static {n : Nat} -> Bits n -> Bits n -> Bits n
 plus (MkBits x) (MkBits y) = MkBits (plus' x y)
 
+||| Subtraction
 minus' : machineTy (nextBytes n) -> machineTy (nextBytes n) -> machineTy (nextBytes n)
 minus' {n=n} x y with (nextBytes n)
     | Z = pad8 n prim__subB8 x y
@@ -183,9 +223,11 @@
     | S (S (S _)) = pad64 n prim__subB64 x y
     | _ = assert_unreachable
 
+||| Subtraction
 minus : %static {n : Nat} -> Bits n -> Bits n -> Bits n
 minus (MkBits x) (MkBits y) = MkBits (minus' x y)
 
+||| Multiplication
 times' : machineTy (nextBytes n) -> machineTy (nextBytes n) -> machineTy (nextBytes n)
 times' {n=n} x y with (nextBytes n)
     | Z = pad8 n prim__mulB8 x y
@@ -194,9 +236,11 @@
     | S (S (S _)) = pad64 n prim__mulB64 x y
     | _ = assert_unreachable
 
+||| Multiplication
 times : %static {n : Nat} -> Bits n -> Bits n -> Bits n
 times (MkBits x) (MkBits y) = MkBits (times' x y)
 
+||| Signed integer division
 partial
 sdiv' : machineTy (nextBytes n) -> machineTy (nextBytes n) -> machineTy (nextBytes n)
 sdiv' {n=n} x y with (nextBytes n)
@@ -206,10 +250,12 @@
     | S (S (S _)) = prim__sdivB64 x y
     | _ = assert_unreachable
 
+||| Signed integer division
 partial
 sdiv : %static {n : Nat} -> Bits n -> Bits n -> Bits n
 sdiv (MkBits x) (MkBits y) = MkBits (sdiv' x y)
 
+||| Unsigned integer division
 partial
 udiv' : %static {n : Nat} -> machineTy (nextBytes n) -> machineTy (nextBytes n) -> machineTy (nextBytes n)
 udiv' {n=n} x y with (nextBytes n)
@@ -219,10 +265,12 @@
     | S (S (S _)) = prim__udivB64 x y
     | _ = assert_unreachable
 
+||| Unsigned integer division
 partial
 udiv : %static {n : Nat} -> Bits n -> Bits n -> Bits n
 udiv (MkBits x) (MkBits y) = MkBits (udiv' x y)
 
+||| Signed remainder (mod)
 partial
 srem' : %static {n : Nat} -> machineTy (nextBytes n) -> machineTy (nextBytes n) -> machineTy (nextBytes n)
 srem' {n=n} x y with (nextBytes n)
@@ -232,10 +280,12 @@
     | S (S (S _)) = prim__sremB64 x y
     | _ = assert_unreachable
 
+||| Signed remainder (mod)
 partial
 srem : %static {n : Nat} -> Bits n -> Bits n -> Bits n
 srem (MkBits x) (MkBits y) = MkBits (srem' x y)
 
+||| Unsigned remainder (mod)
 partial
 urem' : %static {n : Nat} -> machineTy (nextBytes n) -> machineTy (nextBytes n) -> machineTy (nextBytes n)
 urem' {n=n} x y with (nextBytes n)
@@ -245,6 +295,7 @@
     | S (S (S _)) = prim__uremB64 x y
     | _ = assert_unreachable
 
+||| Unsigned remainder (mod)
 partial
 urem : %static {n : Nat} -> Bits n -> Bits n -> Bits n
 urem (MkBits x) (MkBits y) = MkBits (urem' x y)
@@ -447,4 +498,3 @@
 
 implementation Show (Bits n) where
     show = bitsToStr
-
diff --git a/libs/base/Data/Complex.idr b/libs/base/Data/Complex.idr
--- a/libs/base/Data/Complex.idr
+++ b/libs/base/Data/Complex.idr
@@ -63,15 +63,23 @@
 implementation Functor Complex where
     map f (r :+ i) = f r :+ f i
 
--- We can't do "implementation Num a => Num (Complex a)" because
--- we need "abs" which needs "magnitude" which needs "sqrt" which needs Double
-implementation Num (Complex Double) where
+-- We can do "implementation Neg a => Num (Complex a)" because
+-- we don't need "abs", only (-)
+implementation Neg a => Num (Complex a) where
     (+) (a:+b) (c:+d) = ((a+c):+(b+d))
     (*) (a:+b) (c:+d) = ((a*c-b*d):+(b*c+a*d))
     fromInteger x = (fromInteger x:+0)
 
+-- We can't do "implementation Neg a => Neg (Complex a)" because
+-- we need "abs" which needs "magnitude" which needs "sqrt" which needs Double
 implementation Neg (Complex Double) where
     negate = map negate
     (-) (a:+b) (c:+d) = ((a-c):+(b-d))
     abs (a:+b) = (magnitude (a:+b):+0)
 
+-- As soon as abs moves out of Neg (issue #3500), the following would become a
+-- valid instance:
+
+-- implementation Neg a => Neg (Complex a) where
+--     negate = map negate
+--     (-) (a:+b) (c:+d) = ((a-c):+(b-d))
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
@@ -225,5 +225,3 @@
   vList (ys ++ zs) | (MkSplitBal prf) 
         = toVList ys (snocList zs) prf
 
-
-
diff --git a/libs/base/Data/String/Views.idr b/libs/base/Data/String/Views.idr
--- a/libs/base/Data/String/Views.idr
+++ b/libs/base/Data/String/Views.idr
@@ -1,5 +1,7 @@
 module Data.String.Views
 
+%access public export
+
 ||| View for traversing a String one character at a time
 data StrList : String -> Type where
      SNil  : StrList ""
diff --git a/libs/base/Debug/Error.idr b/libs/base/Debug/Error.idr
--- a/libs/base/Debug/Error.idr
+++ b/libs/base/Debug/Error.idr
@@ -12,9 +12,6 @@
         (message : String) ->
         a
 error {loc = FileLoc filename (line, col) _} message =
-  believe_me . unsafePerformIO $ 
-    do let place = filename ++ " line " ++ show line ++ " column " ++ show col
-       let message' = place ++ ": " ++ message
-       putStrLn message'
-       exit 1
-
+    let place = filename ++ " line " ++ show line ++ " column " ++ show col
+        message' = place ++ ": " ++ message in
+        idris_crash message'
diff --git a/libs/base/Language/Reflection/Utils.idr b/libs/base/Language/Reflection/Utils.idr
--- a/libs/base/Language/Reflection/Utils.idr
+++ b/libs/base/Language/Reflection/Utils.idr
@@ -264,6 +264,18 @@
           equalp (UType u)    (UType u')       = u == u'
           equalp x            y                = False
 
+implementation Eq Raw where
+  a == b = equalp a b
+    where equalp : Raw -> Raw -> Bool
+          equalp (Var x)         (Var y)         = assert_total $ x == y
+          equalp (RBind x b1 e1) (RBind y b2 e2) = assert_total $ x == y && b1 == b2 && e1 == e2
+          equalp (RApp f1 a1)    (RApp f2 a2)    = assert_total $ f1 == f2 && a1 == a2
+          equalp RType           RType           = True
+          equalp (RUType u1)     (RUType u2)     = u1 == u2
+          equalp (RConstant c1)  (RConstant c2)  = c1 == c2
+          equalp _               _               = False
+
+
 total
 forget : TT -> Maybe Raw
 forget tm = fe [] tm
diff --git a/libs/base/System.idr b/libs/base/System.idr
--- a/libs/base/System.idr
+++ b/libs/base/System.idr
@@ -1,5 +1,7 @@
 module System
 
+import public Data.So
+
 %include C "unistd.h"
 %default partial
 %access public export
@@ -52,18 +54,48 @@
          then pure $ reverse $ map splitEq acc
          else getAllPairs (n + 1) (envPair :: acc)
 
+||| Programs can either terminate successfully, or end in a caught
+||| failure.
+data ExitCode : Type where
+  ||| Terminate successfully.
+  ExitSuccess : ExitCode
+  ||| Program terminated for some prescribed reason.
+  |||
+  ||| @errNo A non-zero numerical value indicating failure.
+  ||| @prf   Proof that the int value is non-zero.
+  ExitFailure : (errNo    : Int)
+             -> {auto prf : So (not $ errNo == 0)}
+             -> ExitCode
+
 ||| Quit with a particular exit code
-exit : Int -> IO ()
-exit code = foreign FFI_C "exit" (Int -> IO ()) code
+exit : Int -> IO a
+exit code = believe_me $ foreign FFI_C "exit" (Int -> IO ()) code
 
-||| Get the numbers of seconds since 1st January 1970, 00:00 UTC 
+||| Terminate the program with an `ExitCode`. This code indicates the
+||| success of the program's execution, and returns the success code
+||| to the program's caller.
+|||
+||| @code The `ExitCode` for program.
+exitWith : (code : ExitCode) -> IO a
+exitWith ExitSuccess         = exit 0
+exitWith (ExitFailure errNo) = exit errNo
+
+||| Exit the program indicating failure.
+exitFailure : IO a
+exitFailure = exitWith (ExitFailure 1)
+
+||| Exit the program after a successful run.
+exitSuccess : IO a
+exitSuccess = exitWith ExitSuccess
+
+||| Get the numbers of seconds since 1st January 1970, 00:00 UTC
 time : IO Integer
 time = do MkRaw t <- foreign FFI_C "idris_time" (IO (Raw Integer))
           pure t
 
-usleep : Int -> IO ()
+||| Specify interval to sleep for, must be in range [0, 1000000]
+usleep : (i : Int) -> { auto prf : So (i >= 0 && i <= 1000000) } -> IO ()
 usleep i = foreign FFI_C "usleep" (Int -> IO ()) i
 
 system : String -> IO Int
 system cmd = foreign FFI_C "system" (String -> IO Int) cmd
-
diff --git a/libs/base/base.ipkg b/libs/base/base.ipkg
--- a/libs/base/base.ipkg
+++ b/libs/base/base.ipkg
@@ -1,6 +1,6 @@
 package base
 
-opts = "--nobasepkgs --total --no-elim-deprecation-warnings -i ../prelude"
+opts = "--nobasepkgs --total --no-elim-deprecation-warnings --partial-eval -i ../prelude"
 modules = System,
 
           Debug.Error, Debug.Trace,
diff --git a/libs/contrib/CFFI/Types.idr b/libs/contrib/CFFI/Types.idr
--- a/libs/contrib/CFFI/Types.idr
+++ b/libs/contrib/CFFI/Types.idr
@@ -126,13 +126,15 @@
         offsets' [] acc _ = reverse acc
         offsets' (x::xs) acc pos = offsets' xs (pos::acc) (sizeOf x)
 
+%language ElabReflection -- needed for 'error', which finds a line number
+
 private
 indexOrFail : Nat -> List a -> a
 indexOrFail i xs = case index' i xs of
                         Just x => x
                         Nothing => error "Out of bounds access"
 
-||| The offset of a firld in a composite type
+||| The offset of a field in a composite type
 export
 offset : Composite -> Nat -> Int
 offset (STRUCT xs) i = indexOrFail i (offsetsStruct xs)
diff --git a/libs/contrib/Control/ST.idr b/libs/contrib/Control/ST.idr
new file mode 100644
--- /dev/null
+++ b/libs/contrib/Control/ST.idr
@@ -0,0 +1,541 @@
+module Control.ST
+
+import Language.Reflection.Utils
+
+%default total
+
+infix 5 :::
+
+{- A resource is a pair of a label and the current type stored there -}
+public export
+data Resource : Type where
+     MkRes : label -> Type -> Resource
+
+%error_reverse
+public export
+(:::) : label -> Type -> Resource
+(:::) = MkRes
+
+export
+data Var = MkVar -- Phantom, just for labelling purposes
+
+{- Contexts for holding current resources states -}
+namespace Context
+  public export
+  data Context : Type where
+       Nil : Context
+       (::) : Resource -> Context -> Context
+
+  public export
+  (++) : Context -> Context -> Context
+  (++) [] ys = ys
+  (++) (x :: xs) ys = x :: xs ++ ys
+
+{- Proof that a label has a particular type in a given context -}
+public export
+data InState : lbl -> Type -> Context -> Type where
+     Here : InState lbl st (MkRes lbl st :: rs)
+     There : InState lbl st rs -> InState lbl st (r :: rs)
+
+{- Update an entry in a context with a new state -}
+public export
+updateCtxt : (ctxt : Context) -> 
+             InState lbl st ctxt -> Type -> Context
+updateCtxt (MkRes lbl _ :: rs) Here val = (MkRes lbl val :: rs)
+updateCtxt (r :: rs) (There x) ty = r :: updateCtxt rs x ty
+
+{- Remove an entry from a context -}
+public export
+drop : (ctxt : Context) -> (prf : InState lbl st ctxt) -> 
+       Context
+drop (MkRes lbl st :: rs) Here = rs
+drop (r :: rs) (There p) = r :: drop rs p
+
+{- Proof that a resource state (label/type) is in a context -}
+public export
+data ElemCtxt : Resource -> Context -> Type where
+     HereCtxt : ElemCtxt a (a :: as)
+     ThereCtxt : ElemCtxt a as -> ElemCtxt a (b :: as)
+
+public export %error_reduce
+dropEl : (ys: _) -> ElemCtxt x ys -> Context
+dropEl (x :: as) HereCtxt = as
+dropEl (x :: as) (ThereCtxt p) = x :: dropEl as p
+
+{- Proof that a variable name is in a context -}
+public export
+data VarInCtxt : Var -> Context -> Type where
+     VarHere   : VarInCtxt a (MkRes a st :: as)
+     VarThere  : VarInCtxt a as -> VarInCtxt a (b :: as)
+
+public export %error_reduce
+dropVarIn : (ys: _) -> VarInCtxt x ys -> Context
+dropVarIn ((MkRes x _) :: as) VarHere = as
+dropVarIn (x :: as) (VarThere p) = x :: dropVarIn as p
+
+public export
+data Composite : List Type -> Type where
+     CompNil : Composite []
+     CompCons : (x : a) -> Composite as -> Composite (a :: as)
+
+namespace VarList
+  public export
+  data VarList : List Type -> Type where
+       Nil : VarList []
+       (::) : Var -> VarList ts -> VarList (t :: ts)
+
+  public export
+  mkCtxt : VarList tys -> Context
+  mkCtxt [] = []
+  mkCtxt {tys = (t :: ts)} (v :: vs) = (v ::: t) :: mkCtxt vs
+
+{- Proof that a context is a subset of another context -}
+public export
+data SubCtxt : Context -> Context -> Type where
+     SubNil : SubCtxt [] []
+     InCtxt : (el : ElemCtxt x ys) -> SubCtxt xs (dropEl ys el) ->
+              SubCtxt (x :: xs) ys
+     Skip : SubCtxt xs ys -> SubCtxt xs (y :: ys)
+
+%hint
+public export
+subCtxtId : SubCtxt xs xs
+subCtxtId {xs = []} = SubNil
+subCtxtId {xs = (x :: xs)} = InCtxt HereCtxt subCtxtId
+
+public export
+subCtxtNil : SubCtxt [] xs
+subCtxtNil {xs = []} = SubNil
+subCtxtNil {xs = (x :: xs)} = Skip subCtxtNil
+
+{- Proof that every variable in the list appears once in the context -}
+public export
+data VarsIn : List Var -> Context -> Type where
+     VarsNil : VarsIn [] []
+     InCtxtVar : (el : VarInCtxt x ys) -> VarsIn xs (dropVarIn ys el) ->
+                 VarsIn (x :: xs) ys
+     SkipVar : VarsIn xs ys -> VarsIn xs (y :: ys)
+
+public export
+Uninhabited (ElemCtxt x []) where
+  uninhabited HereCtxt impossible
+  uninhabited (ThereCtxt _) impossible
+
+public export %error_reduce
+updateWith : (new : Context) -> (xs : Context) ->
+             SubCtxt ys xs -> Context
+-- At the end, add the ones which were updated by the subctxt
+updateWith new [] SubNil = new
+updateWith new [] (InCtxt el z) = absurd el
+-- Don't add the ones which were consumed by the subctxt
+updateWith [] (x :: xs) (InCtxt el p) 
+    = updateWith [] (dropEl _ el) p
+updateWith (n :: ns) (x :: xs) (InCtxt el p) 
+    = n :: updateWith ns (dropEl _ el) p
+-- Do add the ones we didn't use in the subctxt
+updateWith new (x :: xs) (Skip p) = x :: updateWith new xs p
+
+public export
+getVarType : (xs : Context) -> VarInCtxt v xs -> Type
+getVarType ((MkRes v st) :: as) VarHere = st
+getVarType (b :: as) (VarThere x) = getVarType as x
+
+public export
+getCombineType : VarsIn ys xs -> List Type
+getCombineType VarsNil = []
+getCombineType (InCtxtVar el y) = getVarType _ el :: getCombineType y
+getCombineType (SkipVar x) = getCombineType x
+
+public export
+dropCombined : VarsIn vs ctxt -> Context
+dropCombined {ctxt = []} VarsNil = []
+dropCombined {ctxt} (InCtxtVar el y) = dropCombined y
+dropCombined {ctxt = (y :: ys)} (SkipVar x) = y :: dropCombined x
+
+public export
+combineVarsIn : (ctxt : Context) -> VarsIn (comp :: vs) ctxt -> Context
+combineVarsIn {comp} ctxt (InCtxtVar el x) 
+     = ((comp ::: Composite (getCombineType x)) :: dropCombined (InCtxtVar el x))
+combineVarsIn (y :: ys) (SkipVar x) = y :: combineVarsIn ys x
+
+namespace Env
+  public export
+  data Env : Context -> Type where
+       Nil : Env []
+       (::) : ty -> Env xs -> Env ((lbl ::: ty) :: xs)
+
+lookupEnv : InState lbl ty ctxt -> Env ctxt -> ty
+lookupEnv Here (x :: xs) = x
+lookupEnv (There p) (x :: xs) = lookupEnv p xs
+
+updateEnv : (prf : InState lbl ty ctxt) -> Env ctxt -> ty' -> 
+            Env (updateCtxt ctxt prf ty')
+updateEnv Here (x :: xs) val = val :: xs
+updateEnv (There p) (x :: xs) val = x :: updateEnv p xs val
+
+dropVal : (prf : InState lbl st ctxt) -> Env ctxt -> Env (drop ctxt prf)
+dropVal Here (x :: xs) = xs
+dropVal (There p) (x :: xs) = x :: dropVal p xs
+
+envElem : ElemCtxt x xs -> Env xs -> Env [x]
+envElem HereCtxt (x :: xs) = [x]
+envElem (ThereCtxt p) (x :: xs) = envElem p xs
+
+dropDups : Env xs -> (el : ElemCtxt x xs) -> Env (dropEl xs el)
+dropDups (y :: ys) HereCtxt = ys
+dropDups (y :: ys) (ThereCtxt p) = y :: dropDups ys p
+
+
+dropEntry : Env ctxt -> (prf : VarInCtxt x ctxt) -> Env (dropVarIn ctxt prf)
+dropEntry (x :: env) VarHere = env
+dropEntry (x :: env) (VarThere y) = x :: dropEntry env y
+
+dropVarsIn : Env ctxt -> (prf : VarsIn vs ctxt) -> Env (dropCombined prf)
+dropVarsIn [] VarsNil = []
+dropVarsIn env (InCtxtVar el z) = dropVarsIn (dropEntry env el) z
+dropVarsIn (x :: env) (SkipVar z) = x :: dropVarsIn env z
+
+getVarEntry : Env ctxt -> (prf : VarInCtxt v ctxt) -> getVarType ctxt prf
+getVarEntry (x :: xs) VarHere = x
+getVarEntry (x :: env) (VarThere p) = getVarEntry env p
+
+mkComposite : Env ctxt -> (prf : VarsIn vs ctxt) -> Composite (getCombineType prf)
+mkComposite [] VarsNil = CompNil
+mkComposite env (InCtxtVar el z) 
+    = CompCons (getVarEntry env el) (mkComposite (dropEntry env el) z)
+mkComposite (x :: env) (SkipVar z) = mkComposite env z
+
+rebuildVarsIn : Env ctxt -> (prf : VarsIn (comp :: vs) ctxt) -> 
+                Env (combineVarsIn ctxt prf)
+rebuildVarsIn env (InCtxtVar el p) 
+     = mkComposite (dropEntry env el) p :: dropVarsIn env (InCtxtVar el p)
+rebuildVarsIn (x :: env) (SkipVar p) = x :: rebuildVarsIn env p
+
+{- Some things to make STrans interfaces look prettier -}
+
+infix 6 :->
+          
+public export
+data Action : Type -> Type where
+     Stable : lbl -> Type -> Action ty
+     Trans : lbl -> Type -> (ty -> Type) -> Action ty
+     Remove : lbl -> Type -> Action ty
+     Add : (ty -> Context) -> Action ty
+
+namespace Stable
+  public export %error_reduce
+  (:::) : lbl -> Type -> Action ty
+  (:::) = Stable
+
+namespace Trans
+  public export
+  data Trans ty = (:->) Type Type
+
+  public export %error_reduce
+  (:::) : lbl -> Trans ty -> Action ty
+  (:::) lbl (st :-> st') = Trans lbl st (const st')
+
+namespace DepTrans
+  public export
+  data DepTrans ty = (:->) Type (ty -> Type)
+
+  public export %error_reduce
+  (:::) : lbl -> DepTrans ty -> Action ty
+  (:::) lbl (st :-> st') = Trans lbl st st'
+
+public export
+or : a -> a -> Either b c -> a
+or x y = either (const x) (const y)
+
+public export
+add : Type -> Action a
+add ty = Add (\var => [var ::: ty])
+
+public export
+addIfRight : Type -> Action (Either a b)
+addIfRight ty = Add (either (const []) (\var => [var ::: ty]))
+
+public export
+addIfJust : Type -> Action (Maybe a)
+addIfJust ty = Add (maybe [] (\var => [var ::: ty]))
+
+public export
+kept : SubCtxt xs ys -> Context
+kept SubNil = []
+kept (InCtxt el p) = kept p
+kept (Skip {y} p) = y :: kept p
+
+-- We can only use new/delete/read/write on things wrapped in State. Only an
+-- interface implementation should know that a thing is defined as State,
+-- so it's the only thing that's able to peek at the internals
+public export
+data State : Type -> Type where
+     Value : ty -> State ty
+
+export
+data STrans : (m : Type -> Type) ->
+              (ty : Type) ->
+              Context -> (ty -> Context) ->
+              Type where
+     Pure : (result : ty) -> 
+            STrans m ty (out_fn result) out_fn
+     Bind : STrans m a st1 st2_fn ->
+            ((result : a) -> 
+                STrans m b (st2_fn result) st3_fn) ->
+            STrans m b st1 st3_fn
+     Lift : Monad m => m t -> STrans m t ctxt (const ctxt)
+
+     New : (val : state) -> 
+           STrans m Var ctxt (\lbl => (lbl ::: state) :: ctxt)
+     Delete : (lbl : Var) ->
+              (prf : InState lbl st ctxt) ->
+              STrans m () ctxt (const (drop ctxt prf))
+     DropSubCtxt : (prf : SubCtxt ys xs) ->
+                   STrans m (Env ys) xs (const (kept prf))
+
+     Split : (lbl : Var) ->
+             (prf : InState lbl (Composite vars) ctxt) ->
+             STrans m (VarList vars) ctxt 
+                   (\ vs => mkCtxt vs ++ 
+                            updateCtxt ctxt prf (State ()))
+     Combine : (comp : Var) -> (vs : List Var) ->
+               (prf : VarsIn (comp :: vs) ctxt) ->
+               STrans m () ctxt
+                   (const (combineVarsIn ctxt prf))
+
+     Call : STrans m t sub new_f -> (ctxt_prf : SubCtxt sub old) ->
+            STrans m t old (\res => updateWith (new_f res) old ctxt_prf)
+
+     Read : (lbl : Var) ->
+            (prf : InState lbl ty ctxt) ->
+            STrans m ty ctxt (const ctxt)
+     Write : (lbl : Var) ->
+             (prf : InState lbl ty ctxt) ->
+             (val : ty') ->
+             STrans m () ctxt (const (updateCtxt ctxt prf ty'))
+
+export
+dropEnv : Env ys -> SubCtxt xs ys -> Env xs
+dropEnv [] SubNil = []
+dropEnv [] (InCtxt idx rest) = absurd idx
+dropEnv (z :: zs) (InCtxt idx rest) 
+    = let [e] = envElem idx (z :: zs) in
+          e :: dropEnv (dropDups (z :: zs) idx) rest
+dropEnv (z :: zs) (Skip p) = dropEnv zs p
+
+keepEnv : Env ys -> (prf : SubCtxt xs ys) -> Env (kept prf)
+keepEnv env SubNil = env
+keepEnv env (InCtxt el prf) = keepEnv (dropDups env el) prf
+keepEnv (z :: zs) (Skip prf) = z :: keepEnv zs prf
+
+-- Corresponds pretty much exactly to 'updateWith'
+rebuildEnv : Env new -> Env old -> (prf : SubCtxt sub old) ->
+             Env (updateWith new old prf)
+rebuildEnv new [] SubNil = new
+rebuildEnv new [] (InCtxt el p) = absurd el
+rebuildEnv [] (x :: xs) (InCtxt el p) 
+    = rebuildEnv [] (dropDups (x :: xs) el) p
+rebuildEnv (e :: es) (x :: xs) (InCtxt el p) 
+    = e :: rebuildEnv es (dropDups (x :: xs) el) p
+rebuildEnv new (x :: xs) (Skip p) = x :: rebuildEnv new xs p
+
+runST : Env invars -> STrans m a invars outfn ->
+        ((x : a) -> Env (outfn x) -> m b) -> m b
+runST env (Pure result) k = k result env
+runST env (Bind prog next) k 
+   = runST env prog (\prog', env' => runST env' (next prog') k)
+runST env (Lift action) k 
+   = do res <- action
+        k res env
+runST env (New val) k = k MkVar (val :: env)
+runST env (Delete lbl prf) k = k () (dropVal prf env)
+runST env (DropSubCtxt prf) k = k (dropEnv env prf) (keepEnv env prf)
+runST env (Split lbl prf) k = let val = lookupEnv prf env 
+                                  env' = updateEnv prf env (Value ()) in
+                                  k (mkVars val) (addToEnv val env')
+  where
+    mkVars : Composite ts -> VarList ts
+    mkVars CompNil = []
+    mkVars (CompCons x xs) = MkVar :: mkVars xs
+
+    addToEnv : (comp : Composite ts) -> Env xs -> Env (mkCtxt (mkVars comp) ++ xs)
+    addToEnv CompNil env = env
+    addToEnv (CompCons x xs) env = x :: addToEnv xs env
+runST env (Combine lbl vs prf) k = k () (rebuildVarsIn env prf)
+runST env (Call prog ctxt_prf) k 
+   = let env' = dropEnv env ctxt_prf in
+         runST env' prog
+                 (\prog', envk => k prog' (rebuildEnv envk env ctxt_prf))
+runST env (Read lbl prf) k = k (lookupEnv prf env) env
+runST env (Write lbl prf val) k = k () (updateEnv prf env val)
+
+
+export 
+pure : (result : ty) -> STrans m ty (out_fn result) out_fn
+pure = Pure
+ 
+export 
+(>>=) : STrans m a st1 st2_fn ->
+        ((result : a) -> STrans m b (st2_fn result) st3_fn) ->
+        STrans m b st1 st3_fn
+(>>=) = Bind
+
+export
+lift : Monad m => m t -> STrans m t ctxt (const ctxt)
+lift = Lift
+
+export
+new : (val : state) -> 
+      STrans m Var ctxt (\lbl => (lbl ::: State state) :: ctxt)
+new val = New (Value val)
+
+export
+delete : (lbl : Var) ->
+         {auto prf : InState lbl (State st) ctxt} ->
+         STrans m () ctxt (const (drop ctxt prf))
+delete lbl {prf} = Delete lbl prf
+
+-- Keep only a subset of the current set of resources. Returns the
+-- environment corresponding to the dropped portion.
+export
+dropSubCtxt : {auto prf : SubCtxt ys xs} ->
+              STrans m (Env ys) xs (const (kept prf))
+dropSubCtxt {prf} = DropSubCtxt prf
+
+export
+split : (lbl : Var) ->
+        {auto prf : InState lbl (Composite vars) ctxt} ->
+        STrans m (VarList vars) ctxt 
+              (\ vs => mkCtxt vs ++ 
+                       updateCtxt ctxt prf (State ()))
+split lbl {prf} = Split lbl prf
+
+export
+combine : (comp : Var) -> (vs : List Var) ->
+          {auto prf : InState comp (State ()) ctxt} ->
+          {auto var_prf : VarsIn (comp :: vs) ctxt} ->
+          STrans m () ctxt
+              (const (combineVarsIn ctxt var_prf))
+combine comp vs {var_prf} = Combine comp vs var_prf
+
+export -- implicit ???
+call : STrans m t sub new_f ->
+       {auto ctxt_prf : SubCtxt sub old} ->
+       STrans m t old (\res => updateWith (new_f res) old ctxt_prf)
+call prog {ctxt_prf} = Call prog ctxt_prf
+ 
+export
+read : (lbl : Var) ->
+       {auto prf : InState lbl (State ty) ctxt} ->
+       STrans m ty ctxt (const ctxt)
+read lbl {prf} = do Value x <- Read lbl prf
+                    pure x
+
+export
+write : (lbl : Var) ->
+        {auto prf : InState lbl ty ctxt} ->
+        (val : ty') ->
+        STrans m () ctxt (const (updateCtxt ctxt prf (State ty')))
+write lbl {prf} val = Write lbl prf (Value val)
+    
+public export %error_reduce
+out_res : ty -> (as : List (Action ty)) -> Context
+out_res x [] = []
+out_res x ((Stable lbl inr) :: xs) = (lbl ::: inr) :: out_res x xs
+out_res x ((Trans lbl inr outr) :: xs) 
+    = (lbl ::: outr x) :: out_res x xs
+out_res x ((Remove lbl inr) :: xs) = out_res x xs
+out_res x (Add outf :: xs) = outf x ++ out_res x xs
+
+public export %error_reduce
+in_res : (as : List (Action ty)) -> Context
+in_res [] = []
+in_res ((Stable lbl inr) :: xs) = (lbl ::: inr) :: in_res xs
+in_res ((Trans lbl inr outr) :: xs) = (lbl ::: inr) :: in_res xs
+in_res ((Remove lbl inr) :: xs) = (lbl ::: inr) :: in_res xs
+in_res (Add outf :: xs) = in_res xs
+
+public export
+%error_reduce -- always evaluate this before showing errors
+ST : (m : Type -> Type) ->
+     (ty : Type) -> 
+     List (Action ty) -> Type
+ST m ty xs = STrans m ty (in_res xs) (\result : ty => out_res result xs)
+
+-- Console IO is useful sufficiently often that let's have it here
+public export
+interface ConsoleIO (m : Type -> Type) where
+  putStr : String -> STrans m () xs (const xs)
+  getStr : STrans m String xs (const xs)
+
+export
+ConsoleIO IO where
+  putStr str = lift (Interactive.putStr str)
+  getStr = lift Interactive.getLine
+
+
+export
+run : Applicative m => ST m a [] -> m a
+run prog = runST [] prog (\res, env' => pure res)
+
+||| runWith allows running an STrans program with an initial environment,
+||| which must be consumed.
+||| It's only allowed in the IO monad, because it's inherently unsafe, so
+||| we don't want to be able to use it under a 'lift in just *any* ST program -
+||| if we have access to an 'Env' we can easily duplicate it - so it's the
+||| responsibility of an implementation of an interface in IO which uses it
+||| to ensure that it isn't duplicated.
+export
+runWith : {ctxtf : _} ->
+          Env ctxt -> STrans IO a ctxt (\res => ctxtf res) -> 
+          IO (res ** Env (ctxtf res))
+runWith env prog = runST env prog (\res, env' => pure (res ** env'))
+
+export
+runPure : ST Basics.id a [] -> a
+runPure prog = runST [] prog (\res, env' => res)
+
+%language ErrorReflection
+
+%error_handler
+export
+st_precondition : Err -> Maybe (List ErrorReportPart)
+st_precondition (CantSolveGoal `(SubCtxt ~sub ~all) _)
+   = pure 
+      [TextPart "'call' is not valid here. ",
+       TextPart "The operation has preconditions ",
+       TermPart sub,
+       TextPart " which is not a sub set of ",
+       TermPart all]
+st_precondition (CantUnify _ tm1 tm2 _ _ _)
+   = do reqPre <- getPreconditions tm1
+        gotPre <- getPreconditions tm2
+        reqPost <- getPostconditions tm1
+        gotPost <- getPostconditions tm2
+        pure $ [TextPart "Error in state transition:"] ++
+                renderPre gotPre reqPre ++
+                renderPost gotPost reqPost
+
+  where
+    getPreconditions : TT -> Maybe TT
+    getPreconditions `(STrans ~m ~ret ~pre ~post) = Just pre
+    getPreconditions _ = Nothing
+
+    getPostconditions : TT -> Maybe TT
+    getPostconditions `(STrans ~m ~ret ~pre ~post) = Just post
+    getPostconditions _ = Nothing
+
+    renderPre : TT -> TT -> List (ErrorReportPart)
+    renderPre got req 
+        = [SubReport [TextPart "Operation has preconditions: ",
+                      TermPart req],
+           SubReport [TextPart "States here are: ",
+                      TermPart got]]
+    renderPost : TT -> TT -> List (ErrorReportPart)
+    renderPost got req 
+        = [SubReport [TextPart "Operation has postconditions: ",
+                      TermPart req],
+           SubReport [TextPart "Required result states here are: ",
+                      TermPart got]]
+
+st_precondition _ = Nothing
diff --git a/libs/contrib/Control/ST/ImplicitCall.idr b/libs/contrib/Control/ST/ImplicitCall.idr
new file mode 100644
--- /dev/null
+++ b/libs/contrib/Control/ST/ImplicitCall.idr
@@ -0,0 +1,13 @@
+module Control.ST.ImplicitCall
+
+import Control.ST
+
+||| Make 'call' implicit.
+||| This makes ST programs less verbose, at the cost of making error messages
+||| potentially more difficult to read.
+export implicit
+imp_call : STrans m t ys ys' ->
+       {auto ctxt_prf : SubCtxt ys xs} ->
+       STrans m t xs (\res => updateWith (ys' res) xs ctxt_prf)
+imp_call = call
+
diff --git a/libs/contrib/Data/List/Zipper.idr b/libs/contrib/Data/List/Zipper.idr
new file mode 100644
--- /dev/null
+++ b/libs/contrib/Data/List/Zipper.idr
@@ -0,0 +1,160 @@
+||| A Zipper implementation for Lists
+||| inspired by
+||| https://hackage.haskell.org/package/ListZipper-1.2.0.2/docs/src/Data-List-Zipper.html
+module Data.List.Zipper
+
+%default total
+%access public export
+
+||| A Zipper for Lists
+data Zipper: Type -> Type where
+  Zip: List a -> List a -> Zipper a
+
+%name Zipper z1, z2
+
+-- Implementations
+--------------------------------------------------------------------------------
+
+Functor Zipper where
+  map f (Zip xs ys) = Zip (map f xs) (map f ys)
+
+Foldable Zipper where
+  foldr f acc (Zip xs ys) = foldr f acc (reverse xs ++ ys)
+
+Show a => Show (Zipper a) where
+  show (Zip xs []) = show $ reverse xs
+  show (Zip xs (x :: ys)) = unwords [show $ reverse xs, "-", show x, "-", show ys]
+
+||| Equality for Zippers
+||| Two zipper are equal if they zip the same list and point to the same cursor
+Eq a => Eq (Zipper a) where
+  (==) (Zip xs ys) (Zip zs ws) = (xs == zs) && (ys == ws)
+-- Functions
+--------------------------------------------------------------------------------
+
+||| creates an empty Zipper
+||| ```idris example
+||| empty {a = Nat}
+||| ```
+empty: Zipper a
+empty = Zip [] []
+
+||| checks whether this Zipper is empty
+||| ```idris example
+||| isEmpty empty {a = Nat}
+||| ```
+isEmpty: Zipper a -> Bool
+isEmpty (Zip [] []) = True
+isEmpty _ = False
+
+||| creates a Zipper from a List
+||| ```idris example
+||| show $ fromList [1,2,3,4,5]
+||| ```
+fromList: List a -> Zipper a
+fromList xs = Zip [] xs
+
+||| moves the cursor to the right or leaves the cursor unchanged
+||| ```idris example
+|||  show $ right $ fromList [1,2,3,4,5]
+||| ```
+right: Zipper a -> Zipper a
+right (Zip xs (x :: ys)) = Zip (x :: xs) ys
+right z = z
+
+||| moves the cursor to the left or leaves the cursor unchanged
+||| ```idris example
+||| show $ left $ fromList [1,2,3,4,5]
+||| ```
+left: Zipper a -> Zipper a
+left (Zip (x :: xs) ys) = Zip xs (x :: ys)
+left z = z
+
+||| gets the element at the current cursor
+||| ```idris example
+||| cursor $ fromList [1,2,3,4,5]
+||| ```
+cursor: Zipper a -> Maybe a
+cursor (Zip xs ys) = listToMaybe ys
+
+||| move the cursor to the start of the Zipper
+||| ```idris example
+||| show $ start $ fromList [1,2,3,4,5]
+||| ```
+start: Zipper a -> Zipper a
+start (Zip xs ys) = Zip [] (reverse xs ++ ys)
+
+||| move the cursor to the end of the Zipper
+||| ```idris example
+||| show $ end $ fromList [1,2,3,4,5]
+||| ```
+end: Zipper a -> Zipper a
+end (Zip xs ys) = Zip (reverse ys ++ xs) []
+
+||| checks whether the cursor is at the start of the Zipper
+||| ```idris example
+||| startp $ fromList [1,2,3,4,5]
+||| ```
+startp: Zipper a -> Bool
+startp (Zip [] ys) = True
+startp _ = False
+
+||| checks whether the cursor is at the end of the Zipper
+||| ```idris example
+||| endp $ fromList [1,2,3,4,5]
+||| ```
+endp: Zipper a -> Bool
+endp (Zip xs []) = True
+endp _ = False
+
+||| inserts an element at the current cursor
+||| ```idris example
+||| show $ insert 0 $ fromList [1,2,3,4,5]
+||| ```
+insert: a -> Zipper a -> Zipper a
+insert x (Zip xs ys) = Zip xs (x :: ys)
+
+||| push an element into the Zipper and move the cursor past it
+||| ```idris example
+||| show $ push 0 $ fromList [1,2,3,4,5]
+||| ```
+push: a -> Zipper a -> Zipper a
+push x (Zip xs ys) = Zip (x :: xs) (ys)
+
+||| pop an element from the Zipper
+||| ```idris example
+||| show $ pop $ right $ fromList [1,2,3,4,5]
+||| ```
+pop: Zipper a -> Zipper a
+pop (Zip (_ :: xs) ys) = Zip xs ys
+pop z = z
+
+||| delete the element at the current cursor
+||| ```idris example
+||| show $ Data.List.Zipper.delete $ fromList [1,2,3,4,5]
+||| ```
+delete: Zipper a -> Zipper a
+delete (Zip xs (x :: ys)) = Zip xs ys
+delete z = z
+
+||| remove an element from the zipper
+||| ```idris example
+||| show $ replace 9 $ fromList[1,2,3,4,5]
+||| ```
+replace: a -> Zipper a -> Zipper a
+replace x (Zip xs (_ :: ys)) = Zip xs (x :: ys)
+replace _ z1 = z1
+
+||| Return the index of the current cursor
+||| ```idris example
+||| index $ fromList [1,2,3,4,5]
+||| ```
+index: Zipper a -> Nat
+index (Zip xs ys) = length xs
+
+||| convert this Zipper to a list
+||| ```idris example
+||| toList $ fromList[1,2,3,4,5]
+||| ```
+toList: Zipper a -> List a
+toList (Zip xs ys) = reverse xs ++ ys
diff --git a/libs/contrib/Data/Monoid.idr b/libs/contrib/Data/Monoid.idr
new file mode 100644
--- /dev/null
+++ b/libs/contrib/Data/Monoid.idr
@@ -0,0 +1,33 @@
+||| Ported from Haskell:
+||| https://hackage.haskell.org/package/base-4.9.0.0/docs/src/Data.Monoid.html
+module Data.Monoid
+
+%access public export
+%default total
+
+-- TODO: These instances exist, but can't be named the same.
+-- Decide on names for these
+
+-- [all] Semigroup Bool where
+--   a <+> b = a && b
+--
+-- [all] Monoid Bool where
+--   neutral = True
+--
+-- [any] Semigroup Bool where
+--   a <+> b = a || b
+--
+-- [any] Monoid Bool where
+--   neutral = False
+
+Semigroup () where
+  (<+>) _ _ = ()
+
+Monoid () where
+  neutral = ()
+
+(Semigroup m, Semigroup n) => Semigroup (m, n) where
+  (a, b) <+> (c, d) = (a <+> c, b <+> d)
+
+(Monoid m, Monoid n) => Monoid (m, n) where
+  neutral = (neutral, neutral)
diff --git a/libs/contrib/Data/ZZ.idr b/libs/contrib/Data/ZZ.idr
--- a/libs/contrib/Data/ZZ.idr
+++ b/libs/contrib/Data/ZZ.idr
@@ -6,7 +6,6 @@
 %default total
 %access public export
 
-
 ||| An integer is either a positive `Nat` or the negated successor of a `Nat`.
 |||
 ||| For example, 3 is `Pos 3` and -2 is `NegS 1`. Zero is arbitrarily chosen
@@ -51,7 +50,6 @@
   (NegS n) == (NegS m) = n == m
   _ == _ = False
 
-
 implementation Ord ZZ where
   compare (Pos n) (Pos m) = compare n m
   compare (NegS n) (NegS m) = compare m n
@@ -84,7 +82,7 @@
     negate (Pos Z)     = Pos Z
     negate (Pos (S n)) = NegS n
     negate (NegS n)    = Pos (S n)
-  
+
     (-) = subZ
     abs = cast . absZ
 
@@ -92,7 +90,6 @@
   subZ : ZZ -> ZZ -> ZZ
   subZ n m = plusZ n (negate m)
 
-
 implementation Cast ZZ Integer where
   cast (Pos n) = cast n
   cast (NegS n) = (-1) * (cast n + 1)
@@ -100,7 +97,6 @@
 implementation Cast Integer ZZ where
   cast = fromInteger
 
-
 --------------------------------------------------------------------------------
 -- Properties
 --------------------------------------------------------------------------------
@@ -141,6 +137,7 @@
     | No p = No $ \h => p $ negSInjective h
 
 -- Plus
+
 plusZeroLeftNeutralZ : (right : ZZ) -> 0 + right = right
 plusZeroLeftNeutralZ (Pos n) = Refl
 plusZeroLeftNeutralZ (NegS n) = Refl
@@ -155,3 +152,202 @@
 plusCommutativeZ (NegS n) (Pos m) = Refl
 plusCommutativeZ (NegS n) (NegS m) = cong {f=NegS} $ cong {f=S} $ plusCommutative n m
 
+minusNatZAntiCommutative : (j, k : Nat) -> negate (minusNatZ j k) = minusNatZ k j
+minusNatZAntiCommutative Z Z = Refl
+minusNatZAntiCommutative Z (S k) = Refl
+minusNatZAntiCommutative (S j) Z = Refl
+minusNatZAntiCommutative (S j) (S k) = minusNatZAntiCommutative j k
+
+negateDistributesPlus : (a, b : ZZ) -> negate (a + b) = (negate a) + (negate b)
+negateDistributesPlus (Pos Z) b = rewrite plusZeroLeftNeutralZ b in
+                                  rewrite plusZeroLeftNeutralZ (negate b) in Refl
+negateDistributesPlus (Pos (S k)) (Pos Z) = rewrite plusZeroRightNeutral k in Refl
+negateDistributesPlus (Pos (S k)) (Pos (S j)) = rewrite plusCommutative k (S j) in
+                                                rewrite plusCommutative j k in Refl
+negateDistributesPlus (Pos (S k)) (NegS j) = minusNatZAntiCommutative k j
+negateDistributesPlus (NegS k) (Pos Z) = rewrite plusZeroRightNeutral k in Refl
+negateDistributesPlus (NegS k) (Pos (S j)) = minusNatZAntiCommutative j k
+negateDistributesPlus (NegS k) (NegS j) = rewrite plusCommutative k (S j) in
+                                          rewrite plusCommutative k j in Refl
+
+lemmaMinusSucc : (k, j, i : Nat) -> plusZ (minusNatZ k (S j)) (Pos i) = plusZ (minusNatZ k (S (S j))) (Pos (S i))
+lemmaMinusSucc Z j i = Refl
+lemmaMinusSucc (S Z) Z i = Refl
+lemmaMinusSucc (S (S k)) Z i = rewrite plusCommutative k (S i) in
+                               rewrite plusCommutative i k in Refl
+lemmaMinusSucc (S k) (S j) i = lemmaMinusSucc k j i
+
+lemmaAssocNegation : (k : Nat) -> (c, r : ZZ) -> (Pos (S k)) + (c + r) = ((Pos (S k)) + c) + r -> (NegS k) + ((negate c) + (negate r)) = ((NegS k) + (negate c)) + (negate r)
+lemmaAssocNegation k c r prf = rewrite sym $ negateDistributesPlus c r in
+                               rewrite sym $ negateDistributesPlus (Pos (S k)) (plusZ c r) in
+                               rewrite sym $ negateDistributesPlus (Pos (S k)) c in
+                               rewrite sym $ negateDistributesPlus (plusZ (Pos (S k)) c) r in
+                               cong $ prf
+
+lemmaAssocPos : (k : Nat) -> (c, r : ZZ) -> (Pos k) + (c + r) = ((Pos k) + c) + r
+lemmaAssocPos k (Pos j) (Pos i) = cong $ plusAssociative k j i
+lemmaAssocPos k (Pos Z) (NegS i) = rewrite plusZeroRightNeutral k in Refl
+lemmaAssocPos k (Pos (S j)) (NegS Z) = rewrite plusCommutative k (S j) in
+                                       rewrite plusCommutative j k in Refl
+lemmaAssocPos k (Pos (S j)) (NegS (S i)) = let ind = lemmaAssocPos k (assert_smaller (Pos (S j)) (Pos j)) (assert_smaller (NegS (S i)) (NegS i)) in
+                                           rewrite ind in
+                                           rewrite plusCommutative k (S j) in
+                                           rewrite plusCommutative j k in Refl
+lemmaAssocPos k (NegS j) (Pos Z) = rewrite plusZeroRightNeutralZ (minusNatZ k (S j)) in Refl
+lemmaAssocPos Z (NegS Z) (Pos (S i)) = Refl
+lemmaAssocPos (S k) (NegS Z) (Pos (S i)) = rewrite plusCommutative k (S i) in
+                                           rewrite plusCommutative k i in Refl
+lemmaAssocPos k (NegS (S j)) (Pos (S i)) = let ind = lemmaAssocPos k (assert_smaller (NegS (S j)) (NegS j)) (assert_smaller (Pos (S i)) (Pos i)) in
+                                           rewrite ind in
+                                           rewrite lemmaMinusSucc k j i in Refl
+lemmaAssocPos Z (NegS j) (NegS i) = Refl
+lemmaAssocPos (S k) (NegS Z) (NegS i) = Refl
+lemmaAssocPos (S k) (NegS (S j)) (NegS i) = let ind = lemmaAssocPos (assert_smaller (S k) k) (assert_smaller (NegS (S j)) (NegS j)) (NegS i) in
+                                            rewrite ind in Refl
+
+plusAssociativeZ : (l, c, r : ZZ) -> l + (c + r) = (l + c) + r
+plusAssociativeZ (Pos k) c r = lemmaAssocPos k c r
+plusAssociativeZ (NegS k) c r = rewrite sym $ doubleNegElim c in
+                                rewrite sym $ doubleNegElim r in
+                                lemmaAssocNegation k (negate c) (negate r) (lemmaAssocPos (S k) (negate c) (negate r))
+
+lemmaMinusSymmZero : (k : Nat) -> minusNatZ k k = Pos 0
+lemmaMinusSymmZero Z = Refl
+lemmaMinusSymmZero (S k) = let ind = lemmaMinusSymmZero k in
+                           rewrite ind in Refl
+
+plusNegateInverseLZ : (a : ZZ) -> a + negate a = Pos Z
+plusNegateInverseLZ (Pos Z) = Refl
+plusNegateInverseLZ (Pos (S k)) = rewrite lemmaMinusSymmZero k in Refl
+plusNegateInverseLZ (NegS k) = rewrite lemmaMinusSymmZero k in Refl
+
+plusNegateInverseRZ : (a : ZZ) -> negate a + a = Pos Z
+plusNegateInverseRZ (Pos Z) = Refl
+plusNegateInverseRZ (Pos (S k)) = rewrite lemmaMinusSymmZero k in Refl
+plusNegateInverseRZ (NegS k) = rewrite lemmaMinusSymmZero k in Refl
+
+-- Mult
+multZeroLeftZeroZ : (right : ZZ) -> (Pos Z) * right = (Pos Z)
+multZeroLeftZeroZ (Pos k) = Refl
+multZeroLeftZeroZ (NegS k) = Refl
+
+multZeroRightZeroZ : (left : ZZ) -> left * (Pos Z) = (Pos Z)
+multZeroRightZeroZ (Pos k) = rewrite multZeroRightZero k in Refl
+multZeroRightZeroZ (NegS k) = rewrite multZeroRightZero k in Refl
+
+multOneLeftNeutralZ : (right : ZZ) -> 1 * right = right
+multOneLeftNeutralZ (Pos k) = rewrite plusZeroRightNeutral k in Refl
+multOneLeftNeutralZ (NegS k) = rewrite plusZeroRightNeutral k in Refl
+
+multOneRightNeutralZ : (left : ZZ) -> left * 1 = left
+multOneRightNeutralZ (Pos Z) = Refl
+multOneRightNeutralZ (Pos (S k)) = cong $ multOneRightNeutral (S k)
+multOneRightNeutralZ (NegS k) = cong $ multOneRightNeutral k
+
+multCommutativeZ : (left : ZZ) -> (right : ZZ) -> (left * right = right * left)
+multCommutativeZ (Pos k) (Pos j) = cong $ multCommutative k j
+multCommutativeZ (Pos k) (NegS j) = rewrite multCommutative j k in
+                                    cong $ multRightSuccPlus k j
+multCommutativeZ (NegS k) (Pos j) = rewrite multCommutative j (S k) in Refl
+multCommutativeZ (NegS k) (NegS j) = cong $ multCommutative (S k) (S j)
+
+lemmaPosMultNegNat : (k, j : Nat) -> multZ (Pos k) (negNat j) = negNat (mult k j)
+lemmaPosMultNegNat k Z = rewrite multZeroRightZero k in Refl
+lemmaPosMultNegNat k (S j) = Refl
+
+lemmaNegMultNegNat : (k, j : Nat) -> multZ (NegS k) (negNat j) = multZ (Pos (S k)) (Pos j)
+lemmaNegMultNegNat k Z = rewrite multZeroRightZero k in Refl
+lemmaNegMultNegNat k (S j) = Refl
+
+lemmaNegatePosNegNat : (k : Nat) -> negate (Pos k) = negNat k
+lemmaNegatePosNegNat Z = Refl
+lemmaNegatePosNegNat (S k) = Refl
+
+multNegLeftZ : (k : Nat) -> (j : ZZ) -> (NegS k) * j = negate (Pos (S k) * j)
+multNegLeftZ k (Pos j) = rewrite lemmaNegatePosNegNat ((S k) * j) in Refl
+multNegLeftZ k (NegS j) = Refl
+
+multNegateLeftZ : (k, j : ZZ) -> (negate k) * j = negate (k * j)
+multNegateLeftZ (Pos Z) j = rewrite multZeroLeftZeroZ j in Refl
+multNegateLeftZ (Pos (S k)) (Pos j) = rewrite lemmaNegatePosNegNat ((S k) * j) in Refl
+multNegateLeftZ (Pos (S k)) (NegS j) = Refl
+multNegateLeftZ (NegS k) j = rewrite sym $ doubleNegElim (multZ (Pos (S k)) j) in
+                             rewrite multNegLeftZ k j in Refl
+
+multAssociativeZPos : (k : Nat) -> (c, r : ZZ) -> (Pos k) * (c * r) = ((Pos k) * c) * r
+multAssociativeZPos k (Pos j) (Pos i) = cong $ multAssociative k j i
+multAssociativeZPos k (Pos j) (NegS i) = rewrite sym $ multAssociative k j (S i) in lemmaPosMultNegNat k (mult j (S i))
+multAssociativeZPos k (NegS j) (Pos i) = rewrite multCommutative j i in
+                                         rewrite sym $ multRightSuccPlus i j in
+                                         rewrite lemmaPosMultNegNat k (mult i (S j)) in
+                                         rewrite multCommutativeZ (negNat (mult k (S j))) (Pos i) in
+                                         rewrite lemmaPosMultNegNat i (mult k (S j)) in
+                                         rewrite multAssociative k i (S j) in
+                                         rewrite multAssociative i k (S j) in
+                                         rewrite multCommutative i k in Refl
+multAssociativeZPos k (NegS j) (NegS i) = rewrite multCommutativeZ (negNat (mult k (S j))) (NegS i) in
+                                          rewrite lemmaNegMultNegNat i (mult k (S j)) in
+                                          rewrite multAssociative k (S j) (S i) in
+                                          rewrite multCommutative (mult k (S j)) (S i) in Refl
+
+multAssociativeZ : (l, c, r : ZZ) -> l * (c * r) = (l * c) * r
+multAssociativeZ (Pos k) c r = multAssociativeZPos k c r
+multAssociativeZ (NegS k) c r = rewrite multNegLeftZ k (c * r) in
+                                rewrite multNegLeftZ k c in
+                                rewrite multNegateLeftZ (multZ (Pos (S k)) c) r in
+                                cong $ multAssociativeZPos (S k) c r
+
+lemmaPlusPosNegCancel : (k, j, i : Nat) -> plusZ (Pos (plus k j)) (negNat (plus k i)) = plusZ (Pos j) (negNat i)
+lemmaPlusPosNegCancel Z j i = Refl
+lemmaPlusPosNegCancel (S Z) j Z = rewrite plusZeroRightNeutral j in Refl
+lemmaPlusPosNegCancel (S Z) j (S i) = Refl
+lemmaPlusPosNegCancel (S (S k)) j i = lemmaPlusPosNegCancel (S k) j i
+
+lemmaPlusPosNegZero : (k : Nat) -> plusZ (Pos k) (negNat k) = Pos Z
+lemmaPlusPosNegZero Z = Refl
+lemmaPlusPosNegZero (S k) = rewrite lemmaMinusSymmZero k in Refl
+
+negNatDistributesPlus : (j, k : Nat) -> plusZ (negNat j) (negNat k) = negNat (plus j k)
+negNatDistributesPlus Z k = rewrite plusZeroLeftNeutralZ (negNat k) in Refl
+negNatDistributesPlus (S j) Z = rewrite plusZeroRightNeutral j in Refl
+negNatDistributesPlus (S j) (S k) = rewrite plusSuccRightSucc j k in Refl
+
+-- Distributivity
+
+multDistributesOverPlusRightPosPosZ : (l, c : Nat) -> (r : ZZ) -> (Pos l) * ((Pos c) + r) = ((Pos l) * (Pos c)) + ((Pos l) * r)
+multDistributesOverPlusRightPosPosZ l c (Pos i) = rewrite multDistributesOverPlusRight l c i in Refl
+multDistributesOverPlusRightPosPosZ l Z (NegS i) = rewrite multZeroRightZero l in
+                                                   rewrite plusZeroLeftNeutralZ (negNat (mult l (S i))) in Refl
+multDistributesOverPlusRightPosPosZ l (S c) (NegS Z) = rewrite multOneRightNeutral l in
+                                                       rewrite multRightSuccPlus l c in
+                                                       rewrite sym $ plusAssociativeZ (Pos l) (Pos (mult l c)) (negNat l) in
+                                                       rewrite plusCommutativeZ (Pos (mult l c)) (negNat l) in
+                                                       rewrite plusAssociativeZ (Pos l) (negNat l) (Pos (mult l c)) in
+                                                       rewrite lemmaPlusPosNegZero l in Refl
+multDistributesOverPlusRightPosPosZ l (S c) (NegS (S i)) = let ind = multDistributesOverPlusRightPosPosZ l (assert_smaller (S c) c) (assert_smaller (NegS (S i)) (NegS i)) in
+                                                           rewrite ind in
+                                                           rewrite multRightSuccPlus l (S i) in
+                                                           rewrite multRightSuccPlus l c in
+                                                           rewrite lemmaPlusPosNegCancel l (mult l c) (mult l (S i)) in Refl
+
+multDistributesOverPlusRightPosZ : (k : Nat) -> (c, r : ZZ) -> (Pos k) * (c + r) = ((Pos k) * c) + ((Pos k) * r)
+multDistributesOverPlusRightPosZ k (Pos j) r = multDistributesOverPlusRightPosPosZ k j r
+multDistributesOverPlusRightPosZ k (NegS j) (Pos i) = rewrite plusCommutativeZ ((Pos k) * (NegS j)) ((Pos k) * (Pos i)) in
+                                                      rewrite multDistributesOverPlusRightPosPosZ k i (NegS j) in Refl
+multDistributesOverPlusRightPosZ k (NegS j) (NegS i) = rewrite negNatDistributesPlus (mult k (S j)) (mult k (S i)) in
+                                                       rewrite sym $ multDistributesOverPlusRight k (S j) (S i) in
+                                                       rewrite plusSuccRightSucc j i in Refl
+
+multDistributesOverPlusRightZ : (l, c, r : ZZ) -> l * (c + r) = (l * c) + (l * r)
+multDistributesOverPlusRightZ (Pos k) c r = multDistributesOverPlusRightPosZ k c r
+multDistributesOverPlusRightZ (NegS k) c r = rewrite multNegLeftZ k (plusZ c r) in
+                                             rewrite multNegLeftZ k c in
+                                             rewrite multNegLeftZ k r in
+                                             rewrite sym $ negateDistributesPlus (multZ (Pos (S k)) c) (multZ (Pos (S k)) r) in
+                                             rewrite multDistributesOverPlusRightPosZ (S k) c r in Refl
+
+multDistributesOverPlusLeftZ : (l, c, r : ZZ) -> (l + c) * r = (l * r) + (c * r)
+multDistributesOverPlusLeftZ l c r = rewrite multCommutativeZ (l + c) r in
+                                     rewrite multDistributesOverPlusRightZ r l c in
+                                     rewrite multCommutativeZ r l in
+                                     rewrite multCommutativeZ r c in Refl
diff --git a/libs/contrib/Interfaces/Verified.idr b/libs/contrib/Interfaces/Verified.idr
--- a/libs/contrib/Interfaces/Verified.idr
+++ b/libs/contrib/Interfaces/Verified.idr
@@ -36,7 +36,7 @@
                                  mx >>= \x =>
                                         pure (f x)
   monadLeftIdentity : (x : a) -> (f : a -> m b) -> pure x >>= f = f x
-  monadRightIdentity : (mx : m a) -> mx >>= pure = mx
+  monadRightIdentity : (mx : m a) -> mx >>= Applicative.pure = mx
   monadAssociativity : (mx : m a) -> (f : a -> m b) -> (g : b -> m c) ->
                        (mx >>= f) >>= g = mx >>= (\x => f x >>= g)
 
diff --git a/libs/contrib/Network/Socket.idr b/libs/contrib/Network/Socket.idr
--- a/libs/contrib/Network/Socket.idr
+++ b/libs/contrib/Network/Socket.idr
@@ -4,210 +4,20 @@
 ||| Modified (C) The Idris Community, 2015, 2016
 module Network.Socket
 
+import public Network.Socket.Data
+import Network.Socket.Raw
+
 %include C "idris_net.h"
 %include C "sys/types.h"
 %include C "sys/socket.h"
 %include C "netdb.h"
 
--- ------------------------------------------------------------ [ Type Aliases ]
-
-public export
-ByteLength : Type
-ByteLength = Int
-
-public export
-ResultCode : Type
-ResultCode = Int
-
-||| Protocol Number.
-|||
-||| Generally good enough to just set it to 0.
-public export
-ProtocolNumber : Type
-ProtocolNumber = Int
-
-||| SocketError: Error thrown by a socket operation
-public export
-SocketError : Type
-SocketError = Int
-
-||| SocketDescriptor: Native C Socket Descriptor
-public export
-SocketDescriptor : Type
-SocketDescriptor = Int
-
-public export
-Port : Type
-Port = Int
-
--- --------------------------------------------------------------- [ Constants ]
-
-||| Backlog used within listen() call -- number of incoming calls
-public export
-BACKLOG : Int
-BACKLOG = 20
-
--- FIXME: This *must* be pulled in from C
-public export
-EAGAIN : Int
-EAGAIN = 11
-
--- -------------------------------------------------------------- [ Interfaces ]
-
-export
-interface ToCode a where
-  toCode : a -> Int
-
--- --------------------------------------------------------- [ Socket Families ]
-
-||| Socket Families
-|||
-||| The ones that people might actually use. We're not going to need US
-||| Government proprietary ones.
-public export
-data SocketFamily : Type where
-  ||| Unspecified
-  AF_UNSPEC : SocketFamily
-
-  ||| IP / UDP etc. IPv4
-  AF_INET : SocketFamily
-
-  |||  IP / UDP etc. IPv6
-  AF_INET6 : SocketFamily
-
-export
-Show SocketFamily where
-  show AF_UNSPEC = "AF_UNSPEC"
-  show AF_INET   = "AF_INET"
-  show AF_INET6  = "AF_INET6"
-
-export
-ToCode SocketFamily where
-  toCode AF_UNSPEC = 0
-  toCode AF_INET   = 2
-  toCode AF_INET6  = 10
-
-getSocketFamily : Int -> Maybe SocketFamily
-getSocketFamily i =
-    Prelude.List.lookup i [ (0, AF_UNSPEC)
-                          , (2, AF_INET)
-                          , (10, AF_INET6)
-                          ]
-
--- ------------------------------------------------------------ [ Socket Types ]
-||| Socket Types.
-public export
-data SocketType : Type where
-  ||| Not a socket, used in certain operations
-  NotASocket : SocketType
-
-  ||| TCP
-  Stream : SocketType
-
-  ||| UDP
-  Datagram : SocketType
-
-  ||| Raw sockets
-  RawSocket : SocketType
-
-export
-Show SocketType where
-  show NotASocket = "Not a socket"
-  show Stream     = "Stream"
-  show Datagram   = "Datagram"
-  show RawSocket  = "Raw"
-
-export
-ToCode SocketType where
-  toCode NotASocket = 0
-  toCode Stream     = 1
-  toCode Datagram   = 2
-  toCode RawSocket  = 3
-
--- ---------------------------------------------------------------- [ Pointers ]
-
-data RecvStructPtr = RSPtr Ptr
-data RecvfromStructPtr = RFPtr Ptr
-
-export
-data BufPtr = BPtr Ptr
-
-export
-data SockaddrPtr = SAPtr Ptr
-
--- --------------------------------------------------------------- [ Addresses ]
-
-||| Network Addresses
-public export
-data SocketAddress : Type where
-  IPv4Addr : Int -> Int -> Int -> Int -> SocketAddress
-
-  ||| Not implemented (yet)
-  IPv6Addr : SocketAddress
-
-  Hostname : String -> SocketAddress
-
-  ||| Used when there's a parse error
-  InvalidAddress : SocketAddress
-
-export
-Show SocketAddress where
-  show (IPv4Addr i1 i2 i3 i4) = concat $ Prelude.List.intersperse "." (map show [i1, i2, i3, i4])
-  show IPv6Addr               = "NOT IMPLEMENTED YET"
-  show (Hostname host)        = host
-  show InvalidAddress         = "Invalid"
-
--- --------------------------------------------------------- [ UDP Information ]
-
--- TODO: Expand to non-string payloads
-export
-record UDPRecvData where
-  constructor MkUDPRecvData
-  remote_addr : SocketAddress
-  remote_port : Port
-  recv_data   : String
-  data_len    : Int
-
-export
-record UDPAddrInfo where
-  constructor MkUDPAddrInfo
-  remote_addr : SocketAddress
-  remote_port : Port
-
--- ---------------------------------------------------------- [ Socket Utilies ]
-
-||| Frees a given pointer
-export
-sock_free : BufPtr -> IO ()
-sock_free (BPtr ptr) = foreign FFI_C "idrnet_free" (Ptr -> IO ()) ptr
-
-export
-sockaddr_free : SockaddrPtr -> IO ()
-sockaddr_free (SAPtr ptr) = foreign FFI_C "idrnet_free" (Ptr -> IO ()) ptr
-
-||| Allocates an amount of memory given by the ByteLength parameter.
-|||
-||| Used to allocate a mutable pointer to be given to the Recv functions.
-export
-sock_alloc : ByteLength -> IO BufPtr
-sock_alloc bl = map BPtr $ foreign FFI_C "idrnet_malloc" (Int -> IO Ptr) bl
-
--- ----------------------------------------------------------------- [ Sockets ]
-||| The metadata about a socket
-export
-record Socket where
-  constructor MkSocket
-  descriptor     : SocketDescriptor
-  family         : SocketFamily
-  socketType     : SocketType
-  protocolNumber : ProtocolNumber
-
+%access export
 
 -- ----------------------------------------------------- [ Network Socket API. ]
 
 ||| Creates a UNIX socket with the given family, socket type and protocol
 ||| number. Returns either a socket or an error.
-export
 socket : (fam  : SocketFamily)
       -> (ty   : SocketType)
       -> (pnum : ProtocolNumber)
@@ -222,34 +32,30 @@
     else pure $ Right (MkSocket socket_res sf st pn)
 
 ||| Close a socket
-export
 close : Socket -> IO ()
 close sock = foreign FFI_C "close" (Int -> IO ()) (descriptor sock)
 
-private
-saString : (Maybe SocketAddress) -> String
-saString (Just sa) = show sa
-saString Nothing = ""
-
 ||| Binds a socket to the given socket address and port.
 ||| Returns 0 on success, an error code otherwise.
-export
 bind : (sock : Socket)
     -> (addr : Maybe SocketAddress)
     -> (port : Port)
     -> IO Int
 bind sock addr port = do
-  bind_res <- foreign FFI_C "idrnet_bind"
-                  (Int -> Int -> Int -> String -> Int -> IO Int)
-                  (descriptor sock) (toCode $ family sock)
-                  (toCode $ socketType sock) (saString addr) port
-  if bind_res == (-1)
-    then getErrno
-    else pure 0
+    bind_res <- foreign FFI_C "idrnet_bind"
+                    (Int -> Int -> Int -> String -> Int -> IO Int)
+                    (descriptor sock) (toCode $ family sock)
+                    (toCode $ socketType sock) (saString addr) port
+    if bind_res == (-1)
+      then getErrno
+      else pure 0
+  where
+    saString : Maybe SocketAddress -> String
+    saString (Just sa) = show sa
+    saString Nothing   = ""
 
 ||| Connects to a given address and port.
 ||| Returns 0 on success, and an error number on error.
-export
 connect : (sock : Socket)
        -> (addr : SocketAddress)
        -> (port : Port)
@@ -266,7 +72,6 @@
 ||| Listens on a bound socket.
 |||
 ||| @sock The socket to listen on.
-export
 listen : (sock : Socket) -> IO Int
 listen sock = do
   listen_res <- foreign FFI_C "listen" (Int -> Int -> IO Int)
@@ -275,40 +80,6 @@
     then getErrno
     else pure 0
 
-||| Parses a textual representation of an IPv4 address into a SocketAddress
-parseIPv4 : String -> SocketAddress
-parseIPv4 str =
-    case splitted of
-      (i1 :: i2 :: i3 :: i4 :: _) => IPv4Addr i1 i2 i3 i4
-      otherwise                   => InvalidAddress
-  where
-    toInt' : String -> Integer
-    toInt' = cast
-
-    toInt : String -> Int
-    toInt s = fromInteger $ toInt' s
-
-    splitted : List Int
-    splitted = map toInt (Prelude.Strings.split (\c => c == '.') str)
-
-||| Retrieves a socket address from a sockaddr pointer
-getSockAddr : SockaddrPtr -> IO SocketAddress
-getSockAddr (SAPtr ptr) = do
-  addr_family_int <- foreign FFI_C "idrnet_sockaddr_family"
-                             (Ptr -> IO Int)
-                             ptr
-
-  -- ASSUMPTION: Foreign call returns a valid int
-  assert_total (case getSocketFamily addr_family_int of
-    Just AF_INET => do
-      ipv4_addr <- foreign FFI_C "idrnet_sockaddr_ipv4"
-                           (Ptr -> IO String)
-                           ptr
-
-      pure $ parseIPv4 ipv4_addr
-    Just AF_INET6 => pure IPv6Addr
-    Just AF_UNSPEC => pure InvalidAddress)
-
 ||| Accept a connection on the provided socket.
 |||
 ||| Returns on failure a `SocketError`
@@ -317,7 +88,6 @@
 ||| + `SocketAddress` :: The
 |||
 ||| @sock The socket used to establish connection.
-export
 accept : (sock : Socket)
       -> IO (Either SocketError (Socket, SocketAddress))
 accept sock = do
@@ -346,7 +116,6 @@
 |||
 ||| @sock The socket on which to send the message.
 ||| @msg  The data to send.
-export
 send : (sock : Socket)
     -> (msg  : String)
     -> IO (Either SocketError ResultCode)
@@ -359,20 +128,6 @@
     then map Left getErrno
     else pure $ Right send_res
 
-freeRecvStruct : RecvStructPtr -> IO ()
-freeRecvStruct (RSPtr p) =
-    foreign FFI_C "idrnet_free_recv_struct"
-            (Ptr -> IO ())
-            p
-
-||| Utility to extract data.
-freeRecvfromStruct : RecvfromStructPtr -> IO ()
-freeRecvfromStruct (RFPtr p) =
-    foreign FFI_C "idrnet_free_recvfrom_struct"
-            (Ptr -> IO ())
-            p
-
-
 ||| Receive data on the specified socket.
 |||
 ||| Returns on failure a `SocketError`
@@ -382,7 +137,6 @@
 |||
 ||| @sock The socket on which to receive the message.
 ||| @len  How much of the data to send.
-export
 recv : (sock : Socket)
     -> (len : ByteLength)
     -> IO (Either SocketError (String, ResultCode))
@@ -413,48 +167,6 @@
            freeRecvStruct (RSPtr recv_struct_ptr)
            pure $ Right (payload, recv_res)
 
-||| Sends the data in a given memory location
-|||
-||| Returns on failure a `SocketError`
-||| Returns on success the `ResultCode`
-|||
-||| @sock The socket on which to send the message.
-||| @ptr  The location containing the data to send.
-||| @len  How much of the data to send.
-sendBuf : (sock : Socket)
-       -> (ptr  : BufPtr)
-       -> (len  : ByteLength)
-       -> IO (Either SocketError ResultCode)
-sendBuf sock (BPtr ptr) len = do
-  send_res <- foreign FFI_C "idrnet_send_buf"
-                      (Int -> Ptr -> Int -> IO Int)
-                      (descriptor sock) ptr len
-
-  if send_res == (-1)
-   then map Left getErrno
-   else pure $ Right send_res
-
-||| Receive data from a given memory location.
-|||
-||| Returns on failure a `SocketError`
-||| Returns on success the `ResultCode`
-|||
-||| @sock The socket on which to receive the message.
-||| @ptr  The location containing the data to receive.
-||| @len  How much of the data to receive.
-recvBuf : (sock : Socket)
-       -> (ptr  : BufPtr)
-       -> (len  : ByteLength)
-       -> IO (Either SocketError ResultCode)
-recvBuf sock (BPtr ptr) len = do
-  recv_res <- foreign FFI_C "idrnet_recv_buf"
-                      (Int -> Ptr -> Int -> IO Int)
-                      (descriptor sock) ptr len
-
-  if (recv_res == (-1))
-    then map Left getErrno
-    else pure $ Right recv_res
-
 ||| Send a message.
 |||
 ||| Returns on failure a `SocketError`
@@ -464,7 +176,6 @@
 ||| @addr Address of the recipient.
 ||| @port The port on which to send the message.
 ||| @msg  The message to send.
-export
 sendTo : (sock : Socket)
       -> (addr : SocketAddress)
       -> (port : Port)
@@ -479,58 +190,6 @@
     then map Left getErrno
     else pure $ Right sendto_res
 
-||| Send a message stored in some buffer.
-|||
-||| Returns on failure a `SocketError`
-||| Returns on success the `ResultCode`
-|||
-||| @sock The socket on which to send the message.
-||| @addr Address of the recipient.
-||| @port The port on which to send the message.
-||| @ptr  A Pointer to the buffer containing the message.
-||| @len  The size of the message.
-sendToBuf : (sock : Socket)
-         -> (addr : SocketAddress)
-         -> (port : Port)
-         -> (ptr  : BufPtr)
-         -> (len  : ByteLength)
-         -> IO (Either SocketError ResultCode)
-sendToBuf sock addr p (BPtr dat) len = do
-  sendto_res <- foreign FFI_C "idrnet_sendto_buf"
-                   (Int -> Ptr -> Int -> String -> Int -> Int -> IO Int)
-                   (descriptor sock) dat len (show addr) p (toCode $ family sock)
-
-  if sendto_res == (-1)
-    then map Left getErrno
-    else pure $ Right sendto_res
-
-||| Utility function to get the payload of the sent message as a `String`.
-foreignGetRecvfromPayload : RecvfromStructPtr -> IO String
-foreignGetRecvfromPayload (RFPtr p) =
-  foreign FFI_C "idrnet_get_recvfrom_payload"
-                (Ptr -> IO String)
-                p
-
-||| Utility function to return senders socket address.
-foreignGetRecvfromAddr : RecvfromStructPtr -> IO SocketAddress
-foreignGetRecvfromAddr (RFPtr p) = do
-  sockaddr_ptr <- map SAPtr $ foreign FFI_C "idrnet_get_recvfrom_sockaddr"
-                                      (Ptr -> IO Ptr)
-                                      p
-  getSockAddr sockaddr_ptr
-
-||| Utility function to return sender's IPV4 port.
-foreignGetRecvfromPort : RecvfromStructPtr -> IO Port
-foreignGetRecvfromPort (RFPtr p) = do
-  sockaddr_ptr <- foreign FFI_C "idrnet_get_recvfrom_sockaddr"
-                          (Ptr -> IO Ptr)
-                          p
-  port         <- foreign FFI_C "idrnet_sockaddr_ipv4_port"
-                          (Ptr -> IO Int)
-                          sockaddr_ptr
-  pure port
-
-
 ||| Receive a message.
 |||
 ||| Returns on failure a `SocketError`.
@@ -542,7 +201,6 @@
 ||| @sock The channel on which to receive.
 ||| @len  Size of the expected message.
 |||
-export
 recvFrom : (sock : Socket)
         -> (len  : ByteLength)
         -> IO (Either SocketError (UDPAddrInfo, String, ResultCode))
@@ -570,42 +228,3 @@
           freeRecvfromStruct recv_ptr'
           pure $ Right (MkUDPAddrInfo addr port, payload, result)
 
-||| Receive a message placed on a 'known' buffer.
-|||
-||| Returns on failure a `SocketError`.
-||| Returns on success a pair of
-||| + `UDPAddrInfo` :: The address of the sender.
-||| + `Int`         :: Result value from underlying function.
-|||
-||| @sock The channel on which to receive.
-||| @ptr  Pointer to the buffer to place the message.
-||| @len  Size of the expected message.
-|||
-recvFromBuf : (sock : Socket)
-           -> (ptr  : BufPtr)
-           -> (len  : ByteLength)
-           -> IO (Either SocketError (UDPAddrInfo, ResultCode))
-recvFromBuf sock (BPtr ptr) bl = do
-  recv_ptr <- foreign FFI_C "idrnet_recvfrom_buf"
-                      (Int -> Ptr -> Int -> IO Ptr)
-                      (descriptor sock) ptr bl
-
-  let recv_ptr' = RFPtr recv_ptr
-
-  if !(nullPtr recv_ptr)
-    then map Left getErrno
-    else do
-      result <- foreign FFI_C "idrnet_get_recvfrom_res"
-                        (Ptr -> IO Int)
-                        recv_ptr
-      if result == -1
-        then do
-          freeRecvfromStruct recv_ptr'
-          map Left getErrno
-        else do
-          port <- foreignGetRecvfromPort recv_ptr'
-          addr <- foreignGetRecvfromAddr recv_ptr'
-          freeRecvfromStruct recv_ptr'
-          pure $ Right (MkUDPAddrInfo addr port, result + 1)
-
--- --------------------------------------------------------------------- [ EOF ]
diff --git a/libs/contrib/Network/Socket/Data.idr b/libs/contrib/Network/Socket/Data.idr
new file mode 100644
--- /dev/null
+++ b/libs/contrib/Network/Socket/Data.idr
@@ -0,0 +1,172 @@
+||| Low-Level C Sockets bindings for Idris. Used by higher-level, cleverer things.
+||| Types used by Network.Socket.Raw and Network.Socket.
+|||
+||| Original (C) SimonJF, MIT Licensed, 2014
+||| Modified (C) The Idris Community, 2015, 2016
+module Network.Socket.Data
+
+%access public export
+
+-- ------------------------------------------------------------ [ Type Aliases ]
+
+ByteLength : Type
+ByteLength = Int
+
+ResultCode : Type
+ResultCode = Int
+
+||| Protocol Number.
+|||
+||| Generally good enough to just set it to 0.
+ProtocolNumber : Type
+ProtocolNumber = Int
+
+||| SocketError: Error thrown by a socket operation
+SocketError : Type
+SocketError = Int
+
+||| SocketDescriptor: Native C Socket Descriptor
+SocketDescriptor : Type
+SocketDescriptor = Int
+
+Port : Type
+Port = Int
+
+-- --------------------------------------------------------------- [ Constants ]
+
+||| Backlog used within listen() call -- number of incoming calls
+BACKLOG : Int
+BACKLOG = 20
+
+EAGAIN : Int
+EAGAIN =
+  -- I'm sorry
+  -- maybe
+  unsafePerformIO $ foreign FFI_C "idrnet_geteagain" (() -> IO Int) ()
+
+-- -------------------------------------------------------------- [ Interfaces ]
+
+interface ToCode a where
+  toCode : a -> Int
+
+-- --------------------------------------------------------- [ Socket Families ]
+
+||| Socket Families
+|||
+||| The ones that people might actually use. We're not going to need US
+||| Government proprietary ones.
+data SocketFamily : Type where
+  ||| Unspecified
+  AF_UNSPEC : SocketFamily
+
+  ||| IP / UDP etc. IPv4
+  AF_INET : SocketFamily
+
+  |||  IP / UDP etc. IPv6
+  AF_INET6 : SocketFamily
+
+Show SocketFamily where
+  show AF_UNSPEC = "AF_UNSPEC"
+  show AF_INET   = "AF_INET"
+  show AF_INET6  = "AF_INET6"
+
+ToCode SocketFamily where
+  toCode AF_UNSPEC = 0
+  toCode AF_INET   = 2
+  toCode AF_INET6  = 10
+
+getSocketFamily : Int -> Maybe SocketFamily
+getSocketFamily i =
+    Prelude.List.lookup i [ (0, AF_UNSPEC)
+                          , (2, AF_INET)
+                          , (10, AF_INET6)
+                          ]
+
+-- ------------------------------------------------------------ [ Socket Types ]
+
+||| Socket Types.
+data SocketType : Type where
+  ||| Not a socket, used in certain operations
+  NotASocket : SocketType
+
+  ||| TCP
+  Stream : SocketType
+
+  ||| UDP
+  Datagram : SocketType
+
+  ||| Raw sockets
+  RawSocket : SocketType
+
+Show SocketType where
+  show NotASocket = "Not a socket"
+  show Stream     = "Stream"
+  show Datagram   = "Datagram"
+  show RawSocket  = "Raw"
+
+ToCode SocketType where
+  toCode NotASocket = 0
+  toCode Stream     = 1
+  toCode Datagram   = 2
+  toCode RawSocket  = 3
+
+-- --------------------------------------------------------------- [ Addresses ]
+
+||| Network Addresses
+data SocketAddress : Type where
+  IPv4Addr : Int -> Int -> Int -> Int -> SocketAddress
+
+  ||| Not implemented (yet)
+  IPv6Addr : SocketAddress
+
+  Hostname : String -> SocketAddress
+
+  ||| Used when there's a parse error
+  InvalidAddress : SocketAddress
+
+Show SocketAddress where
+  show (IPv4Addr i1 i2 i3 i4) = concat $ Prelude.List.intersperse "." (map show [i1, i2, i3, i4])
+  show IPv6Addr               = "NOT IMPLEMENTED YET"
+  show (Hostname host)        = host
+  show InvalidAddress         = "Invalid"
+
+||| Parses a textual representation of an IPv4 address into a SocketAddress
+parseIPv4 : String -> SocketAddress
+parseIPv4 str =
+    case splitted of
+      (i1 :: i2 :: i3 :: i4 :: _) => IPv4Addr i1 i2 i3 i4
+      otherwise                   => InvalidAddress
+  where
+    toInt' : String -> Integer
+    toInt' = cast
+
+    toInt : String -> Int
+    toInt s = fromInteger $ toInt' s
+
+    splitted : List Int
+    splitted = map toInt (Prelude.Strings.split (\c => c == '.') str)
+
+-- --------------------------------------------------------- [ UDP Information ]
+
+-- TODO: Expand to non-string payloads
+record UDPRecvData where
+  constructor MkUDPRecvData
+  remote_addr : SocketAddress
+  remote_port : Port
+  recv_data   : String
+  data_len    : Int
+
+record UDPAddrInfo where
+  constructor MkUDPAddrInfo
+  remote_addr : SocketAddress
+  remote_port : Port
+
+-- ----------------------------------------------------------------- [ Sockets ]
+||| The metadata about a socket
+record Socket where
+  constructor MkSocket
+  descriptor     : SocketDescriptor
+  family         : SocketFamily
+  socketType     : SocketType
+  protocolNumber : ProtocolNumber
+
diff --git a/libs/contrib/Network/Socket/Raw.idr b/libs/contrib/Network/Socket/Raw.idr
new file mode 100644
--- /dev/null
+++ b/libs/contrib/Network/Socket/Raw.idr
@@ -0,0 +1,202 @@
+||| Low-Level C Sockets bindings for Idris. Used by higher-level, cleverer things.
+||| Type-unsafe parts. Use Network.Socket for a safe variant.
+|||
+||| Original (C) SimonJF, MIT Licensed, 2014
+||| Modified (C) The Idris Community, 2015, 2016
+module Network.Socket.Raw
+
+import public Network.Socket.Data
+
+%include C "idris_net.h"
+%include C "sys/types.h"
+%include C "sys/socket.h"
+%include C "netdb.h"
+
+%access public export
+
+-- ---------------------------------------------------------------- [ Pointers ]
+
+data RecvStructPtr     = RSPtr Ptr
+data RecvfromStructPtr = RFPtr Ptr
+
+data BufPtr = BPtr Ptr
+
+data SockaddrPtr = SAPtr Ptr
+
+-- ---------------------------------------------------------- [ Socket Utilies ]
+
+||| Frees a given pointer
+sock_free : BufPtr -> IO ()
+sock_free (BPtr ptr) = foreign FFI_C "idrnet_free" (Ptr -> IO ()) ptr
+
+sockaddr_free : SockaddrPtr -> IO ()
+sockaddr_free (SAPtr ptr) = foreign FFI_C "idrnet_free" (Ptr -> IO ()) ptr
+
+||| Allocates an amount of memory given by the ByteLength parameter.
+|||
+||| Used to allocate a mutable pointer to be given to the Recv functions.
+sock_alloc : ByteLength -> IO BufPtr
+sock_alloc bl = map BPtr $ foreign FFI_C "idrnet_malloc" (Int -> IO Ptr) bl
+
+||| Retrieves a socket address from a sockaddr pointer
+getSockAddr : SockaddrPtr -> IO SocketAddress
+getSockAddr (SAPtr ptr) = do
+  addr_family_int <- foreign FFI_C "idrnet_sockaddr_family"
+                             (Ptr -> IO Int)
+                             ptr
+
+  -- ASSUMPTION: Foreign call returns a valid int
+  assert_total (case getSocketFamily addr_family_int of
+    Just AF_INET => do
+      ipv4_addr <- foreign FFI_C "idrnet_sockaddr_ipv4"
+                           (Ptr -> IO String)
+                           ptr
+
+      pure $ parseIPv4 ipv4_addr
+    Just AF_INET6 => pure IPv6Addr
+    Just AF_UNSPEC => pure InvalidAddress)
+
+freeRecvStruct : RecvStructPtr -> IO ()
+freeRecvStruct (RSPtr p) =
+    foreign FFI_C "idrnet_free_recv_struct"
+            (Ptr -> IO ())
+            p
+
+||| Utility to extract data.
+freeRecvfromStruct : RecvfromStructPtr -> IO ()
+freeRecvfromStruct (RFPtr p) =
+    foreign FFI_C "idrnet_free_recvfrom_struct"
+            (Ptr -> IO ())
+            p
+
+||| Sends the data in a given memory location
+|||
+||| Returns on failure a `SocketError`
+||| Returns on success the `ResultCode`
+|||
+||| @sock The socket on which to send the message.
+||| @ptr  The location containing the data to send.
+||| @len  How much of the data to send.
+sendBuf : (sock : Socket)
+       -> (ptr  : BufPtr)
+       -> (len  : ByteLength)
+       -> IO (Either SocketError ResultCode)
+sendBuf sock (BPtr ptr) len = do
+  send_res <- foreign FFI_C "idrnet_send_buf"
+                      (Int -> Ptr -> Int -> IO Int)
+                      (descriptor sock) ptr len
+
+  if send_res == (-1)
+   then map Left getErrno
+   else pure $ Right send_res
+
+||| Receive data from a given memory location.
+|||
+||| Returns on failure a `SocketError`
+||| Returns on success the `ResultCode`
+|||
+||| @sock The socket on which to receive the message.
+||| @ptr  The location containing the data to receive.
+||| @len  How much of the data to receive.
+recvBuf : (sock : Socket)
+       -> (ptr  : BufPtr)
+       -> (len  : ByteLength)
+       -> IO (Either SocketError ResultCode)
+recvBuf sock (BPtr ptr) len = do
+  recv_res <- foreign FFI_C "idrnet_recv_buf"
+                      (Int -> Ptr -> Int -> IO Int)
+                      (descriptor sock) ptr len
+
+  if (recv_res == (-1))
+    then map Left getErrno
+    else pure $ Right recv_res
+
+||| Send a message stored in some buffer.
+|||
+||| Returns on failure a `SocketError`
+||| Returns on success the `ResultCode`
+|||
+||| @sock The socket on which to send the message.
+||| @addr Address of the recipient.
+||| @port The port on which to send the message.
+||| @ptr  A Pointer to the buffer containing the message.
+||| @len  The size of the message.
+sendToBuf : (sock : Socket)
+         -> (addr : SocketAddress)
+         -> (port : Port)
+         -> (ptr  : BufPtr)
+         -> (len  : ByteLength)
+         -> IO (Either SocketError ResultCode)
+sendToBuf sock addr p (BPtr dat) len = do
+  sendto_res <- foreign FFI_C "idrnet_sendto_buf"
+                   (Int -> Ptr -> Int -> String -> Int -> Int -> IO Int)
+                   (descriptor sock) dat len (show addr) p (toCode $ family sock)
+
+  if sendto_res == (-1)
+    then map Left getErrno
+    else pure $ Right sendto_res
+
+||| Utility function to get the payload of the sent message as a `String`.
+foreignGetRecvfromPayload : RecvfromStructPtr -> IO String
+foreignGetRecvfromPayload (RFPtr p) =
+  foreign FFI_C "idrnet_get_recvfrom_payload"
+                (Ptr -> IO String)
+                p
+
+||| Utility function to return senders socket address.
+foreignGetRecvfromAddr : RecvfromStructPtr -> IO SocketAddress
+foreignGetRecvfromAddr (RFPtr p) = do
+  sockaddr_ptr <- map SAPtr $ foreign FFI_C "idrnet_get_recvfrom_sockaddr"
+                                      (Ptr -> IO Ptr)
+                                      p
+  getSockAddr sockaddr_ptr
+
+||| Utility function to return sender's IPV4 port.
+foreignGetRecvfromPort : RecvfromStructPtr -> IO Port
+foreignGetRecvfromPort (RFPtr p) = do
+  sockaddr_ptr <- foreign FFI_C "idrnet_get_recvfrom_sockaddr"
+                          (Ptr -> IO Ptr)
+                          p
+  port         <- foreign FFI_C "idrnet_sockaddr_ipv4_port"
+                          (Ptr -> IO Int)
+                          sockaddr_ptr
+  pure port
+
+||| Receive a message placed on a 'known' buffer.
+|||
+||| Returns on failure a `SocketError`.
+||| Returns on success a pair of
+||| + `UDPAddrInfo` :: The address of the sender.
+||| + `Int`         :: Result value from underlying function.
+|||
+||| @sock The channel on which to receive.
+||| @ptr  Pointer to the buffer to place the message.
+||| @len  Size of the expected message.
+|||
+recvFromBuf : (sock : Socket)
+           -> (ptr  : BufPtr)
+           -> (len  : ByteLength)
+           -> IO (Either SocketError (UDPAddrInfo, ResultCode))
+recvFromBuf sock (BPtr ptr) bl = do
+  recv_ptr <- foreign FFI_C "idrnet_recvfrom_buf"
+                      (Int -> Ptr -> Int -> IO Ptr)
+                      (descriptor sock) ptr bl
+
+  let recv_ptr' = RFPtr recv_ptr
+
+  if !(nullPtr recv_ptr)
+    then map Left getErrno
+    else do
+      result <- foreign FFI_C "idrnet_get_recvfrom_res"
+                        (Ptr -> IO Int)
+                        recv_ptr
+      if result == -1
+        then do
+          freeRecvfromStruct recv_ptr'
+          map Left getErrno
+        else do
+          port <- foreignGetRecvfromPort recv_ptr'
+          addr <- foreignGetRecvfromAddr recv_ptr'
+          freeRecvfromStruct recv_ptr'
+          pure $ Right (MkUDPAddrInfo addr port, result + 1)
+
diff --git a/libs/contrib/contrib.ipkg b/libs/contrib/contrib.ipkg
--- a/libs/contrib/contrib.ipkg
+++ b/libs/contrib/contrib.ipkg
@@ -1,6 +1,6 @@
 package contrib
 
-opts = "--nobasepkgs --total -i ../prelude -i ../base"
+opts = "--nobasepkgs --partial-eval --total -i ../prelude -i ../base"
 modules = CFFI, CFFI.Types, CFFI.Memory,
 
           Control.Algebra,
@@ -8,6 +8,7 @@
           Control.Algebra.NumericImplementations,
           Control.Isomorphism.Primitives,
           Control.Partial,
+          Control.ST, Control.ST.ImplicitCall,
 
           Interfaces.Verified,
 
@@ -20,10 +21,11 @@
           Data.Heap,
           Data.SortedMap, Data.SortedSet,
           Data.CoList, Data.Storable,
+	  Data.List.Zipper,
 
           Decidable.Decidable, Decidable.Order,
 
-          Network.Cgi, Network.Socket,
+          Network.Cgi, Network.Socket.Data, Network.Socket.Raw, Network.Socket,
 
           System.Concurrency.Process,
 
diff --git a/libs/effects/Effect/Exception.idr b/libs/effects/Effect/Exception.idr
--- a/libs/effects/Effect/Exception.idr
+++ b/libs/effects/Effect/Exception.idr
@@ -17,7 +17,7 @@
 
 implementation Show a => Handler (Exception a) IO where
      handle _ (Raise e) k = do printLn e
-                               believe_me (exit 1)
+                               (exit 1)
 
 implementation Handler (Exception a) (IOExcept a) where
      handle _ (Raise e) k = ioe_fail e
@@ -30,4 +30,3 @@
 
 raise : a -> Eff b [EXCEPTION a]
 raise err = call $ Raise err
-
diff --git a/libs/effects/effects.ipkg b/libs/effects/effects.ipkg
--- a/libs/effects/effects.ipkg
+++ b/libs/effects/effects.ipkg
@@ -1,6 +1,6 @@
 package effects
 
-opts    = "--nobasepkgs --typeintype -i ../prelude -i ../base"
+opts    = "--nobasepkgs --partial-eval --typeintype -i ../prelude -i ../base"
 
 modules = Effects
         , Effect.Default
diff --git a/libs/prelude/Builtins.idr b/libs/prelude/Builtins.idr
--- a/libs/prelude/Builtins.idr
+++ b/libs/prelude/Builtins.idr
@@ -2,6 +2,7 @@
 
 %access public export
 %default total
+%language UniquenessTypes
 
 ||| The canonical single-element type, also known as the trivially
 ||| true proposition.
@@ -176,6 +177,12 @@
 ||| is unreachable
 assert_unreachable : a
 -- compiled as primitive
+
+||| Abort immediately with an error message
+idris_crash : (msg : String) -> a
+-- compiled as primitive
+
+%used idris_crash msg
 
 ||| Subvert the type checker. This function is abstract, so it will not reduce in
 ||| the type checker. Use it with care - it can result in segfaults or worse!
diff --git a/libs/prelude/Prelude.idr b/libs/prelude/Prelude.idr
--- a/libs/prelude/Prelude.idr
+++ b/libs/prelude/Prelude.idr
@@ -37,6 +37,8 @@
 %access public export
 %default total
 
+%language ElabReflection
+
 -- Things that can't be elsewhere for import cycle reasons
 -- See comment after declaration of void in Builtins.idr
 -- for explanation of this definition's location
@@ -144,9 +146,14 @@
   where go Z = []
         go (S n) = n :: go n
 
+
 -- predefine Nat versions of Enum, so we can use them in the default impls
+countFrom : Num n => n -> n -> Stream n
+countFrom start diff = start :: countFrom (start + diff) diff
+
 total natEnumFromThen : Nat -> Nat -> Stream Nat
-natEnumFromThen n next = n :: natEnumFromThen next (minus next n)
+natEnumFromThen n next = countFrom n (minus next n)
+
 total natEnumFromTo : Nat -> Nat -> List Nat
 natEnumFromTo n m = if n <= m
                     then go n m
@@ -195,7 +202,7 @@
   succ n = n + 1
   toNat n = cast n
   fromNat n = cast n
-  enumFromThen n inc = n :: enumFromThen (inc + n) inc
+  enumFromThen n inc = countFrom n (inc - n)
   enumFromTo n m = if n <= m
                    then go n m
                    else List.reverse $ go m n
@@ -224,7 +231,8 @@
           go' acc (S k) m = go' (m :: acc) k (m - 1)
           go : Int -> Int -> List Int
           go n m = go' [] (cast {to = Nat} (m - n)) m
-  enumFromThen n inc = n :: enumFromThen (inc + n) inc
+  enumFromThen n inc = countFrom n (inc - n)
+
   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)))
diff --git a/libs/prelude/Prelude/Chars.idr b/libs/prelude/Prelude/Chars.idr
--- a/libs/prelude/Prelude/Chars.idr
+++ b/libs/prelude/Prelude/Chars.idr
@@ -1,3 +1,8 @@
+||| Functions operating over Chars.
+|||
+||| The representation of a Char is backend dependent,
+||| for the C backend, it is a Unicode code point.
+|||
 module Prelude.Chars
 -- Functions operating over Chars
 
@@ -9,7 +14,7 @@
 
 %access public export
 
-||| Convert the number to its ASCII equivalent.
+||| Convert the number to its backend dependent (usually Unicode) Char equivelent.
 chr : Int -> Char
 chr x = if (x >= 0 && x < 0x110000)
                 then assert_total (prim__intToChar x)
@@ -18,7 +23,7 @@
 Cast Int Char where
     cast = chr
 
-||| Return the ASCII representation of the character.
+||| Return the backend dependent (usually Unicode) numerical equivelent of the Char.
 ord : Char -> Int
 ord x = prim__charToInt x
 
diff --git a/libs/prelude/Prelude/List.idr b/libs/prelude/Prelude/List.idr
--- a/libs/prelude/Prelude/List.idr
+++ b/libs/prelude/Prelude/List.idr
@@ -547,7 +547,8 @@
 -- Filters
 --------------------------------------------------------------------------------
 
-||| filter, applied to a predicate and a list, returns the list of those elements that satisfy the predicate; e.g.,
+||| filter, applied to a predicate and a list, returns the list of those
+||| elements that satisfy the predicate; e.g.,
 |||
 ||| ````idris example
 ||| filter (< 3) [Z, S Z, S (S Z), S (S (S Z)), S (S (S (S Z)))]
@@ -569,7 +570,8 @@
   filterSmaller {p = p} (x :: xs) | True = LTESucc (filterSmaller xs)
 
 
-||| The nubBy function behaves just like nub, except it uses a user-supplied equality predicate instead of the overloaded == function.
+||| The nubBy function behaves just like nub, except it uses a user-supplied
+||| equality predicate instead of the overloaded == function.
 nubBy : (a -> a -> Bool) -> List a -> List a
 nubBy = nubBy' []
   where
@@ -680,7 +682,9 @@
 splitAt : (n : Nat) -> (xs : List a) -> (List a, List a)
 splitAt n xs = (take n xs, drop n xs)
 
-||| The partition function takes a predicate a list and returns the pair of lists of elements which do and do not satisfy the predicate, respectively; e.g.,
+||| The partition function takes a predicate a list and returns the pair of
+||| lists of elements which do and do not satisfy the predicate, respectively;
+||| e.g.,
 |||
 ||| ```idris example
 ||| partition (<3) [0, 1, 2, 3, 4, 5]
@@ -763,7 +767,8 @@
 isSuffixOf : Eq a => List a -> List a -> Bool
 isSuffixOf = isSuffixOfBy (==)
 
-||| The isInfixOf function takes two lists and returns True iff the first list is contained, wholly and intact, anywhere within the second.
+||| The isInfixOf function takes two lists and returns True iff the first list
+||| is contained, wholly and intact, anywhere within the second.
 |||
 ||| ```idris example
 ||| isInfixOf ['b','c'] ['a', 'b', 'c', 'd']
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
@@ -91,6 +91,12 @@
 -- Comparisons
 --------------------------------------------------------------------------------
 
+||| Proofs that `n` or `m` is not equal to Z
+data NotBothZero : (n, m : Nat) -> Type where
+  LeftIsNotZero  : NotBothZero (S n) m
+  RightIsNotZero : NotBothZero n     (S m)
+
+
 ||| Proofs that `n` is less than or equal to `m`
 ||| @ n the smaller number
 ||| @ m the larger number
@@ -386,16 +392,15 @@
 --------------------------------------------------------------------------------
 -- GCD and LCM
 --------------------------------------------------------------------------------
-partial
-gcd : Nat -> Nat -> Nat
-gcd a Z = a
-gcd a b = assert_total (gcd b (a `modNat` b))
+gcd : (a: Nat) -> (b: Nat) -> .{auto ok: NotBothZero a b} -> Nat
+gcd a Z     = a
+gcd Z b     = b
+gcd a (S b) = assert_total $ gcd (S b) (modNatNZ a (S b) SIsNotZ)
 
-partial
 lcm : Nat -> Nat -> Nat
-lcm _ Z = Z
-lcm Z _ = Z
-lcm x y = divNat (x * y) (gcd x y)
+lcm _ Z     = Z
+lcm Z _     = Z
+lcm a (S b) = assert_total $ divNat (a * (S b)) (gcd a (S b))
 
 
 --------------------------------------------------------------------------------
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
@@ -45,7 +45,8 @@
 ||| ```
 partial
 strHead : String -> Char
-strHead = prim__strHead
+strHead "" = idris_crash "Prelude.Strings: attempt to take the head of an empty string"
+strHead x = prim__strHead x
 
 ||| Returns the characters specified after the head of the string.
 |||
@@ -59,7 +60,8 @@
 ||| ```
 partial
 strTail : String -> String
-strTail = prim__strTail
+strTail "" = idris_crash "Prelude.Strings: attempt to take the tail of an empty string"
+strTail xs = prim__strTail xs
 
 ||| Adds a character to the front of the specified string.
 |||
@@ -72,6 +74,18 @@
 strCons : Char -> String -> String
 strCons = prim__strCons
 
+||| Returns the length of the string.
+|||
+||| ```idris example
+||| length ""
+||| ```
+||| ```idris example
+||| length "ABC"
+||| ```
+length : String -> Nat
+length = fromInteger . prim__zextInt_BigInt . prim_lenString
+
+
 ||| Returns the nth character (starting from 0) of the specified string.
 |||
 ||| Precondition: '0 < i < length s' for 'strIndex s i'.
@@ -81,7 +95,9 @@
 ||| ```
 partial
 strIndex : String -> Int -> Char
-strIndex = prim__strIndex
+strIndex x i = if (i < 0 || i >= cast (length x))
+                  then idris_crash "Prelude.Strings: String index out of bounds"
+                  else prim__strIndex x i
 
 ||| Reverses the elements within a String.
 |||
@@ -296,17 +312,6 @@
 ||| ```
 unlines : List String -> String
 unlines = pack . unlines' . map unpack
-
-||| Returns the length of the string.
-|||
-||| ```idris example
-||| length ""
-||| ```
-||| ```idris example
-||| length "ABC"
-||| ```
-length : String -> Nat
-length = fromInteger . prim__zextInt_BigInt . prim_lenString
 
 ||| Returns a substring of a given string
 |||
diff --git a/libs/prelude/prelude.ipkg b/libs/prelude/prelude.ipkg
--- a/libs/prelude/prelude.ipkg
+++ b/libs/prelude/prelude.ipkg
@@ -1,6 +1,6 @@
 package prelude
 
-opts = "--nobuiltins --total --no-elim-deprecation-warnings"
+opts = "--nobuiltins --total --no-elim-deprecation-warnings --partial-eval"
 modules = Builtins, Prelude, IO,
 
           Prelude.Algebra, Prelude.Basics, Prelude.Bool, Prelude.Cast,
diff --git a/libs/pruviloj/Pruviloj/Induction.idr b/libs/pruviloj/Pruviloj/Induction.idr
--- a/libs/pruviloj/Pruviloj/Induction.idr
+++ b/libs/pruviloj/Pruviloj/Induction.idr
@@ -132,7 +132,9 @@
        (_, ty) <- check !getEnv subj
        ty' <- forget ty
        case headName ty' of
-         Nothing => fail [TermPart ty, TextPart "is not an inductive family"]
+         Nothing =>
+           fail [TermPart ty,
+                 TextPart "is not a datatype declared with the data keyword"]
          Just fam =>
            do let elim = elimN fam
               (_,_,elimTy) <- (lookupTyExact elim) <|> (do deriveElim fam elim
diff --git a/libs/pruviloj/pruviloj.ipkg b/libs/pruviloj/pruviloj.ipkg
--- a/libs/pruviloj/pruviloj.ipkg
+++ b/libs/pruviloj/pruviloj.ipkg
@@ -1,6 +1,6 @@
 package pruviloj
 
-opts    = "--nobasepkgs -i ../prelude -i ../base"
+opts    = "--nobasepkgs --partial-eval -i ../prelude -i ../base"
 modules = Pruviloj
         , Pruviloj.Core
         , Pruviloj.Derive.DecEq
diff --git a/main/Main.hs b/main/Main.hs
--- a/main/Main.hs
+++ b/main/Main.hs
@@ -1,10 +1,10 @@
 module Main where
 
-import System.Exit ( ExitCode(..), exitWith, exitSuccess )
+import System.Exit (ExitCode(..), exitSuccess, exitWith)
 
-import Control.Monad ( unless, when, (>=>) )
-import Data.Maybe    ( fromMaybe )
-import Data.Foldable ( foldrM )
+import Control.Monad (unless, when, (>=>))
+import Data.Foldable (foldrM)
+import Data.Maybe (fromMaybe)
 
 import Idris.AbsSyntax
 import Idris.CmdOptions
@@ -15,8 +15,8 @@
 
 import Util.System (setupBundledCC)
 
-import Util.System ( setupBundledCC )
-import System.Exit ( ExitCode(..), exitWith)
+import System.Exit (ExitCode(..), exitWith)
+import Util.System (setupBundledCC)
 
 processShowOptions :: [Opt] -> Idris ()
 processShowOptions opts = runIO $ do
@@ -39,7 +39,7 @@
 processClientOptions opts = check opts getClient $ \fs -> case fs of
   []      -> ifail "No --client argument. This indicates a bug. Please report."
   (c : _) -> do
-    setVerbose False
+    setVerbose 0
     setQuiet True
     case getPort opts of
       Just  DontListen       -> ifail "\"--client\" and \"--port none\" are incompatible"
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 "28 November 2016" "0.99" "Idris man page"
+.TH man 1 "5 March 2017" "0.99.1" "Idris man page"
 .SH NAME
 idris -\ a general purpose pure functional programming language with dependent types.
 .SH SYNOPSIS
@@ -68,7 +68,9 @@
   --listlibs               Display installed libraries
   --libdir                 Display library directory
   --include                Display the includes flags
-  -V,--verbose             Loud verbosity
+  --V2                     Loudest verbosity
+  --V1                     Louder verbosity
+  -V, --V0, --verbose      Loud verbosity
   --ibcsubdir FILE         Write IBC files into sub directory
   -i,--idrispath ARG       Add directory to the list of import paths
   --sourcepath ARG         Add directory to the list of source search paths
@@ -91,8 +93,7 @@
   --exec EXPR              Execute as idris
   -X,--extension EXT       Turn on language extension (TypeProviders or
                            ErrorReflection)
-  --no-partial-eval        Switch off partial evaluation, mainly for debugging
-                           purposes
+  --partial-eval           Switch on partial evaluation
   --target TRIPLE          If supported the codegen will target the named triple.
   --cpu CPU                If supported the codegen will target the named CPU
                            e.g. corei7 or cortex-m3.
diff --git a/mkpkg.sh b/mkpkg.sh
--- a/mkpkg.sh
+++ b/mkpkg.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/usr/bin/env sh
 
 set -euo pipefail
 
@@ -62,3 +62,6 @@
          --version "v$VERSION"       \
          --root /tmp/idris-pkg/      \
          idris-$VERSION.pkg
+
+echo "==> Creating SHA256 hash (don't forget to update web site!)"
+shasum -a 256 idris-$VERSION.pkg > idris-$VERSION.pkg.sha256
diff --git a/rts/idris_bitstring.c b/rts/idris_bitstring.c
--- a/rts/idris_bitstring.c
+++ b/rts/idris_bitstring.c
@@ -823,37 +823,37 @@
 }
 
 VAL idris_peekB8(VM* vm, VAL ptr, VAL offset) {
-    return MKB8(vm, *(uint8_t*)(GETPTR(ptr) + GETINT(offset)));
+    return MKB8(vm, *(uint8_t*)((char *)GETPTR(ptr) + GETINT(offset)));
 }
 
 VAL idris_pokeB8(VAL ptr, VAL offset, VAL data) {
-    *(uint8_t*)(GETPTR(ptr) + GETINT(offset)) = GETBITS8(data);
+    *(uint8_t*)((char *)GETPTR(ptr) + GETINT(offset)) = GETBITS8(data);
     return MKINT(0);
 }
 
 VAL idris_peekB16(VM* vm, VAL ptr, VAL offset) {
-    return MKB16(vm, *(uint16_t*)(GETPTR(ptr) + GETINT(offset)));
+    return MKB16(vm, *(uint16_t*)((char *)GETPTR(ptr) + GETINT(offset)));
 }
 
 VAL idris_pokeB16(VAL ptr, VAL offset, VAL data) {
-    *(uint16_t*)(GETPTR(ptr) + GETINT(offset)) = GETBITS16(data);
+    *(uint16_t*)((char *)GETPTR(ptr) + GETINT(offset)) = GETBITS16(data);
     return MKINT(0);
 }
 
 VAL idris_peekB32(VM* vm, VAL ptr, VAL offset) {
-    return MKB32(vm, *(uint32_t*)(GETPTR(ptr) + GETINT(offset)));
+    return MKB32(vm, *(uint32_t*)((char *)GETPTR(ptr) + GETINT(offset)));
 }
 
 VAL idris_pokeB32(VAL ptr, VAL offset, VAL data) {
-    *(uint32_t*)(GETPTR(ptr) + GETINT(offset)) = GETBITS32(data);
+    *(uint32_t*)((char *)GETPTR(ptr) + GETINT(offset)) = GETBITS32(data);
     return MKINT(0);
 }
 
 VAL idris_peekB64(VM* vm, VAL ptr, VAL offset) {
-    return MKB64(vm, *(uint64_t*)(GETPTR(ptr) + GETINT(offset)));
+    return MKB64(vm, *(uint64_t*)((char *)GETPTR(ptr) + GETINT(offset)));
 }
 
 VAL idris_pokeB64(VAL ptr, VAL offset, VAL data) {
-    *(uint64_t*)(GETPTR(ptr) + GETINT(offset)) = GETBITS64(data);
+    *(uint64_t*)((char *)GETPTR(ptr) + GETINT(offset)) = GETBITS64(data);
     return MKINT(0);
 }
diff --git a/rts/idris_gc.c b/rts/idris_gc.c
--- a/rts/idris_gc.c
+++ b/rts/idris_gc.c
@@ -1,3 +1,4 @@
+#include "idris_heap.h"
 #include "idris_rts.h"
 #include "idris_gc.h"
 #include "idris_bitstring.h"
@@ -73,7 +74,7 @@
 void cheney(VM *vm) {
     int i;
     int ar;
-    char* scan = vm->heap.heap;
+    char* scan = aligned_heap_pointer(vm->heap.heap);
 
     while(scan < vm->heap.next) {
        size_t inc = *((size_t*)scan);
diff --git a/rts/idris_gmp.c b/rts/idris_gmp.c
--- a/rts/idris_gmp.c
+++ b/rts/idris_gmp.c
@@ -14,7 +14,7 @@
 // much space is needed (or find another way of preventing copying)
 #define IDRIS_MAXGMP 65536
 
-void init_gmpalloc() {
+void init_gmpalloc(void) {
     mp_set_memory_functions(idris_alloc, idris_realloc, idris_free);
 }
 
diff --git a/rts/idris_gmp.h b/rts/idris_gmp.h
--- a/rts/idris_gmp.h
+++ b/rts/idris_gmp.h
@@ -8,7 +8,7 @@
 #endif
 
 // Set memory allocation functions
-void init_gmpalloc();
+void init_gmpalloc(void);
 
 VAL MKBIGI(int val);
 VAL MKBIGC(VM* vm, char* bigint);
diff --git a/rts/idris_heap.c b/rts/idris_heap.c
--- a/rts/idris_heap.c
+++ b/rts/idris_heap.c
@@ -118,14 +118,7 @@
     }
 
     h->heap = mem;
-#ifdef FORCE_ALIGNMENT
-    if (((i_int)(h->heap)&1) == 1) {
-        h->next = h->heap + 1;
-    } else
-#endif
-    {
-        h->next = h->heap;
-    }
+    h->next = aligned_heap_pointer(h->heap);
     h->end  = h->heap + heap_size;
 
     h->size   = heap_size;
@@ -167,6 +160,17 @@
 
 int ref_in_heap(Heap * heap, VAL v) {
     return ((VAL)heap->heap <= v) && (v < (VAL)heap->next);
+}
+
+char* aligned_heap_pointer(char * heap) {
+#ifdef FORCE_ALIGNMENT
+    if (((i_int)heap&1) == 1) {
+	    return (heap + 1);
+    } else
+#endif
+    {
+	    return heap;
+    }
 }
 
 // Checks three important properties:
diff --git a/rts/idris_heap.h b/rts/idris_heap.h
--- a/rts/idris_heap.h
+++ b/rts/idris_heap.h
@@ -98,7 +98,7 @@
 
 void alloc_heap(Heap * heap, size_t heap_size, size_t growth, char * old);
 void free_heap(Heap * heap);
-
+char* aligned_heap_pointer(char * heap);
 
 #ifdef IDRIS_DEBUG
 void heap_check_all(Heap * heap);
diff --git a/rts/idris_main.c b/rts/idris_main.c
--- a/rts/idris_main.c
+++ b/rts/idris_main.c
@@ -1,7 +1,32 @@
+#include "idris_gmp.h"
 #include "idris_opts.h"
-#include "idris_stats.h"
 #include "idris_rts.h"
-#include "idris_gmp.h"
+#include "idris_stats.h"
+
+#if defined(WIN32) || defined(__WIN32) || defined(__WIN32__)
+#include <Windows.h>
+int win32_get_argv_utf8(int *argc_ptr, char ***argv_ptr)
+{
+    int argc;
+    char **argv;
+    wchar_t **argv_utf16 = CommandLineToArgvW(GetCommandLineW(), &argc);
+    int i;
+    int offset = (argc + 1) * sizeof(char *);
+    int size = offset;
+    for (i = 0; i < argc; i++) {
+        size += WideCharToMultiByte(CP_UTF8, 0, argv_utf16[i], -1, 0, 0, 0, 0);
+    }
+    argv = (char **)malloc(size);
+    for (i = 0; i < argc; i++) {
+        argv[i] = (char *)argv + offset;
+        offset += WideCharToMultiByte(CP_UTF8, 0, argv_utf16[i], -1, argv[i], size - offset, 0, 0);
+    }
+    *argc_ptr = argc;
+    *argv_ptr = argv;
+    return 0;
+}
+#endif
+
 // The default options should give satisfactory results under many circumstances.
 RTSOpts opts = { 
     .init_heap_size = 16384000,
@@ -9,7 +34,14 @@
     .show_summary   = 0
 };
 
-int main(int argc, char* argv[]) {
+#if defined(WIN32) || defined(__WIN32) || defined(__WIN32__)
+int main() {
+    int argc;
+    char **argv;
+    win32_get_argv_utf8(&argc, &argv);
+#else
+int main(int argc, char **argv) {
+#endif
     parse_shift_args(&opts, &argc, &argv);
 
     __idris_argc = argc;
diff --git a/rts/idris_net.c b/rts/idris_net.c
--- a/rts/idris_net.c
+++ b/rts/idris_net.c
@@ -315,3 +315,8 @@
         }
     }
 }
+
+int idrnet_geteagain() {
+    return EAGAIN;
+}
+
diff --git a/rts/idris_net.h b/rts/idris_net.h
--- a/rts/idris_net.h
+++ b/rts/idris_net.h
@@ -73,5 +73,6 @@
 int idrnet_getaddrinfo(struct addrinfo** address_res, char* host, 
     int port, int family, int socket_type);
 
+int idrnet_geteagain();
 
 #endif
diff --git a/rts/idris_opts.c b/rts/idris_opts.c
--- a/rts/idris_opts.c
+++ b/rts/idris_opts.c
@@ -99,7 +99,7 @@
     return argc;
 }
 
-void parse_shift_args(RTSOpts * opts, int * argc, char ** argv[]) {
+void parse_shift_args(RTSOpts * opts, int * argc, char *** argv) {
     size_t shift = parse_args(opts, (*argc) - 1, (*argv) + 1);
 
     char *prg = (*argv)[0];
diff --git a/rts/idris_opts.h b/rts/idris_opts.h
--- a/rts/idris_opts.h
+++ b/rts/idris_opts.h
@@ -14,6 +14,6 @@
 
 // Parse rts options and shift arguments such that rts options becomes invisible
 // for main program.
-void parse_shift_args(RTSOpts * opts, int * argc, char ** argv[]);
+void parse_shift_args(RTSOpts * opts, int * argc, char *** argv);
 
 #endif
diff --git a/rts/idris_rts.c b/rts/idris_rts.c
--- a/rts/idris_rts.c
+++ b/rts/idris_rts.c
@@ -70,7 +70,7 @@
     return vm;
 }
 
-VM* idris_vm() {
+VM* idris_vm(void) {
     VM* vm = init_vm(4096000, 4096000, 1);
     init_threadkeys();
     init_threaddata(vm);
@@ -95,12 +95,12 @@
 }
 
 #ifdef HAS_PTHREAD
-void create_key() {
+void create_key(void) {
     pthread_key_create(&vm_key, (void*)free_key);
 }
 #endif
 
-void init_threadkeys() {
+void init_threadkeys(void) {
 #ifdef HAS_PTHREAD
     static pthread_once_t key_once = PTHREAD_ONCE_INIT;
     pthread_once(&key_once, create_key);
@@ -113,7 +113,7 @@
 #endif
 }
 
-void init_signals() {
+void init_signals(void) {
 #if (__linux__ || __APPLE__ || __FreeBSD__ || __DragonFly__)
     signal(SIGPIPE, SIG_IGN);
 #endif
@@ -173,7 +173,7 @@
 #endif
 }
 
-void idris_doneAlloc() {
+void idris_doneAlloc(void) {
 #ifdef HAS_PTHREAD
     VM* vm = pthread_getspecific(vm_key);
     int lock = vm->processes > 0;
@@ -191,7 +191,7 @@
     Closure* cl = (Closure*) allocate(sizeof(Closure)+size, 0);
     SETTY(cl, CT_RAWDATA);
     cl->info.size = size;
-    return (void*)cl+sizeof(Closure);
+    return (void*)((char *)cl+sizeof(Closure));
 }
 
 void* idris_realloc(void* old, size_t old_size, size_t size) {
@@ -449,36 +449,36 @@
 
 
 VAL idris_peekPtr(VM* vm, VAL ptr, VAL offset) {
-    void** addr = GETPTR(ptr) + GETINT(offset);
+    void** addr = (void **)((char *)GETPTR(ptr) + GETINT(offset));
     return MKPTR(vm, *addr);
 }
 
 VAL idris_pokePtr(VAL ptr, VAL offset, VAL data) {
-    void** addr = GETPTR(ptr) + GETINT(offset);
+    void** addr = (void **)((char *)GETPTR(ptr) + GETINT(offset));
     *addr = GETPTR(data);
     return MKINT(0);
 }
 
 VAL idris_peekDouble(VM* vm, VAL ptr, VAL offset) {
-    return MKFLOAT(vm, *(double*)(GETPTR(ptr) + GETINT(offset)));
+    return MKFLOAT(vm, *(double*)((char *)GETPTR(ptr) + GETINT(offset)));
 }
 
 VAL idris_pokeDouble(VAL ptr, VAL offset, VAL data) {
-    *(double*)(GETPTR(ptr) + GETINT(offset)) = GETFLOAT(data);
+    *(double*)((char *)GETPTR(ptr) + GETINT(offset)) = GETFLOAT(data);
     return MKINT(0);
 }
 
 VAL idris_peekSingle(VM* vm, VAL ptr, VAL offset) {
-    return MKFLOAT(vm, *(float*)(GETPTR(ptr) + GETINT(offset)));
+    return MKFLOAT(vm, *(float*)((char *)GETPTR(ptr) + GETINT(offset)));
 }
 
 VAL idris_pokeSingle(VAL ptr, VAL offset, VAL data) {
-    *(float*)(GETPTR(ptr) + GETINT(offset)) = GETFLOAT(data);
+    *(float*)((char *)GETPTR(ptr) + GETINT(offset)) = GETFLOAT(data);
     return MKINT(0);
 }
 
 void idris_memmove(void* dest, void* src, i_int dest_offset, i_int src_offset, i_int size) {
-    memmove(dest + dest_offset, src + src_offset, size);
+    memmove((char *)dest + dest_offset, (char *)src + src_offset, size);
 }
 
 VAL idris_castIntStr(VM* vm, VAL i) {
@@ -595,6 +595,11 @@
     return ret;
 }
 
+void idris_crash(char* msg) {
+    fprintf(stderr, "%s\n", msg);
+    exit(1);
+}
+
 VAL idris_strHead(VM* vm, VAL str) {
     return idris_strIndex(vm, str, 0);
 }
@@ -1041,7 +1046,7 @@
     free(msg);
 }
 
-int idris_errno() {
+int idris_errno(void) {
     return errno;
 }
 
@@ -1051,7 +1056,7 @@
 
 VAL* nullary_cons;
 
-void init_nullaries() {
+void init_nullaries(void) {
     int i;
     VAL cl;
     nullary_cons = malloc(256 * sizeof(VAL));
@@ -1063,7 +1068,7 @@
     }
 }
 
-void free_nullaries() {
+void free_nullaries(void) {
     int i;
     for(i = 0; i < 256; ++i) {
         free(nullary_cons[i]);
@@ -1074,7 +1079,7 @@
 int __idris_argc;
 char **__idris_argv;
 
-int idris_numArgs() {
+int idris_numArgs(void) {
     return __idris_argc;
 }
 
@@ -1082,12 +1087,12 @@
     return __idris_argv[i];
 }
 
-void idris_disableBuffering() {
+void idris_disableBuffering(void) {
   setvbuf(stdin, NULL, _IONBF, 0);
   setvbuf(stdout, NULL, _IONBF, 0);
 }
 
-void stackOverflow() {
+void stackOverflow(void) {
   fprintf(stderr, "Stack overflow");
   exit(-1);
 }
diff --git a/rts/idris_rts.h b/rts/idris_rts.h
--- a/rts/idris_rts.h
+++ b/rts/idris_rts.h
@@ -161,11 +161,11 @@
 
 // Create a new VM, set up everything with sensible defaults (use when
 // calling Idris from C)
-VM* idris_vm();
+VM* idris_vm(void);
 void close_vm(VM* vm);
 
 // Set up key for thread-local data - called once from idris_main
-void init_threadkeys();
+void init_threadkeys(void);
 
 // Functions all take a pointer to their VM, and previous stack base,
 // and return nothing.
@@ -278,7 +278,7 @@
 // may take a lock if other threads are running).
 
 void idris_requireAlloc(size_t size);
-void idris_doneAlloc();
+void idris_doneAlloc(void);
 
 // public interface to allocation (note that this may move other pointers
 // if allocating beyond the limits given by idris_requireAlloc!)
@@ -299,14 +299,14 @@
 
 #define NULL_CON(x) nullary_cons[x]
 
-int idris_errno();
+int idris_errno(void);
 char* idris_showerror(int err);
 
 extern VAL* nullary_cons;
-void init_nullaries();
-void free_nullaries();
+void init_nullaries(void);
+void free_nullaries(void);
 
-void init_signals();
+void init_signals(void);
 
 void* vmThread(VM* callvm, func f, VAL arg);
 void* idris_stopThread(VM* vm);
@@ -364,6 +364,9 @@
 VAL idris_peekSingle(VM* vm, VAL ptr, VAL offset);
 VAL idris_pokeSingle(VAL ptr, VAL offset, VAL data);
 
+// Crash with a message (used for partial primitives)
+void idris_crash(char* msg);
+
 // String primitives
 VAL idris_concat(VM* vm, VAL l, VAL r);
 VAL idris_strlt(VM* vm, VAL l, VAL r);
@@ -391,16 +394,16 @@
 extern int __idris_argc;
 extern char **__idris_argv;
 
-int idris_numArgs();
+int idris_numArgs(void);
 const char *idris_getArg(int i);
 
 // disable stdin/stdout buffering
-void idris_disableBuffering();
+void idris_disableBuffering(void);
 
 // Handle stack overflow.
 // Just reports an error and exits.
 
-void stackOverflow();
+void stackOverflow(void);
 
 // I think these names are nicer for an API...
 
diff --git a/rts/idris_stdfgn.c b/rts/idris_stdfgn.c
--- a/rts/idris_stdfgn.c
+++ b/rts/idris_stdfgn.c
@@ -11,6 +11,8 @@
 
 #if defined(WIN32) || defined(__WIN32) || defined(__WIN32__)
 int win_fpoll(void* h);
+FILE *win32_u8fopen(const char *path, const char *mode);
+FILE *win32_u8popen(const char *path, const char *mode);
 #else
 #include <sys/select.h>
 #endif
@@ -21,9 +23,13 @@
     printf("%s", str);
 }
 
-void* fileOpen(char* name, char* mode) {
-    FILE* f = fopen(name, mode);
-    return (void*)f;
+void *fileOpen(char *name, char *mode) {
+#if defined(WIN32) || defined(__WIN32) || defined(__WIN32__)
+    FILE *f = win32_u8fopen(name, mode);
+#else
+    FILE *f = fopen(name, mode);
+#endif
+    return (void *)f;
 }
 
 void fileClose(void* h) {
@@ -82,10 +88,14 @@
 #endif
 }
 
-void* do_popen(const char* cmd, const char* mode) {
-    FILE* f = popen(cmd, mode);
-//    int d = fileno(f);
-//    fcntl(d, F_SETFL, O_NONBLOCK);
+void *do_popen(const char *cmd, const char *mode) {
+#if defined(WIN32) || defined(__WIN32) || defined(__WIN32__)
+    FILE *f = win32_u8popen(cmd, mode);
+#else
+    FILE *f = popen(cmd, mode);
+    //    int d = fileno(f);
+    //    fcntl(d, F_SETFL, O_NONBLOCK);
+#endif
     return f;
 }
 
diff --git a/rts/windows/idris_net.c b/rts/windows/idris_net.c
--- a/rts/windows/idris_net.c
+++ b/rts/windows/idris_net.c
@@ -193,3 +193,8 @@
 int idrnet_errno() {
     return errno;
 }
+
+int idrnet_geteagain() {
+    return EAGAIN;
+}
+
diff --git a/rts/windows/win_utils.c b/rts/windows/win_utils.c
--- a/rts/windows/win_utils.c
+++ b/rts/windows/win_utils.c
@@ -1,13 +1,13 @@
-#include <windows.h>
 #include <io.h>
 #include <stdio.h>
+#include <windows.h>
 
 // THis file exists to avoid clashes between windows.h and idris_rts.h
 //
 
-int win_fpoll(void* h)
+int win_fpoll(void *h)
 {
-    HANDLE wh =(HANDLE) _get_osfhandle(_fileno((FILE*)h));
+    HANDLE wh =(HANDLE) _get_osfhandle(_fileno((FILE *)h));
     if (wh == INVALID_HANDLE_VALUE) {
         return -1;
     }
@@ -18,4 +18,34 @@
     if (ret == WAIT_TIMEOUT)
         return 0;
     return -1;
+}
+
+int widen_utf8(const char *filename_utf8, LPWSTR *filename_w)
+{
+    int num_chars = MultiByteToWideChar(CP_UTF8, 0, filename_utf8, -1, 0, 0);
+    int size = sizeof(WCHAR);
+    *filename_w = (LPWSTR)malloc(size * num_chars);
+    MultiByteToWideChar(CP_UTF8, 0, filename_utf8, -1, *filename_w, num_chars);
+    return num_chars;
+}
+FILE *win32_u8fopen(const char *path, const char *mode)
+{
+    LPWSTR wpath, wmode;
+    widen_utf8(path, &wpath);
+    widen_utf8(mode, &wmode);
+    FILE *f = _wfopen(wpath, wmode);
+    free(wpath);
+    free(wmode);
+    return f;
+}
+
+FILE *win32_u8popen(const char *path, const char *mode)
+{
+    LPWSTR wpath, wmode;
+    widen_utf8(path, &wpath);
+    widen_utf8(mode, &wmode);
+    FILE *f = _wpopen(wpath, wmode);
+    free(wpath);
+    free(wmode);
+    return f;
 }
diff --git a/src/IRTS/CodegenC.hs b/src/IRTS/CodegenC.hs
--- a/src/IRTS/CodegenC.hs
+++ b/src/IRTS/CodegenC.hs
@@ -617,6 +617,7 @@
 doOp v (LIntCh ITChar) args = doOp v (LIntCh ITNative) args
 
 doOp v LSystemInfo [x] = v ++ "idris_systemInfo(vm, " ++ creg x ++ ")"
+doOp v LCrash [x] = "idris_crash(GETSTR(" ++ creg x ++ "))"
 doOp v LNoOp args = v ++ creg (last args)
 
 -- Pointer primitives (declared as %extern in Builtins.idr)
@@ -673,7 +674,7 @@
 doOp v (LExternal mpt) [p] | mpt == sUN "prim__asPtr"
     = v ++ "MKPTR(vm, GETMPTR("++ creg p ++"))"
 doOp v (LExternal offs) [p, n] | offs == sUN "prim__ptrOffset"
-    = v ++ "MKPTR(vm, GETPTR(" ++ creg p ++ ") + GETINT(" ++ creg n ++ "))"
+    = v ++ "MKPTR(vm, (void *)((char *)GETPTR(" ++ creg p ++ ") + GETINT(" ++ creg n ++ ")))"
 doOp _ op args = error $ "doOp not implemented (" ++ show (op, args) ++ ")"
 
 
diff --git a/src/IRTS/CodegenCommon.hs b/src/IRTS/CodegenCommon.hs
--- a/src/IRTS/CodegenCommon.hs
+++ b/src/IRTS/CodegenCommon.hs
@@ -8,6 +8,7 @@
 -}
 module IRTS.CodegenCommon where
 
+import Idris.Core.Evaluate
 import Idris.Core.TT
 import IRTS.Defunctionalise
 import IRTS.Simplified
@@ -39,6 +40,7 @@
   , liftDecls     :: [(Name, LDecl)]
   , interfaces    :: Bool
   , exportDecls   :: [ExportIFace]
+  , ttDecls       :: [(Name, TTDecl)]
   }
 
 type CodeGenerator = CodegenInfo -> IO ()
diff --git a/src/IRTS/Compiler.hs b/src/IRTS/Compiler.hs
--- a/src/IRTS/Compiler.hs
+++ b/src/IRTS/Compiler.hs
@@ -52,8 +52,10 @@
 
 -- |  Compile to simplified forms and return CodegenInfo
 compile :: Codegen -> FilePath -> Maybe Term -> Idris CodegenInfo
-compile codegen f mtm
-   = do checkMVs  -- check for undefined metavariables
+compile codegen f mtm = do
+        logCodeGen 1 "Compiling Output."
+        iReport 2 "Compiling Output."
+        checkMVs  -- check for undefined metavariables
         checkTotality -- refuse to compile if there are totality problems
         exports <- findExports
         let rootNames = case mtm of
@@ -72,6 +74,7 @@
         flags <- getFlags codegen
         hdrs <- getHdrs codegen
         impdirs <- allImportDirs
+        ttDeclarations <- getDeclarations reachableNames
         defsIn <- mkDecls reachableNames
         -- if no 'main term' given, generate interface files
         let iface = case mtm of
@@ -89,9 +92,11 @@
         let ctxtIn = addAlist tagged emptyContext
 
         logCodeGen 1 "Defunctionalising"
+        iReport 3 "Defunctionalising"
         let defuns_in = defunctionalise nexttag ctxtIn
         logCodeGen 5 $ show defuns_in
         logCodeGen 1 "Inlining"
+        iReport 3 "Inlining"
         let defuns = inline defuns_in
         logCodeGen 5 $ show defuns
         logCodeGen 1 "Resolving variables for CG"
@@ -108,12 +113,14 @@
             Just f -> runIO $ writeFile f (dumpDefuns defuns)
         triple <- Idris.AbsSyntax.targetTriple
         cpu <- Idris.AbsSyntax.targetCPU
-        logCodeGen 1 "Building output"
+        logCodeGen 1 "Generating Code."
+        iReport 2 "Generating Code."
         case checked of
             OK c -> do return $ CodegenInfo f outty triple cpu
                                             hdrs impdirs objs libs flags
                                             NONE c (toAlist defuns)
                                             tagged iface exports
+                                            ttDeclarations
             Error e -> ierror e
   where checkMVs = do i <- getIState
                       case map fst (idris_metavars i) \\ primDefs of
@@ -159,6 +166,12 @@
          decls <- mapM build ds
          return decls
 
+getDeclarations :: [Name] -> Idris ([(Name, TTDecl)])
+getDeclarations used
+    = do i <- getIState
+         let ds = filter (\(n, (d,_,_,_,_,_)) -> n `elem` used || isCon d) $ ((toAlist . definitions . tt_ctxt) i)
+         return ds
+
 showCaseTrees :: [(Name, LDecl)] -> String
 showCaseTrees = showSep "\n\n" . map showCT . sortBy (comparing defnRank)
   where
@@ -258,6 +271,11 @@
         | u == txt "assert_unreachable"
         -> return $ LError $ "ABORT: Reached an unreachable case in " ++ show top
 
+    (P _ (UN u) _, [_, msg])
+        | u == txt "idris_crash"
+        -> do msg' <- irTerm top vs env msg
+              return $ LOp LCrash [msg']
+
     -- TMP HACK - until we get inlining.
     (P _ (UN r) _, [_, _, _, _, _, arg])
         | r == txt "replace"
@@ -456,14 +474,14 @@
             | otherwise = n
 
         used = maybe [] (map fst . usedpos) $ lookupCtxtExact uName (idris_callgraph ist)
-        fst4 (x,_,_,_,_) = x
+        fst4 (x,_,_,_,_,_) = x
 
 irTerm top vs env (P _ n _) = return $ LV (Glob n)
 irTerm top vs env (V i)
     | i >= 0 && i < length env = return $ LV (Glob (env!!i))
     | otherwise = ifail $ "bad de bruijn index: " ++ show i
 
-irTerm top vs env (Bind n (Lam _) sc) = LLam [n'] <$> irTerm top vs (n':env) sc
+irTerm top vs env (Bind n (Lam _ _) sc) = LLam [n'] <$> irTerm top vs (n':env) sc
   where
     n' = uniqueName n env
 
diff --git a/src/IRTS/Lang.hs b/src/IRTS/Lang.hs
--- a/src/IRTS/Lang.hs
+++ b/src/IRTS/Lang.hs
@@ -92,6 +92,8 @@
             | LPar -- evaluate argument anywhere, possibly on another
                    -- core or another machine. 'id' is a valid implementation
             | LExternal Name
+            | LCrash
+
             | LNoOp
   deriving (Show, Eq, Generic)
 
diff --git a/src/IRTS/Portable.hs b/src/IRTS/Portable.hs
--- a/src/IRTS/Portable.hs
+++ b/src/IRTS/Portable.hs
@@ -9,6 +9,7 @@
 module IRTS.Portable (writePortable) where
 
 import Idris.Core.CaseTree
+import Idris.Core.Evaluate
 import Idris.Core.TT
 import IRTS.Bytecode
 import IRTS.CodegenCommon
@@ -29,7 +30,7 @@
 
 -- Update the version when the format changes
 formatVersion :: Int
-formatVersion = 1
+formatVersion = 3
 
 writePortable :: Handle -> CodegenInfo -> IO ()
 writePortable file ci = do
@@ -53,7 +54,8 @@
                         "lift-decls" .= (liftDecls ci),
                         "defun-decls" .= (defunDecls ci),
                         "simple-decls" .= (simpleDecls ci),
-                        "bytecode" .= (map toBC (simpleDecls ci))]
+                        "bytecode" .= (map toBC (simpleDecls ci)),
+                        "tt-decls" .= (ttDecls ci)]
 
 instance ToJSON Name where
     toJSON n = toJSON $ showCG n
@@ -236,13 +238,13 @@
     toJSON (SApp tail name exps) = object ["SApp" .= (tail, name, exps)]
     toJSON (SLet lv a b) = object ["SLet" .= (lv, a, b)]
     toJSON (SUpdate lv exp) = object ["SUpdate" .= (lv, exp)]
-    toJSON (SProj lv i) = object ["DProj" .= (lv, i)]
+    toJSON (SProj lv i) = object ["SProj" .= (lv, i)]
     toJSON (SCon lv i name vars) = object ["SCon" .= (lv, i, name, vars)]
     toJSON (SCase ct lv alts) = object ["SCase" .= (ct, lv, alts)]
-    toJSON (SChkCase lv alts) = object ["DChkCase" .= (lv, alts)]
+    toJSON (SChkCase lv alts) = object ["SChkCase" .= (lv, alts)]
     toJSON (SConst c) = object ["SConst" .= c]
     toJSON (SForeign fd ret exps) = object ["SForeign" .= (fd, ret, exps)]
-    toJSON (SOp prim vars) = object ["DOp" .= (prim, vars)]
+    toJSON (SOp prim vars) = object ["SOp" .= (prim, vars)]
     toJSON SNothing = object ["SNothing" .= Null]
     toJSON (SError s) = object ["SError" .= s]
 
@@ -279,3 +281,84 @@
     toJSON (T i) = object ["T" .= i]
     toJSON (L i) = object ["L" .= i]
     toJSON Tmp = object ["Tmp" .= Null]
+
+instance ToJSON RigCount where
+    toJSON r = object ["RigCount" .= show r]
+
+instance ToJSON Totality where
+    toJSON t = object ["Totality" .= show t]
+
+instance ToJSON MetaInformation where
+    toJSON m = object ["MetaInformation" .= show m]
+
+instance ToJSON Def where
+    toJSON (Function ty tm) = object ["Function" .= (ty, tm)]
+    toJSON (TyDecl nm ty) = object ["TyDecl" .= (nm, ty)]
+    toJSON (Operator ty n f) = Null -- Operator and CaseOp omits same values as in IBC.hs
+    toJSON (CaseOp info ty argTy _ _ cdefs) = object ["CaseOp" .= (info, ty, argTy, cdefs)]
+
+instance (ToJSON t) => ToJSON (TT t) where
+    toJSON (P nt name term) = object ["P" .= (nt, name, term)]
+    toJSON (V n) = object ["V" .= n]
+    toJSON (Bind n b tt) = object ["Bind" .= (n, b, tt)]
+    toJSON (App s t1 t2) = object ["App" .= (s, t1, t2)]
+    toJSON (Constant c) = object ["Constant" .= c]
+    toJSON (Proj tt n) = object ["Proj" .= (tt, n)]
+    toJSON Erased = object ["Erased" .= Null]
+    toJSON Impossible = object ["Impossible" .= Null]
+    toJSON (Inferred tt) = object ["Inferred" .= tt]
+    toJSON (TType u) = object ["TType" .= u]
+    toJSON (UType u) = object ["UType" .= (show u)]
+
+instance ToJSON UExp where
+    toJSON (UVar src n) = object ["UVar" .= (src, n)]
+    toJSON (UVal n) = object ["UVal" .= n]
+
+
+instance (ToJSON t) => ToJSON (AppStatus t) where
+    toJSON Complete = object ["Complete" .= Null]
+    toJSON MaybeHoles = object ["MaybeHoles" .= Null]
+    toJSON (Holes ns) = object ["Holes" .= ns]
+
+instance (ToJSON t) => ToJSON (Binder t) where
+    toJSON (Lam rc bty) = object ["Lam" .= (rc, bty)]
+    toJSON (Pi c i t k) = object ["Pi" .= (c, i, t, k)]
+    toJSON (Let t v) = object ["Let" .= (t, v)]
+    toJSON (NLet t v) = object ["NLet" .= (t, v)]
+    toJSON (Hole t) = object ["Hole" .= (t)]
+    toJSON (GHole l ns t) = object ["GHole" .= (l, ns, t)]
+    toJSON (Guess t v) = object ["Guess" .= (t, v)]
+    toJSON (PVar rc t) = object ["PVar" .= (rc, t)]
+    toJSON (PVTy t) = object ["PVTy" .= (t)]
+
+instance ToJSON ImplicitInfo where
+    toJSON (Impl a b c) = object ["Impl" .= (a, b, c)]
+
+instance ToJSON NameType where
+    toJSON Bound = object ["Bound" .= Null]
+    toJSON Ref = object ["Ref" .= Null]
+    toJSON (DCon a b c) = object ["DCon" .= (a, b, c)]
+    toJSON (TCon a b) = object ["TCon" .= (a, b)]
+
+instance ToJSON CaseDefs where
+    toJSON (CaseDefs rt ct) = object ["Runtime" .= rt, "Compiletime" .= ct]
+
+instance (ToJSON t) => ToJSON (SC' t) where
+    toJSON (Case ct n alts) = object ["Case" .= (ct, n, alts)]
+    toJSON (ProjCase t alts) = object ["ProjCase" .= (t, alts)]
+    toJSON (STerm t) = object ["STerm" .= t]
+    toJSON (UnmatchedCase s) = object ["UnmatchedCase" .= s]
+    toJSON ImpossibleCase = object ["ImpossibleCase" .= Null]
+
+instance (ToJSON t) => ToJSON (CaseAlt' t) where
+    toJSON (ConCase n c ns sc) = object ["ConCase" .= (n, c, ns, sc)]
+    toJSON (FnCase n ns sc) = object ["FnCase" .= (n, ns, sc)]
+    toJSON (ConstCase c sc) = object ["ConstCase" .= (c, sc)]
+    toJSON (SucCase n sc) = object ["SucCase" .= (n, sc)]
+    toJSON (DefaultCase sc) = object ["DefaultCase" .=  sc]
+
+instance ToJSON CaseInfo where
+    toJSON (CaseInfo a b c) = object ["CaseInfo" .= (a, b, c)]
+
+instance ToJSON Accessibility where
+    toJSON a = object ["Accessibility" .= show a]
diff --git a/src/IRTS/Simplified.hs b/src/IRTS/Simplified.hs
--- a/src/IRTS/Simplified.hs
+++ b/src/IRTS/Simplified.hs
@@ -42,15 +42,15 @@
 data SDecl = SFun Name [Name] Int SExp
   deriving Show
 
-hvar :: State (DDefs, Int) Int
-hvar = do (l, h) <- get
-          put (l, h + 1)
-          return h
 
 ldefs :: State (DDefs, Int) DDefs
 ldefs = do (l, h) <- get
            return l
 
+-- | Simplify an expression by let-binding argument expressions that
+-- are not variables
+-- The boolean parameter indicates whether the expression is at tail
+-- call position.
 simplify :: Bool -> DExp -> State (DDefs, Int) SExp
 simplify tl (DV (Loc i)) = return (SV (Loc i))
 simplify tl (DV (Glob x))
@@ -58,67 +58,62 @@
          case lookupCtxtExact x ctxt of
               Just (DConstructor _ t 0) -> return $ SCon Nothing t x []
               _ -> return $ SV (Glob x)
-simplify tl (DApp tc n args) = do args' <- mapM sVar args
-                                  mkapp (SApp (tl || tc) n) args'
+simplify tl (DApp tc n args) = bindExprs args (SApp (tl || tc) n)
 simplify tl (DForeign ty fn args)
-                            = do args' <- mapM sVar (map snd args)
-                                 let fargs = zip (map fst args) args'
-                                 mkfapp (SForeign ty fn) fargs
+    = let (fdescs, exprs) = unzip args
+      in bindExprs exprs (\vars -> SForeign ty fn (zip fdescs vars))
 simplify tl (DLet n v e) = do v' <- simplify False v
                               e' <- simplify tl e
                               return (SLet (Glob n) v' e')
 simplify tl (DUpdate n e) = do e' <- simplify False e
                                return (SUpdate (Glob n) e')
-simplify tl (DC loc i n args) = do args' <- mapM sVar args
-                                   mkapp (SCon loc i n) args'
-simplify tl (DProj t i) = do v <- sVar t
-                             case v of
-                                (x, Nothing) -> return (SProj x i)
-                                (Glob x, Just e) ->
-                                    return (SLet (Glob x) e (SProj (Glob x) i))
-simplify tl (DCase up e alts) = do v <- sVar e
-                                   alts' <- mapM (sAlt tl) alts
-                                   case v of
-                                      (x, Nothing) -> return (SCase up x alts')
-                                      (Glob x, Just e) ->
-                                          return (SLet (Glob x) e (SCase up (Glob x) alts'))
+simplify tl (DC loc i n args) = bindExprs args (SCon loc i n)
+simplify tl (DProj t i) = bindExpr t (\var -> SProj var i)
+simplify tl (DCase up e alts)
+    = do alts' <- mapM (sAlt tl) alts
+         bindExpr e (\var -> SCase up var alts')
 simplify tl (DChkCase e alts)
-                           = do v <- sVar e
-                                alts' <- mapM (sAlt tl) alts
-                                case v of
-                                    (x, Nothing) -> return (SChkCase x alts')
-                                    (Glob x, Just e) ->
-                                        return (SLet (Glob x) e (SChkCase (Glob x) alts'))
+    = do alts' <- mapM (sAlt tl) alts
+         bindExpr e (\var -> SChkCase var alts')
 simplify tl (DConst c) = return (SConst c)
-simplify tl (DOp p args) = do args' <- mapM sVar args
-                              mkapp (SOp p) args'
+simplify tl (DOp p args) = bindExprs args (SOp p)
 simplify tl DNothing = return SNothing
 simplify tl (DError str) = return $ SError str
 
-sVar (DV (Glob x))
+
+-- | Let-bind a list of expressions to variables and construct the
+-- inner expression with the bound variables.
+-- If an expression in the list is already a variable we don’t bind it
+-- again.
+bindExprs :: [DExp] -> ([LVar] -> SExp) -> State (DDefs, Int) SExp
+bindExprs es f = bindExprs' es f [] where
+    bindExprs' [] f vars = return $ f (reverse vars)
+    bindExprs' (e:es) f vars =
+        bindExprM e (\var -> bindExprs' es f (var:vars))
+
+-- | Special case of 'bindExprs' for just one expression
+bindExpr :: DExp -> (LVar -> SExp) -> State (DDefs, Int) SExp
+bindExpr e f = bindExprM e (return . f)
+
+bindExprM :: DExp -> (LVar -> State (DDefs, Int) SExp) -> State (DDefs, Int) SExp
+bindExprM (DV (Glob x)) f
     = do ctxt <- ldefs
          case lookupCtxtExact x ctxt of
-              Just (DConstructor _ t 0) -> sVar (DC Nothing t x [])
-              _ -> return (Glob x, Nothing)
-sVar (DV x) = return (x, Nothing)
-sVar e = do e' <- simplify False e
-            i <- hvar
-            return (Glob (sMN i "R"), Just e')
+              Just (DConstructor _ t 0) -> bindExprM (DC Nothing t x []) f
+              _ -> f (Glob x)
+bindExprM (DV var) f = f var
+bindExprM e f =
+    do e' <- simplify False e
+       var <- freshVar
+       f' <- f var
+       return $ SLet var e' f'
+    where
+        freshVar = do (defs, i) <- get
+                      put (defs, i + 1)
+                      return (Glob (sMN i "R"))
 
-mkapp f args = mkapp' f args [] where
-   mkapp' f [] args = return $ f (reverse args)
-   mkapp' f ((x, Nothing) : xs) args = mkapp' f xs (x : args)
-   mkapp' f ((x, Just e) : xs) args
-       = do sc <- mkapp' f xs (x : args)
-            return (SLet x e sc)
 
-mkfapp f args = mkapp' f args [] where
-   mkapp' f [] args = return $ f (reverse args)
-   mkapp' f ((ty, (x, Nothing)) : xs) args = mkapp' f xs ((ty, x) : args)
-   mkapp' f ((ty, (x, Just e)) : xs) args
-       = do sc <- mkapp' f xs ((ty, x) : args)
-            return (SLet x e sc)
-
+sAlt :: Bool -> DAlt -> State (DDefs, Int) SAlt
 sAlt tl (DConCase i n args e) = do e' <- simplify tl e
                                    return (SConCase (-1) i n args e')
 sAlt tl (DConstCase c e) = do e' <- simplify tl e
diff --git a/src/IRTS/System.hs b/src/IRTS/System.hs
--- a/src/IRTS/System.hs
+++ b/src/IRTS/System.hs
@@ -6,7 +6,7 @@
 Maintainer  : The Idris Community.
 -}
 {-# LANGUAGE CPP #-}
-module IRTS.System( getDataFileName
+module IRTS.System( getIdrisDataFileByName
                   , getCC
                   , getLibFlags
                   , getIdrisDataDir
@@ -41,6 +41,11 @@
       ddir <- getDataDir
       return ddir
     Just ddir -> return ddir
+
+getIdrisDataFileByName :: String -> IO FilePath
+getIdrisDataFileByName fn = do
+  dir <- getIdrisDataDir
+  return $ dir </> fn
 
 overrideIdrisSubDirWith :: String  -- ^ Sub directory in `getDataDir` location.
                         -> String  -- ^ Environment variable to get new location from.
diff --git a/src/Idris/ASTUtils.hs b/src/Idris/ASTUtils.hs
--- a/src/Idris/ASTUtils.hs
+++ b/src/Idris/ASTUtils.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE MultiParamTypeClasses #-}
 {-|
 Module      : Idris.ASTUtils
 Description : This implements just a few basic lens-like concepts to ease state updates. Similar to fclabels in approach, just without the extra dependency.
@@ -148,7 +149,7 @@
 --
 -- This has a terrible name, but I'm not sure of a better one that
 -- isn't confusingly close to tt_ctxt
-known_terms :: Field IState (Ctxt (Def, Injectivity, Accessibility, Totality, MetaInformation))
+known_terms :: Field IState (Ctxt (Def, RigCount, Injectivity, Accessibility, Totality, MetaInformation))
 known_terms = Field (definitions . tt_ctxt)
                     (\v state -> state {tt_ctxt = (tt_ctxt state) {definitions = v}})
 
diff --git a/src/Idris/AbsSyntax.hs b/src/Idris/AbsSyntax.hs
--- a/src/Idris/AbsSyntax.hs
+++ b/src/Idris/AbsSyntax.hs
@@ -5,9 +5,9 @@
 License     : BSD3
 Maintainer  : The Idris Community.
 -}
-{-# LANGUAGE DeriveFunctor, FlexibleInstances, MultiParamTypeClasses,
-             PatternGuards, TypeSynonymInstances #-}
 
+{-# LANGUAGE DeriveFunctor, PatternGuards #-}
+
 module Idris.AbsSyntax(
     module Idris.AbsSyntax
   , module Idris.AbsSyntaxTree
@@ -15,37 +15,33 @@
 
 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 Util.Pretty
-import Util.ScreenSize
-import Util.System
+import System.Directory (canonicalizePath, doesFileExist)
+import System.IO
 
 import Control.Applicative
-import Control.Monad (liftM3)
 import Control.Monad.State
-import Data.Char
+import Prelude hiding (Applicative, Foldable, Traversable, (<$>))
+
 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 System.IO.Error (tryIOError)
+
+import Data.Generics.Uniplate.Data (descend, descendM)
+
 import Debug.Trace
-import Network (PortID(PortNumber))
-import System.Console.Haskeline
-import System.Directory (canonicalizePath, doesFileExist)
-import System.IO
-import System.IO.Error (ioeGetErrorString, isUserError, tryIOError)
+import Util.DynamicLinker
+import Util.Pretty
+import Util.System
 
 getContext :: Idris Context
 getContext = do i <- getIState; return (tt_ctxt i)
@@ -91,9 +87,9 @@
                          Just x -> do putIState $ i { idris_dynamic_libs = x:ls }
                                       return (Left x)
     where findDyLib :: [DynamicLib] -> String -> Maybe DynamicLib
-          findDyLib []         l                     = Nothing
-          findDyLib (lib:libs) l | l == lib_name lib = Just lib
-                                 | otherwise         = findDyLib libs l
+          findDyLib []         _                     = Nothing
+          findDyLib (lib:libs') l | l == lib_name lib = Just lib
+                                  | otherwise         = findDyLib libs' l
 
 getAutoImports :: Idris [FilePath]
 getAutoImports = do i <- getIState
@@ -102,7 +98,6 @@
 addAutoImport :: FilePath -> Idris ()
 addAutoImport fp = do i <- getIState
                       let opts = idris_options i
-                      let autoimps = opt_autoImport opts
                       put (i { idris_options = opts { opt_autoImport =
                                                        fp : opt_autoImport opts } } )
 
@@ -142,14 +137,10 @@
           putIState $ i { idris_imported = nub $ (f, pub) : idris_imported i }
 
 addLangExt :: LanguageExt -> Idris ()
-addLangExt TypeProviders = do i <- getIState
-                              putIState $ i {
-                                idris_language_extensions = TypeProviders : idris_language_extensions i
-                              }
-addLangExt ErrorReflection = do i <- getIState
-                                putIState $ i {
-                                  idris_language_extensions = ErrorReflection : idris_language_extensions i
-                                }
+addLangExt e = do i <- getIState
+                  putIState $ i {
+                    idris_language_extensions = e : idris_language_extensions i
+                  }
 
 -- | Transforms are organised by the function being applied on the lhs
 -- of the transform, to make looking up appropriate transforms quicker
@@ -162,10 +153,18 @@
                 putIState $ i { idris_transforms = addDef basefn t'
                                                           (idris_transforms i) }
 
+-- | Add transformation rules from a definition, which will reverse the
+-- definition for an error to make it more readable
 addErrRev :: (Term, Term) -> Idris ()
 addErrRev t = do i <- getIState
                  putIState $ i { idris_errRev = t : idris_errRev i }
 
+-- | Say that the name should always be reduced in error messages, to
+-- help readability/error reflection
+addErrReduce :: Name -> Idris ()
+addErrReduce t = do i <- getIState
+                    putIState $ i { idris_errReduce = t : idris_errReduce i }
+
 addErasureUsage :: Name -> Int -> Idris ()
 addErasureUsage n i = do ist <- getIState
                          putIState $ ist { idris_erasureUsed = (n, i) : idris_erasureUsed ist }
@@ -254,7 +253,7 @@
     let cs = idris_coercions i
         (fn,_) = unApply (getRetTy ty) in
         findCoercions fn cs
-    where findCoercions t [] = []
+    where findCoercions _ [] = []
           findCoercions t (n : ns) =
              let ps = case lookupTy n (tt_ctxt i) of
                         [ty'] -> case unApply (getRetTy (normalise (tt_ctxt i) [] ty')) of
@@ -326,10 +325,10 @@
               do let (fx, _) = unApply x
                  let (fy, _) = unApply y
                  case (fx, fy) of
-                      (P (TCon _ _) n _, P (TCon _ _) n' _) -> errWhen (n/=n)
+                      (P (TCon _ _) n _, P (TCon _ _) n' _) -> errWhen (n/=n')
                       (P (TCon _ _) n _, Constant _) -> errWhen True
                       (Constant _, P (TCon _ _) n' _) -> errWhen True
-                      (P (DCon _ _ _) n _, P (DCon _ _ _) n' _) -> errWhen (n/=n)
+                      (P (DCon _ _ _) n _, P (DCon _ _ _) n' _) -> errWhen (n/=n')
                       _ -> return ()
 
               where errWhen True
@@ -357,12 +356,6 @@
                         -- will always be one of those two, thus no extra case
     putIState $ i { idris_function_errorhandlers = newHandlers }
 
-getFunctionErrorHandlers :: Name -> Name -> Idris [Name]
-getFunctionErrorHandlers f arg = do i <- getIState
-                                    return . maybe [] S.toList $
-                                     undefined --lookup arg =<< lookupCtxtExact f (idris_function_errorhandlers i)
-
-
 -- | Trace all the names in a call graph starting at the given name
 getAllNames :: Name -> Idris [Name]
 getAllNames n = do i <- getIState
@@ -389,7 +382,7 @@
                    case getCGAllNames i n of
                         Just ns -> return ns
                         Nothing -> case lookupCtxtExact n (idris_callgraph i) of
-                                        Just ci -> 
+                                        Just ci ->
                                           do more <- mapM (allNames (n:ns)) (calls ci)
                                              let ns' = nub (n : concat more)
                                              addCGAllNames i n ns'
@@ -418,7 +411,7 @@
         putIState $ i { idris_namehints = addDef ty' ns' (idris_namehints i) }
 
 getNameHints :: IState -> Name -> [Name]
-getNameHints i (UN arr) | arr == txt "->" = [sUN "f",sUN "g"]
+getNameHints _ (UN arr) | arr == txt "->" = [sUN "f",sUN "g"]
 getNameHints i n =
         case lookupCtxt n (idris_namehints i) of
              [ns] -> ns
@@ -434,7 +427,6 @@
   i <- getIState
   return $ lookupCtxtExact n (idris_deprecated i)
 
-
 addFragile :: Name -> String -> Idris ()
 addFragile n reason = do
   i <- getIState
@@ -446,15 +438,15 @@
   return $ lookupCtxtExact n (idris_fragile i)
 
 push_estack :: Name -> Bool -> Idris ()
-push_estack n impl
+push_estack n implementation
     = do i <- getIState
-         putIState (i { elab_stack = (n, impl) : elab_stack i })
+         putIState (i { elab_stack = (n, implementation) : elab_stack i })
 
 pop_estack :: Idris ()
 pop_estack = do i <- getIState
                 putIState (i { elab_stack = ptail (elab_stack i) })
     where ptail [] = []
-          ptail (x : xs) = xs
+          ptail (_ : xs) = xs
 
 -- | Add an interface implementation function.
 --
@@ -519,10 +511,25 @@
 addInterface n i
    = do ist <- getIState
         let i' = case lookupCtxt n (idris_interfaces ist) of
-                      [c] -> c { interface_implementations = interface_implementations i }
+                      [c] -> i { interface_implementations = interface_implementations c ++
+                                                             interface_implementations i }
                       _ -> i
         putIState $ ist { idris_interfaces = addDef n i' (idris_interfaces ist) }
 
+updateIMethods :: Name -> [(Name, PTerm)] -> Idris ()
+updateIMethods n meths
+   = do ist <- getIState
+        let i = case lookupCtxtExact n (idris_interfaces ist) of
+                     Just c -> c { interface_methods = update (interface_methods c) }
+                     Nothing -> error "Can't happen updateIMethods"
+        putIState $ ist { idris_interfaces = addDef n i (idris_interfaces ist) }
+  where
+    update [] = []
+    update (m@(n, (b, opts, t)) : rest)
+        | Just ty <- lookup n meths
+             = (n, (b, opts, ty)) : update rest
+        | otherwise = m : update rest
+
 addRecord :: Name -> RecordInfo -> Idris ()
 addRecord n ri = do ist <- getIState
                     putIState $ ist { idris_records = addDef n ri (idris_records ist) }
@@ -550,7 +557,7 @@
                 when (notDef (ibc_write i)) $
                   putIState $ i { ibc_write = ibc : ibc_write i }
    where notDef [] = True
-         notDef (IBCDef n': is) | n == n' = False
+         notDef (IBCDef n': _) | n == n' = False
          notDef (_ : is) = notDef is
 addIBC ibc = do i <- getIState; putIState $ i { ibc_write = ibc : ibc_write i }
 
@@ -687,7 +694,7 @@
 clearPTypes = do i <- get
                  let ctxt = tt_ctxt i
                  put (i { tt_ctxt = mapDefCtxt pErase ctxt })
-   where pErase (CaseOp c t tys orig tot cds)
+   where pErase (CaseOp c t tys orig _ cds)
             = CaseOp c t tys orig [] (pErase' cds)
          pErase x = x
          pErase' (CaseDefs (cs, c) rs)
@@ -703,7 +710,7 @@
              _ -> return ()
 
 isUndefined :: FC -> Name -> Idris Bool
-isUndefined fc n
+isUndefined _ n
     = do i <- getContext
          case lookupTyExact n i of
              Just _ -> return False
@@ -760,7 +767,7 @@
         tidyNames used (Bind n b sc)
             = let n' = uniqueNameSet n used in
                   Bind n' b $ tidyNames (S.insert n' used) sc
-        tidyNames used b = b
+        tidyNames _    b = b
 
 solveDeferred :: FC -> Name -> Idris ()
 solveDeferred fc n
@@ -1028,18 +1035,32 @@
 targetCPU = do i <- getIState
                return (opt_cpu (idris_options i))
 
-verbose :: Idris Bool
-verbose = do i <- getIState
-             -- Quietness overrides verbosity
-             return (not (opt_quiet (idris_options i)) &&
-                     opt_verbose (idris_options i))
+verbose :: Idris Int
+verbose = do
+  i <- getIState
+  -- Quietness overrides verbosity
+  let quiet = opt_quiet   $ idris_options i
+  if quiet
+    then return $ 0
+    else return $ (opt_verbose $ idris_options i)
 
-setVerbose :: Bool -> Idris ()
-setVerbose t = do i <- getIState
-                  let opts = idris_options i
-                  let opt' = opts { opt_verbose = t }
-                  putIState $ i { idris_options = opt' }
+setVerbose :: Int -> Idris ()
+setVerbose t = do
+  i <- getIState
+  let opts = idris_options i
+  let opt' = opts { opt_verbose = t }
+  putIState $ i { idris_options = opt' }
 
+iReport :: Int -> String -> Idris ()
+iReport level msg = do
+  verbosity <- verbose
+  i <- getIState
+  when (level <= verbosity) $
+    case idris_outputmode i of
+      RawOutput h -> runIO $ hPutStrLn h msg
+      IdeMode n h -> runIO . hPutStrLn h $ convSExp "write-string" msg n
+  return ()
+
 typeInType :: Idris Bool
 typeInType = do i <- getIState
                 return (opt_typeintype (idris_options i))
@@ -1134,7 +1155,6 @@
           setColour' PromptColour    c t = t { promptColour = c }
           setColour' PostulateColour c t = t { postulateColour = c }
 
-
 logLvl :: Int -> String -> Idris ()
 logLvl = logLvlCats []
 
@@ -1168,7 +1188,7 @@
            -> Int      -- ^ The Logging level the message should appear.
            -> String   -- ^ The message to show the developer.
            -> Idris ()
-logLvlCats cs l str = do
+logLvlCats cs l msg = do
     i <- getIState
     let lvl  = opt_logLevel (idris_options i)
     let cats = opt_logcats (idris_options i)
@@ -1176,9 +1196,9 @@
       when (inCat cs cats || null cats) $
         case idris_outputmode i of
           RawOutput h -> do
-            runIO $ hPutStrLn h str
+            runIO $ hPutStrLn h msg
           IdeMode n h -> do
-            let good = SexpList [IntegerAtom (toInteger l), toSExp str]
+            let good = SexpList [IntegerAtom (toInteger l), toSExp msg]
             runIO . hPutStrLn h $ convSExp "log" good n
   where
     inCat :: [LogCat] -> [LogCat] -> Bool
@@ -1200,7 +1220,30 @@
                    let opt' = opts { opt_typecase = t }
                    putIState $ i { idris_options = opt' }
 
+getIndentWith :: Idris Int
+getIndentWith = do
+  i <- getIState
+  return $ interactiveOpts_indentWith (idris_interactiveOpts i)
 
+setIndentWith :: Int -> Idris ()
+setIndentWith indentWith = do
+  i <- getIState
+  let opts = idris_interactiveOpts i
+  let opts' = opts { interactiveOpts_indentWith = indentWith }
+  putIState $ i { idris_interactiveOpts = opts' }
+
+getIndentClause :: Idris Int
+getIndentClause = do
+  i <- getIState
+  return $ interactiveOpts_indentClause (idris_interactiveOpts i)
+
+setIndentClause :: Int -> Idris ()
+setIndentClause indentClause = do
+  i <- getIState
+  let opts = idris_interactiveOpts i
+  let opts' = opts { interactiveOpts_indentClause = indentClause }
+  putIState $ i { idris_interactiveOpts = opts' }
+
 -- Dealing with parameters
 
 expandParams :: (Name -> Name) -> [(Name, PTerm)] ->
@@ -1296,8 +1339,8 @@
 
     nseq x y = nsroot x == nsroot y
 
-    enTacImp ql (TacImp aos st scr)  = TacImp aos st (en ql scr)
-    enTacImp ql other                = other
+    enTacImp ql (TacImp aos st scr rig) = TacImp aos st (en ql scr) rig
+    enTacImp ql other                   = other
 
 expandParamsD :: Bool -> -- True = RHS only
                  IState ->
@@ -1465,10 +1508,10 @@
        putIState $ i { idris_statics = addDef n stpos (idris_statics i) }
        addIBC (IBCStatic n)
   where
-    initStatics (Bind n (Pi _ ty _) sc) (PPi p n' fc t s)
+    initStatics (Bind n (Pi _ _ ty _) sc) (PPi p n' fc t s)
             | n /= n' = let (static, dynamic) = initStatics sc (PPi p n' fc t s) in
                             (static, (n, ty) : dynamic)
-    initStatics (Bind n (Pi _ ty _) sc) (PPi p n' fc _ s)
+    initStatics (Bind n (Pi _ _ ty _) sc) (PPi p n' fc _ s)
             = let (static, dynamic) = initStatics (instantiate (P Bound n ty) sc) s in
                   if pstatic p == Static then ((n, ty) : static, dynamic)
                     else if (not (searchArg p))
@@ -1484,16 +1527,16 @@
             getNamePos i ps (P _ n _ : as)
                  | i `elem` ps = n : getNamePos (i + 1) ps as
             getNamePos i ps (_ : as) = getNamePos (i + 1) ps as
-    getParamNames ist (Bind t (Pi _ (P _ n _) _) sc)
+    getParamNames ist (Bind t (Pi _ _ (P _ n _) _) sc)
        = n : getParamNames ist sc
     getParamNames ist _ = []
 
-    getNamesFrom i ps (Bind n (Pi _ _ _) sc)
+    getNamesFrom i ps (Bind n (Pi _ _ _ _) sc)
        | i `elem` ps = n : getNamesFrom (i + 1) ps sc
        | otherwise = getNamesFrom (i + 1) ps sc
     getNamesFrom i ps sc = []
 
-    freeArgNames (Bind n (Pi _ ty _) sc)
+    freeArgNames (Bind n (Pi _ _ ty _) sc)
           = nub $ freeNames ty ++ freeNames sc -- treat '->' as fn here
     freeArgNames tm = let (_, args) = unApply tm in
                           concatMap freeNames args
@@ -1501,11 +1544,11 @@
     -- if a name appears in an interface or tactic implicit index, it doesn't
     -- affect its 'uniquely inferrable' from a static status since these are
     -- resolved by searching.
-    searchArg (Constraint _ _) = True
-    searchArg (TacImp _ _ _) = True
+    searchArg (Constraint _ _ _) = True
+    searchArg (TacImp _ _ _ _) = True
     searchArg _ = False
 
-    staticList sts (Bind n (Pi _ _ _) sc) = (n `elem` sts) : staticList sts sc
+    staticList sts (Bind n (Pi _ _ _ _) sc) = (n `elem` sts) : staticList sts sc
     staticList _ _ = []
 
 -- Dealing with implicit arguments
@@ -1537,14 +1580,14 @@
          -- if all of args in ns, then add it
          doAdd (UConstraint c args : cs) ns t
              | all (\n -> elem n ns) args
-                   = PPi (Constraint [] Dynamic) (sMN 0 "cu") NoFC
+                   = PPi (Constraint [] Dynamic RigW) (sMN 0 "cu") NoFC
                          (mkConst c args) (doAdd cs ns t)
              | otherwise = doAdd cs ns t
 
          mkConst c args = PApp fc (PRef fc [] c)
                            (map (PExp 0 [] (sMN 0 "carg") . PRef fc []) args)
 
-         getConstraints (PPi (Constraint _ _) _ _ c sc)
+         getConstraints (PPi (Constraint _ _ _) _ _ c sc)
              = getcapp c ++ getConstraints sc
          getConstraints (PPi _ _ _ c sc) = getConstraints sc
          getConstraints _ = []
@@ -1613,25 +1656,25 @@
         scopedimpl (Just i) = not (toplevel_imp i)
         scopedimpl _ = False
 
-        getImps (Bind n (Pi i _ _) sc) imps
+        getImps (Bind n (Pi _ i _ _) sc) imps
              | scopedimpl i = getImps sc imps
-        getImps (Bind n (Pi _ t _) sc) imps
+        getImps (Bind n (Pi _ _ t _) sc) imps
             | Just (p, t') <- lookup n imps = argInfo n p t' : getImps sc imps
          where
-            argInfo n (Imp opt _ _ _ _) Placeholder
+            argInfo n (Imp opt _ _ _ _ _) Placeholder
                    = (True, PImp 0 True opt n Placeholder)
-            argInfo n (Imp opt _ _ _ _) t'
+            argInfo n (Imp opt _ _ _ _ _) t'
                    = (False, PImp (getPriority i t') True opt n t')
-            argInfo n (Exp opt _ _) t'
+            argInfo n (Exp opt _ _ _) t'
                    = (InaccessibleArg `elem` opt,
                           PExp (getPriority i t') opt n t')
-            argInfo n (Constraint opt _) t'
+            argInfo n (Constraint opt _ _) t'
                    = (InaccessibleArg `elem` opt,
                           PConstraint 10 opt n t')
-            argInfo n (TacImp opt _ scr) t'
+            argInfo n (TacImp opt _ scr _) t'
                    = (InaccessibleArg `elem` opt,
                           PTacImplicit 10 opt n scr t')
-        getImps (Bind n (Pi _ t _) sc) imps = impBind n t : getImps sc imps
+        getImps (Bind n (Pi _ _ t _) sc) imps = impBind n t : getImps sc imps
            where impBind n t = (True, PImp 1 True [] n Placeholder)
         getImps sc tm = []
 
@@ -1714,13 +1757,13 @@
        = do (decls, ns) <- get
             let isn = nub (implNamesIn uvars ty)
             put (decls, nub (ns ++ (isn `dropAll` (env ++ map fst (getImps decls)))))
-    imps top env (PPi (Imp l _ _ _ _) n _ ty sc)
+    imps top env (PPi (Imp l _ _ _ _ _) n _ ty sc)
         = do let isn = nub (implNamesIn uvars ty) `dropAll` [n]
              (decls , ns) <- get
              put (PImp (getPriority ist ty) True l n Placeholder : decls,
                   nub (ns ++ (isn `dropAll` (env ++ map fst (getImps decls)))))
              imps True (n:env) sc
-    imps top env (PPi (Exp l _ _) n _ ty sc)
+    imps top env (PPi (Exp l _ _ _) n _ ty sc)
         = do let isn = nub (implNamesIn uvars ty ++ case sc of
                             (PRef _ _ x) -> namesIn uvars ist sc `dropAll` [n]
                             _ -> [])
@@ -1728,7 +1771,7 @@
              put (PExp (getPriority ist ty) l n Placeholder : decls,
                   nub (ns ++ (isn `dropAll` (env ++ map fst (getImps decls)))))
              imps True (n:env) sc
-    imps top env (PPi (Constraint l _) n _ ty sc)
+    imps top env (PPi (Constraint l _ _) n _ ty sc)
         = do let isn = nub (implNamesIn uvars ty ++ case sc of
                             (PRef _ _ x) -> namesIn uvars ist sc `dropAll` [n]
                             _ -> [])
@@ -1736,7 +1779,7 @@
              put (PConstraint 10 l n Placeholder : decls,
                   nub (ns ++ (isn `dropAll` (env ++ map fst (getImps decls)))))
              imps True (n:env) sc
-    imps top env (PPi (TacImp l _ scr) n _ ty sc)
+    imps top env (PPi (TacImp l _ scr _) n _ ty sc)
         = do let isn = nub (implNamesIn uvars ty ++ case sc of
                             (PRef _ _ x) -> namesIn uvars ist sc `dropAll` [n]
                             _ -> [])
@@ -1908,7 +1951,8 @@
     ai inpat qq env ds (PPi p n nfc ty sc)
       = let ty' = ai inpat qq env ds ty
             env' = if n `elem` imp_meths then env
-                      else ((n, Just ty) : env)
+                      else
+                      ((n, Just ty) : env)
             sc' = ai inpat qq env' ds sc in
             PPi p n nfc ty' sc'
     ai inpat qq env ds (PGoal fc r n sc)
@@ -2136,7 +2180,7 @@
 stripUnmatchable i (PApp fc fn args) = PApp fc fn (fmap (fmap su) args) where
     su :: PTerm -> PTerm
     su tm@(PRef fc hl f)
-       | (Bind n (Pi _ t _) sc :_) <- lookupTy f (tt_ctxt i)
+       | (Bind n (Pi _ _ t _) sc :_) <- lookupTy f (tt_ctxt i)
           = Placeholder
        | (TType _ : _) <- lookupTy f (tt_ctxt i),
          not (implicitable f)
@@ -2149,8 +2193,12 @@
        -- check will not necessarily fully resolve constructor names,
        -- and these bare names will otherwise get in the way of
        -- impossbility checking.
-       | canBeDConName fn ctxt
+       | -- Just fn <- getFn f,
+         canBeDConName fn ctxt
           = PApp fc f (fmap (fmap su) args)
+      where getFn (PRef _ _ fn) = Just fn
+            getFn (PApp _ f args) = getFn f
+            getFn _ = Nothing
     su (PApp fc f args)
           = PHidden (PApp fc f args)
     su (PAlternative ms b alts)
@@ -2216,9 +2264,10 @@
 instance Monad (EitherErr a) where
     return = RightOK
 
-    (LeftErr e) >>= k = LeftErr e
+    (LeftErr e) >>= _ = LeftErr e
     RightOK v   >>= k = k v
 
+toEither :: EitherErr a b -> Either a b
 toEither (LeftErr e)  = Left e
 toEither (RightOK ho) = Right ho
 
@@ -2359,6 +2408,8 @@
                    PPi p x' fc (sm (x':xs) (substMatch x (PRef emptyFC [] x') t))
                                (sm (x':xs) (substMatch x (PRef emptyFC [] x') sc))
          | otherwise = PPi p x fc (sm xs t) (sm (x : xs) sc)
+    sm xs (PLet fc x xfc val t sc)
+         = PLet fc x xfc (sm xs val) (sm xs t) (sm xs sc)
     sm xs (PApp f x as) = fullApp $ PApp f (sm xs x) (map (fmap (sm xs)) as)
     sm xs (PCase f x as) = PCase f (sm xs x) (map (pmap (sm xs)) as)
     sm xs (PIfThenElse fc c t f) = PIfThenElse fc (sm xs c) (sm xs t) (sm xs f)
@@ -2429,7 +2480,7 @@
   -- looking for too long...)
   initN (UN n) l = UN $ txt (str n ++ show l)
   initN (MN i s) l = MN (i+l) s
-  initN n l = n
+  initN n _ = n
 
   -- FIXME: Probably ought to do this for completeness! It's fine as
   -- long as there are no bindings inside tactics though.
@@ -2537,50 +2588,49 @@
 
   mkUniq ql nmap tm = descendM (mkUniq ql nmap) tm
 
-
 getFile :: Opt -> Maybe String
-getFile (Filename str) = Just str
+getFile (Filename s) = Just s
 getFile _ = Nothing
 
 getBC :: Opt -> Maybe String
-getBC (BCAsm str) = Just str
+getBC (BCAsm s) = Just s
 getBC _ = Nothing
 
 getOutput :: Opt -> Maybe String
-getOutput (Output str) = Just str
+getOutput (Output s) = Just s
 getOutput _ = Nothing
 
 getIBCSubDir :: Opt -> Maybe String
-getIBCSubDir (IBCSubDir str) = Just str
+getIBCSubDir (IBCSubDir s) = Just s
 getIBCSubDir _ = Nothing
 
 getImportDir :: Opt -> Maybe String
-getImportDir (ImportDir str) = Just str
+getImportDir (ImportDir s) = Just s
 getImportDir _ = Nothing
 
 getSourceDir :: Opt -> Maybe String
-getSourceDir (SourceDir str) = Just str
+getSourceDir (SourceDir s) = Just s
 getSourceDir _ = Nothing
 
 getPkgDir :: Opt -> Maybe String
-getPkgDir (Pkg str) = Just str
+getPkgDir (Pkg s) = Just s
 getPkgDir _ = Nothing
 
 getPkg :: Opt -> Maybe (Bool, String)
-getPkg (PkgBuild   str) = Just (False, str)
-getPkg (PkgInstall str) = Just (True, str)
+getPkg (PkgBuild s)   = Just (False, s)
+getPkg (PkgInstall s) = Just (True, s)
 getPkg _ = Nothing
 
 getPkgClean :: Opt -> Maybe String
-getPkgClean (PkgClean str) = Just str
+getPkgClean (PkgClean s) = Just s
 getPkgClean _ = Nothing
 
 getPkgREPL :: Opt -> Maybe String
-getPkgREPL (PkgREPL str) = Just str
+getPkgREPL (PkgREPL s) = Just s
 getPkgREPL _ = Nothing
 
 getPkgCheck :: Opt -> Maybe String
-getPkgCheck (PkgCheck str) = Just str
+getPkgCheck (PkgCheck s) = Just s
 getPkgCheck _              = Nothing
 
 -- | Returns None if given an Opt which is not PkgMkDoc
@@ -2608,7 +2658,6 @@
 getConsoleWidth (UseConsoleWidth x) = Just x
 getConsoleWidth _ = Nothing
 
-
 getExecScript :: Opt -> Maybe String
 getExecScript (InterpretScript expr) = Just expr
 getExecScript _ = Nothing
@@ -2657,7 +2706,7 @@
 -- Get the first valid port
 getPort :: [Opt] -> Maybe REPLPort
 getPort []            = Nothing
-getPort (Port p : xs) = Just p
+getPort (Port p : _ ) = Just p
 getPort (_      : xs) = getPort xs
 
 opt :: (Opt -> Maybe a) -> [Opt] -> [a]
diff --git a/src/Idris/AbsSyntaxTree.hs b/src/Idris/AbsSyntaxTree.hs
--- a/src/Idris/AbsSyntaxTree.hs
+++ b/src/Idris/AbsSyntaxTree.hs
@@ -5,50 +5,47 @@
 License     : BSD3
 Maintainer  : The Idris Community.
 -}
-{-# LANGUAGE DeriveDataTypeable, DeriveFunctor, DeriveGeneric,
-             FlexibleInstances, MultiParamTypeClasses, PatternGuards,
-             TypeSynonymInstances #-}
 
+{-# LANGUAGE DeriveDataTypeable, DeriveFunctor, DeriveGeneric, PatternGuards #-}
+
 module Idris.AbsSyntaxTree where
 
-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.CodegenCommon
 import IRTS.Lang
 import Util.DynamicLinker
 import Util.Pretty
 
-import Prelude hiding ((<$>))
+import Idris.Colours
 
+import System.IO
+
+import Prelude hiding (Foldable, Traversable, (<$>))
+
 import Control.Applicative ((<|>))
 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 (children, universe)
 import Data.List hiding (group)
 import qualified Data.Map.Strict as M
-import Data.Maybe (fromMaybe, mapMaybe, maybeToList)
+import Data.Maybe (mapMaybe, maybeToList)
 import qualified Data.Set as S
 import qualified Data.Text as T
 import Data.Traversable (Traversable)
 import Data.Typeable
-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
   deriving (Show, Eq)
 
@@ -66,7 +63,7 @@
   , elabFC    :: Maybe FC
   , constraintNS :: String        -- ^ filename for adding to constraint variables
   , pe_depth  :: Int
-
+  , noCaseLift :: [Name]         -- ^ types which shouldn't be made arguments to case
   -- | We may, recursively, collect transformations to do on the rhs,
   -- e.g. rewriting recursive calls to functions defined by 'with'
   , rhs_trans :: PTerm -> PTerm
@@ -74,10 +71,10 @@
   }
 
 toplevel :: ElabInfo
-toplevel = EInfo [] emptyContext id [] Nothing "(toplevel)" 0 id (\_ _ _ -> fail "Not implemented")
+toplevel = EInfo [] emptyContext id [] Nothing "(toplevel)" 0 [] id (\_ _ _ -> fail "Not implemented")
 
 toplevelWith :: String -> ElabInfo
-toplevelWith ns = EInfo [] emptyContext id [] Nothing ns 0 id (\_ _ _ -> fail "Not implemented")
+toplevelWith ns = EInfo [] emptyContext id [] Nothing ns 0 [] id (\_ _ _ -> fail "Not implemented")
 
 eInfoNames :: ElabInfo -> [Name]
 eInfoNames info = map fst (params info) ++ M.keys (inblock info)
@@ -91,7 +88,7 @@
   , opt_showimp      :: Bool          -- ^ show implicits
   , opt_errContext   :: Bool
   , opt_repl         :: Bool
-  , opt_verbose      :: Bool
+  , opt_verbose      :: Int
   , opt_nobanner     :: Bool
   , opt_quiet        :: Bool
   , opt_codegen      :: Codegen
@@ -112,6 +109,7 @@
   , opt_autoimpls    :: Bool
   } deriving (Show, Eq, Generic)
 
+defaultOpts :: IOption
 defaultOpts = IOption { opt_logLevel   = 0
                       , opt_logcats    = []
                       , opt_typecase   = False
@@ -120,7 +118,7 @@
                       , opt_showimp    = False
                       , opt_errContext = False
                       , opt_repl       = True
-                      , opt_verbose    = True
+                      , opt_verbose    = 0
                       , opt_nobanner   = False
                       , opt_quiet      = False
                       , opt_codegen    = Via IBCFormat "c"
@@ -151,7 +149,8 @@
 data Optimisation = PETransform -- ^ partial eval and associated transforms
   deriving (Show, Eq, Generic)
 
-defaultOptimise = [PETransform]
+defaultOptimise :: [Optimisation]
+defaultOptimise = []
 
 -- | Pretty printing options with default verbosity.
 defaultPPOption :: PPOption
@@ -184,7 +183,9 @@
 ppOptionIst :: IState -> PPOption
 ppOptionIst = ppOption . idris_options
 
-data LanguageExt = TypeProviders | ErrorReflection
+data LanguageExt = TypeProviders | ErrorReflection | UniquenessTypes
+                 | DSLNotation   | ElabReflection  | FCReflection
+                 | LinearTypes
   deriving (Show, Eq, Read, Ord, Generic)
 
 -- | The output mode in use
@@ -204,6 +205,12 @@
                      | DefaultCheckingCovering -- ^Total coverage, but may diverge
   deriving (Show, Eq, Generic)
 
+-- | Configuration options for interactive editing.
+data InteractiveOpts = InteractiveOpts {
+    interactiveOpts_indentWith :: Int
+  , interactiveOpts_indentClause :: Int
+} deriving (Show, Generic)
+
 -- | The global state used in the Idris monad
 data IState = IState {
     tt_ctxt            :: Context            -- ^ All the currently defined names and their terms
@@ -250,6 +257,7 @@
   , idris_metavars      :: [(Name, (Maybe Name, Int, [Name], Bool, Bool))]
   , idris_coercions              :: [Name]
   , idris_errRev                 :: [(Term, Term)]
+  , idris_errReduce              :: [Name]
   , syntax_rules                 :: SyntaxRules
   , syntax_keywords              :: [String]
   , imported                     :: [FilePath]                    -- ^ The imported modules
@@ -285,14 +293,12 @@
   , idris_postulates             :: S.Set Name
   , idris_externs                :: S.Set (Name, Int)
   , idris_erasureUsed            :: [(Name, Int)]                  -- ^ Function/constructor name, argument position is used
-  , idris_whocalls               :: Maybe (M.Map Name [Name])
-  , idris_callswho               :: Maybe (M.Map Name [Name])
 
   -- | List of names that were defined in the repl, and can be re-/un-defined
   , idris_repl_defs              :: [Name]
 
   -- | Stack of names currently being elaborated, Bool set if it's an
-  -- implementation (implementations appear twice; also as a funtion name)
+  -- implementation (implementations appear twice; also as a function name)
   , elab_stack                   :: [(Name, Bool)]
 
 
@@ -304,8 +310,8 @@
   , idris_inmodule               :: S.Set Name                -- ^ Names defined in current module
   , idris_ttstats                :: M.Map Term (Int, Term)
   , idris_fragile                :: Ctxt String               -- ^ Fragile names and explanation.
-  }
-  deriving Generic
+  , idris_interactiveOpts        :: InteractiveOpts
+  } deriving Generic
 
 -- Required for parsers library, and therefore trifecta
 instance Show IState where
@@ -330,11 +336,13 @@
 deriving instance Binary CGInfo
 !-}
 
+primDefs :: [Name]
 primDefs = [ sUN "unsafePerformPrimIO"
            , sUN "mkLazyForeignPrim"
            , sUN "mkForeignPrim"
            , sUN "void"
            , sUN "assert_unreachable"
+           , sUN "idris_crash"
            ]
 
 -- information that needs writing for the current module's .ibc file
@@ -366,6 +374,7 @@
               | IBCFnInfo Name FnInfo
               | IBCTrans Name (Term, Term)
               | IBCErrRev (Term, Term)
+              | IBCErrReduce Name
               | IBCCG Name
               | IBCDoc Name
               | IBCCoercion Name
@@ -387,6 +396,12 @@
               | IBCConstraint FC UConstraint
   deriving (Show, Generic)
 
+initialInteractiveOpts :: InteractiveOpts
+initialInteractiveOpts = InteractiveOpts {
+    interactiveOpts_indentWith = 2
+  , interactiveOpts_indentClause = 2
+}
+
 -- | The initial state for the compiler
 idrisInit :: IState
 idrisInit = IState initContext S.empty []
@@ -395,11 +410,11 @@
                    emptyContext emptyContext emptyContext emptyContext
                    emptyContext emptyContext emptyContext emptyContext
                    emptyContext
-                   [] [] [] defaultOpts 6 [] [] [] [] emptySyntaxRules [] [] [] [] [] [] []
+                   [] [] [] defaultOpts 6 [] [] [] [] [] emptySyntaxRules [] [] [] [] [] [] []
                    [] [] Nothing [] Nothing [] [] Nothing Nothing emptyContext Private DefaultCheckingPartial [] Nothing [] []
                    (RawOutput stdout) True defaultTheme [] (0, emptyContext) emptyContext M.empty
-                   AutomaticWidth S.empty S.empty [] Nothing Nothing [] [] M.empty [] [] []
-                   emptyContext S.empty M.empty emptyContext
+                   AutomaticWidth S.empty S.empty [] [] [] M.empty [] [] []
+                   emptyContext S.empty M.empty emptyContext initialInteractiveOpts
 
 
 -- | The monad for the main REPL - reading and processing files and
@@ -485,6 +500,8 @@
          | ColourREPL Bool
          | Idemode
          | IdemodeSocket
+         | IndentWith Int
+         | IndentClause Int
          | ShowAll
          | ShowLibs
          | ShowLibDir
@@ -506,11 +523,12 @@
          | DefaultPartial
          | WarnPartial
          | WarnReach
+         | AuditIPkg
          | EvalTypes
          | NoCoverage
          | ErrContext
          | ShowImpl
-         | Verbose
+         | Verbose Int
          | Port REPLPort -- ^ REPL TCP port
          | IBCSubDir String
          | ImportDir String
@@ -597,17 +615,21 @@
                    , pparam    :: Bool
                    , pscoped   :: Maybe ImplicitInfo -- ^ Nothing, if top level
                    , pinsource :: Bool               -- ^ Explicitly written in source
+                   , pcount    :: RigCount
                    }
              | Exp { pargopts :: [ArgOpt]
                    , pstatic  :: Static
                    , pparam   :: Bool -- ^ this is a param (rather than index)
+                   , pcount    :: RigCount
                    }
              | Constraint { pargopts :: [ArgOpt]
-                         ,  pstatic :: Static
+                          , pstatic :: Static
+                          , pcount    :: RigCount
                          }
              | TacImp { pargopts :: [ArgOpt]
                       , pstatic  :: Static
                       , pscript  :: PTerm
+                      , pcount    :: RigCount
                       }
              deriving (Show, Eq, Ord, Data, Generic, Typeable)
 
@@ -616,24 +638,32 @@
 !-}
 
 is_scoped :: Plicity -> Maybe ImplicitInfo
-is_scoped (Imp _ _ _ s _) = s
-is_scoped _               = Nothing
+is_scoped (Imp _ _ _ s _ _) = s
+is_scoped _                 = Nothing
 
 -- Top level implicit
-impl              = Imp [] Dynamic False (Just (Impl False True False)) False
+impl              :: Plicity
+impl              = Imp [] Dynamic False (Just (Impl False True False)) False RigW
 -- Machine generated top level implicit
-impl_gen          = Imp [] Dynamic False (Just (Impl False True True)) False
+impl_gen          :: Plicity
+impl_gen          = Imp [] Dynamic False (Just (Impl False True True)) False RigW
 
 -- Scoped implicits
-forall_imp        = Imp [] Dynamic False (Just (Impl False False True)) False
-forall_constraint = Imp [] Dynamic False (Just (Impl True False True)) False
+forall_imp        :: Plicity
+forall_imp        = Imp [] Dynamic False (Just (Impl False False True)) False RigW
+forall_constraint :: Plicity
+forall_constraint = Imp [] Dynamic False (Just (Impl True False True)) False RigW
 
-expl              = Exp [] Dynamic False
-expl_param        = Exp [] Dynamic True
+expl              :: Plicity
+expl              = Exp [] Dynamic False RigW
+expl_param        :: Plicity
+expl_param        = Exp [] Dynamic True RigW
 
-constraint        = Constraint [] Static
+constraint        :: Plicity
+constraint        = Constraint [] Static RigW
 
-tacimpl t         = TacImp [] Dynamic t
+tacimpl           :: PTerm -> Plicity
+tacimpl t         = TacImp [] Dynamic t RigW
 
 data FnOpt = Inlinable -- ^ always evaluate when simplifying
            | TotalFn | PartialFn | CoveringFn
@@ -649,14 +679,9 @@
            | CExport String                 -- ^ export, with a C name
            | ErrorHandler                   -- ^ an error handler for use with the ErrorReflection extension
            | ErrorReverse                   -- ^ attempt to reverse normalise before showing in error
+           | ErrorReduce                    -- ^ unfold definition before showing an 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
@@ -1403,7 +1428,7 @@
 -- Interface data
 
 data InterfaceInfo = CI {
-    implementationCtorName                   :: Name
+    implementationCtorName             :: Name
   , 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]
@@ -1617,8 +1642,8 @@
 getInferTerm tm = tm -- error ("getInferTerm " ++ show tm)
 
 getInferType (Bind n b sc)  = Bind n (toTy b) $ getInferType sc
-  where toTy (Lam t)        = Pi Nothing t (TType (UVar [] 0))
-        toTy (PVar t)       = PVTy t
+  where toTy (Lam r t)      = Pi r Nothing t (TType (UVar [] 0))
+        toTy (PVar _ t)     = PVTy t
         toTy b              = b
 getInferType (App _ (App _ _ ty) _) = ty
 
@@ -1813,7 +1838,15 @@
       depth d . bracket p startPrec . group . align $
       kwd "let" <+> (group . align . hang 2 $ prettyBindingOf n False <+> text "=" <$> prettySe (decD d) startPrec bnd v) </>
       kwd "in" <+> (group . align . hang 2 $ prettySe (decD d) startPrec ((n, False):bnd) sc)
-    prettySe d p bnd (PPi (Exp l s _) n _ ty sc)
+    prettySe d p bnd (PPi (Exp l s _ rig) n _ ty sc)
+      | Rig0 <- rig =
+          depth d . bracket p startPrec . group $
+          enclose lparen rparen (group . align $ text "0" <+> prettyBindingOf n False <+> colon <+> prettySe (decD d) startPrec bnd ty) <+>
+          st <> text "->" <$> prettySe (decD d) startPrec ((n, False):bnd) sc
+      | Rig1 <- rig =
+          depth d . bracket p startPrec . group $
+          enclose lparen rparen (group . align $ text "1" <+> prettyBindingOf n False <+> colon <+> prettySe (decD d) startPrec bnd ty) <+>
+          st <> text "->" <$> prettySe (decD d) startPrec ((n, False):bnd) sc
       | n `elem` allNamesIn sc || ppopt_impl ppo && uname n || n `elem` docArgs
           || ppopt_pinames ppo && uname n =
           depth d . bracket p startPrec . group $
@@ -1833,24 +1866,28 @@
           case s of
             Static -> text "%static" <> space
             _      -> empty
-    prettySe d p bnd (PPi (Imp l s _ fa _) n _ ty sc)
+    prettySe d p bnd (PPi (Imp l s _ fa _ rig) n _ ty sc)
       | ppopt_impl ppo =
           depth d . bracket p startPrec $
-          lbrace <> prettyBindingOf n True <+> colon <+> prettySe (decD d) startPrec bnd ty <> rbrace <+>
+          lbrace <> showRig rig n <+> colon <+> prettySe (decD d) startPrec bnd ty <> rbrace <+>
           st <> text "->" </> prettySe (decD d) startPrec ((n, True):bnd) sc
       | otherwise = depth d $ prettySe (decD d) startPrec ((n, True):bnd) sc
       where
+        showRig Rig0 n = text "0" <+> prettyBindingOf n True
+        showRig Rig1 n = text "1" <+> prettyBindingOf n True
+        showRig _ n = prettyBindingOf n True
+
         st =
           case s of
             Static -> text "%static" <> space
             _      -> empty
-    prettySe d p bnd (PPi (Constraint _ _) n _ ty sc) =
+    prettySe d p bnd (PPi (Constraint _ _ rig) n _ ty sc) =
       depth d . bracket p startPrec $
       prettySe (decD d) (startPrec + 1) bnd ty <+> text "=>" </> prettySe (decD d) startPrec ((n, True):bnd) sc
-    prettySe d p bnd (PPi (TacImp _ _ (PTactics [ProofSearch{}])) n _ ty sc) =
+    prettySe d p bnd (PPi (TacImp _ _ (PTactics [ProofSearch{}]) rig) n _ ty sc) =
       lbrace <> kwd "auto" <+> pretty n <+> colon <+> prettySe (decD d) startPrec bnd ty <>
       rbrace <+> text "->" </> prettySe (decD d) startPrec ((n, True):bnd) sc
-    prettySe d p bnd (PPi (TacImp _ _ s) n _ ty sc) =
+    prettySe d p bnd (PPi (TacImp _ _ s rig) n _ ty sc) =
       depth d . bracket p startPrec $
       lbrace <> kwd "default" <+> prettySe (decD d) (funcAppPrec + 1) bnd s <+> pretty n <+> colon <+> prettySe (decD d) startPrec bnd ty <>
       rbrace <+> text "->" </> prettySe (decD d) startPrec ((n, True):bnd) sc
@@ -2250,7 +2287,7 @@
 
 getShowArgs :: [PArg] -> [PArg]
 getShowArgs [] = []
-getShowArgs (e@(PExp _ _ _ tm) : xs) = e : getShowArgs xs
+getShowArgs (e@(PExp _ _ _ _) : xs) = e : getShowArgs xs
 getShowArgs (e : xs) | AlwaysShow `elem` argopts e = e : getShowArgs xs
                      | PImp _ _ _ _ tm <- e
                      , containsHole tm = e : getShowArgs xs
@@ -2378,7 +2415,7 @@
     ni i env (PUnquote tm)        = ni (i - 1) env tm
     ni i env tm                   = concatMap (ni i env) (children tm)
 
-    niTacImp i env (TacImp _ _ scr) = ni i env scr
+    niTacImp i env (TacImp _ _ scr _) = ni i env scr
     niTacImp _ _ _                  = []
 
 
@@ -2414,7 +2451,7 @@
     niTms i set []        = set
     niTms i set (x : xs)  = niTms i (ni i set x) xs
 
-    niTacImp i set (TacImp _ _ scr) = ni i set scr
+    niTacImp i set (TacImp _ _ scr _) = ni i set scr
     niTacImp i set _                = set
 
 -- Return names which are valid implicits in the given term (type).
@@ -2470,6 +2507,8 @@
     ni 0 env (PIfThenElse _ c t f)            = mapM_ (ni 0 env) [c, t, f]
     ni 0 env (PLam fc n _ ty sc)              = do ni 0 env ty; ni 0 (n:env) sc
     ni 0 env (PPi p n _ ty sc)                = do ni 0 env ty; ni 0 (n:env) sc
+    ni 0 env (PLet fc n _ ty val sc)          = do ni 0 env ty;
+                                                   ni 0 env val; ni 0 (n:env) sc
     ni 0 env (PRewrite _ _ l r _)             = do ni 0 env l; ni 0 env r
     ni 0 env (PTyped l r)                     = do ni 0 env l; ni 0 env r
     ni 0 env (PPair _ _ _ l r)                = do ni 0 env l; ni 0 env r
@@ -2523,7 +2562,7 @@
 
     ni i env tm                     = concatMap (ni i env) (children tm)
 
-    niTacImp i env (TacImp _ _ scr) = ni i env scr
+    niTacImp i env (TacImp _ _ scr _) = ni i env scr
     niTacImp _ _ _                  = []
 
 -- Return which of the given names are used in the given term.
@@ -2558,12 +2597,12 @@
 
     ni i env tm                     = concatMap (ni i env) (children tm)
 
-    niTacImp i env (TacImp _ _ scr) = ni i env scr
+    niTacImp i env (TacImp _ _ scr _) = ni i env scr
     niTacImp _ _ _                = []
 
 -- Return the list of inaccessible (= dotted) positions for a name.
 getErasureInfo :: IState -> Name -> [Int]
 getErasureInfo ist n =
     case lookupCtxtExact n (idris_optimisation ist) of
-        Just (Optimise inacc detag force) -> map fst inacc
+        Just (Optimise inacc _ _) -> 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
@@ -72,8 +72,8 @@
   isApropos str (CaseOp _ ty ty' _ _ _) = isApropos str ty
 
 instance Apropos (Binder (TT Name)) where
-  isApropos str (Lam ty)      = str == T.pack "\\" || isApropos str ty
-  isApropos str (Pi _ ty _)   = str == T.pack "->" || isApropos str ty
+  isApropos str (Lam _ ty)    = str == T.pack "\\" || isApropos str ty
+  isApropos str (Pi _ _ ty _) = str == T.pack "->" || isApropos str ty
   isApropos str (Let ty val)  = str == T.pack "let" || isApropos str ty || isApropos str val
   isApropos str (NLet ty val) = str == T.pack "let" || isApropos str ty || isApropos str val
   isApropos str _             = False -- these shouldn't occur in defined libraries
diff --git a/src/Idris/CaseSplit.hs b/src/Idris/CaseSplit.hs
--- a/src/Idris/CaseSplit.hs
+++ b/src/Idris/CaseSplit.hs
@@ -15,8 +15,8 @@
 Finally, merge the generated patterns with the original, by matching.
 Always take the "more specific" argument when there is a discrepancy, i.e.
 names over '_', patterns over names, etc.
-
 -}
+
 {-# LANGUAGE PatternGuards #-}
 
 module Idris.CaseSplit(
@@ -28,10 +28,8 @@
   ) where
 
 import Idris.AbsSyntax
-import Idris.AbsSyntaxTree (IState, Idris, PTerm)
 import Idris.Core.Evaluate
 import Idris.Core.TT
-import Idris.Core.Typecheck
 import Idris.Delaborate
 import Idris.Elab.Term
 import Idris.Elab.Value
@@ -39,18 +37,11 @@
 import Idris.Error
 import Idris.Output
 import Idris.Parser
-import Idris.Parser.Helpers
 
 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.Trifecta (Result(..), parseString)
-import Text.Trifecta.Delta
 
 -- | Given a variable to split, and a term application, return a list
 -- of variable updates, paired with a flag to say whether the given
@@ -109,11 +100,11 @@
                        explicit :: [Name],
                        updates :: [(Name, PTerm)] }
 
-addUpdate :: Name -> Idris.AbsSyntaxTree.PTerm -> State MergeState ()
+addUpdate :: Name -> PTerm -> State MergeState ()
 addUpdate n tm = do ms <- get
                     put (ms { updates = ((n, stripNS tm) : updates ms) } )
 
-inventName :: Idris.AbsSyntaxTree.IState -> Maybe Name -> Name -> State MergeState Name
+inventName :: IState -> Maybe Name -> Name -> State MergeState Name
 inventName ist ty n =
     do ms <- get
        let supp = case ty of
@@ -142,7 +133,7 @@
 varlist :: [Name]
 varlist = map (sUN . (:[])) "xyzwstuv" -- EB's personal preference :)
 
-stripNS :: Idris.AbsSyntaxTree.PTerm -> Idris.AbsSyntaxTree.PTerm
+stripNS :: PTerm -> PTerm
 stripNS tm = mapPT dens tm where
     dens (PRef fc hls n) = PRef fc hls (nsroot n)
     dens t = t
@@ -212,7 +203,7 @@
            [ty] -> let ty' = normalise (tt_ctxt ist) [] ty in
                        map (tyName . snd) (getArgTys ty') ++ repeat Nothing
            _ -> repeat Nothing
-  where tyName (Bind _ (Pi _ _ _) _) = Just (sUN "->")
+  where tyName (Bind _ (Pi _ _ _ _) _) = Just (sUN "->")
         tyName t | (P _ d _, [_, ty]) <- unApply t,
                    d == sUN "Delayed" = tyName ty
                  | (P _ n _, _) <- unApply t = Just n
@@ -395,27 +386,29 @@
           -> Name     -- ^ User given name
           -> FilePath -- ^ Source file name
           -> Idris String
-getClause l fn un fp
+getClause l _ un fp
     = do i <- getIState
+         indentClause <- getIndentClause
+--         runIO . traceIO $ "indentClause = " ++ show indentClause
          case lookupCtxt un (idris_interfaces i) of
-              [c] -> return (mkInterfaceBodies i (interface_methods c))
+              [c] -> return (mkInterfaceBodies indentClause i (interface_methods c))
               _ -> do ty_in <- getInternalApp fp l
                       let ty = case ty_in of
-                                    PTyped n t -> t
+                                    PTyped _ t -> t
                                     x -> x
                       ist <- get
-                      let ap = mkApp ist ty []
-                      return (showLHSName un ++ " " ++ ap ++ "= ?"
+                      let app = mkApp ist ty []
+                      return (showLHSName un ++ " " ++ app ++ "= ?"
                                       ++ showRHSName un ++ "_rhs")
    where mkApp :: IState -> PTerm -> [Name] -> String
-         mkApp i (PPi (Exp _ _ False) (MN _ _) _ ty sc) used
+         mkApp i (PPi (Exp _ _ False _) (MN _ _) _ ty sc) used
                = let n = getNameFrom i used ty in
                      show n ++ " " ++ mkApp i sc (n : used)
-         mkApp i (PPi (Exp _ _ False) (UN n) _ ty sc) used
+         mkApp i (PPi (Exp _ _ False _) (UN n) _ ty sc) used
             | thead n == '_'
                = let n = getNameFrom i used ty in
                      show n ++ " " ++ mkApp i sc (n : used)
-         mkApp i (PPi (Exp _ _ False) n _ _ sc) used
+         mkApp i (PPi (Exp _ _ False _) n _ _ sc) used
                = show n ++ " " ++ mkApp i sc (n : used)
          mkApp i (PPi _ _ _ _ sc) used = mkApp i sc used
          mkApp i _ _ = ""
@@ -431,11 +424,11 @@
          getNameFrom i used _ = uniqueNameFrom (mkSupply [sUN "x", sUN "y",
                                                           sUN "z"]) used
 
-         -- write method declarations, indent with 4 spaces
-         mkInterfaceBodies :: IState -> [(Name, (Bool, FnOpts, PTerm))] -> String
-         mkInterfaceBodies i ns
+         -- write method declarations, indent with `indent` spaces.
+         mkInterfaceBodies :: Int -> IState -> [(Name, (Bool, FnOpts, PTerm))] -> String
+         mkInterfaceBodies indent i ns
              = showSep "\n"
-                  (zipWith (\(n, (_, _, ty)) m -> "    " ++
+                  (zipWith (\(n, (_, _, ty)) m -> replicate indent ' ' ++
                             def (show (nsroot n)) ++ " "
                                  ++ mkApp i ty []
                                  ++ "= ?"
@@ -460,9 +453,9 @@
 -- Purely syntactic - turn a pattern match clause into a with and a new
 -- match clause
 
-mkWith :: String -> Name -> String
-mkWith str n = let str' = replaceRHS str "with (_)"
-               in str' ++ "\n" ++ newpat str
+mkWith :: String -> Name -> Int -> String
+mkWith str n indent = let str' = replaceRHS str "with (_)"
+                      in str' ++ "\n" ++ newpat str
 
    where replaceRHS [] str = str
          replaceRHS ('?':'=': rest) str = str
@@ -471,8 +464,7 @@
          replaceRHS (x : rest) str = x : replaceRHS rest str
 
          newpat ('>':patstr) = '>':newpat patstr
-         newpat patstr =
-           "  " ++
+         newpat patstr = replicate indent ' ' ++
            replaceRHS patstr "| with_pat = ?" ++ showRHSName n ++ "_rhs"
 
 -- Replace _ with names in missing clauses
diff --git a/src/Idris/CmdOptions.hs b/src/Idris/CmdOptions.hs
--- a/src/Idris/CmdOptions.hs
+++ b/src/Idris/CmdOptions.hs
@@ -5,7 +5,9 @@
 License     : BSD3
 Maintainer  : The Idris Community.
 -}
+
 {-# LANGUAGE Arrows #-}
+
 module Idris.CmdOptions
   (
     module Idris.CmdOptions
@@ -19,7 +21,6 @@
                         getPort, opt)
 import Idris.AbsSyntaxTree
 import Idris.Info (getIdrisVersion)
--- import Idris.REPL
 import IRTS.CodegenCommon
 
 import Control.Monad.Trans (lift)
@@ -33,8 +34,10 @@
 import Options.Applicative
 import Options.Applicative.Arrows
 import Options.Applicative.Types (ReadM(..))
-import Safe (lastMay)
+
 import Text.ParserCombinators.ReadP hiding (many, option)
+
+import Safe (lastMay)
 import qualified Text.PrettyPrint.ANSI.Leijen as PP
 
 runArgParser :: IO [Opt]
@@ -97,14 +100,15 @@
   <|> flag' Idemode       (long "ide-mode"        <> help "Run the Idris REPL with machine-readable syntax")
   <|> flag' IdemodeSocket (long "ide-mode-socket" <> help "Choose a socket for IDE mode to listen on")
 
-  <|> (Client <$> strOption (long "client"))
+  -- Client flags
+  <|> Client <$> strOption (long "client")
 
   -- Logging Flags
-  <|> (OLogging <$> option auto (long "log" <> metavar "LEVEL" <> help "Debugging log level"))
-  <|> (OLogCats <$> option (str >>= parseLogCats)
+  <|> OLogging <$> option auto (long "log" <> metavar "LEVEL" <> help "Debugging log level")
+  <|> OLogCats <$> option (str >>= parseLogCats)
                            (long "logging-categories"
                          <> metavar "CATS"
-                         <> help "Colon separated logging categories. Use --listlogcats to see list."))
+                         <> help "Colon separated logging categories. Use --listlogcats to see list.")
 
   -- Turn off things
   <|> flag' NoBasePkgs (long "nobasepkgs" <> help "Do not use the given base package")
@@ -113,7 +117,7 @@
 
   <|> flag' NoREPL     (long "check"      <> help "Typecheck only, don't start the REPL")
 
-  <|> (Output <$> strOption (short 'o' <> long "output" <> metavar "FILE" <> help "Specify output file"))
+  <|> Output <$> strOption (short 'o' <> long "output" <> metavar "FILE" <> help "Specify output file")
 
   --   <|> flag' TypeCase (long "typecase")
   <|> flag' Interface      (long "interface"   <> help "Generate interface files from ExportLists")
@@ -122,6 +126,7 @@
   <|> flag' DefaultPartial (long "partial")
   <|> flag' WarnPartial    (long "warnpartial" <> help "Warn about undeclared partial functions")
   <|> flag' WarnReach      (long "warnreach"   <> help "Warn about reachable but inaccessible arguments")
+  <|> flag' AuditIPkg      (long "warnipkg"    <> help "Warn about possible incorrect package specifications")
   <|> flag' NoCoverage     (long "nocoverage")
   <|> flag' ErrContext     (long "errorcontext")
 
@@ -134,35 +139,45 @@
   <|> 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")
+  <|> flag' (Verbose 3) (long "V2" <> help "Loudest verbosity")
+  <|> flag' (Verbose 2) (long "V1" <> help "Louder verbosity")
+  <|> flag' (Verbose 1) (short 'V' <> long "V0" <>long "verbose" <> help "Loud verbosity")
 
-  <|> (IBCSubDir <$> strOption (long "ibcsubdir" <> metavar "FILE" <> help "Write IBC files into sub directory"))
-  <|> (ImportDir <$> strOption (short 'i' <> long "idrispath" <> help "Add directory to the list of import paths"))
-  <|> (SourceDir <$> strOption (long "sourcepath" <> help "Add directory to the list of source search paths"))
+  <|> IBCSubDir <$> strOption (long "ibcsubdir" <> metavar "FILE" <> help "Write IBC files into sub directory")
+  <|> ImportDir <$> strOption (short 'i' <> long "idrispath" <> help "Add directory to the list of import paths")
+  <|> SourceDir <$> strOption (long "sourcepath" <> help "Add directory to the list of source search paths")
 
   <|> flag' WarnOnly (long "warn")
 
-  <|> (Pkg  <$> strOption (short 'p' <> long "package" <> help "Add package as a dependency"))
-  <|> (Port <$> option portReader (long "port" <> metavar "PORT" <> help "REPL TCP port - pass \"none\" to not bind any port"))
+  <|> Pkg  <$> strOption (short 'p' <> long "package" <> help "Add package as a dependency")
+  <|> 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"))
+  <|> 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"))
+  <|> 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")
 
+  -- Interactive Editing Flags
+  <|> IndentWith    <$> option auto (long "indent-with"
+                                           <> metavar "INDENT"
+                                           <> help "Indentation to use with :makewith (default 2)")
+  <|> IndentClause  <$> option auto (long "indent-clause"
+                                           <> metavar "INDENT"
+                                           <> help "Indentation to use with :addclause (default 2)")
+
   -- Misc options
-  <|> (BCAsm <$> strOption (long "bytecode"))
+  <|> BCAsm <$> strOption (long "bytecode")
 
   <|> flag' (OutputTy Raw)          (short 'S' <> long "codegenonly" <> help "Do no further compilation of code generator output")
   <|> flag' (OutputTy Object)       (short 'c' <> long "compileonly" <> help "Compile to object files rather than an executable")
 
-  <|> (DumpDefun <$> strOption (long "dumpdefuns"))
-  <|> (DumpCases <$> strOption (long "dumpcases"))
+  <|> DumpDefun <$> strOption (long "dumpdefuns")
+  <|> DumpCases <$> strOption (long "dumpcases")
 
   <|> (UseCodegen . parseCodegen) <$> strOption (long "codegen"
                                               <> metavar "TARGET"
@@ -172,14 +187,17 @@
                                                  <> metavar "TARGET"
                                                  <> help "Pass the name of the code generator. This option is for codegens that take JSON formatted IR."))
 
-  <|> (CodegenArgs <$> strOption (long "cg-opt"
-                               <> metavar "ARG"
-                               <> help "Arguments to pass to code generator"))
+  <|> CodegenArgs <$> strOption (long "cg-opt"
+                                 <> metavar "ARG"
+                                 <> help "Arguments to pass to code generator")
 
-  <|> (EvalExpr <$> strOption (long "eval" <> short 'e' <> metavar "EXPR" <> help "Evaluate an expression without loading the REPL"))
+  <|> EvalExpr <$> strOption (long "eval"
+                              <> short 'e'
+                              <> metavar "EXPR"
+                              <> help "Evaluate an expression without loading the REPL")
 
   <|> flag' (InterpretScript "Main.main") (long "execute" <> help "Execute as idris")
-  <|> (InterpretScript <$> strOption      (long "exec" <> metavar "EXPR" <> help "Execute as idris"))
+  <|> InterpretScript <$> strOption      (long "exec" <> metavar "EXPR" <> help "Execute as idris")
 
   <|> ((Extension . getExt) <$> strOption (long "extension"
                                         <> short 'X'
@@ -195,10 +213,10 @@
   <|> flag' (AddOpt PETransform) (long "partial-eval")
   <|> flag' (RemoveOpt PETransform) (long "no-partial-eval" <> help "Switch off partial evaluation, mainly for debugging purposes")
 
-  <|> (OptLevel <$> option auto (short 'O' <> long "level"))
+  <|> OptLevel <$> option auto (short 'O' <> long "level")
 
-  <|> (TargetTriple <$> strOption (long "target" <> metavar "TRIPLE" <> help "If supported the codegen will target the named triple."))
-  <|> (TargetCPU    <$> strOption (long "cpu"    <> metavar "CPU"    <> help "If supported the codegen will target the named CPU e.g. corei7 or cortex-m3"))
+  <|> TargetTriple <$> strOption (long "target" <> metavar "TRIPLE" <> help "If supported the codegen will target the named triple.")
+  <|> TargetCPU    <$> strOption (long "cpu"    <> metavar "CPU"    <> help "If supported the codegen will target the named CPU e.g. corei7 or cortex-m3")
 
   -- Colour Options
   <|> flag' (ColourREPL True)  (long "colour"   <> long "color"   <> help "Force coloured output")
diff --git a/src/Idris/Completion.hs b/src/Idris/Completion.hs
--- a/src/Idris/Completion.hs
+++ b/src/Idris/Completion.hs
@@ -159,6 +159,7 @@
 completeCmd :: String -> CompletionFunc Idris
 completeCmd cmd (prev, next) = fromMaybe completeCmdName $ fmap completeArg $ lookupInHelp cmd
     where completeArg FileArg = completeFilename (prev, next)
+          completeArg ShellCommandArg = completeFilename (prev, next)
           completeArg NameArg = completeName UpTo [] (prev, next)
           completeArg OptionArg = completeOption (prev, next)
           completeArg ModuleArg = noCompletion (prev, next)
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
@@ -490,6 +490,19 @@
                            return (RUType x1)
                    _ -> error "Corrupted binary data for Raw"
 
+instance Binary RigCount where
+        put x = case x of
+                     Rig0 -> putWord8 0
+                     Rig1 -> putWord8 1
+                     RigW -> putWord8 2
+        get = do i <- getWord8
+                 case i of
+                     0 -> return Rig0
+                     1 -> return Rig1
+                     2 -> return RigW
+                     _ -> error "Corrupted binary data for RigCount"
+
+
 instance Binary ImplicitInfo where
         put x
           = case x of
@@ -502,12 +515,14 @@
 instance (Binary b) => Binary (Binder b) where
         put x
           = case x of
-                Lam x1 -> do putWord8 0
-                             put x1
-                Pi x1 x2 x3 -> do putWord8 1
-                                  put x1
-                                  put x2
-                                  put x3
+                Lam x1 x2 -> do putWord8 0
+                                put x1
+                                put x2
+                Pi x1 x2 x3 x4 -> do putWord8 1
+                                     put x1
+                                     put x2
+                                     put x3
+                                     put x4
                 Let x1 x2 -> do putWord8 2
                                 put x1
                                 put x2
@@ -523,19 +538,22 @@
                 Guess x1 x2 -> do putWord8 6
                                   put x1
                                   put x2
-                PVar x1 -> do putWord8 7
-                              put x1
+                PVar x1 x2 -> do putWord8 7
+                                 put x1
+                                 put x2
                 PVTy x1 -> do putWord8 8
                               put x1
         get
           = do i <- getWord8
                case i of
                    0 -> do x1 <- get
-                           return (Lam x1)
+                           x2 <- get
+                           return (Lam x1 x2)
                    1 -> do x1 <- get
                            x2 <- get
                            x3 <- get
-                           return (Pi x1 x2 x3)
+                           x4 <- get
+                           return (Pi x1 x2 x3 x4)
                    2 -> do x1 <- get
                            x2 <- get
                            return (Let x1 x2)
@@ -552,7 +570,8 @@
                            x2 <- get
                            return (Guess x1 x2)
                    7 -> do x1 <- get
-                           return (PVar x1)
+                           x2 <- get
+                           return (PVar x1 x2)
                    8 -> do x1 <- get
                            return (PVTy x1)
                    _ -> error "Corrupted binary data for Binder"
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
@@ -174,7 +174,7 @@
                   then S.empty
                   else if n `elem` ps
                           then S.union (nut ps f) (nut ps a)
-                          else S.insert (n, map argNames args) 
+                          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)
@@ -245,7 +245,7 @@
 runCaseBuilder ei bld = runState $ runReaderT bld ei
 
 data Phase = CoverageCheck [Int] -- list of positions explicitly given
-           | CompileTime 
+           | CompileTime
            | RunTime
     deriving (Show, Eq)
 
@@ -253,7 +253,7 @@
 -- Work Right to Left
 
 simpleCase :: Bool -> SC -> Bool ->
-              Phase -> FC -> 
+              Phase -> FC ->
               -- Following two can be empty lists when Phase = CoverageCheck
               [Int] -> -- Inaccessible argument positions
               [(Type, Bool)] -> -- (Argument type, whether it's canonical)
@@ -392,7 +392,7 @@
     toPat' [] (Constant x) | isTypeConst x = PTyPat
                            | otherwise     = PConst x
 
-    toPat' [] (Bind n (Pi _ t _) sc)
+    toPat' [] (Bind n (Pi _ _ t _) sc)
         | reflect && noOccurrence n sc
         = PReflected (sUN "->") [toPat' [] t, toPat' [] sc]
 
@@ -444,7 +444,7 @@
 -- order CompileTime ns cs _ = (map fst ns, cs)
 order _ []  cs cans = ([], cs)
 order _ ns' [] cans = (map fst ns', [])
-order (CoverageCheck pos) 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)
@@ -454,7 +454,7 @@
     -- 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) 
+    pick i skipped (x : xs)
          | i `elem` pos = x : pick (i + 1) skipped xs
          | otherwise    = pick (i + 1) (x : skipped) xs
 
@@ -823,7 +823,7 @@
 prune _ t = t
 
 stripLambdas :: CaseDef -> CaseDef
-stripLambdas (CaseDef ns (STerm (Bind x (Lam _) sc)) tm)
+stripLambdas (CaseDef ns (STerm (Bind x (Lam _ _) sc)) tm)
     = stripLambdas (CaseDef (ns ++ [x]) (STerm (instantiate (P Bound x Erased) sc)) tm)
 stripLambdas x = x
 
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
@@ -1,3 +1,4 @@
+{-# LANGUAGE FlexibleContexts, MultiParamTypeClasses #-}
 {-|
 Module      : Idris.Core.Constraints
 Description : Check universe constraints.
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
@@ -40,6 +40,7 @@
 instance NFData Err
 instance NFData ErrorReportPart
 instance NFData ImplicitInfo
+instance NFData RigCount
 instance (NFData b) => NFData (Binder b)
 instance NFData UExp
 instance NFData NameType
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
@@ -99,7 +99,7 @@
 setNextName = do env <- get_env
                  ES (p, a) s e <- get
                  let pargs = map fst (getArgTys (ptype p))
-                 initNextNameFrom (pargs ++ map fst env)
+                 initNextNameFrom (pargs ++ map fstEnv env)
 
 initNextNameFrom :: [Name] -> Elab' aux ()
 initNextNameFrom ns = do ES (p, a) s e <- get
@@ -327,7 +327,7 @@
         isInj ctxt (App _ f a) = isInj ctxt f
         isInj ctxt (Constant _) = True
         isInj ctxt (TType _) = True
-        isInj ctxt (Bind _ (Pi _ _ _) sc) = True
+        isInj ctxt (Bind _ (Pi _ _ _ _) sc) = True
         isInj ctxt _ = False
 
 -- | get implementation argument names
@@ -441,8 +441,8 @@
 introTy :: Raw -> Maybe Name -> Elab' aux ()
 introTy ty n = processTactic' (IntroTy ty n)
 
-forall :: Name -> Maybe ImplicitInfo -> Raw -> Elab' aux ()
-forall n i t = processTactic' (Forall n i t)
+forall :: Name -> RigCount -> Maybe ImplicitInfo -> Raw -> Elab' aux ()
+forall n r i t = processTactic' (Forall n r i t)
 
 letbind :: Name -> Raw -> Raw -> Elab' aux ()
 letbind n t v = processTactic' (LetBind n t v)
@@ -463,18 +463,17 @@
 equiv tm = processTactic' (Equiv tm)
 
 -- | Turn the current hole into a pattern variable with the provided
--- name, made unique if MN
+-- name, made unique if not the same as the head of the hole queue
 patvar :: Name -> Elab' aux ()
 patvar n@(SN _) = do apply (Var n) []; solve
 patvar n = do env <- get_env
               hs <- get_holes
-              if (n `elem` map fst env) then do apply (Var n) []; solve
-                else do n' <- case n of
-                                    UN _ -> return $! n
-                                    MN _ _ -> unique_hole n
-                                    NS _ _ -> return $! n
-                                    x -> return $! n
-                        processTactic' (PatVar n')
+              if (n `elem` map fstEnv env) then do apply (Var n) []; solve
+                else do n' <- case hs of
+                                   (h : hs) -> if n == h then return n
+                                                  else unique_hole n
+                                   _ -> unique_hole n
+                        processTactic' (PatVar n)
 
 -- | Turn the current hole into a pattern variable with the provided
 -- name, but don't make MNs unique.
@@ -482,11 +481,11 @@
 patvar' n@(SN _) = do apply (Var n) [] ; solve
 patvar' n = do env <- get_env
                hs <- get_holes
-               if (n `elem` map fst env) then do apply (Var n) [] ; solve
+               if (n `elem` map fstEnv env) then do apply (Var n) [] ; solve
                   else processTactic' (PatVar n)
 
-patbind :: Name -> Elab' aux ()
-patbind n = processTactic' (PatBind n)
+patbind :: Name -> RigCount -> Elab' aux ()
+patbind n r = processTactic' (PatBind n r)
 
 focus :: Name -> Elab' aux ()
 focus n = processTactic' (Focus n)
@@ -579,9 +578,9 @@
        -- Count arguments to check if we need to normalise the type
        let usety = if argsOK (finalise ty) imps
                       then finalise ty
-                      else whnfArgs ctxt env (finalise ty)
+                      else normalise ctxt env (finalise ty)
        claims <- -- trace (show (fn, imps, ty, map fst env, normalise ctxt env (finalise ty))) $
-                 mkClaims usety imps [] (map fst env)
+                 mkClaims usety imps [] (map fstEnv env)
        ES (p, a) s prev <- get
        -- reverse the claims we made so that args go left to right
        let n = length (filter not imps)
@@ -590,7 +589,7 @@
        return $! claims
   where
     argsOK :: Type -> [a] -> Bool
-    argsOK (Bind n (Pi _ _ _) sc) (i : is) = argsOK sc is
+    argsOK (Bind n (Pi _ _ _ _) sc) (i : is) = argsOK sc is
     argsOK _ (i : is) = False
     argsOK _ [] = True
 
@@ -599,13 +598,13 @@
              -> [(Name, Name)] -- ^ Accumulator for produced claims
              -> [Name] -- ^ Hypotheses
              -> Elab' aux [(Name, Name)] -- ^ The names of the arguments and their holes, resp.
-    mkClaims (Bind n' (Pi _ t_in _) sc) (i : is) claims hs =
+    mkClaims (Bind n' (Pi _ _ t_in _) sc) (i : is) claims hs =
         do let t = rebind hs t_in
            n <- getNameFrom (mkMN n')
 --            when (null claims) (start_unify n)
            let sc' = instantiate (P Bound n t) sc
            env <- get_env
-           claim n (forgetEnv (map fst env) t)
+           claim n (forgetEnv (map fstEnv env) t)
            when i (movelast n)
            mkClaims sc' is ((n', n) : claims) hs
     mkClaims t [] claims _ = return $! (reverse claims)
@@ -713,7 +712,7 @@
     priOrder _ Nothing = GT
     priOrder (Just (x, _)) (Just (y, _)) = compare x y
 
-    doClaims (Bind n' (Pi _ t _) sc) (i : is) claims =
+    doClaims (Bind n' (Pi _ _ t _) sc) (i : is) claims =
         do n <- unique_hole (mkMN n')
            when (null claims) (start_unify n)
            let sc' = instantiate (P Bound n t) sc
@@ -749,14 +748,14 @@
             = do g <- goal
                  ctxt <- get_context
                  env <- get_env
-                 case (whnf ctxt env g) of
-                    Bind _ (Pi _ _ _) _ -> return ()
+                 case (normalise ctxt env g) of
+                    Bind _ (Pi _ _ _ _) _ -> return ()
                     _ -> do a <- getNameFrom (sMN 0 "__pargTy")
                             b <- getNameFrom (sMN 0 "__pretTy")
                             f <- getNameFrom (sMN 0 "pf")
                             claim a RType
                             claim b RType
-                            claim f (RBind n (Pi Nothing (Var a) RType) (Var b))
+                            claim f (RBind n (Pi RigW Nothing (Var a) RType) (Var b))
                             movelast a
                             movelast b
                             fill (Var f)
@@ -776,7 +775,7 @@
        s <- getNameFrom (sMN 0 "is")
        claim a RType
        claim b RType
-       claim f (RBind (sMN 0 "_aX") (Pi Nothing (Var a) RType) (Var b))
+       claim f (RBind (sMN 0 "_aX") (Pi RigW Nothing (Var a) RType) (Var b))
        tm <- get_term
        start_unify s
        -- if 'infer' is set, we're assuming it's a simply typed application
@@ -824,10 +823,10 @@
        focus s; attack;
        ctxt <- get_context
        env <- get_env
-       case whnf ctxt env fty of
+       case normalise 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)
+            Bind _ (Pi _ _ argty _) _ -> unifyGoal (forget argty)
             -- Can't infer a type for 'f', so fail here (and drop back to
             -- simply typed application where we infer the type for f)
             _ -> fail "Can't make type"
@@ -846,11 +845,11 @@
 
 -- Abstract over an argument of unknown type, giving a name for the hole
 -- which we'll fill with the argument type too.
-arg :: Name -> Maybe ImplicitInfo -> Name -> Elab' aux ()
-arg n i tyhole = do ty <- unique_hole tyhole
-                    claim ty RType
-                    movelast ty
-                    forall n i (Var ty)
+arg :: Name -> RigCount -> Maybe ImplicitInfo -> Name -> Elab' aux ()
+arg n r i tyhole = do ty <- unique_hole tyhole
+                      claim ty RType
+                      movelast ty
+                      forall n r i (Var ty)
 
 -- try a tactic, if it adds any unification problem, return an error
 no_errors :: Elab' aux () -> Maybe Err -> Elab' aux ()
@@ -870,7 +869,7 @@
                case reverse ps' of
                     ((x, y, _, env, inerr, while, _) : _) ->
                        let (xp, yp) = getProvenance inerr
-                           env' = map (\(x, b) -> (x, binderTy b)) env in
+                           env' = map (\(x, rig, b) -> (x, binderTy b)) env in
                                   lift $ tfail $
                                          case err of
                                               Nothing -> CantUnify False (x, xp) (y, yp) inerr env' 0
@@ -1014,7 +1013,7 @@
         getHoleInfo h = do focus h
                            g <- goal
                            env <- get_env
-                           return (h, g, env)
+                           return (h, g, envBinders env)
 
 qshow :: Fails -> String
 qshow fs = show (map (\ (x, y, _, _, _, _, _) -> (x, y)) fs)
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
@@ -14,18 +14,21 @@
                 rt_simplify, simplify, inlineSmall,
                 specialise, unfold, convEq, convEq',
                 Def(..), CaseInfo(..), CaseDefs(..),
-                Accessibility(..), Injectivity, Totality(..), PReason(..), MetaInformation(..),
+                Accessibility(..), Injectivity, Totality(..), TTDecl, PReason(..), MetaInformation(..),
                 Context, initContext, ctxtAlist, next_tvar,
-                addToCtxt, setAccess, setInjective, setTotal, setMetaInformation, addCtxtDef, addTyDecl,
+                addToCtxt, setAccess, setInjective, setTotal, setRigCount,
+                setMetaInformation, addCtxtDef, addTyDecl,
                 addDatatype, addCasedef, simplifyCasedef, addOperator,
                 lookupNames, lookupTyName, lookupTyNameExact, lookupTy, lookupTyExact,
                 lookupP, lookupP_all, lookupDef, lookupNameDef, lookupDefExact, lookupDefAcc, lookupDefAccExact, lookupVal,
                 mapDefCtxt, tcReducible,
                 lookupTotal, lookupTotalExact, lookupInjectiveExact,
+                lookupRigCount, lookupRigCountExact,
                 lookupNameTotal, lookupMetaInformation, lookupTyEnv, isTCDict,
                 isCanonical, isDConName, canBeDConName, isTConName, isConName, isFnName,
+                conGuarded,
                 Value(..), Quote(..), initEval, uniqueNameCtxt, uniqueBindersCtxt, definitions,
-                isUniverse) where
+                isUniverse, linearCheck, linearCheckArg) where
 
 import Idris.Core.CaseTree
 import Idris.Core.TT
@@ -34,6 +37,7 @@
 import Control.Monad.State
 import Data.Binary hiding (get, put)
 import qualified Data.Binary as B
+import Data.List
 import Data.Maybe (listToMaybe)
 import Debug.Trace
 import GHC.Generics (Generic)
@@ -72,6 +76,16 @@
 --            | VLazy Env [Value] Term
            | VTmp Int
 
+canonical :: Value -> Bool
+canonical (VP (DCon _ _ _) _ _) = True
+canonical (VApp f a) = canonical f
+canonical (VConstant _) = True
+canonical (VType _) = True
+canonical (VUType _) = True
+canonical VErased = True
+canonical _ = False
+
+
 instance Show Value where
     show x = show $ evalState (quote 100 x) initEval
 
@@ -132,7 +146,7 @@
          (tm, limited st)
 
 -- | Like normalise, but we only reduce functions that are marked as okay to
--- inline, and lets 
+-- inline, and lets
 simplify :: Context -> Env -> TT Name -> TT Name
 simplify ctxt env t
    = evalState (do val <- eval False ctxt [(sUN "lazy", 0),
@@ -148,7 +162,7 @@
                    quote 0 val) initEval
 
 -- | Like simplify, but we only reduce functions that are marked as okay to
--- inline, and don't reduce lets 
+-- inline, and don't reduce lets
 inlineSmall :: Context -> Env -> TT Name -> TT Name
 inlineSmall ctxt env t
    = evalState (do val <- eval False ctxt []
@@ -187,13 +201,13 @@
 
 -- unbindEnv env (quote 0 (eval ctxt (bindEnv env t)))
 
-finalEntry :: (Name, Binder (TT Name)) -> (Name, Binder (TT Name))
-finalEntry (n, b) = (n, fmap finalise b)
+finalEntry :: (Name, RigCount, Binder (TT Name)) -> (Name, RigCount, Binder (TT Name))
+finalEntry (n, r, b) = (n, r, fmap finalise b)
 
 bindEnv :: EnvTT n -> TT n -> TT n
 bindEnv [] tm = tm
-bindEnv ((n, Let t v):bs) tm = Bind n (NLet t v) (bindEnv bs tm)
-bindEnv ((n, b):bs)       tm = Bind n b (bindEnv bs tm)
+bindEnv ((n, r, Let t v):bs) tm = Bind n (NLet t v) (bindEnv bs tm)
+bindEnv ((n, r, b):bs)       tm = Bind n b (bindEnv bs tm)
 
 unbindEnv :: EnvTT n -> TT n -> TT n
 unbindEnv [] tm = tm
@@ -217,7 +231,7 @@
   = case lookup n ns of
          Just 0 -> return (False, ns)
          Just i -> return $ (True, (n, abs (i-1)) : filter (\ (n', _) -> n/=n') ns)
-         _ -> return $ if uf 
+         _ -> return $ if uf
                           then (False, ns)
                           else (True, (n, depthlimit) : filter (\ (n', _) -> n/=n') ns)
 
@@ -254,6 +268,8 @@
     atRepl = AtREPL `elem` opts
     unfold = Unfold `elem` opts
 
+    noFree = all canonical . map snd
+
     -- returns 'True' if the function should block
     -- normal evaluation should return false
     blockSimplify (CaseInfo inl always dict) n stk
@@ -270,15 +286,15 @@
                 | 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
+        | Just (Let t v) <- lookupBinder n genv = ev ntimes stk top env v
     ev ntimes_in stk top env (P Ref n ty)
          = do let limit = if simpl then 100 else 10000
               (u, ntimes) <- usable spec unfold limit n ntimes_in
-              let red = u && (tcReducible n ctxt || spec || atRepl 
+              let red = u && (tcReducible n ctxt || spec || (atRepl && noFree env)
                                 || runtime || unfold
                                 || sUN "assert_total" `elem` stk)
               if red then
-               do let val = lookupDefAccExact n (spec || unfold || atRepl || runtime) ctxt
+               do let val = lookupDefAccExact n (spec || unfold || (atRepl && noFree env) || runtime) ctxt
                   case val of
                     Just (Function _ tm, Public) ->
                            ev ntimes (n:stk) True env tm
@@ -325,7 +341,7 @@
                 return $ VBind True n (Let t' v') (\x -> return sc')
     ev ntimes stk top env (Bind n b sc)
            = do b' <- vbind env b
-                let n' = uniqueName n (map fst genv ++ map fst env)
+                let n' = uniqueName n (map fstEnv genv ++ map fst env)
                 return $ VBind True -- (vinstances 0 sc < 2)
                                n' b' (\x -> ev ntimes stk False ((n', x):env) sc)
        where vbind env t
@@ -347,7 +363,7 @@
                  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)
-       | Just (CaseOp _ _ _ _ _ _, _) <- lookupDefAccExact n (spec || atRepl || runtime) ctxt,
+       | Just (CaseOp _ _ _ _ _ _, _) <- lookupDefAccExact n (spec || (atRepl && noFree env)|| runtime) ctxt,
          at == txt "assert_total" && not (simpl || unfold)
             = ev ntimes (n : stk) top env arg
     ev ntimes stk top env (App _ f a)
@@ -376,7 +392,7 @@
           = apply ntimes stk top env f args
 
     reapply ntimes stk top env f@(VP Ref n ty) args
-       = let val = lookupDefAccExact n (spec || atRepl || runtime) ctxt in
+       = let val = lookupDefAccExact n (spec || (atRepl && noFree env) || runtime) ctxt in
          case val of
               Just (CaseOp ci _ _ _ _ cd, acc) ->
                  let (ns, tree) = getCases cd in
@@ -391,18 +407,18 @@
             = reapply ntimes stk top env f (a : args)
     reapply ntimes stk top env v args = return v
 
-    apply ntimes stk top env (VBind True n (Lam t) sc) (a:as)
+    apply ntimes stk top env (VBind True n (Lam _ t) sc) (a:as)
          = do a' <- sc a
               app <- apply ntimes stk top env a' as
               wknV 1 app
     apply ntimes_in stk top env f@(VP Ref n ty) args
          = do let limit = if simpl then 100 else 10000
               (u, ntimes) <- usable spec unfold limit n ntimes_in
-              let red = u && (tcReducible n ctxt || spec || atRepl 
+              let red = u && (tcReducible n ctxt || spec || (atRepl && noFree env)
                                 || unfold || runtime
                                 || sUN "assert_total" `elem` stk)
               if red then
-                 do let val = lookupDefAccExact n (spec || unfold || atRepl || runtime) ctxt
+                 do let val = lookupDefAccExact n (spec || unfold || (atRepl && noFree env) || runtime) ctxt
                     case val of
                       Just (CaseOp ci _ _ _ _ cd, acc)
                            | acc == Public || acc == Hidden ->
@@ -508,7 +524,7 @@
         | Just v <- findDefault alts      = return $ Just (amap, v)
     chooseAlt env _ (VP _ n _, args) alts amap
         | Just (ns, sc) <- findFn n alts  = return $ Just (updateAmap (zip ns args) amap, sc)
-    chooseAlt env _ (VBind _ _ (Pi i s k) t, []) alts amap
+    chooseAlt env _ (VBind _ _ (Pi _ i s k) t, []) alts amap
         | Just (ns, sc) <- findFn (sUN "->") alts
            = do t' <- t (VV 0) -- we know it's not in scope or it's not a pattern
                 return $ Just (updateAmap (zip ns [s, t']) amap, sc)
@@ -624,17 +640,17 @@
         | x `elem` holes || y `elem` holes = return True
         | x == y || (x, y) `elem` ps || (y,x) `elem` ps = return True
         | otherwise = sameDefs ps x y
-    ceq ps x (Bind n (Lam t) (App _ y (V 0)))
+    ceq ps x (Bind n (Lam _ t) (App _ y (V 0)))
           = ceq ps x (substV (P Bound n t) y)
-    ceq ps (Bind n (Lam t) (App _ x (V 0))) y
+    ceq ps (Bind n (Lam _ t) (App _ x (V 0))) y
           = ceq ps (substV (P Bound n t) x) y
-    ceq ps x (Bind n (Lam t) (App _ y (P Bound n' _)))
+    ceq ps x (Bind n (Lam _ t) (App _ y (P Bound n' _)))
         | n == n' = ceq ps x y
-    ceq ps (Bind n (Lam t) (App _ x (P Bound n' _))) y
+    ceq ps (Bind n (Lam _ t) (App _ x (P Bound n' _))) y
         | n == n' = ceq ps x y
 
-    ceq ps (Bind n (PVar t) sc) y = ceq ps sc y
-    ceq ps x (Bind n (PVar t) sc) = ceq ps x sc
+    ceq ps (Bind n (PVar _ t) sc) y = ceq ps sc y
+    ceq ps x (Bind n (PVar _ t) sc) = ceq ps x sc
     ceq ps (Bind n (PVTy t) sc) y = ceq ps sc y
     ceq ps x (Bind n (PVTy t) sc) = ceq ps x sc
 
@@ -650,7 +666,7 @@
         where
             ceqB ps (Let v t) (Let v' t') = liftM2 (&&) (ceq ps v v') (ceq ps t t')
             ceqB ps (Guess v t) (Guess v' t') = liftM2 (&&) (ceq ps v v') (ceq ps t t')
-            ceqB ps (Pi i v t) (Pi i' v' t') = liftM2 (&&) (ceq ps v v') (ceq ps t t')
+            ceqB ps (Pi r i v t) (Pi r' i' v' t') = liftM2 (&&) (ceq ps v v') (ceq ps t t')
             ceqB ps b b' = ceq ps (binderTy b) (binderTy b')
     -- Special case for 'case' blocks - size of scope causes complications,
     -- we only want to check the blocks themselves are valid and identical
@@ -854,11 +870,14 @@
 
 -- | Contexts used for global definitions and for proof state. They contain
 -- universe constraints and existing definitions.
+-- Also store maximum RigCount of the name (can't bind a name at multiplicity
+-- 1 in a RigW, for example)
 data Context = MkContext {
                   next_tvar       :: Int,
-                  definitions     :: Ctxt (Def, Injectivity, Accessibility, Totality, MetaInformation)
+                  definitions     :: Ctxt TTDecl
                 } deriving (Show, Generic)
 
+type TTDecl = (Def, RigCount, Injectivity, Accessibility, Totality, MetaInformation)
 
 -- | The initial empty context
 initContext = MkContext 0 emptyContext
@@ -866,53 +885,59 @@
 
 mapDefCtxt :: (Def -> Def) -> Context -> Context
 mapDefCtxt f (MkContext t !defs) = MkContext t (mapCtxt f' defs)
-   where f' (!d, i, a, t, m) = f' (f d, i, a, t, m)
+   where f' (!d, r, i, a, t, m) = f' (f d, r, i, a, t, m)
 
 -- | Get the definitions from a context
 ctxtAlist :: Context -> [(Name, Def)]
-ctxtAlist ctxt = map (\(n, (d, i, a, t, m)) -> (n, d)) $ toAlist (definitions ctxt)
+ctxtAlist ctxt = map (\(n, (d, r, i, a, t, m)) -> (n, d)) $ toAlist (definitions ctxt)
 
 veval ctxt env t = evalState (eval False ctxt [] env t []) initEval
 
 addToCtxt :: Name -> Term -> Type -> Context -> Context
 addToCtxt n tm ty uctxt
     = let ctxt = definitions uctxt
-          !ctxt' = addDef n (Function ty tm, False, Public, Unchecked, EmptyMI) ctxt in
+          !ctxt' = addDef n (Function ty tm, RigW, False, Public, Unchecked, EmptyMI) ctxt in
           uctxt { definitions = ctxt' }
 
 setAccess :: Name -> Accessibility -> Context -> Context
 setAccess n a uctxt
     = let ctxt = definitions uctxt
-          !ctxt' = updateDef n (\ (d, i, _, t, m) -> (d, i, a, t, m)) ctxt in
+          !ctxt' = updateDef n (\ (d, r, i, _, t, m) -> (d, r, i, a, t, m)) ctxt in
           uctxt { definitions = ctxt' }
 
 setInjective :: Name -> Injectivity -> Context -> Context
 setInjective n i uctxt
     = let ctxt = definitions uctxt
-          !ctxt' = updateDef n (\ (d, _, a, t, m) -> (d, i, a, t, m)) ctxt in
+          !ctxt' = updateDef n (\ (d, r, _, a, t, m) -> (d, r, i, a, t, m)) ctxt in
           uctxt { definitions = ctxt' }
 
 setTotal :: Name -> Totality -> Context -> Context
 setTotal n t uctxt
     = let ctxt = definitions uctxt
-          !ctxt' = updateDef n (\ (d, i, a, _, m) -> (d, i, a, t, m)) ctxt in
+          !ctxt' = updateDef n (\ (d, r, i, a, _, m) -> (d, r, i, a, t, m)) ctxt in
           uctxt { definitions = ctxt' }
 
+setRigCount :: Name -> RigCount -> Context -> Context
+setRigCount n rc uctxt
+    = let ctxt = definitions uctxt
+          !ctxt' = updateDef n (\ (d, _, i, a, t, m) -> (d, rc, i, a, t, m)) ctxt in
+          uctxt { definitions = ctxt' }
+
 setMetaInformation :: Name -> MetaInformation -> Context -> Context
 setMetaInformation n m uctxt
     = let ctxt = definitions uctxt
-          !ctxt' = updateDef n (\ (d, i, a, t, _) -> (d, i, a, t, m)) ctxt in
+          !ctxt' = updateDef n (\ (d, r, i, a, t, _) -> (d, r, i, a, t, m)) ctxt in
           uctxt { definitions = ctxt' }
 
 addCtxtDef :: Name -> Def -> Context -> Context
 addCtxtDef n d c = let ctxt = definitions c
-                       !ctxt' = addDef n (d, False, Public, Unchecked, EmptyMI) $! ctxt in
+                       !ctxt' = addDef n (d, RigW, False, Public, Unchecked, EmptyMI) $! ctxt in
                        c { definitions = ctxt' }
 
 addTyDecl :: Name -> NameType -> Type -> Context -> Context
 addTyDecl n nt ty uctxt
     = let ctxt = definitions uctxt
-          !ctxt' = addDef n (TyDecl nt ty, False, Public, Unchecked, EmptyMI) ctxt in
+          !ctxt' = addDef n (TyDecl nt ty, RigW, False, Public, Unchecked, EmptyMI) ctxt in
           uctxt { definitions = ctxt' }
 
 addDatatype :: Datatype Name -> Context -> Context
@@ -920,14 +945,14 @@
     = let ctxt = definitions uctxt
           ty' = normalise uctxt [] ty
           !ctxt' = addCons 0 cons (addDef n
-                     (TyDecl (TCon tag (arity ty')) ty, True, Public, Unchecked, EmptyMI) ctxt) in
+                     (TyDecl (TCon tag (arity ty')) ty, RigW, True, Public, Unchecked, EmptyMI) ctxt) in
           uctxt { definitions = ctxt' }
   where
     addCons tag [] ctxt = ctxt
     addCons tag ((n, ty) : cons) ctxt
         = let ty' = normalise uctxt [] ty in
               addCons (tag+1) cons (addDef n
-                  (TyDecl (DCon tag (arity ty') unique) ty, True, Public, Unchecked, EmptyMI) ctxt)
+                  (TyDecl (DCon tag (arity ty') unique) ty, RigW, True, Public, Unchecked, EmptyMI) ctxt)
 
 -- FIXME: Too many arguments! Refactor all these Bools.
 --
@@ -961,33 +986,34 @@
                                            (args_rt, sc_rt)
                            op = (CaseOp (ci { case_inlinable = inlc })
                                                 ty argtys ps_in ps_ct cdef,
-                                 False, access, Unchecked, EmptyMI)
+                                 RigW, 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 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
+-- simplify a definition by unfolding interface methods
+-- We need this for totality checking, because functions which use interfaces
+-- in an implementation definition themselves need to have the implementation
+-- inlined or it'll be treated as a higher order function that will potentially
+-- loop.
+simplifyCasedef :: Name -> [Name] -> [[Name]] -> ErasureInfo -> Context -> TC Context
+simplifyCasedef n ufnames umethss ei uctxt
    = do let ctxt = definitions uctxt
         ctxt' <- case lookupCtxt n ctxt of
-                   [(CaseOp ci ty atys [] ps _, inj, acc, tot, metainf)] ->
+                   [(CaseOp ci ty atys [] ps _, rc, inj, acc, tot, metainf)] ->
                       return ctxt -- nothing to simplify (or already done...)
-                   [(CaseOp ci ty atys ps_in ps cd, inj, acc, tot, metainf)] ->
+                   [(CaseOp ci ty atys ps_in ps cd, rc, inj, acc, tot, metainf)] ->
                       do let ps_in' = map simpl ps_in
                              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_compiletime = (args, sc) }),
-                                              inj, acc, tot, metainf) ctxt
+                                              rc, inj, acc, tot, metainf) ctxt
 
                    _ -> return ctxt
         return uctxt { definitions = ctxt' }
   where
-    depat acc (Bind n (PVar t) sc)
+    depat acc (Bind n (PVar _ t) sc)
         = depat (n : acc) (instantiate (P Bound n t) sc)
     depat acc x = (acc, x)
     debind (Right (x, y)) = let (vs, x') = depat [] x
@@ -995,17 +1021,45 @@
                                 (vs, x', y')
     debind (Left x)       = let (vs, x') = depat [] x in
                                 (vs, x', Impossible)
-    simpl (Right (x, y)) = Right (x, y) -- inline uctxt [] y)
+    simpl (Right (x, y))
+         = if null ufnames then Right (x, y)
+              else Right (x, unfold uctxt [] (map (\n -> (n, 1)) (uns y)) y)
     simpl t = t
 
+    -- 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.
+    uns tm = getNamesToUnfold ufnames umethss tm
+
+    getNamesToUnfold :: [Name] -> [[Name]] -> Term -> [Name]
+    getNamesToUnfold inames ms tm = nub $ inames ++ getNames Nothing tm ++ concat 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 `elem` inames 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 _ _ = []
+
 addOperator :: Name -> Type -> Int -> ([Value] -> Maybe Value) ->
                Context -> Context
 addOperator n ty a op uctxt
     = let ctxt = definitions uctxt
-          ctxt' = addDef n (Operator ty a op, False, Public, Unchecked, EmptyMI) ctxt in
+          ctxt' = addDef n (Operator ty a op, RigW, False, Public, Unchecked, EmptyMI) ctxt in
           uctxt { definitions = ctxt' }
 
-tfst (a, _, _, _, _) = a
+tfst (a, _, _, _, _, _) = a
 
 lookupNames :: Name -> Context -> [Name]
 lookupNames n ctxt
@@ -1084,6 +1138,17 @@
          Just (CaseOp ci _ _ _ _ _) -> tc_dictionary ci
          _                          -> False
 
+-- Is the name guarded by constructors in the term?
+-- We assume the term is normalised, so no looking under 'let' for example.
+conGuarded :: Context -> Name -> Term -> Bool
+conGuarded ctxt n tm = guarded n tm
+  where
+    guarded n (P _ n' _) = n == n'
+    guarded n ap@(App _ _ _)
+        | (P _ f _, as) <- unApply ap,
+          isConName f ctxt = any (guarded n) as
+    guarded _ _ = False
+
 lookupP :: Name -> Context -> [Term]
 lookupP = lookupP_all False False
 
@@ -1091,10 +1156,10 @@
 lookupP_all all exact n ctxt
    = do (n', def) <- names
         p <- case def of
-          (Function ty tm, inj, a, _, _)      -> return (P Ref n' ty, a)
-          (TyDecl nt ty, _, a, _, _)        -> return (P nt n' ty, a)
-          (CaseOp _ ty _ _ _ _, inj, a, _, _) -> return (P Ref n' ty, a)
-          (Operator ty _ _, inj, a, _, _)     -> return (P Ref n' ty, a)
+          (Function ty tm, _, inj, a, _, _)      -> return (P Ref n' ty, a)
+          (TyDecl nt ty, _, _, a, _, _)        -> return (P nt n' ty, a)
+          (CaseOp _ ty _ _ _ _, _, inj, a, _, _) -> return (P Ref n' ty, a)
+          (Operator ty _ _, _, inj, a, _, _)     -> return (P Ref n' ty, a)
         case snd p of
           Hidden -> if all then return (fst p) else []
           Private -> if all then return (fst p) else []
@@ -1121,29 +1186,64 @@
 lookupDefAcc n mkpublic ctxt
     = map mkp $ lookupCtxt n (definitions ctxt)
   -- io_bind a special case for REPL prettiness
-  where mkp (d, inj, a, _, _) = if mkpublic && (not (n == sUN "io_bind" || n == sUN "io_pure"))
-                                   then (d, Public) else (d, a)
+  where mkp (d, _, inj, a, _, _) = if mkpublic && (not (n == sUN "io_bind" || n == sUN "io_pure"))
+                                      then (d, Public) else (d, a)
 
 lookupDefAccExact :: Name -> Bool -> Context ->
                      Maybe (Def, Accessibility)
 lookupDefAccExact n mkpublic ctxt
     = fmap mkp $ lookupCtxtExact n (definitions ctxt)
   -- io_bind a special case for REPL prettiness
-  where mkp (d, inj, a, _, _) = if mkpublic && (not (n == sUN "io_bind" || n == sUN "io_pure"))
-                                   then (d, Public) else (d, a)
+  where mkp (d, _, inj, a, _, _) = if mkpublic && (not (n == sUN "io_bind" || n == sUN "io_pure"))
+                                      then (d, Public) else (d, a)
 
 lookupTotal :: Name -> Context -> [Totality]
 lookupTotal n ctxt = map mkt $ lookupCtxt n (definitions ctxt)
-  where mkt (d, inj, a, t, m) = t
+  where mkt (d, _, inj, a, t, m) = t
 
 lookupTotalExact :: Name -> Context -> Maybe Totality
 lookupTotalExact n ctxt = fmap mkt $ lookupCtxtExact n (definitions ctxt)
-  where mkt (d, inj, a, t, m) = t
+  where mkt (d, _, inj, a, t, m) = t
 
+lookupRigCount :: Name -> Context -> [Totality]
+lookupRigCount n ctxt = map mkt $ lookupCtxt n (definitions ctxt)
+  where mkt (d, _, inj, a, t, m) = t
+
+lookupRigCountExact :: Name -> Context -> Maybe RigCount
+lookupRigCountExact n ctxt = fmap mkt $ lookupCtxtExact n (definitions ctxt)
+  where mkt (d, rc, inj, a, t, m) = rc
+
 lookupInjectiveExact :: Name -> Context -> Maybe Injectivity
 lookupInjectiveExact n ctxt = fmap mkt $ lookupCtxtExact n (definitions ctxt)
-  where mkt (d, inj, a, t, m) = inj
+  where mkt (d, _, inj, a, t, m) = inj
 
+-- Assume type is at least in whnfArgs form
+linearCheck :: Context -> Type -> TC ()
+linearCheck ctxt t = checkArgs t
+  where
+    checkArgs (Bind n (Pi RigW _ ty _) sc)
+        = do linearCheckArg ctxt ty
+             checkArgs (substV (P Bound n Erased) sc)
+    checkArgs (Bind n (Pi _ _ _ _) sc)
+          = checkArgs (substV (P Bound n Erased) sc)
+    checkArgs _ = return ()
+
+linearCheckArg :: Context -> Type -> TC ()
+linearCheckArg ctxt ty = mapM_ checkNameOK (allTTNames ty)
+  where
+    checkNameOK f
+       = case lookupRigCountExact f ctxt of
+              Just Rig1 ->
+                  tfail $ Msg $ show f ++ " can only appear in a linear binding"
+              _ -> return ()
+
+    checkArgs (Bind n (Pi RigW _ ty _) sc)
+        = do mapM_ checkNameOK (allTTNames ty)
+             checkArgs (substV (P Bound n Erased) sc)
+    checkArgs (Bind n (Pi _ _ _ _) sc)
+          = checkArgs (substV (P Bound n Erased) sc)
+    checkArgs _ = return ()
+
 -- Check if a name is reducible in the type checker. Partial definitions
 -- are not reducible (so treated as a constant)
 tcReducible :: Name -> Context -> Bool
@@ -1154,10 +1254,10 @@
 
 lookupMetaInformation :: Name -> Context -> [MetaInformation]
 lookupMetaInformation n ctxt = map mkm $ lookupCtxt n (definitions ctxt)
-  where mkm (d, inj, a, t, m) = m
+  where mkm (d, _, inj, a, t, m) = m
 
 lookupNameTotal :: Name -> Context -> [(Name, Totality)]
-lookupNameTotal n = map (\(n, (_, _, _, t, _)) -> (n, t)) . lookupCtxtName n . definitions
+lookupNameTotal n = map (\(n, (_, _, _, _, t, _)) -> (n, t)) . lookupCtxtName n . definitions
 
 
 lookupVal :: Name -> Context -> [Value]
@@ -1168,11 +1268,11 @@
           (TyDecl nt ty) -> return (VP nt n (veval ctxt [] ty))
           _ -> []
 
-lookupTyEnv :: Name -> Env -> Maybe (Int, Type)
+lookupTyEnv :: Name -> Env -> Maybe (Int, RigCount, Type)
 lookupTyEnv n env = li n 0 env where
   li n i []           = Nothing
-  li n i ((x, b): xs)
-             | n == x = Just (i, binderTy b)
+  li n i ((x, r, b): xs)
+             | n == x = Just (i, r, binderTy b)
              | otherwise = li n (i+1) xs
 
 -- | Create a unique name given context and other existing names
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
@@ -91,14 +91,14 @@
                            body' <- body $ EP Bound n' EErased
                            b' <- fixBinder b
                            Bind n' b' <$> toTT body'
-    where fixBinder (Lam t)       = Lam     <$> toTT t
-          fixBinder (Pi i t k)    = Pi i    <$> toTT t <*> toTT k
+    where fixBinder (Lam rig t)    = Lam rig  <$> toTT t
+          fixBinder (Pi rig i t k) = Pi rig i <$> toTT t <*> toTT k
           fixBinder (Let t1 t2)   = Let     <$> toTT t1 <*> toTT t2
           fixBinder (NLet t1 t2)  = NLet    <$> toTT t1 <*> toTT t2
           fixBinder (Hole t)      = Hole    <$> toTT t
           fixBinder (GHole i ns t) = GHole i ns <$> toTT t
           fixBinder (Guess t1 t2) = Guess   <$> toTT t1 <*> toTT t2
-          fixBinder (PVar t)      = PVar    <$> toTT t
+          fixBinder (PVar rig t)  = PVar rig <$> toTT t
           fixBinder (PVTy t)      = PVTy    <$> toTT t
           newN n = do (ExecState hs ns) <- lift get
                       let n' = uniqueName n ns
@@ -114,7 +114,7 @@
 toTT (EThunk ctxt env tm) = do env' <- mapM toBinder env
                                return $ normalise ctxt env' tm
   where toBinder (n, v) = do v' <- toTT v
-                             return (n, Let Erased v')
+                             return (n, RigW, Let Erased v')
 toTT (EHandle _) = execFail $ Msg "Can't convert handles back to TT after execution."
 toTT (EPtr ptr) = execFail $ Msg "Can't convert pointers back to TT after execution."
 
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
@@ -88,7 +88,7 @@
             | CheckIn Raw
             | Intro (Maybe Name)
             | IntroTy Raw (Maybe Name)
-            | Forall Name (Maybe ImplicitInfo) Raw
+            | Forall Name RigCount (Maybe ImplicitInfo) Raw
             | LetBind Name Raw Raw
             | ExpandLet Name Term
             | Rewrite Raw
@@ -96,7 +96,7 @@
             | CaseTac Raw
             | Equiv Raw
             | PatVar Name
-            | PatBind Name
+            | PatBind Name RigCount
             | Focus Name
             | Defer [Name] Name
             | DeferType Name Raw [Name]
@@ -129,12 +129,12 @@
                 ") -------\n  " ++
                 show h ++ " : " ++ showG wkenv (goalType g) ++ "\n"
          where showPs env [] = ""
-               showPs env ((n, Let t v):bs)
+               showPs env ((n, _, Let t v):bs)
                    = "  " ++ show n ++ " : " ++
                      showEnv env ({- normalise ctxt env -} t) ++ "   =   " ++
                      showEnv env ({- normalise ctxt env -} v) ++
                      "\n" ++ showPs env bs
-               showPs env ((n, b):bs)
+               showPs env ((n, _, b):bs)
                    = "  " ++ show n ++ " : " ++
                      showEnv env ({- normalise ctxt env -} (binderTy b)) ++
                      "\n" ++ showPs env bs
@@ -160,18 +160,18 @@
       prettyGoal ps b = prettyEnv ps $ binderTy b
 
       prettyPs env [] = empty
-      prettyPs env ((n, Let t v):bs) =
+      prettyPs env ((n, _, Let t v):bs) =
         nest nestingSize (pretty n <+> colon <+>
         prettyEnv env t <+> text "=" <+> prettyEnv env v <+>
         nest nestingSize (prettyPs env bs))
-      prettyPs env ((n, b):bs) =
+      prettyPs env ((n, _, b):bs) =
         nest nestingSize (pretty n <+> colon <+> prettyEnv env (binderTy b) <+>
         nest nestingSize (prettyPs env bs))
 
 holeName i = sMN i "hole"
 
 qshow :: Fails -> String
-qshow fs = show (map (\ (x, y, hs, env, _, _, t) -> (t, map fst env, x, y, hs)) fs)
+qshow fs = show (map (\ (x, y, hs, env, _, _, t) -> (t, map fstEnv env, x, y, hs)) fs)
 
 match_unify' :: Context -> Env ->
                 (TT Name, Maybe Provenance) ->
@@ -363,7 +363,7 @@
    cl env (Bind n' (Let t v) sc)
        | n' == n = let v' = normalise ctxt env v in
                        Bind n' (Let t v') sc
-   cl env (Bind n' b sc) = Bind n' (fmap (cl env) b) (cl ((n, b):env) sc)
+   cl env (Bind n' b sc) = Bind n' (fmap (cl env) b) (cl ((n, Rig0, b):env) sc)
    cl env (App s f a) = App s (cl env f) (cl env a)
    cl env t = t
 
@@ -392,7 +392,7 @@
        lift $ isType ctxt env tyt
        action (\ps -> let (g:gs) = holes ps in
                           ps { holes = g : n : gs } )
-       return $ Bind n (Hole (Bind bn (Pi Nothing tyv tyt) retty)) t
+       return $ Bind n (Hole (Bind bn (Pi RigW Nothing tyv tyt) retty)) t
 claimFn _ _ _ ctxt env _ = fail "Can't make function type here"
 
 reorder_claims :: RunTactic
@@ -463,7 +463,7 @@
 
 defer :: [Name] -> Name -> RunTactic
 defer dropped n ctxt env (Bind x (Hole t) (P nt x' ty)) | x == x' =
-    do let env' = filter (\(n, t) -> n `notElem` dropped) env
+    do let env' = filter (\(n, _, t) -> n `notElem` dropped) env
        action (\ps -> let hs = holes ps in
                           ps { usedns = n : usedns ps,
                                holes = hs \\ [x] })
@@ -472,9 +472,9 @@
                       (mkApp (P Ref n ty) (map getP (reverse env'))))
   where
     mkTy []           t = t
-    mkTy ((n,b) : bs) t = Bind n (Pi Nothing (binderTy b) (TType (UVar [] 0))) (mkTy bs t)
+    mkTy ((n,rig,b) : bs) t = Bind n (Pi RigW Nothing (binderTy b) (TType (UVar [] 0))) (mkTy bs t)
 
-    getP (n, b) = P Bound n (binderTy b)
+    getP (n, rig, b) = P Bound n (binderTy b)
 defer dropped n ctxt env _ = fail "Can't defer a non-hole focus."
 
 -- as defer, but build the type and application explicitly
@@ -488,7 +488,7 @@
        return (Bind n (GHole 0 [] fty)
                       (mkApp (P Ref n ty) (map getP args)))
   where
-    getP n = case lookup n env of
+    getP n = case lookupBinder n env of
                   Just b -> P Bound n (binderTy b)
                   Nothing -> error ("deferType can't find " ++ show n)
 deferType _ _ _ _ _ _ = fail "Can't defer a non-hole focus."
@@ -541,7 +541,7 @@
     -- some expected types show up commonly in errors and indicate a
     -- specific problem.
     --   argTy -> retTy suggests a function applied to too many arguments
-    chkPurpose val (Bind _ (Pi _ (P _ (MN _ _) _) _) (P _ (MN _ _) _))
+    chkPurpose val (Bind _ (Pi _ _ (P _ (MN _ _) _) _) (P _ (MN _ _) _))
                    = TooManyArgs val
     chkPurpose _ _ = ExpectedType
 fill _ _ _ _ = fail "Can't fill here."
@@ -652,27 +652,27 @@
                   Just name -> name
                   Nothing -> x
        let t' = case t of
-                    x@(Bind y (Pi _ s _) _) -> x
+                    x@(Bind y (Pi _ _ s _) _) -> x
                     _ -> normalise ctxt env t
        (tyv, tyt) <- lift $ check ctxt env ty
 --        ns <- lift $ unify ctxt env tyv t'
        case t' of
-           Bind y (Pi _ s _) t -> let t' = updsubst y (P Bound n s) t in
-                                      do ns <- unify' ctxt env (s, Nothing) (tyv, Nothing)
-                                         ps <- get
-                                         let (uh, uns) = unified ps
---                                          put (ps { unified = (uh, uns ++ ns) })
-                                         return $ Bind n (Lam tyv) (Bind x (Hole t') (P Bound x t'))
+           Bind y (Pi rig _ s _) t -> let t' = updsubst y (P Bound n s) t in
+                                        do ns <- unify' ctxt env (s, Nothing) (tyv, Nothing)
+                                           ps <- get
+                                           let (uh, uns) = unified ps
+--                                            put (ps { unified = (uh, uns ++ ns) })
+                                           return $ Bind n (Lam rig tyv) (Bind x (Hole t') (P Bound x t'))
            _ -> lift $ tfail $ CantIntroduce t'
 introTy ty n ctxt env _ = fail "Can't introduce here."
 
 intro :: Maybe Name -> RunTactic
 intro mn ctxt env (Bind x (Hole t) (P _ x' _)) | x == x' =
     do let t' = case t of
-                    x@(Bind y (Pi _ s _) _) -> x
+                    x@(Bind y (Pi _ _ s _) _) -> x
                     _ -> normalise ctxt env t
        case t' of
-           Bind y (Pi _ s _) t ->
+           Bind y (Pi rig _ s _) t ->
                let n = case mn of
                       Just name -> name
                       Nothing -> y
@@ -680,17 +680,17 @@
                -- because we want to substitute even in portions of
                -- terms that we know do not contain holes.
                    t' = subst y (P Bound n s) t
-               in return $ Bind n (Lam s) (Bind x (Hole t') (P Bound x t'))
+               in return $ Bind n (Lam rig s) (Bind x (Hole t') (P Bound x t'))
            _ -> lift $ tfail $ CantIntroduce t'
 intro n ctxt env _ = fail "Can't introduce here."
 
-forall :: Name -> Maybe ImplicitInfo -> Raw -> RunTactic
-forall n impl ty ctxt env (Bind x (Hole t) (P _ x' _)) | x == x' =
+forall :: Name -> RigCount -> Maybe ImplicitInfo -> Raw -> RunTactic
+forall n rig impl ty ctxt env (Bind x (Hole t) (P _ x' _)) | x == x' =
     do (tyv, tyt) <- lift $ check ctxt env ty
        unify' ctxt env (tyt, Nothing) (TType (UVar [] 0), Nothing)
        unify' ctxt env (t, Nothing) (TType (UVar [] 0), Nothing)
-       return $ Bind n (Pi impl tyv (TType (UVar [] 0))) (Bind x (Hole t) (P Bound x t))
-forall n impl ty ctxt env _ = fail "Can't pi bind here"
+       return $ Bind n (Pi rig impl tyv (TType (UVar [] 0))) (Bind x (Hole t) (P Bound x t))
+forall n rig impl ty ctxt env _ = fail "Can't pi bind here"
 
 patvar :: Name -> RunTactic
 patvar n ctxt env (Bind x (Hole t) sc) =
@@ -702,7 +702,7 @@
                                           (notunified ps),
                            injective = addInj n x (injective ps)
                          })
-       return $ Bind n (PVar t) (updsubst x (P Bound n t) sc)
+       return $ Bind n (PVar RigW t) (updsubst x (P Bound n t) sc)
   where addInj n x ps | x `elem` ps = n : ps
                       | otherwise = ps
 patvar n ctxt env tm = fail $ "Can't add pattern var at " ++ show tm
@@ -725,7 +725,7 @@
        let tmt' = normalise ctxt env tmt
        case unApply tmt' of
          (P _ (UN q) _, [lt,rt,l,r]) | q == txt "=" ->
-            do let p = Bind rname (Lam lt) (mkP (P Bound rname lt) r l t)
+            do let p = Bind rname (Lam RigW lt) (mkP (P Bound rname lt) r l t)
                let newt = mkP l r l t
                let sc = forget $ (Bind x (Hole newt)
                                        (mkApp (P Ref (sUN "replace") (TType (UVal 0)))
@@ -785,7 +785,7 @@
                          Var nm -> uniqueNameCtxt ctxt nm currentNames
                          _ -> uniqueNameCtxt ctxt (sMN 0 "iv") currentNames
              let tmvar = P Bound tmnm tmt'
-             prop <- replaceIndicies indxnames indicies $ Bind tmnm (Lam tmt') (mkP tmvar tmv tmvar t)
+             prop <- replaceIndicies indxnames indicies $ Bind tmnm (Lam RigW tmt') (mkP tmvar tmv tmvar t)
              consargs' <- query (\ps -> map (flip (uniqueNameCtxt (context ps)) (holes ps ++ allTTNames (getProofTerm (pterm ps))) *** uniqueBindersCtxt (context ps) (holes ps ++ allTTNames (getProofTerm (pterm ps)))) consargs)
              let res = flip (foldr substV) params $ (substV prop $ bindConsArgs consargs' (mkApp (P Ref (SN (tacn tnm)) (TType (UVal 0)))
                                                         (params ++ [prop] ++ map makeConsArg consargs' ++ indicies ++ [tmv])))
@@ -812,7 +812,7 @@
           makeIndexNames = foldr (\_ nms -> (uniqueNameCtxt ctxt (sMN 0 "idx") nms):nms) []
           replaceIndicies idnms idxs prop = foldM (\t (idnm, idx) -> do (idxv, idxt) <- lift $ check ctxt env (forget idx)
                                                                         let var = P Bound idnm idxt
-                                                                        return $ Bind idnm (Lam idxt) (mkP var idxv var t)) prop $ zip idnms idxs
+                                                                        return $ Bind idnm (Lam RigW idxt) (mkP var idxv var t)) prop $ zip idnms idxs
 casetac tm induction ctxt env _ = fail $ "Can't do " ++ (if induction then "induction" else "case analysis") ++ " here"
 
 
@@ -823,16 +823,16 @@
        return $ Bind x (Hole tmv) sc
 equiv tm ctxt env _ = fail "Can't equiv here"
 
-patbind :: Name -> RunTactic
-patbind n ctxt env (Bind x (Hole t) (P _ x' _)) | x == x' =
+patbind :: Name -> RigCount -> RunTactic
+patbind n rig ctxt env (Bind x (Hole t) (P _ x' _)) | x == x' =
     do let t' = case t of
                     x@(Bind y (PVTy s) t) -> x
                     _ -> 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'))
+                                    return $ Bind n (PVar rig s) (Bind x (Hole t') (P Bound x t'))
            _ -> fail "Nothing to pattern bind"
-patbind n ctxt env _ = fail "Can't pattern bind here"
+patbind n _ ctxt env _ = fail "Can't pattern bind here"
 
 compute :: RunTactic
 compute ctxt env (Bind x (Hole ty) sc) =
@@ -914,8 +914,8 @@
 
 updateEnv [] e = e
 updateEnv ns [] = []
-updateEnv ns ((n, b) : env)
-   = (n, fmap (updateSolvedTerm ns) b) : updateEnv ns env
+updateEnv ns ((n, rig, b) : env)
+   = (n, rig, fmap (updateSolvedTerm ns) b) : updateEnv ns env
 
 updateProv ns (SourceTerm t) = SourceTerm $ updateSolvedTerm ns t
 updateProv ns p = p
@@ -1002,6 +1002,18 @@
              (x', y', newx || newy,
                   updateEnv ns env, updateError ns err, fc, fa)
 
+orderUpdateSolved :: [(Name, Term)] -> ProofTerm -> (ProofTerm, [Name])
+orderUpdateSolved ns tm = update [] ns tm
+  where
+    update done [] t = (t, done)
+    update done ((n, P _ n' _) : ns) t | n == n' = update done ns t
+    update done (n : ns) t = update (fst n : done)
+                                    (map (updateMatch n) ns)
+                                    (updateSolved [n] t)
+
+    -- Update the later solutions too
+    updateMatch n (x, tm) = (x, updateSolvedTerm [n] tm)
+
 -- attempt to solve remaining problems with match_unify
 matchProblems :: Bool -> ProofState -> [(Name, TT Name)] -> Fails
                     -> ([(Name, TT Name)], Fails)
@@ -1065,30 +1077,25 @@
                                          (getProofTerm (pterm ps)) }, "")
 processTactic UnifyProblems ps
     = do let (ns', probs') = updateProblems ps [] (map setReady (problems ps))
-             pterm' = orderUpdateSolved ns' (pterm ps)
-         traceWhen (unifylog ps) ("(UnifyProblems) Dropping holes: " ++ show (map fst ns')) $
+             (pterm', dropped) = orderUpdateSolved ns' (pterm ps)
+         traceWhen (unifylog ps) ("(UnifyProblems) Dropping holes: " ++ show dropped) $
           return (ps { pterm = pterm', solved = Nothing, problems = probs',
                        previous = Just ps, plog = "",
                        notunified = updateNotunified ns' (notunified ps),
-                       recents = recents ps ++ map fst ns',
+                       recents = recents ps ++ dropped,
                        dotted = filter (notIn ns') (dotted ps),
-                       holes = holes ps \\ (map fst ns') }, plog ps)
+                       holes = holes ps \\ dropped }, plog ps)
    where notIn ns (h, _) = h `notElem` map fst ns
-         orderUpdateSolved [] t = t
-         orderUpdateSolved (n : ns) t = orderUpdateSolved ns (updateSolved [n] t)
 processTactic (MatchProblems all) ps
     = do let (ns', probs') = matchProblems all ps [] (map setReady (problems ps))
              (ns'', probs'') = matchProblems all ps ns' probs'
-             pterm' = orderUpdateSolved ns'' (resetProofTerm (pterm ps))
-         traceWhen (unifylog ps) ("(MatchProblems) Dropping holes: " ++ show ns'') $
+             (pterm', dropped) = orderUpdateSolved ns'' (resetProofTerm (pterm ps))
+         traceWhen (unifylog ps) ("(MatchProblems) Dropping holes: " ++ show dropped) $
           return (ps { pterm = pterm', solved = Nothing, problems = probs'',
                        previous = Just ps, plog = "",
                        notunified = updateNotunified ns'' (notunified ps),
-                       recents = recents ps ++ map fst ns'',
-                       holes = holes ps \\ (map fst ns'') }, plog ps)
-  where
-    orderUpdateSolved [] t = t
-    orderUpdateSolved (n : ns) t = orderUpdateSolved ns (updateSolved [n] t)
+                       recents = recents ps ++ dropped,
+                       holes = holes ps \\ dropped }, plog ps)
 processTactic t ps
     = case holes ps of
         [] -> case t of
@@ -1142,7 +1149,7 @@
          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
+         mktac (Forall n r i t)  = forall n r i t
          mktac (LetBind n t v)   = letbind n t v
          mktac (ExpandLet n b)   = expandLet n b
          mktac (Rewrite t)       = rewrite t
@@ -1150,7 +1157,7 @@
          mktac (CaseTac t)       = casetac t False
          mktac (Equiv t)         = equiv t
          mktac (PatVar n)        = patvar n
-         mktac (PatBind n)       = patbind n
+         mktac (PatBind n rig)   = patbind n rig
          mktac (CheckIn r)       = check_in r
          mktac (EvalIn r)        = eval_in r
          mktac (Focus n)         = focus n
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
@@ -84,7 +84,7 @@
       | Just (p, env', tm) <- fh' env path f = Just (AppL s p a, env', tm)
   fh' env path (Bind x b sc)
       | Just (bp, env', tm) <- fhB env path b = Just (InBind x bp sc, env', tm)
-      | Just (p, env', tm) <- fh' ((x,b):env) path sc = Just (InScope x b p, env', tm)
+      | Just (p, env', tm) <- fh' ((x,RigW,b):env) path sc = Just (InScope x b p, env', tm)
   fh' _ _ _ = Nothing
 
   fhB env path (Let t v)
@@ -170,10 +170,10 @@
                    _ -> let (t', _) = updateSolved' xs t in
                             (updsubst n v t', True)
     updateSolved' xs tm@(Bind n b t)
-        | otherwise = let (t', ut) = updateSolved' xs t
-                          (b', ub) = updateSolvedB' xs b in
-                          if ut || ub then (Bind n b' t', True)
-                                      else (tm, False)
+        = let (t', ut) = updateSolved' xs t
+              (b', ub) = updateSolvedB' xs b in
+              if ut || ub then (Bind n b' t', True)
+                          else (tm, False)
     updateSolved' xs t@(App Complete f a) = (t, False)
     updateSolved' xs t@(App s f a)
         = let (f', uf) = updateSolved' xs f
@@ -255,7 +255,7 @@
 updateEnv :: [(Name, Term)] -> Env -> Env
 updateEnv [] e = e
 updateEnv ns [] = []
-updateEnv ns ((n, b) : env) = (n, fmap (updateSolvedTerm ns) b) : updateEnv ns env
+updateEnv ns ((n, r, b) : env) = (n, r, fmap (updateSolvedTerm ns) b) : updateEnv ns env
 
 -- | Fill out solved holes in a term zipper.
 updateSolvedPath :: [(Name, Term)] -> TermPath -> TermPath
@@ -284,7 +284,7 @@
 updateSolved :: [(Name, Term)] -> ProofTerm -> ProofTerm
 updateSolved xs pt@(PT path env sub ups)
      = PT path -- (updateSolvedPath xs path)
-          (updateEnv xs (filter (\(n, t) -> n `notElem` map fst xs) env))
+          (updateEnv xs (filter (\(n, r, t) -> n `notElem` map fst xs) env))
           (updateSolvedTerm xs sub)
           (ups ++ xs)
 
@@ -297,10 +297,10 @@
     g env (Bind n b@(Guess _ _) sc)
                         | same h n = return $ GD env b
                         | otherwise
-                           = gb env b `mplus` g ((n, b):env) sc
+                           = gb env b `mplus` g ((n, RigW, b):env) sc
     g env (Bind n b sc) | hole b && same h n = return $ GD env b
                         | otherwise
-                           = g ((n, b):env) sc `mplus` gb env b
+                           = g ((n, RigW, b):env) sc `mplus` gb env b
     g env (App Complete f a) = fail "Can't find hole"
     g env (App _ f a) = g env a `mplus` g env f
     g env t           = fail "Can't find hole"
@@ -338,12 +338,12 @@
             = do -- binder first
                  (b', u) <- ulift2 f c env Guess t v
                  if u then return (Bind n b' sc, True)
-                      else do (sc', u) <- atH f c ((n, b) : env) sc
+                      else do (sc', u) <- atH f c ((n, RigW, b) : env) sc
                               return (Bind n b' sc', u)
     atH f c env binder@(Bind n b sc)
         | hole b && same h n = updated (f c env binder)
         | otherwise -- scope first
-            = do (sc', u) <- atH f c ((n, b) : env) sc
+            = do (sc', u) <- atH f c ((n, RigW, b) : env) sc
                  if u then return (Bind n b sc', True)
                       else do (b', u) <- atHb f c env b
                               return (Bind n b' sc', u)
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,7 +22,7 @@
    * We have a simple collection of tactics which we use to elaborate source
      programs with implicit syntax into fully explicit terms.
 -}
-{-# LANGUAGE DeriveDataTypeable, DeriveFunctor, DeriveGeneric,
+{-# LANGUAGE DeriveDataTypeable, DeriveFunctor, DeriveGeneric, FlexibleContexts,
              FunctionalDependencies, MultiParamTypeClasses, PatternGuards #-}
 {-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
 module Idris.Core.TT(
@@ -31,7 +31,7 @@
   , Env(..), EnvTT(..), Err(..), Err'(..), ErrorReportPart(..)
   , FC(..), FC'(..), ImplicitInfo(..), IntTy(..), Name(..)
   , NameOutput(..), NameType(..), NativeTy(..), OutputAnnotation(..)
-  , Provenance(..), Raw(..), SpecialName(..), TC(..), Term(..)
+  , Provenance(..), Raw(..), RigCount(..), SpecialName(..), TC(..), Term(..)
   , TermSize(..), TextFormatting(..), TT(..),Type(..), TypeInfo(..)
   , UConstraint(..), UCs(..), UExp(..), Universe(..)
   , addAlist, addBinder, addDef, allTTNames, arity, bindAll
@@ -49,6 +49,8 @@
   , substV, sUN, tcname, termSmallerThan, tfail, thead, tnull
   , toAlist, traceWhen, txt, unApply, uniqueBinders, uniqueName
   , uniqueNameFrom, uniqueNameSet, unList, updateDef, vToP, weakenTm
+  , rigPlus, rigMult, fstEnv, rigEnv, sndEnv, lookupBinder, envBinders
+  , envZero
   ) where
 
 import Util.Pretty hiding (Str)
@@ -851,9 +853,11 @@
 -- | All binding forms are represented in a uniform fashion. This type only represents
 -- the types of bindings (and their values, if any); the attached identifiers are part
 -- of the 'Bind' constructor for the 'TT' type.
-data Binder b = Lam   { binderTy  :: !b {-^ type annotation for bound variable-}}
+data Binder b = Lam   { binderCount :: RigCount,
+                        binderTy  :: !b {-^ type annotation for bound variable-}}
                 -- ^ A function binding
-              | Pi    { binderImpl :: Maybe ImplicitInfo,
+              | Pi    { binderCount :: RigCount,
+                        binderImpl :: Maybe ImplicitInfo,
                         binderTy  :: !b,
                         binderKind :: !b }
                 -- ^ A binding that occurs in a function type
@@ -885,7 +889,8 @@
                 -- substituted - the guess is to keep it
                 -- computationally inert while working on other things
                 -- if necessary.
-              | PVar  { binderTy  :: !b }
+              | PVar  { binderCount :: RigCount,
+                        binderTy  :: !b }
                 -- ^ A pattern variable (these are bound around terms
                 -- that make up pattern-match clauses)
               | PVTy  { binderTy  :: !b }
@@ -896,25 +901,25 @@
 !-}
 
 instance Sized a => Sized (Binder a) where
-  size (Lam ty) = 1 + size ty
-  size (Pi _ ty _) = 1 + size ty
+  size (Lam _ ty) = 1 + size ty
+  size (Pi _ _ ty _) = 1 + size ty
   size (Let ty val) = 1 + size ty + size val
   size (NLet ty val) = 1 + size ty + size val
   size (Hole ty) = 1 + size ty
   size (GHole _ _ ty) = 1 + size ty
   size (Guess ty val) = 1 + size ty + size val
-  size (PVar ty) = 1 + size ty
+  size (PVar _ ty) = 1 + size ty
   size (PVTy ty) = 1 + size ty
 
 fmapMB :: Monad m => (a -> m b) -> Binder a -> m (Binder b)
 fmapMB f (Let t v)   = liftM2 Let (f t) (f v)
 fmapMB f (NLet t v)  = liftM2 NLet (f t) (f v)
 fmapMB f (Guess t v) = liftM2 Guess (f t) (f v)
-fmapMB f (Lam t)     = liftM Lam (f t)
-fmapMB f (Pi i t k)  = liftM2 (Pi i) (f t) (f k)
+fmapMB f (Lam c t)   = liftM (Lam c) (f t)
+fmapMB f (Pi c i t k) = liftM2 (Pi c i) (f t) (f k)
 fmapMB f (Hole t)    = liftM Hole (f t)
 fmapMB f (GHole i ns t) = liftM (GHole i ns) (f t)
-fmapMB f (PVar t)    = liftM PVar (f t)
+fmapMB f (PVar c t)    = liftM (PVar c) (f t)
 fmapMB f (PVTy t)    = liftM PVTy (f t)
 
 raw_apply :: Raw -> [Raw] -> Raw
@@ -1064,8 +1069,43 @@
 instance Pretty a o => Pretty (TT a) o where
   pretty _ = text "test"
 
-type EnvTT n = [(n, Binder (TT n))]
+data RigCount = Rig0 | Rig1 | RigW
+  deriving (Show, Eq, Ord, Data, Generic, Typeable)
 
+rigPlus :: RigCount -> RigCount -> RigCount
+rigPlus Rig0 Rig0 = Rig0
+rigPlus Rig0 Rig1 = Rig1
+rigPlus Rig0 RigW = RigW
+rigPlus Rig1 Rig0 = Rig1
+rigPlus Rig1 Rig1 = RigW
+rigPlus Rig1 RigW = RigW
+rigPlus RigW Rig0 = RigW
+rigPlus RigW Rig1 = RigW
+rigPlus RigW RigW = RigW
+
+rigMult :: RigCount -> RigCount -> RigCount
+rigMult Rig0 Rig0 = Rig0
+rigMult Rig0 Rig1 = Rig0
+rigMult Rig0 RigW = Rig0
+rigMult Rig1 Rig0 = Rig0
+rigMult Rig1 Rig1 = Rig1
+rigMult Rig1 RigW = RigW
+rigMult RigW Rig0 = Rig0
+rigMult RigW Rig1 = RigW
+rigMult RigW RigW = RigW
+
+type EnvTT n = [(n, RigCount, Binder (TT n))]
+
+fstEnv (n, c, b) = n
+rigEnv (n, c, b) = c
+sndEnv (n, c, b) = b
+
+envBinders = map (\(n, _, b) -> (n, b))
+envZero = map (\(n, _, b) -> (n, Rig0, b))
+
+lookupBinder :: Eq n => n -> EnvTT n -> Maybe (Binder (TT n))
+lookupBinder n = lookup n . envBinders
+
 data Datatype n = Data { d_typename :: n,
                          d_typetag  :: Int,
                          d_type     :: (TT n),
@@ -1086,7 +1126,9 @@
                      codata :: Bool,
                      data_opts :: DataOpts,
                      param_pos :: [Int],
-                     mutual_types :: [Name] }
+                     mutual_types :: [Name],
+                     linear_con :: Bool -- is there a linear argument?
+                   }
     deriving (Show, Generic)
 {-!
 deriving instance Binary TypeInfo
@@ -1114,7 +1156,7 @@
 isInjective (P (TCon _ _) _ _) = True
 isInjective (Constant _)       = True
 isInjective (TType x)          = True
-isInjective (Bind _ (Pi _ _ _) sc) = True
+isInjective (Bind _ (Pi _ _ _ _) sc) = True
 isInjective (App _ f a)        = isInjective f
 isInjective _                  = False
 
@@ -1348,7 +1390,7 @@
 
 -- | Return the arity of a (normalised) type
 arity :: TT n -> Int
-arity (Bind n (Pi _ t _) sc) = 1 + arity sc
+arity (Bind n (Pi _ _ t _) sc) = 1 + arity sc
 arity _ = 0
 
 -- | Deconstruct an application; returns the function and a list of arguments
@@ -1444,25 +1486,25 @@
 -- | Return a list of pairs of the names of the outermost 'Pi'-bound
 -- variables in the given term, together with their types.
 getArgTys :: TT n -> [(n, TT n)]
-getArgTys (Bind n (PVar _) sc) = getArgTys sc
+getArgTys (Bind n (PVar _ _) sc) = getArgTys sc
 getArgTys (Bind n (PVTy _) sc) = getArgTys sc
-getArgTys (Bind n (Pi _ t _) sc) = (n, t) : getArgTys sc
+getArgTys (Bind n (Pi _ _ t _) sc) = (n, t) : getArgTys sc
 getArgTys _ = []
 
 getRetTy :: TT n -> TT n
-getRetTy (Bind n (PVar _) sc) = getRetTy sc
+getRetTy (Bind n (PVar _ _) sc) = getRetTy sc
 getRetTy (Bind n (PVTy _) sc) = getRetTy sc
-getRetTy (Bind n (Pi _ _ _) sc)   = getRetTy sc
+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 (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 (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
@@ -1572,15 +1614,15 @@
     prettySe p env (V i) debug
       | i < length env =
         if debug then
-          text . show . fst $ env!!i
+          text . show . fstEnv $ env!!i
         else
           lbracket <+> text (show i) <+> rbracket
       | otherwise      = text "unbound" <+> text (show i) <+> text "!"
-    prettySe p env (Bind n b@(Pi _ t _) sc) debug
+    prettySe p env (Bind n b@(Pi _ _ t _) sc) debug
       | noOccurrence n sc && not debug =
-          bracket p 2 $ prettySb env n b debug <> prettySe 10 ((n, b):env) sc debug
+          bracket p 2 $ prettySb env n b debug <> prettySe 10 ((n, Rig0, b):env) sc debug
     prettySe p env (Bind n b sc) debug =
-      bracket p 2 $ prettySb env n b debug <> prettySe 10 ((n, b):env) sc debug
+      bracket p 2 $ prettySb env n b debug <> prettySe 10 ((n, Rig0, b):env) sc debug
     prettySe p env (App _ f a) debug =
       bracket p 1 $ prettySe 1 env f debug <+> prettySe 0 env a debug
     prettySe p env (Proj x i) debug =
@@ -1593,11 +1635,14 @@
     prettySe p env (UType u) debug = text (show u)
 
     -- Render a `Binder` and its name
-    prettySb env n (Lam t) = prettyB env "λ" "=>" n t
+    prettySb env n (Lam _ t) = prettyB env "λ" "=>" n t
     prettySb env n (Hole t) = prettyB env "?defer" "." n t
     prettySb env n (GHole _ _ t) = prettyB env "?gdefer" "." n t
-    prettySb env n (Pi _ t _) = prettyB env "(" ") ->" n t
-    prettySb env n (PVar t) = prettyB env "pat" "." n t
+    prettySb env n (Pi Rig0 _ t _) = prettyB env "(" ") ->" n t
+    prettySb env n (Pi Rig1 _ t _) = prettyB env "(" ") -o" n t
+    prettySb env n (Pi RigW _ t _) = prettyB env "(" ") ->" n t
+    prettySb env n (PVar Rig1 t) = prettyB env "pat 1 " "." n t
+    prettySb env n (PVar _ t) = prettyB env "pat" "." n t
     prettySb env n (PVTy t) = prettyB env "pty" "." n t
     prettySb env n (Let t v) = prettyBv env "let" "in" n t v
     prettySb env n (NLet t v) = prettyBv env "nlet" "in" n t v
@@ -1620,16 +1665,17 @@
     se p env (P nt n t) = show n
                             ++ if dbg then "{" ++ show nt ++ " : " ++ se 10 env t ++ "}" else ""
     se p env (V i) | i < length env && i >= 0
-                                    = (show $ fst $ env!!i) ++
+                                    = (show $ fstEnv $ env!!i) ++
                                       if dbg then "{" ++ show i ++ "}" else ""
                    | otherwise = "!!V " ++ show i ++ "!!"
-    se p env (Bind n b@(Pi (Just _) t k) sc)
-         = bracket p 2 $ sb env n b ++ se 10 ((n,b):env) sc
-    se p env (Bind n b@(Pi _ t k) sc)
-        | noOccurrence n sc && not dbg = bracket p 2 $ se 1 env t ++ arrow k ++ se 10 ((n,b):env) sc
-       where arrow (TType _) = " -> "
-             arrow u = " [" ++ show u ++ "] -> "
-    se p env (Bind n b sc) = bracket p 2 $ sb env n b ++ se 10 ((n,b):env) sc
+    se p env (Bind n b@(Pi rig (Just _) t k) sc)
+         = bracket p 2 $ sb env n b ++ se 10 ((n, rig, b):env) sc
+    se p env (Bind n b@(Pi rig _ t k) sc)
+        | noOccurrence n sc && not dbg = bracket p 2 $ se 1 env t ++ arrow rig ++ se 10 ((n,Rig0,b):env) sc
+       where arrow Rig0 = " -> "
+             arrow Rig1 = " -o "
+             arrow RigW = " -> "
+    se p env (Bind n b sc) = bracket p 2 $ sb env n b ++ se 10 ((n,Rig0,b):env) sc
     se p env (App _ f a) = bracket p 1 $ se 1 env f ++ " " ++ se 0 env a
     se p env (Proj x i) = se 1 env x ++ "!" ++ show i
     se p env (Constant c) = show c
@@ -1639,12 +1685,17 @@
     se p env (TType i) = "Type " ++ show i
     se p env (UType u) = show u
 
-    sb env n (Lam t)  = showb env "\\ " " => " n t
+    sb env n (Lam Rig1 t)  = showb env "\\ 1 " " => " n t
+    sb env n (Lam _ t)  = showb env "\\ " " => " n t
     sb env n (Hole t) = showb env "? " ". " n t
     sb env n (GHole i ns t) = showb env "?defer " ". " n t
-    sb env n (Pi (Just _) t _)   = showb env "{" "} -> " n t
-    sb env n (Pi _ t _)   = showb env "(" ") -> " n t
-    sb env n (PVar t) = showb env "pat " ". " n t
+    sb env n (Pi Rig1 (Just _) t _)   = showb env "{" "} -o " n t
+    sb env n (Pi _ (Just _) t _)   = showb env "{" "} -> " n t
+    sb env n (Pi Rig1 _ t _)   = showb env "(" ") -0 " n t
+    sb env n (Pi _ _ t _)   = showb env "(" ") -> " n t
+    sb env n (PVar Rig0 t) = showb env "pat 0 " ". " n t
+    sb env n (PVar Rig1 t) = showb env "pat 1 " ". " n t
+    sb env n (PVar _ t) = showb env "pat " ". " n t
     sb env n (PVTy t) = showb env "pty " ". " n t
     sb env n (Let t v)   = showbv env "let " " in " n t v
     sb env n (NLet t v)   = showbv env "nlet " " in " n t v
@@ -1686,14 +1737,14 @@
 weakenEnv :: EnvTT n -> EnvTT n
 weakenEnv env = wk (length env - 1) env
   where wk i [] = []
-        wk i ((n, b) : bs) = (n, weakenTmB i b) : wk (i - 1) bs
+        wk i ((n, c, b) : bs) = (n, c, weakenTmB i b) : wk (i - 1) bs
         weakenTmB i (Let   t v) = Let (weakenTm i t) (weakenTm i v)
         weakenTmB i (Guess t v) = Guess (weakenTm i t) (weakenTm i v)
         weakenTmB i t           = t { binderTy = weakenTm i (binderTy t) }
 
 -- | Weaken every term in the environment by the given amount
 weakenTmEnv :: Int -> EnvTT n -> EnvTT n
-weakenTmEnv i = map (\ (n, b) -> (n, fmap (weakenTm i) b))
+weakenTmEnv i = map (\ (n, c, b) -> (n, c, fmap (weakenTm i) b))
 
 refsIn :: TT Name -> [Name]
 refsIn (P _ n _) = [n]
@@ -1749,16 +1800,16 @@
                             text "Type"
     pp p bound (UType u) = text (show u)
 
-    ppb p bound n (Lam ty) sc =
+    ppb p bound n (Lam rig ty) sc =
       bracket p startPrec . group . align . hang 2 $
       text "λ" <+> bindingOf n False <+> text "." <> line <> sc
-    ppb p bound n (Pi _ ty k) sc =
+    ppb p bound n (Pi rig _ ty k) sc =
       bracket p startPrec . group . align $
       lparen <> (bindingOf n False) <+> colon <+>
       (group . align) (pp startPrec bound ty) <>
-      rparen <+> mkArrow k <> line <> sc
-        where mkArrow (UType UniqueType) = text "⇴"
-              mkArrow (UType NullType) = text "⥛"
+      rparen <+> mkArrow rig <> line <> sc
+        where mkArrow Rig1 = text "⇴"
+              mkArrow Rig0 = text "⥛"
               mkArrow _ = text "→"
     ppb p bound n (Let ty val) sc =
       bracket p startPrec . group . align $
@@ -1787,7 +1838,7 @@
       text "?" <> bindingOf n False <+>
       text "≈" <+> pp startPrec bound val <+>
       text "." <> line <> sc
-    ppb p bound n (PVar ty) sc =
+    ppb p bound n (PVar _ ty) sc =
       bracket p startPrec . group . align . hang 2 $
       annotate AnnKeyword (text "pat") <+>
       bindingOf n False <+> colon <+> pp startPrec bound ty <+>
@@ -1838,10 +1889,10 @@
        , ppb b
        , pprintRaw (n:bound) body]
   where
-    ppb (Lam ty) = enclose lparen rparen . group . align . hang 2 $
-                   text "Lam" <$> pprintRaw bound ty
-    ppb (Pi _ ty k) = enclose lparen rparen . group . align . hang 2 $
-                      vsep [text "Pi", pprintRaw bound ty, pprintRaw bound k]
+    ppb (Lam _ ty) = enclose lparen rparen . group . align . hang 2 $
+                     text "Lam" <$> pprintRaw bound ty
+    ppb (Pi _ _ ty k) = enclose lparen rparen . group . align . hang 2 $
+                        vsep [text "Pi", pprintRaw bound ty, pprintRaw bound k]
     ppb (Let ty v) = enclose lparen rparen . group . align . hang 2 $
                      vsep [text "Let", pprintRaw bound ty, pprintRaw bound v]
     ppb (NLet ty v) = enclose lparen rparen . group . align . hang 2 $
@@ -1852,8 +1903,8 @@
                          text "GHole" <$> pprintRaw bound ty
     ppb (Guess ty v) = enclose lparen rparen . group . align . hang 2 $
                        vsep [text "Guess", pprintRaw bound ty, pprintRaw bound v]
-    ppb (PVar ty) = enclose lparen rparen . group . align . hang 2 $
-                    text "PVar" <$> pprintRaw bound ty
+    ppb (PVar _ ty) = enclose lparen rparen . group . align . hang 2 $
+                      text "PVar" <$> pprintRaw bound ty
     ppb (PVTy ty) = enclose lparen rparen . group . align . hang 2 $
                     text "PVTy" <$> pprintRaw bound ty
 pprintRaw bound (RApp f x) =
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
@@ -13,6 +13,7 @@
 
 import Idris.Core.Evaluate
 import Idris.Core.TT
+import Idris.Core.WHNF
 
 import Control.Monad.State
 import qualified Data.Vector.Unboxed as V (length)
@@ -25,7 +26,7 @@
 
 convertsC :: Context -> Env -> Term -> Term -> StateT UCs TC ()
 convertsC ctxt env x y =
-    do let hs = map fst (filter isHole env)
+    do let hs = map fstEnv (filter isHole env)
        c1 <- convEq ctxt hs x y
        if c1 then return ()
          else
@@ -38,7 +39,7 @@
 
 converts :: Context -> Env -> Term -> Term -> TC ()
 converts ctxt env x y
-     = let hs = map fst (filter isHole env) in
+     = let hs = map fstEnv (filter isHole env) in
        case convEq' ctxt hs x y of
           OK True -> return ()
           _ -> case convEq' ctxt hs (finalise (normalise ctxt env x))
@@ -48,10 +49,10 @@
                            (finalise (normalise ctxt env x))
                            (finalise (normalise ctxt env y)) (errEnv env))
 
-isHole (n, Hole _) = True
+isHole (n, _, Hole _) = True
 isHole _ = False
 
-errEnv = map (\(x, b) -> (x, binderTy b))
+errEnv = map (\(x, _, b) -> (x, binderTy b))
 
 isType :: Context -> Env -> Term -> TC ()
 isType ctxt env tm = isType' (normalise ctxt env tm)
@@ -86,7 +87,10 @@
      = 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
+check' holes tcns ctxt env top
+   = do (tm, ty, _) <- chk Rig1 (TType (UVar tcns (-5))) Nothing env top
+        return (tm, ty)
+ where
 
   smaller (UType NullType) _ = UType NullType
   smaller _ (UType NullType) = UType NullType
@@ -97,75 +101,89 @@
   astate | holes = MaybeHoles
          | otherwise = Complete
 
-  chk :: Type -> -- uniqueness level
+  chk :: RigCount -> -- multiplicity (need enough in context to produce this many of the term)
+         Type -> -- uniqueness level
          Maybe UExp -> -- universe for kind
-         Env -> Raw -> StateT UCs TC (Term, Type)
-  chk u lvl env (Var n)
-      | Just (i, ty) <- lookupTyEnv n env = return (P Bound n ty, ty)
+         Env -> Raw -> StateT UCs TC (Term, Type, [Name])
+  chk rigc u lvl env (Var n)
+      | Just (i, erig, ty) <- lookupTyEnv n env
+             = case rigSafe holes erig rigc n of
+                    Nothing -> return (P Bound n ty, ty, used rigc n)
+                    Just msg -> lift $ tfail $ Msg msg
       -- If we're elaborating, we don't want the private names; if we're
       -- checking an already elaborated term, we do
-      | [P nt n' ty] <- lookupP_all (not holes) False n ctxt
-             = return (P nt n' ty, ty)
-      -- If the names are ambiguous, require it to be fully qualified
       | [P nt n' ty] <- lookupP_all (not holes) True n ctxt
-             = return (P nt n' ty, ty)
+             = return (P nt n' ty, ty, [])
+--       -- If the names are ambiguous, require it to be fully qualified
+--       | [P nt n' ty] <- lookupP_all (not holes) True n ctxt
+--              = return (P nt n' ty, ty, [])
       | otherwise = do lift $ tfail $ NoSuchVariable n
-  chk u lvl env ap@(RApp f RType) | not holes
+    where rigSafe True _    _    n = Nothing
+          rigSafe _    Rig1 RigW n = Just ("Trying to use linear name " ++ show n ++ " in non-linear context")
+          rigSafe _    Rig0 RigW n = Just ("Trying to use irrelevant name " ++ show n ++ " in relevant context")
+          rigSafe _    _    _    n = Nothing
+
+          used Rig0 n = []
+          used _ n = [n]
+
+  chk rigc u lvl env ap@(RApp f RType) | not holes
     -- special case to reduce constraintss
-      = do (fv, fty) <- chk u Nothing env f
-           let fty' = case uniqueBinders (map fst env) (finalise fty) of
-                        ty@(Bind x (Pi i s k) t) -> ty
-                        _ -> uniqueBinders (map fst env)
+      = do (fv, fty, fns) <- chk rigc u Nothing env f
+           let fty' = case uniqueBinders (map fstEnv env) (finalise fty) of
+                        ty@(Bind x (Pi _ i s k) t) -> ty
+                        _ -> uniqueBinders (map fstEnv env)
                                  $ case normalise ctxt env fty of
-                                     ty@(Bind x (Pi i s k) t) -> ty
+                                     ty@(Bind x (Pi _ i s k) t) -> ty
                                      _ -> normalise ctxt env fty
            case fty' of
-             Bind x (Pi i (TType v') k) t ->
+             Bind x (Pi rig i (TType v') k) t ->
                do (v, cs) <- get
                   put (v+1, ULT (UVar tcns v) v' : cs)
                   let apty = simplify initContext env
                                  (Bind x (Let (TType v') (TType (UVar tcns v))) t)
-                  return (App Complete fv (TType (UVar tcns v)), apty)
-             Bind x (Pi i s k) t ->
-                 do (av, aty) <- chk u Nothing env RType
+                  return (App Complete fv (TType (UVar tcns v)), apty, fns)
+             Bind x (Pi rig i s k) t ->
+                 do (av, aty, _) <- chk rigc u Nothing env RType
                     convertsC ctxt env aty s
                     let apty = simplify initContext env
                                         (Bind x (Let aty av) t)
-                    return (App astate fv av, apty)
+                    return (App astate fv av, apty, fns)
              t -> lift $ tfail $ NonFunctionType fv fty
-  chk u lvl env ap@(RApp f a)
-      = do (fv, fty) <- chk u Nothing env f
-           let fty' = case uniqueBinders (map fst env) (finalise fty) of
-                        ty@(Bind x (Pi i s k) t) -> ty
-                        _ -> uniqueBinders (map fst env)
-                                 $ 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
+  chk rigc u lvl env ap@(RApp f a)
+      = do (fv, fty, fns) <- chk rigc u Nothing env f
+           let (rigf, fty') =
+                   case uniqueBinders (map fstEnv env) (finalise fty) of
+                        ty@(Bind x (Pi rig i s k) t) -> (rig, ty)
+                        _ -> case normalise ctxt env fty of
+                                  ty@(Bind x (Pi rig i s k) t) ->
+                                     (rig, uniqueBinders (map fstEnv env) ty)
+                                  _ -> (RigW, uniqueBinders (map fstEnv env)
+                                                    (normalise ctxt env fty)) -- This is an error, caught below...
+           (av, aty, ans) <- chk (rigMult rigc rigf) u Nothing env a
            case fty' of
-             Bind x (Pi i s k) t ->
+             Bind x (Pi rig i s k) t ->
                  do convertsC ctxt env aty s
                     let apty = simplify initContext env
                                         (Bind x (Let aty av) t)
-                    return (App astate fv av, apty)
+                    return (App astate fv av, apty, fns ++ ans)
              t -> lift $ tfail $ NonFunctionType fv fty
-  chk u lvl env RType
-    | holes = return (TType (UVal 0), TType (UVal 0))
+  chk rigc u lvl env RType
+    | holes = return (TType (UVal 0), TType (UVal 0), [])
     | otherwise = do (v, cs) <- get
                      let c = ULT (UVar tcns v) (UVar tcns (v+1))
                      put (v+2, (c:cs))
-                     return (TType (UVar tcns v), TType (UVar tcns (v+1)))
-  chk u lvl env (RUType un)
-    | holes = return (UType un, TType (UVal 0))
+                     return (TType (UVar tcns v), TType (UVar tcns (v+1)), [])
+  chk rigc u lvl env (RUType un)
+    | holes = return (UType un, TType (UVal 0), [])
     | otherwise = do -- TODO! Issue #1715 on the issue tracker.
                      -- https://github.com/idris-lang/Idris-dev/issues/1715
                      -- (v, cs) <- get
                      -- let c = ULT (UVar v) (UVar (v+1))
                      -- put (v+2, (c:cs))
                      -- return (TType (UVar v), TType (UVar (v+1)))
-                     return (UType un, TType (UVal 0))
-  chk u lvl env (RConstant Forgot) = return (Erased, Erased)
-  chk u lvl env (RConstant c) = return (Constant c, constType c)
+                     return (UType un, TType (UVal 0), [])
+  chk rigc u lvl env (RConstant Forgot) = return (Erased, Erased, [])
+  chk rigc u lvl env (RConstant c) = return (Constant c, constType c, [])
     where constType (I _)   = Constant (AType (ATInt ITNative))
           constType (BI _)  = Constant (AType (ATInt ITBig))
           constType (Fl _)  = Constant (AType ATFloat)
@@ -178,15 +196,17 @@
           constType TheWorld = Constant WorldType
           constType Forgot  = Erased
           constType _       = TType (UVal 0)
-  chk u lvl env (RBind n (Pi i s k) t)
-      = do (sv, st) <- chk u Nothing env s
+  chk rigc u lvl env (RBind n (Pi rig i s k) t)
+      = do (sv, st, sns) <- chk Rig0 u Nothing (envZero env) s
+           when (rig == RigW) $
+                lift $ linearCheckArg ctxt (normalise ctxt env sv)
            (v, cs) <- get
-           (kv, kt) <- chk u Nothing env k -- no need to validate these constraints, they are independent
+           (kv, kt, _) <- chk Rig0 u Nothing (envZero env) k -- no need to validate these constraints, they are independent
            put (v+1, cs)
            let maxu = case lvl of
                            Nothing -> UVar tcns v
                            Just v' -> v'
-           (tv, tt) <- chk st (Just maxu) ((n, Pi i sv kv) : env) t
+           (tv, tt, tns) <- chk Rig0 st (Just maxu) ((n, Rig0, Pi Rig0 i sv kv) : envZero env) t
 
 --            convertsC ctxt env st (TType maxu)
 --            convertsC ctxt env tt (TType maxu)
@@ -200,18 +220,18 @@
                                           put (v, ULE su maxu :
                                                   ULE tu maxu : cs)
                     let k' = TType (UVar tcns v) `smaller` st `smaller` kv `smaller` u
-                    return (Bind n (Pi i (uniqueBinders (map fst env) sv) k')
-                              (pToV n tv), k')
+                    return (Bind n (Pi rig i (uniqueBinders (map fstEnv env) sv) k')
+                              (pToV n tv), k', sns ++ tns)
                 (un, un') ->
                    let k' = st `smaller` kv `smaller` un `smaller` un' `smaller` u in
-                    return (Bind n (Pi i (uniqueBinders (map fst env) sv) k')
-                                (pToV n tv), k')
+                    return (Bind n (Pi rig i (uniqueBinders (map fstEnv env) sv) k')
+                                (pToV n tv), k', sns ++ tns)
 
-      where mkUniquePi kv (Bind n (Pi i s k) sc)
+      where mkUniquePi kv (Bind n (Pi rig i s k) sc)
                     = let k' = smaller kv k in
-                          Bind n (Pi i s k') (mkUniquePi k' sc)
-            mkUniquePi kv (Bind n (Lam t) sc)
-                    = Bind n (Lam (mkUniquePi kv t)) (mkUniquePi kv sc)
+                          Bind n (Pi rig i s k') (mkUniquePi k' sc)
+            mkUniquePi kv (Bind n (Lam rig t) sc)
+                    = Bind n (Lam rig (mkUniquePi kv t)) (mkUniquePi kv sc)
             mkUniquePi kv (Bind n (Let t v) sc)
                     = Bind n (Let (mkUniquePi kv t) v) (mkUniquePi kv sc)
             mkUniquePi kv t = t
@@ -219,84 +239,103 @@
             -- Kind of the whole thing is the kind of the most unique thing
             -- in the environment (because uniqueness taints everything...)
             mostUnique [] k = k
-            mostUnique (Pi _ _ pk : es) k = mostUnique es (smaller pk k)
+            mostUnique (Pi _ _ _ pk : es) k = mostUnique es (smaller pk k)
             mostUnique (_ : es) k = mostUnique es k
 
-  chk u lvl env (RBind n b sc)
-      = do (b', bt') <- checkBinder b
-           (scv, sct) <- chk (smaller bt' u) Nothing ((n, b'):env) sc
-           discharge n b' bt' (pToV n scv) (pToV n sct)
-    where checkBinder (Lam t)
-            = do (tv, tt) <- chk u Nothing env t
+  chk rigc u lvl env (RBind n b sc)
+      = do (b', bt', bns) <- checkBinder b
+           (scv, sct, scns) <- chk rigc (smaller bt' u) Nothing ((n, getCount b, b'):env) sc
+           when (getCount b == RigW) $
+             lift $ linearCheckArg ctxt (normalise ctxt env (binderTy b'))
+           checkUsageOK (getCount b) scns
+           discharge n b' bt' (pToV n scv) (pToV n sct) (bns ++ scns)
+    where getCount (Pi rig _ _ _) = rigMult rigc rig
+          getCount (PVar rig _) = rigMult rigc rig
+          getCount (Lam rig _) = rigMult rigc rig
+          getCount _ = rigMult rigc RigW
+
+          checkUsageOK Rig0 _ = return ()
+          checkUsageOK RigW _ = return ()
+          checkUsageOK Rig1 ns
+              = let used = length (filter (==n) ns) in
+                    if used == 1 then return ()
+                       else lift $ tfail $ Msg $ "There are " ++ (show used) ++
+                              " uses of linear name " ++ show n
+
+          checkBinder (Lam rig t)
+            = do (tv, tt, _) <- chk Rig0 u Nothing (envZero env) t
                  let tv' = normalise ctxt env tv
                  convType tcns ctxt env tt
-                 return (Lam tv, tt)
+                 return (Lam rig tv, tt, [])
           checkBinder (Let t v)
-            = do (tv, tt) <- chk u Nothing env t
-                 (vv, vt) <- chk u Nothing env v
+            = do (tv, tt, _) <- chk Rig0 u Nothing (envZero env) t
+                 -- May have multiple uses, check at RigW
+                 -- (or rather, like an application of a lambda, multiply)
+                 -- (Consider: adding a single use let?)
+                 (vv, vt, vns) <- chk (rigMult rigc RigW) u Nothing env v
                  let tv' = normalise ctxt env tv
                  convertsC ctxt env vt tv
                  convType tcns ctxt env tt
-                 return (Let tv vv, tt)
+                 return (Let tv vv, tt, vns)
           checkBinder (NLet t v)
-            = do (tv, tt) <- chk u Nothing env t
-                 (vv, vt) <- chk u Nothing env v
+            = do (tv, tt, _) <- chk Rig0 u Nothing (envZero env) t
+                 (vv, vt, vns) <- chk rigc u Nothing env v
                  let tv' = normalise ctxt env tv
                  convertsC ctxt env vt tv
                  convType tcns ctxt env tt
-                 return (NLet tv vv, tt)
+                 return (NLet tv vv, tt, vns)
           checkBinder (Hole t)
             | not holes = lift $ tfail (IncompleteTerm undefined)
             | otherwise
-                   = do (tv, tt) <- chk u Nothing env t
+                   = do (tv, tt, _) <- chk Rig0 u Nothing (envZero env) t
                         let tv' = normalise ctxt env tv
                         convType tcns ctxt env tt
-                        return (Hole tv, tt)
+                        return (Hole tv, tt, [])
           checkBinder (GHole i ns t)
-            = do (tv, tt) <- chk u Nothing env t
+            = do (tv, tt, _) <- chk Rig0 u Nothing (envZero env) t
                  let tv' = normalise ctxt env tv
                  convType tcns ctxt env tt
-                 return (GHole i ns tv, tt)
+                 return (GHole i ns tv, tt, [])
           checkBinder (Guess t v)
             | not holes = lift $ tfail (IncompleteTerm undefined)
             | otherwise
-                   = do (tv, tt) <- chk u Nothing env t
-                        (vv, vt) <- chk u Nothing env v
+                   = do (tv, tt, _) <- chk Rig0 u Nothing (envZero env) t
+                        (vv, vt, vns) <- chk rigc u Nothing env v
                         let tv' = normalise ctxt env tv
                         convertsC ctxt env vt tv
                         convType tcns ctxt env tt
-                        return (Guess tv vv, tt)
-          checkBinder (PVar t)
-            = do (tv, tt) <- chk u Nothing env t
+                        return (Guess tv vv, tt, vns)
+          checkBinder (PVar rig t)
+            = do (tv, tt, _) <- chk Rig0 u Nothing (envZero env) t
                  let tv' = normalise ctxt env tv
                  convType tcns ctxt env tt
                  -- Normalised version, for erasure purposes (it's easier
                  -- to tell if it's a collapsible variable)
-                 return (PVar tv, tt)
+                 return (PVar rig tv, tt, [])
           checkBinder (PVTy t)
-            = do (tv, tt) <- chk u Nothing env t
+            = do (tv, tt, _) <- chk Rig0 u Nothing (envZero env) t
                  let tv' = normalise ctxt env tv
                  convType tcns ctxt env tt
-                 return (PVTy tv, tt)
+                 return (PVTy tv, tt, [])
 
-          discharge n (Lam t) bt scv sct
-            = return (Bind n (Lam t) scv, Bind n (Pi Nothing t bt) sct)
-          discharge n (Pi i t k) bt scv sct
-            = return (Bind n (Pi i t k) scv, sct)
-          discharge n (Let t v) bt scv sct
-            = return (Bind n (Let t v) scv, Bind n (Let t v) sct)
-          discharge n (NLet t v) bt scv sct
-            = return (Bind n (NLet t v) scv, Bind n (Let t v) sct)
-          discharge n (Hole t) bt scv sct
-            = return (Bind n (Hole t) scv, sct)
-          discharge n (GHole i ns t) bt scv sct
-            = return (Bind n (GHole i ns t) scv, sct)
-          discharge n (Guess t v) bt scv sct
-            = return (Bind n (Guess t v) scv, sct)
-          discharge n (PVar t) bt scv sct
-            = return (Bind n (PVar t) scv, Bind n (PVTy t) sct)
-          discharge n (PVTy t) bt scv sct
-            = return (Bind n (PVTy t) scv, sct)
+          discharge n (Lam r t) bt scv sct ns
+            = return (Bind n (Lam r t) scv, Bind n (Pi r Nothing t bt) sct, ns)
+          discharge n (Pi r i t k) bt scv sct ns
+            = return (Bind n (Pi r i t k) scv, sct, ns)
+          discharge n (Let t v) bt scv sct ns
+            = return (Bind n (Let t v) scv, Bind n (Let t v) sct, ns)
+          discharge n (NLet t v) bt scv sct ns
+            = return (Bind n (NLet t v) scv, Bind n (Let t v) sct, ns)
+          discharge n (Hole t) bt scv sct ns
+            = return (Bind n (Hole t) scv, sct, ns)
+          discharge n (GHole i ns t) bt scv sct uns
+            = return (Bind n (GHole i ns t) scv, sct, uns)
+          discharge n (Guess t v) bt scv sct ns
+            = return (Bind n (Guess t v) scv, sct, ns)
+          discharge n (PVar r t) bt scv sct ns
+            = return (Bind n (PVar r t) scv, Bind n (PVTy t) sct, ns)
+          discharge n (PVTy t) bt scv sct ns
+            = return (Bind n (PVTy t) scv, sct, ns)
 
 -- Number of times a name can be used
 data UniqueUse = Never -- no more times
@@ -316,7 +355,7 @@
     isVar _ = False
 
     chkBinders :: Env -> Term -> StateT [(Name, (UniqueUse, Universe))] TC ()
-    chkBinders env (V i) | length env > i = chkName (fst (env!!i))
+    chkBinders env (V i) | length env > i = chkName (fstEnv (env!!i))
     chkBinders env (P _ n _) = chkName n
     -- 'lending' a unique or nulltype variable doesn't count as a use,
     -- but we still can't lend something that's already been used.
@@ -336,13 +375,13 @@
             case b of
                  Let t v -> chkBinders env v
                  _ -> return ()
-            chkBinders ((n, b) : env) t
+            chkBinders ((n, Rig0, b) : env) t
     chkBinders env t = return ()
 
     chkBinderName :: Env -> Name -> Binder Term ->
                      StateT [(Name, (UniqueUse, Universe))] TC ()
     chkBinderName env n b
-       = do let rawty = forgetEnv (map fst env) (binderTy b)
+       = do let rawty = forgetEnv (map fstEnv env) (binderTy b)
             (_, kind) <- lift $ check ctxt env rawty
             case kind of
                  UType UniqueType -> do ns <- get
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
@@ -105,10 +105,10 @@
 
     un names tx@(P _ x _) tm
         | tx /= tm && holeIn env x || x `elem` holes
-            = do sc 1; checkCycle names (x, tm)
+            = do sc 1; checkCycle names tx (x, tm)
     un names tm ty@(P _ y _)
         | ty /= tm && holeIn env y || y `elem` holes
-            = do sc 1; checkCycle names (y, tm)
+            = do sc 1; checkCycle names ty (y, tm)
     un bnames (V i) (P _ x _)
         | length bnames > i,
           fst (fst (bnames!!i)) == x ||
@@ -140,8 +140,8 @@
     uB bnames (Let tx vx) (Let ty vy) = do h1 <- un bnames tx ty
                                            h2 <- un bnames vx vy
                                            combine bnames h1 h2
-    uB bnames (Lam tx) (Lam ty) = un bnames tx ty
-    uB bnames (Pi i tx _) (Pi i' ty _) = un bnames tx ty
+    uB bnames (Lam _ tx) (Lam _ ty) = un bnames tx ty
+    uB bnames (Pi r i tx _) (Pi r' i' ty _) = un bnames tx ty
     uB bnames x y = do UI s f <- get
                        let r = recoverable (normalise ctxt env (binderTy x))
                                            (normalise ctxt env (binderTy y))
@@ -183,11 +183,12 @@
 
 --     substN n tm (var, sol) = (var, subst n tm sol)
 
-    checkCycle ns p@(x, P _ x' _) | x == x' = return []
-    checkCycle ns p@(x, P _ _ _) = return [p]
-    checkCycle ns (x, tm)
-        | not (x `elem` freeNames tm) = checkScope ns (x, tm)
-        | otherwise = lift $ tfail (InfiniteUnify x tm (errEnv env))
+    checkCycle ns xtm p@(x, P _ x' _) | x == x' = return []
+    checkCycle ns xtm p@(x, P _ _ _) = return [p]
+    checkCycle ns xtm (x, tm)
+        | conGuarded ctxt x tm = lift $ tfail (InfiniteUnify x tm (errEnv env))
+        | x `elem` freeNames tm = unifyFail xtm tm
+        | otherwise = checkScope ns (x, tm)
 
     checkScope ns (x, tm) =
 --           case boundVs (envPos x 0 env) tm of
@@ -204,13 +205,13 @@
     bind i ns tm
       | i < 0 = tm
       | otherwise = let ((x,y),ty) = ns!!i in
-                        App MaybeHoles (Bind y (Lam ty) (bind (i-1) ns tm))
+                        App MaybeHoles (Bind y (Lam RigW ty) (bind (i-1) ns tm))
                             (P Bound x ty)
 
 renameBinders env (x, t) = (x, renameBindersTm env t)
 
 renameBindersTm :: Env -> TT Name -> TT Name
-renameBindersTm env tm = uniqueBinders (map fst env) tm
+renameBindersTm env tm = uniqueBinders (map fstEnv env) tm
   where
     uniqueBinders env (Bind n b sc)
         | n `elem` env
@@ -368,16 +369,16 @@
         | tx /= ty && (holeIn env x || x `elem` holes)
                    && (holeIn env y || y `elem` holes)
             = case compare (envPos 0 x env) (envPos 0 y env) of
-                   LT -> do sc 1; checkCycle bnames (x, ty)
-                   _ -> do sc 1; checkCycle bnames (y, tx)
-       where envPos i n ((n',_):env) | n == n' = i
+                   LT -> do sc 1; checkCycle bnames tx (x, ty)
+                   _ -> do sc 1; checkCycle bnames ty (y, tx)
+       where envPos i n ((n',_,_):env) | n == n' = i
              envPos i n (_:env) = envPos (i+1) n env
              envPos _ _ _ = 100000
     un' env fn bnames xtm@(P _ x _) tm
         | pureTerm tm, holeIn env x || x `elem` holes
                        = do UI s f <- get
                             -- injectivity check
-                            x <- checkCycle bnames (x, tm)
+                            x <- checkCycle bnames xtm (x, tm)
                             if (notP tm && fn)
 --                               trace (show (x, tm, normalise ctxt env tm)) $
 --                                 put (UI s ((tm, topx, topy) : i) f)
@@ -385,13 +386,13 @@
                                  else do sc 1
                                          return x
         | pureTerm tm, not (injective xtm) && injective tm
-                       = do checkCycle bnames (x, tm)
+                       = do checkCycle bnames xtm (x, tm)
                             unifyTmpFail xtm tm
     un' env fn bnames tm ytm@(P _ y _)
         | pureTerm tm, holeIn env y || y `elem` holes
                        = do UI s f <- get
                             -- injectivity check
-                            x <- checkCycle bnames (y, tm)
+                            x <- checkCycle bnames ytm (y, tm)
                             if (notP tm && fn)
 --                               trace (show (y, tm, normalise ctxt env tm)) $
 --                                 put (UI s ((tm, topx, topy) : i) f)
@@ -399,7 +400,7 @@
                                  else do sc 1
                                          return x
         | pureTerm tm, not (injective ytm) && injective tm
-                       = do checkCycle bnames (y, tm)
+                       = do checkCycle bnames ytm (y, tm)
                             unifyTmpFail tm ytm
     un' env fn bnames (V i) (P _ x _)
         | length bnames > i,
@@ -415,16 +416,16 @@
 
 -- Pattern unification rule
     un' env fn bnames tm app@(App _ _ _)
-        | (P _ mv _, args) <- unApply app,
+        | (mvtm@(P _ mv _), args) <- unApply app,
           holeIn env mv || mv `elem` holes,
           all rigid args,
           containsOnly (mapMaybe getname args) (mapMaybe getV args) tm
           -- && TODO: tm does not refer to any variables other than those
           -- in 'args'
         = -- trace ("PATTERN RULE SOLVE: " ++ show (mv, tm, env, bindLams args (substEnv env tm))) $
-          checkCycle bnames (mv, eta [] $ bindLams args (substEnv env tm))
+          checkCycle bnames mvtm (mv, eta [] $ bindLams args (substEnv env tm))
       where rigid (V i) = True
-            rigid (P _ t _) = t `elem` map fst env &&
+            rigid (P _ t _) = t `elem` map fstEnv env &&
                               not (holeIn env t || t `elem` holes)
             rigid _ = False
 
@@ -450,24 +451,24 @@
             bindLams [] tm = tm
             bindLams (a : as) tm = bindLam a (bindLams as tm)
 
-            bindLam (V i) tm = Bind (fst (env !! i))
-                                    (Lam (binderTy (snd (env !! i))))
+            bindLam (V i) tm = Bind (fstEnv (env !! i))
+                                    (Lam RigW (binderTy (sndEnv (env !! i))))
                                     tm
-            bindLam (P _ n ty) tm = Bind n (Lam ty) tm
+            bindLam (P _ n ty) tm = Bind n (Lam RigW ty) tm
             bindLam _ tm = error "Can't happen [non rigid bindLam]"
 
             substEnv [] tm = tm
-            substEnv ((n, t) : env) tm
+            substEnv ((n, _, t) : env) tm
                 = substEnv env (substV (P Bound n (binderTy t)) tm)
 
             -- remove any unnecessary lambdas (helps with interface
             -- resolution later).
-            eta ks (Bind n (Lam ty) sc) = eta ((n, ty) : ks) sc
+            eta ks (Bind n (Lam r ty) sc) = eta ((n, r, ty) : ks) sc
             eta ks t = rebind ks t
 
-            rebind ((n, ty) : ks) (App _ f (P _ n' _))
+            rebind ((n, r, ty) : ks) (App _ f (P _ n' _))
                 | n == n' = eta ks f
-            rebind ((n, ty) : ks) t = rebind ks (Bind n (Lam ty) t)
+            rebind ((n, r, ty) : ks) t = rebind ks (Bind n (Lam r ty) t)
             rebind _ t = t
 
     un' env fn bnames appx@(App _ _ _) appy@(App _ _ _)
@@ -475,13 +476,13 @@
 --         = uplus (unApp fn bnames appx appy)
 --                 (unifyTmpFail appx appy) -- take the whole lot
 
-    un' env fn bnames x (Bind n (Lam t) (App _ y (P Bound n' _)))
+    un' env fn bnames x (Bind n (Lam _ t) (App _ y (P Bound n' _)))
         | n == n' = un' env False bnames x y
-    un' env fn bnames (Bind n (Lam t) (App _ x (P Bound n' _))) y
+    un' env fn bnames (Bind n (Lam _ t) (App _ x (P Bound n' _))) y
         | n == n' = un' env False bnames x y
-    un' env fn bnames x (Bind n (Lam t) (App _ y (V 0)))
+    un' env fn bnames x (Bind n (Lam _ t) (App _ y (V 0)))
         = un' env False bnames x y
-    un' env fn bnames (Bind n (Lam t) (App _ x (V 0))) y
+    un' env fn bnames (Bind n (Lam _ t) (App _ x (V 0))) y
         = un' env False bnames x y
 --     un' env fn bnames (Bind x (PVar _) sx) (Bind y (PVar _) sy)
 --         = un' env False ((x,y):bnames) sx sy
@@ -491,27 +492,27 @@
     -- f D unifies with t -> D. This is dubious, but it helps with
     -- interface resolution for interfaces over functions.
 
-    un' env fn bnames (App _ f x) (Bind n (Pi i t k) y)
+    un' env fn bnames (App _ f x) (Bind n (Pi r i t k) y)
       | noOccurrence n y && injectiveApp f
         = do ux <- un' env False bnames x y
-             uf <- un' env False bnames f (Bind (sMN 0 "uv") (Lam (TType (UVar [] 0)))
-                                      (Bind n (Pi i t k) (V 1)))
+             uf <- un' env False bnames f (Bind (sMN 0 "uv") (Lam RigW (TType (UVar [] 0)))
+                                      (Bind n (Pi r i t k) (V 1)))
              combine env bnames ux uf
 
-    un' env fn bnames (Bind n (Pi i t k) y) (App _ f x)
+    un' env fn bnames (Bind n (Pi r i t k) y) (App _ f x)
       | noOccurrence n y && injectiveApp f
         = do ux <- un' env False bnames y x
-             uf <- un' env False bnames (Bind (sMN 0 "uv") (Lam (TType (UVar [] 0)))
-                                    (Bind n (Pi i t k) (V 1))) f
+             uf <- un' env False bnames (Bind (sMN 0 "uv") (Lam RigW (TType (UVar [] 0)))
+                                    (Bind n (Pi r i t k) (V 1))) f
              combine env bnames ux uf
 
     un' env fn bnames (Bind x bx sx) (Bind y by sy)
         | sameBinder bx by
            = do h1 <- uB env bnames bx by
-                h2 <- un' ((x, bx) : env) False (((x,y),binderTy bx):bnames) sx sy
+                h2 <- un' ((x, RigW, bx) : env) False (((x,y),binderTy bx):bnames) sx sy
                 combine env bnames h1 h2
-      where sameBinder (Lam _) (Lam _) = True
-            sameBinder (Pi i _ _) (Pi i' _ _) = True
+      where sameBinder (Lam _ _) (Lam _ _) = True
+            sameBinder (Pi _ i _ _) (Pi _ i' _ _) = True
             sameBinder _ _ = False -- never unify holes/guesses/etc
     un' env fn bnames x y
         | OK True <- convEq' ctxt holes x y = do sc 1; return []
@@ -606,7 +607,7 @@
                          P _ x _ -> x `elem` holes || patIn env x
                          _ -> False
             inenv t = case t of
-                           P _ x _ -> x `elem` (map fst env)
+                           P _ x _ -> x `elem` (map fstEnv env)
                            _ -> False
 
             notFn t = injective t || metavar t || inenv t
@@ -642,10 +643,10 @@
              h2 <- un' env False bnames vx vy
              sc 1
              combine env bnames h1 h2
-    uB env bnames (Lam tx) (Lam ty) = do sc 1; un' env False bnames tx ty
-    uB env bnames (Pi _ tx _) (Pi _ ty _) = do sc 1; un' env False bnames tx ty
+    uB env bnames (Lam _ tx) (Lam _ ty) = do sc 1; un' env False bnames tx ty
+    uB env bnames (Pi _ _ tx _) (Pi _ _ ty _) = do sc 1; un' env False bnames tx ty
     uB env bnames (Hole tx) (Hole ty) = un' env False bnames tx ty
-    uB env bnames (PVar tx) (PVar ty) = un' env False bnames tx ty
+    uB env bnames (PVar _ tx) (PVar _ ty) = un' env False bnames tx ty
     uB env bnames x y
                   = do UI s f <- get
                        let r = recoverable (normalise ctxt env (binderTy x))
@@ -658,10 +659,11 @@
                                    env, err, from, Unify) : f))
                        return [] -- lift $ tfail err
 
-    checkCycle ns p@(x, P _ _ _) = return [p]
-    checkCycle ns (x, tm)
-        | not (x `elem` freeNames tm) = checkScope ns (x, tm)
-        | otherwise = lift $ tfail (InfiniteUnify x tm (errEnv env))
+    checkCycle ns xtm p@(x, P _ _ _) = return [p]
+    checkCycle ns xtm (x, tm)
+        | conGuarded ctxt x tm = lift $ tfail (InfiniteUnify x tm (errEnv env))
+        | x `elem` freeNames tm = unifyTmpFail xtm tm
+        | otherwise = checkScope ns (x, tm)
 
     checkScope ns (x, tm) | pureTerm tm =
 --           case boundVs (envPos x 0 env) tm of
@@ -679,7 +681,7 @@
     bind i ns tm
       | i < 0 = tm
       | otherwise = let ((x,y),ty) = ns!!i in
-                        App MaybeHoles (Bind y (Lam ty) (bind (i-1) ns tm))
+                        App MaybeHoles (Bind y (Lam RigW ty) (bind (i-1) ns tm))
                             (P Bound x ty)
 
     combine env bnames as [] = return as
@@ -754,33 +756,33 @@
     | f == f' = recoverable a a'
 recoverable (App _ f a) (App _ f' a')
     = recoverable f f' -- && recoverable a a'
-recoverable f (Bind _ (Pi _ _ _) sc)
+recoverable f (Bind _ (Pi _ _ _ _) sc)
     | (P (DCon _ _ _) _ _, _) <- unApply f = False
     | (P (TCon _ _) _ _, _) <- unApply f = False
     | (Constant _) <- f = False
     | TType _ <- f = False
     | UType _ <- f = False
-recoverable (Bind _ (Pi _ _ _) sc) f
+recoverable (Bind _ (Pi _ _ _ _) sc) f
     | (P (DCon _ _ _) _ _, _) <- unApply f = False
     | (P (TCon _ _) _ _, _) <- unApply f = False
     | (Constant _) <- f = False
     | TType _ <- f = False
     | UType _ <- f = False
-recoverable (Bind _ (Lam _) sc) f = recoverable sc f
-recoverable f (Bind _ (Lam _) sc) = recoverable f sc
+recoverable (Bind _ (Lam _ _) sc) f = recoverable sc f
+recoverable f (Bind _ (Lam _ _) sc) = recoverable f sc
 recoverable x y = True
 
-errEnv :: [(a, Binder b)] -> [(a, b)]
-errEnv = map (\(x, b) -> (x, binderTy b))
+errEnv :: [(a, r, Binder b)] -> [(a, b)]
+errEnv = map (\(x, _, b) -> (x, binderTy b))
 
 holeIn :: Env -> Name -> Bool
-holeIn env n = case lookup n env of
+holeIn env n = case lookupBinder n env of
                     Just (Hole _) -> True
                     Just (Guess _ _) -> True
                     _ -> False
 
 patIn :: Env -> Name -> Bool
-patIn env n = case lookup n env of
-                    Just (PVar _) -> True
+patIn env n = case lookupBinder n env of
+                    Just (PVar _ _) -> True
                     Just (PVTy _) -> True
                     _ -> False
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
@@ -55,13 +55,13 @@
 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 = 
+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 = 
+whnf' ctxt env tm =
      quote (do_whnf ctxt (map finalEntry env) (finalise tm))
 
 -- | Reduce a type so that all arguments are expanded
@@ -72,13 +72,13 @@
            -- 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) 
+           Bind n b@(Pi rig _ ty _) sc ->
+                    Bind n b (whnfArgs' ctxt ((n, rig, 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)
+finalEntry :: (Name, RigCount, Binder (TT Name)) -> (Name, RigCount, Binder (TT Name))
+finalEntry (n, r, b) = (n, r, fmap finalise b)
 
 do_whnf :: Context -> Env -> Term -> WHNF
 do_whnf ctxt genv tm = eval (WEnv 0 []) [] tm
@@ -90,14 +90,14 @@
          | 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) ((tm, tenv) : stk) (Bind n b@(Lam _) 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
+         =let n' = uniqueName n (map fstEnv 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)
+         | Just (Let t v) <- lookupBinder 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
@@ -112,7 +112,7 @@
     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)
@@ -122,7 +122,7 @@
             if not (tcReducible n ctxt)
                then unload wp stk
                else case lookupDefAccExact n False ctxt of
-                         Just (CaseOp ci _ _ _ _ cd, acc) 
+                         Just (CaseOp ci _ _ _ _ cd, acc)
                              | acc == Public || acc == Hidden ->
                           let (ns, tree) = cases_compiletime cd in
                               case evalCase env ns tree stk of
@@ -230,7 +230,7 @@
 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 (WV i) = V i
-quote (WBind n b (sc, env)) = Bind n (fmap (\ (t, env) -> quoteEnv env t) b) 
+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
diff --git a/src/Idris/Coverage.hs b/src/Idris/Coverage.hs
--- a/src/Idris/Coverage.hs
+++ b/src/Idris/Coverage.hs
@@ -62,30 +62,30 @@
 --
 -- 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) 
+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 [] = return []
 genClauses fc n lhs_tms given
    = do i <- getIState
-      
-        let lhs_given = zipWith removePlaceholders lhs_tms 
+
+        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) <- 
+        (cns, ctree_in) <-
                          case simpleCase False (UnmatchedCase "Undefined") False
                               (CoverageCheck givenpos) emptyFC [] []
-                              lhs_given 
+                              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
@@ -94,9 +94,9 @@
 
         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" 
+        logCoverage 3 $ "Missing clauses:\n" ++ showSep "\n"
                               (map showTmImpls missing)
-        logCoverage 10 $ "Covered clauses:\n" ++ showSep "\n" 
+        logCoverage 10 $ "Covered clauses:\n" ++ showSep "\n"
                               (map showTmImpls covered)
         return missing
     where
@@ -132,16 +132,16 @@
        | (tf, [tyl, tyr, tl, tr]) <- unApply tm
            = let tl' = rp tl pl
                  tr' = rp tr pr in
-                 mkApp tf [Erased, Erased, tl', tr'] 
+                 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'] 
+                 mkApp tf [Erased, Erased, tl', tr']
     rp tm _ = tm
 
 mkNewClauses :: Context -> Name -> [Name] -> SC -> ([Term], [Term])
-mkNewClauses ctxt fn ns sc 
+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)) $
@@ -149,7 +149,7 @@
   where
     mkPlApp f args = mkApp f (map erasePs args)
 
-    erasePs ap@(App t f a) 
+    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
@@ -157,16 +157,16 @@
     mkFromSC cov args sc = evalState (mkFromSC' cov args sc) []
 
     mkFromSC' :: Bool -> [Term] -> SC -> State [[Term]] [[Term]]
-    mkFromSC' cov args (STerm _) 
+    mkFromSC' cov args (STerm _)
         = if cov then return [args] else return [] -- leaf of provided case
-    mkFromSC' cov args (UnmatchedCase _) 
+    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 
+               else do alts' <- mapM (mkFromAlt cov args x) alts
                        put (args : done)
                        return (concat alts')
     mkFromSC' cov args _ = return [] -- Should never happen
@@ -178,7 +178,7 @@
              args' = map (subst x argrep) args in
              mkFromSC' cov args' sc
     mkFromAlt cov args x (ConstCase c sc)
-       = let argrep = Constant c 
+       = let argrep = Constant c
              args' = map (subst x argrep) args in
              mkFromSC' cov args' sc
     mkFromAlt cov args x (DefaultCase sc)
@@ -195,18 +195,18 @@
 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) 
+    addMissingAlt (ConCase n i ns sc)
          = liftM (ConCase n i ns) (addMissingConsSt ist sc)
-    addMissingAlt (FnCase n ns sc) 
+    addMissingAlt (FnCase n ns sc)
          = liftM (FnCase n ns) (addMissingConsSt ist sc)
-    addMissingAlt (ConstCase c sc) 
+    addMissingAlt (ConstCase c sc)
          = liftM (ConstCase c) (addMissingConsSt ist sc)
-    addMissingAlt (SucCase n sc) 
+    addMissingAlt (SucCase n sc)
          = liftM (SucCase n) (addMissingConsSt ist sc)
-    addMissingAlt (DefaultCase sc) 
+    addMissingAlt (DefaultCase sc)
          = liftM DefaultCase (addMissingConsSt ist sc)
 
-    addMissingAlts argn as 
+    addMissingAlts argn as
 --          | any hasDefault as = map addMissingAlt as
          | cons@(n:_) <- mapMaybe collectCons as,
            Just tyn <- getConType n,
@@ -226,7 +226,7 @@
     addCases missing (DefaultCase rhs : rest)
        = do missing' <- mapM (genMissingAlt rhs) missing
             return (mapMaybe id missing' ++ rest)
-    addCases missing (c : rest) 
+    addCases missing (c : rest)
        = liftM (c :) $ addCases missing rest
 
     addCons missing [] = []
@@ -258,7 +258,7 @@
                       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)
@@ -312,7 +312,7 @@
     substMatch ca (_:cs) = substMatch ca cs
 
     substNames [] sc = sc
-    substNames ((n, n') : ns) sc 
+    substNames ((n, n') : ns) sc
        = substNames ns (substSC n n' sc)
 
     notConMatch cs (ConCase cn t args sc) = cn `notElem` cs
@@ -349,10 +349,29 @@
 recoverableCoverage ctxt (CantUnify r (topx, _) (topy, _) e _ _)
     = let topx' = normalise ctxt [] topx
           topy' = normalise ctxt [] topy in
-          checkRec topx' topy'
+          evalState (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
+        -- to unify with a function that may be reduced later, or if any
+        -- variables need to have two different constructor forms
+
+        -- The state is a mapping of name to what it has failed to unify
+        -- with
+        checkRec :: Term -> Term -> State [(Name, Term)] Bool
+        checkRec (P Bound x _) tm
+           | (P yt _ _, _) <- unApply tm,
+             conType yt = do nmap <- get
+                             case lookup x nmap of
+                                  Nothing -> do put ((x, tm) : nmap)
+                                                return True
+                                  Just y' -> checkRec tm y'
+        checkRec tm (P Bound y _)
+           | (P xt _ _, _) <- unApply tm,
+             conType xt = do nmap <- get
+                             case lookup y nmap of
+                                  Nothing -> do put ((y, tm) : nmap)
+                                                return True
+                                  Just x' -> checkRec tm x'
         checkRec (App _ f a) p@(P _ _ _) = checkRec f p
         checkRec p@(P _ _ _) (App _ f a) = checkRec p f
         checkRec fa@(App _ _ _) fa'@(App _ _ _)
@@ -360,14 +379,31 @@
               (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
+                      else checkRecs (f : as) (f' : as')
+          where
+            checkRecs [] [] = return True
+            checkRecs (a : as) (b : bs) = do aok <- checkRec a b
+                                             asok <- checkRecs as bs
+                                             return (aok && asok)
+        checkRec (P xt x _) (P yt y _)
+           | x == y = return True
+           | ntRec xt yt = return True
+        checkRec _ _ = return False
 
+        conType (DCon _ _ _) = True
+        conType (TCon _ _) = True
+        conType _ = False
+
+        -- If either name is a reference or a bound variable, then further
+        -- development may fix the error, so consider it recoverable.
+        -- If both names are constructors, and the name is different, then
+        -- it's not recoverable
         ntRec x y | Ref <- x = True
                   | Ref <- y = True
-                  | (Bound, Bound) <- (x, y) = True
+                  | Bound <- x = True
+                  | Bound <- y = True
                   | otherwise = False -- name is different, unrecoverable
+recoverableCoverage ctxt (InfiniteUnify _ _ _) = False -- always unrecoverable
 recoverableCoverage ctxt (At _ e) = recoverableCoverage ctxt e
 recoverableCoverage ctxt (Elaborating _ _ _ e) = recoverableCoverage ctxt e
 recoverableCoverage ctxt (ElaboratingArg _ _ _ e) = recoverableCoverage ctxt e
diff --git a/src/Idris/DataOpts.hs b/src/Idris/DataOpts.hs
--- a/src/Idris/DataOpts.hs
+++ b/src/Idris/DataOpts.hs
@@ -103,7 +103,7 @@
     satArgs n = map (\i -> sMN i "sat") [1..n]
 
     bind [] tm = tm
-    bind (n:ns) tm = Bind n (Lam Erased) (pToV n (bind ns tm))
+    bind (n:ns) tm = Bind n (Lam RigW Erased) (pToV n (bind ns tm))
 
     -- Nat special cases
     -- TODO: Would be nice if this was configurable in idris source!
diff --git a/src/Idris/DeepSeq.hs b/src/Idris/DeepSeq.hs
--- a/src/Idris/DeepSeq.hs
+++ b/src/Idris/DeepSeq.hs
@@ -108,3 +108,4 @@
 instance NFData SyntaxInfo
 instance NFData DefaultTotality
 instance NFData IState
+instance NFData InteractiveOpts
diff --git a/src/Idris/Delaborate.hs b/src/Idris/Delaborate.hs
--- a/src/Idris/Delaborate.hs
+++ b/src/Idris/Delaborate.hs
@@ -135,29 +135,29 @@
                             = case lookup n (idris_metavars ist) of
                                   Just (Just _, mi, _, _, _) -> mkMVApp n []
                                   _ -> PRef un [] n
-    de env _ (Bind n (Lam ty) sc)
+    de env _ (Bind n (Lam _ ty) sc)
           = PLam un n NoFC (de env [] ty) (de ((n,n):env) [] sc)
-    de env (_ : is) (Bind n (Pi (Just impl) ty _) sc)
+    de env (_ : is) (Bind n (Pi rig (Just impl) ty _) sc)
        | toplevel_imp impl -- information in 'imps' repeated
-          = PPi (Imp [] Dynamic False (Just impl) False) n NoFC (de env [] ty) (de ((n,n):env) is sc)
-    de env is (Bind n (Pi (Just impl) ty _) sc)
+          = PPi (Imp [] Dynamic False (Just impl) False rig) n NoFC (de env [] ty) (de ((n,n):env) is sc)
+    de env is (Bind n (Pi rig (Just impl) ty _) sc)
        | tcimplementation impl
           = PPi constraint n NoFC (de env [] ty) (de ((n,n):env) is sc)
        | otherwise
-          = PPi (Imp [] Dynamic False (Just impl) False) n NoFC (de env [] ty) (de ((n,n):env) is sc)
-    de env ((PImp { argopts = opts }):is) (Bind n (Pi _ ty _) sc)
-          = PPi (Imp opts Dynamic False Nothing False) n NoFC (de env [] ty) (de ((n,n):env) is sc)
-    de env (PConstraint _ _ _ _:is) (Bind n (Pi _ ty _) sc)
-          = PPi constraint n NoFC (de env [] ty) (de ((n,n):env) is sc)
-    de env (PTacImplicit _ _ _ tac _:is) (Bind n (Pi _ ty _) sc)
-          = PPi (tacimpl tac) n NoFC (de env [] ty) (de ((n,n):env) is sc)
-    de env (plic:is) (Bind n (Pi _ ty _) sc)
-          = PPi (Exp (argopts plic) Dynamic False)
+          = PPi (Imp [] Dynamic False (Just impl) False rig) n NoFC (de env [] ty) (de ((n,n):env) is sc)
+    de env ((PImp { argopts = opts }):is) (Bind n (Pi rig _ ty _) sc)
+          = PPi (Imp opts Dynamic False Nothing False rig) n NoFC (de env [] ty) (de ((n,n):env) is sc)
+    de env (PConstraint _ _ _ _:is) (Bind n (Pi rig _ ty _) sc)
+          = PPi (constraint { pcount = rig}) n NoFC (de env [] ty) (de ((n,n):env) is sc)
+    de env (PTacImplicit _ _ _ tac _:is) (Bind n (Pi rig _ ty _) sc)
+          = PPi ((tacimpl tac) { pcount = rig }) n NoFC (de env [] ty) (de ((n,n):env) is sc)
+    de env (plic:is) (Bind n (Pi rig _ ty _) sc)
+          = PPi (Exp (argopts plic) Dynamic False rig)
                 n NoFC
                 (de env [] ty)
                 (de ((n,n):env) is sc)
-    de env [] (Bind n (Pi _ ty _) sc)
-          = PPi expl n NoFC (de env [] ty) (de ((n,n):env) [] sc)
+    de env [] (Bind n (Pi rig _ ty _) sc)
+          = PPi (expl { pcount = rig }) n NoFC (de env [] ty) (de ((n,n):env) [] sc)
 
     de env imps (Bind n (Let ty val) sc)
           | docases
@@ -188,7 +188,7 @@
     deFn env (P _ n _) [l,r]
          | n == pairTy    = PPair un [] IsType (de env [] l) (de env [] r)
          | n == sUN "lazy" = de env [] r -- TODO: Fix string based matching
-    deFn env (P _ n _) [ty, Bind x (Lam _) r]
+    deFn env (P _ n _) [ty, Bind x (Lam _ _) r]
          | n == sigmaTy
                = PDPair un [] IsType (PRef un [] x) (de env [] ty)
                            (de ((x,x):env) [] (instantiate (P Bound x ty) r))
@@ -339,9 +339,9 @@
   indented (annTm y_ns (pprintTerm' i (map (\ (n, b) -> (n, False)) env)
                y)) <>
   if (opt_errContext (idris_options i)) then line <> text "Conversion failure" <$>  showSc i env else empty
-    where flagUnique (Bind n (Pi i t k@(UType u)) sc)
+    where flagUnique (Bind n (Pi rig i t k@(UType u)) sc)
               = App Complete (P Ref (sUN (show u)) Erased)
-                    (Bind n (Pi i (flagUnique t) k) (flagUnique sc))
+                    (Bind n (Pi rig i (flagUnique t) k) (flagUnique sc))
           flagUnique (App s f a) = App s (flagUnique f) (flagUnique a)
           flagUnique (Bind n b sc) = Bind n (fmap flagUnique b) (flagUnique sc)
           flagUnique t = t
@@ -527,13 +527,13 @@
   indented (vsep (map ppHole holes)) <> line <> line <>
   text "Term: " <> indented (pprintTT [] tm)
 
-  where ppHole :: (Name, Type, Env) -> Doc OutputAnnotation
+  where ppHole :: (Name, Type, [(Name, Binder Type)]) -> Doc OutputAnnotation
         ppHole (hn, goal, env) =
           ppAssumptions [] (reverse env) <>
           text "----------------------------------" <> line <>
           bindingOf hn False <+> text ":" <+>
           pprintTT (map fst (reverse env)) goal <> line
-        ppAssumptions :: [Name] -> Env -> Doc OutputAnnotation
+        ppAssumptions :: [Name] -> [(Name, Binder Type)] -> Doc OutputAnnotation
         ppAssumptions ns [] = empty
         ppAssumptions ns ((n, b) : rest) =
           bindingOf n False <+>
diff --git a/src/Idris/Docs.hs b/src/Idris/Docs.hs
--- a/src/Idris/Docs.hs
+++ b/src/Idris/Docs.hs
@@ -5,16 +5,21 @@
 License     : BSD3
 Maintainer  : The Idris Community.
 -}
+
 {-# LANGUAGE DeriveFunctor, MultiWayIf, PatternGuards #-}
 {-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
+
 module Idris.Docs (
     pprintDocs
   , getDocs, pprintConstDocs, pprintTypeDoc
   , FunDoc, FunDoc'(..), Docs, Docs'(..)
   ) where
 
-import Idris.AbsSyntax
-import Idris.AbsSyntaxTree
+import Idris.AbsSyntax (FixDecl(..), Fixity, HowMuchDocs(..), IState(..), Idris,
+                        InterfaceInfo(..), PArg'(..), PDecl'(..), PPOption(..),
+                        PTerm(..), Plicity(..), RecordInfo(..), basename,
+                        getIState, modDocName, ppOptionIst, pprintPTerm,
+                        prettyIst, prettyName, type1Doc, typeDescription)
 import Idris.Core.Evaluate
 import Idris.Core.TT
 import Idris.Delaborate
@@ -26,7 +31,6 @@
 
 import Prelude hiding ((<$>))
 
-import Control.Arrow (first)
 import Data.List
 import Data.Maybe
 import qualified Data.Text as T
@@ -220,7 +224,7 @@
     dumpImplementation :: PTerm -> Doc OutputAnnotation
     dumpImplementation = pprintPTerm ppo params' [] infixes
 
-    prettifySubInterfaces (PPi (Constraint _ _) _ _ tm _)    = prettifySubInterfaces tm
+    prettifySubInterfaces (PPi (Constraint _ _ _) _ _ tm _)  = prettifySubInterfaces tm
     prettifySubInterfaces (PPi plcity           nm fc t1 t2) = PPi plcity (safeHead nm pNames) NoFC (prettifySubInterfaces t1) (prettifySubInterfaces t2)
     prettifySubInterfaces (PApp fc ref args)                 = PApp fc ref $ updateArgs pNames args
     prettifySubInterfaces tm                                 = tm
@@ -235,7 +239,7 @@
     updateRef nm (PRef fc _ _) = PRef fc [] nm
     updateRef _  pt          = pt
 
-    isSubInterface (PPi (Constraint _ _) _ _ (PApp _ _ args) (PApp _ (PRef _ _ nm) args')) = nm == n && map getTm args == map getTm args'
+    isSubInterface (PPi (Constraint _ _ _) _ _ (PApp _ _ args) (PApp _ (PRef _ _ nm) args')) = nm == n && map getTm args == map getTm args'
     isSubInterface (PPi _   _            _ _ pt)                                           = isSubInterface pt
     isSubInterface _                                                                       = False
 
@@ -356,7 +360,7 @@
     getDImpl (PImplementation _ _ _ _ _ _ _ _ _ _ _ _ t _ _) = Just t
     getDImpl _                                         = Nothing
 
-    isSubInterface (PPi (Constraint _ _) _ _ (PApp _ _ args) (PApp _ (PRef _ _ nm) args'))
+    isSubInterface (PPi (Constraint _ _ _) _ _ (PApp _ _ args) (PApp _ (PRef _ _ nm) args'))
       = nm == n && map getTm args == map getTm args'
     isSubInterface (PPi _ _ _ _ pt)
       = isSubInterface pt
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
@@ -16,6 +16,7 @@
 import Idris.Core.Execute
 import Idris.Core.TT
 import Idris.Core.Typecheck
+import Idris.Core.WHNF
 import Idris.Coverage
 import Idris.DataOpts
 import Idris.DeepSeq
@@ -75,6 +76,8 @@
          -- Check n actually exists, with no definition yet
          let tys = lookupTy n ctxt
          let reflect = Reflection `elem` opts
+         when (reflect && FCReflection `notElem` idris_language_extensions ist) $
+           ierror $ At fc (Msg "You must turn on the FirstClassReflection extension to use %reflection")
          checkUndefined n ctxt
          unless (length tys > 1) $ do
            fty <- case tys of
@@ -147,13 +150,13 @@
 
            -- pdef is the compile-time pattern definition, after forcing
            -- optimisation applied to LHS
-           let pdef = map (\(ns, lhs, rhs) -> (map fst ns, lhs, rhs)) $ 
+           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 (\(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, with no forcing optimisation of the LHS because
@@ -186,7 +189,7 @@
            pmissing <-
                    if cov && not (hasDefault pats_raw)
                       then do -- Generate clauses from the given possible cases
-                              missing <- genClauses fc n 
+                              missing <- genClauses fc n
                                                  (map (\ (ns,tm,_) -> (ns, tm)) pdef)
                                                  cs_full
                               -- missing <- genMissing n scargs sc
@@ -284,6 +287,10 @@
                                       Just Public -> mapM_ (checkVisibility fc n Public Public) calls
                                       _ -> return ()
                                  addCalls n calls
+                                 let rig = if linearArg (whnfArgs ctxt [] ty)
+                                              then Rig1
+                                              else RigW
+                                 updateContext (setRigCount n (minRig ctxt rig calls))
                                  addIBC (IBCCG n)
                           _ -> return ()
                       return ()
@@ -327,12 +334,12 @@
     debind (Left x)       = let (vs, x') = depat [] x in
                                 (vs, x', Impossible)
 
-    depat acc (Bind n (PVar t) sc) = depat ((n, t) : acc) (instantiate (P Bound n t) sc)
+    depat acc (Bind n (PVar rig t) sc) = depat ((n, t) : acc) (instantiate (P Bound n t) sc)
     depat acc x = (acc, x)
 
 
-    getPVs (Bind x (PVar _) tm) = let (vs, tm') = getPVs tm
-                                  in (x:vs, tm')
+    getPVs (Bind x (PVar rig _) tm) = let (vs, tm') = getPVs tm
+                                          in (x:vs, tm')
     getPVs tm = ([], tm)
 
     isPatVar vs (P Bound n _) = n `elem` vs
@@ -347,7 +354,7 @@
 
     -- Simplify the left hand side of a definition, to remove any lets
     -- that may have arisen during elaboration
-    simple_lhs ctxt (Right (x, y)) 
+    simple_lhs ctxt (Right (x, y))
         = Right (Idris.Core.Evaluate.simplify ctxt [] x, y)
     simple_lhs ctxt t = t
 
@@ -376,6 +383,12 @@
                                 Just t -> return t
                                 Nothing -> ierror (At fc (Msg "No specialisation achieved"))
 
+    minRig :: Context -> RigCount -> [Name] -> RigCount
+    minRig c minr [] = minr
+    minRig c minr (r : rs) = case lookupRigCountExact r c of
+                                  Nothing -> minRig c minr rs
+                                  Just rc -> minRig c (min minr rc) rs
+
 forceWith :: Ctxt OptInfo -> Term -> Term
 forceWith opts lhs = -- trace (show lhs ++ "\n==>\n" ++ show (force lhs) ++ "\n----") $
                       force lhs
@@ -495,7 +508,7 @@
         | (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) 
+    specName simpl (ConstraintS, tm)
         | (P Ref n _, _) <- unApply tm = Just (n, Just (if simpl then 1 else 0))
     specName simpl _ = Nothing
 
@@ -526,8 +539,8 @@
              [] -> False
              _ -> True
     concreteTm ist (Constant _) = True
-    concreteTm ist (Bind n (Lam _) sc) = True
-    concreteTm ist (Bind n (Pi _ _ _) sc) = True
+    concreteTm ist (Bind n (Lam _ _) sc) = True
+    concreteTm ist (Bind n (Pi _ _ _ _) sc) = True
     concreteTm ist (Bind n (Let _ _) sc) = concreteTm ist sc
     concreteTm ist _ = False
 
@@ -585,12 +598,12 @@
                   updateIState $ \i -> i { idris_name = newGName }
                   let lhs_tm = normalise ctxt [] (orderPats (getInferTerm lhs'))
                   let emptyPat = hasEmptyPat ctxt (idris_datatypes i) lhs_tm
-                  if emptyPat then 
+                  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, _, _) -> 
+                           OK (tm, _, _) ->
                                     do logElab 10 $ "Valid " ++ show tm ++ "\n"
                                                  ++ " from " ++ show lhs
                                        return (Just (delab' i tm True True))
@@ -605,7 +618,7 @@
                             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 " ++ 
+  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
@@ -624,8 +637,8 @@
         -- 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 
+        case ok of
+             Nothing -> return restpos
              Just lhstm -> return (lhstm : restpos)
   where
     qmatch _ Placeholder = True
@@ -634,52 +647,24 @@
             = 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 (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)
+   = let rawTy = forgetEnv (map fstEnv env) (binderTy b)
          uniq = case check ctxt env rawTy of
                      OK (_, UType UniqueType) -> True
                      OK (_, UType NullType) -> True
                      OK (_, UType AllTypes) -> True
                      _ -> False in
-         if uniq then n : findUnique ctxt ((n, b) : env) sc
-                 else findUnique ctxt ((n, b) : env) sc
+         if uniq then n : findUnique ctxt ((n, RigW, b) : env) sc
+                 else findUnique ctxt ((n, RigW, 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)
@@ -846,20 +831,12 @@
 
         when inf $ addTyInfConstraints fc (map (\(x,y,_,_,_,_,_) -> (x,y)) probs)
 
-        logElab 5 "DONE CHECK"
+        logElab 3 "DONE CHECK"
         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'
 
+        let rhs' = rhsElab
+
         when (not (null defer)) $ logElab 1 $ "DEFERRED " ++
                     show (map (\ (n, (_,_,t,_)) -> (n, t)) defer)
 
@@ -920,7 +897,7 @@
         rev <- case ret_fam of
                     P _ rfamn _ ->
                         case lookupCtxt rfamn (idris_datatypes i) of
-                             [TI _ _ dopts _ _] ->
+                             [TI _ _ dopts _ _ _] ->
                                  return (DataErrRev `elem` dopts &&
                                          size clhs <= size crhs)
                              _ -> return False
@@ -929,6 +906,9 @@
         when (rev || ErrorReverse `elem` opts) $ do
            addIBC (IBCErrRev (crhs, clhs))
            addErrRev (crhs, clhs)
+        when (rev || ErrorReduce `elem` opts) $ do
+           addIBC (IBCErrReduce fname)
+           addErrReduce fname
         pop_estack
         return (Right (clhs, crhs), lhs)
   where
@@ -1025,7 +1005,12 @@
 
         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
+        wval <- case wval_in of
+                     Placeholder -> ierror $ At fc $
+                          Msg "No expression for the with block to inspect.\nYou need to replace the _ with an expression."
+                     _ -> return $
+                            rhs_trans info $
+                              addImplBound i (map fst bargs) wval_in
         logElab 5 ("Checking " ++ showTmImpls wval)
         -- Elaborate wval in this context
         ((wvalElab, defer, is, ctxt', newDecls, highlights, newGName), _) <-
@@ -1051,18 +1036,9 @@
         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
-        
+        let wval' = 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)
@@ -1099,7 +1075,7 @@
         let wargname = sMN windex "warg"
 
         logElab 5 ("Abstract over " ++ show wargval ++ " in " ++ show wargtype)
-        let wtype = bindTyArgs (flip (Pi Nothing) (TType (UVar [] 0))) (bargs_pre ++
+        let wtype = bindTyArgs (flip (Pi RigW Nothing) (TType (UVar [] 0))) (bargs_pre ++
                      (wargname, wargtype) :
                      map (abstract wargname wargval wargtype) bargs_post ++
                      case mpn of
@@ -1132,13 +1108,9 @@
         wb <- mapM (mkAuxC mpn wname lhs (map fst bargs_pre) (map fst bargs_post))
                        withblock
         logElab 3 ("with block " ++ show wb)
-        -- 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)
+        setFlags wname [Inlinable]
+        when (AssertTotal `elem` opts) $
+           setFlags wname [Inlinable, AssertTotal]
         i <- getIState
         let rhstrans' = updateWithTerm i mpn wname lhs (map fst bargs_pre) (map fst (bargs_post))
                              . rhs_trans info
@@ -1168,22 +1140,13 @@
                         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'
 
+        ctxt <- getContext
+        let rhs' = rhsElab
 
         def' <- checkDef info fc iderr True defer
         let def'' = map (\(n, (i, top, t, ns)) -> (n, (i, top, t, ns, False, True))) def'
@@ -1193,7 +1156,7 @@
         (crhs, crhsty) <- recheckC (constraintNS info) fc id [] rhs'
         return (Right (clhs, crhs), lhs)
   where
-    getImps (Bind n (Pi _ _ _) t) = pexp Placeholder : getImps t
+    getImps (Bind n (Pi _ _ _ _) t) = pexp Placeholder : getImps t
     getImps _ = []
 
     mkAuxC pn wname lhs ns ns' (PClauses fc o n cs)
@@ -1292,13 +1255,13 @@
          -- This is something of a hack, because matching on the top level
          -- application won't find this information for us
          addResolvesArgs :: FC -> Term -> [PArg] -> [PArg]
-         addResolvesArgs fc (Bind n (Pi _ ty _) sc) (a : args)
+         addResolvesArgs fc (Bind n (Pi _ _ ty _) sc) (a : args)
              | (P _ cn _, _) <- unApply ty,
                getTm a == Placeholder
                  = case lookupCtxtExact cn (idris_interfaces ist) of
                         Just _ -> a { getTm = PResolveTC fc } : addResolvesArgs fc sc args
                         Nothing -> a : addResolvesArgs fc sc args
-         addResolvesArgs fc (Bind n (Pi _ ty _) sc) (a : args)
+         addResolvesArgs fc (Bind n (Pi _ _ ty _) sc) (a : args)
                  = a : addResolvesArgs fc sc args
          addResolvesArgs fc _ args = args
 
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
@@ -104,7 +104,8 @@
          -- TI contains information about mutually declared types - this will
          -- be updated when the mutual block is complete
          putIState (i { idris_datatypes =
-                          addDef n (TI (map fst cons) codata opts params [n])
+                          addDef n (TI (map fst cons) codata opts params [n]
+                                             (any linearArg (map snd cons)))
                                              (idris_datatypes i) })
          addIBC (IBCDef n)
          addIBC (IBCData n)
@@ -119,6 +120,9 @@
          -- TMP HACK! Make this a data option
          updateContext (addDatatype (Data n ttag cty unique cons))
          updateContext (setMetaInformation n metainf)
+         when (any linearArg (map snd cons)) $
+            updateContext (setRigCount n Rig1)
+
          mapM_ totcheck (zip (repeat fc) (map fst cons))
 --          mapM_ (checkPositive n) cons
 
@@ -189,7 +193,7 @@
 
          -- Check that the constructor type is, in fact, a part of the family being defined
          tyIs n cty'
-         let force = if tn == sUN "Delayed" 
+         let force = if tn == sUN "Delayed"
                         then [] -- TMP HACK! Totality checker needs this info
                         else forceArgs ctxt cty'
 
@@ -267,9 +271,9 @@
     -- 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 (Bind n (Pi _ _ _ _) sc)
        = forceFrom (i + 1) (substV (P Ref (sMN i "FF") Erased) sc)
-    forceFrom i 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
@@ -288,14 +292,14 @@
     -- Only look under constructors in applications
     findForcePos ap@(App _ f a)
         | (P _ con _, args) <- unApply ap,
-          isDConName con ctxt 
+          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 
+    -- be forced
     findNonForcePos fok ap@(App _ f a)
         | (P _ con _, args) <- unApply ap
             = nub $ concatMap (findNonForcePos (fok && isConName con ctxt)) args
@@ -310,7 +314,7 @@
   where
     getParamNames (n, ty) = (ty, getPs ty)
 
-    getPs (Bind n (Pi _ _ _) sc)
+    getPs (Bind n (Pi _ _ _ _) sc)
        = getPs (substV (P Ref n Erased) sc)
     getPs t | (f, args) <- unApply t
        = paramArgs 0 args
@@ -321,7 +325,7 @@
 
     addConConstraint ps cvar (ty, pnames) = constraintTy ty
       where
-        constraintTy (Bind n (Pi _ ty _) sc)
+        constraintTy (Bind n (Pi _ _ ty _) sc)
            = case getRetTy ty of
                   TType avar -> do tit <- typeInType
                                    when (not tit) $ do
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
@@ -93,7 +93,7 @@
          -- 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 
+            Nothing
                | OverlappingDictionary `notElem` opts ->
                        do mapM_ (maybe (return ()) overlapping . findOverlapping ist (interface_determiners ci) (delab ist nty))
                                 (map fst $ interface_implementations ci)
@@ -130,7 +130,7 @@
                               Just ty -> (map (\n -> (n, getTypeIn ist n ty)) headVars, ty)
                               _ -> (zip headVars (repeat Placeholder), Erased)
 
-         let impps = getImpParams ist (interface_impparams ci) 
+         let impps = getImpParams ist (interface_impparams ci)
                           (snd (unApply (substRetTy ty)))
          let iimpps = zip (interface_impparams ci) impps
 
@@ -154,8 +154,7 @@
          let ds_defs = insertDefaults ist iname (interface_defaults ci) ns ds
          logElab 3 ("After defaults: " ++ show ds_defs ++ "\n")
 
-         let ds' = map (addUnfold iname (map fst (interface_methods ci))) $
-                    reorderDefs (map fst (interface_methods ci)) ds_defs
+         let ds' = reorderDefs (map fst (interface_methods ci)) ds_defs
          logElab 1 ("Reordered: " ++ show ds' ++ "\n")
 
          mapM_ (warnMissing ds' ns iname) (map fst (interface_methods ci))
@@ -223,12 +222,6 @@
                 [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
@@ -310,16 +303,16 @@
        where
           needed is p = pname p `elem` map pname is
 
-    lamBind i (PPi (Constraint _ _) _ _ _ sc) sc'
+    lamBind i (PPi (Constraint _ _ _) _ _ _ sc) sc'
           = PLam fc (sMN i "meth") NoFC Placeholder (lamBind (i+1) sc sc')
     lamBind i (PPi _ n _ ty sc) sc'
           = PLam fc (sMN i "meth") NoFC Placeholder (lamBind (i+1) sc sc')
     lamBind i _ sc = sc
-    methArgs i (PPi (Imp _ _ _ _ _) n _ ty sc)
+    methArgs i (PPi (Imp _ _ _ _ _ _) n _ ty sc)
         = PImp 0 True [] n (PRef fc [] (sMN i "meth")) : methArgs (i+1) sc
-    methArgs i (PPi (Exp _ _ _) n _ ty sc)
+    methArgs i (PPi (Exp _ _ _ _) n _ ty sc)
         = PExp 0 [] (sMN 0 "marg") (PRef fc [] (sMN i "meth")) : methArgs (i+1) sc
-    methArgs i (PPi (Constraint _ _) n _ ty sc)
+    methArgs i (PPi (Constraint _ _ _) n _ ty sc)
         = PConstraint 0 [] (sMN 0 "marg") (PResolveTC fc) : methArgs (i+1) sc
     methArgs i _ = []
 
@@ -354,7 +347,7 @@
     extrabind [] x = x
 
     coninsert :: [(Name, PTerm)] -> [(Name, PTerm)] -> PTerm -> PTerm
-    coninsert cs ex (PPi p@(Imp _ _ _ _ _) n fc t sc) = PPi p n fc t (coninsert cs ex sc)
+    coninsert cs ex (PPi p@(Imp _ _ _ _ _ _) n fc t sc) = PPi p n fc t (coninsert cs ex sc)
     coninsert cs ex sc = conbind cs (extrabind ex sc)
 
     -- Reorder declarations to be in the same order as defined in the
@@ -516,6 +509,6 @@
     isInj i (Bind n b sc) = isInj i sc
     isInj _ _ = True
 
-    instantiateRetTy (Bind n (Pi _ _ _) sc)
+    instantiateRetTy (Bind n (Pi _ _ _ _) sc)
        = substV (P Bound n Erased) (instantiateRetTy sc)
     instantiateRetTy t = t
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
@@ -61,6 +61,7 @@
 elabInterface :: ElabInfo
               -> SyntaxInfo
               -> Docstring (Either Err PTerm)
+              -> ElabWhat
               -> FC
               -> [(Name, PTerm)] -- ^ Superclass constraints
               -> Name
@@ -72,7 +73,7 @@
               -> Maybe (Name, FC)             -- ^ implementation ctor name and location
               -> Docstring (Either Err PTerm) -- ^ implementation ctor docs
               -> Idris ()
-elabInterface info syn_in doc fc constraints tn tnfc ps pDocs fds ds mcn cd
+elabInterface info_in syn_in doc what fc constraints tn tnfc ps pDocs fds ds mcn cd
     = do let cn = fromMaybe (SN (ImplementationCtorN tn)) (fst <$> mcn)
          let constraint = PApp fc (PRef fc [] tn)
                                   (map (pexp . PRef fc []) (map (\(n, _, _) -> n) ps))
@@ -81,16 +82,16 @@
               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) 
+                            concatMap (implicitNamesIn [] ist)
                                       (map (\ (_,_,x) -> x) ps)
-         let impps = filter (\ (n, _, _) -> 
+         let impps = filter (\ (n, _, _) ->
                                n `notElem` (map (\ (n, _, _) -> n) ps)) impps_ns
 
-         let tty = impbind (map (\(n, _, ty) -> (n, ty)) impps) $ 
+         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
@@ -101,67 +102,156 @@
          let idecls = filter impldecl ds -- default super interface implementation declarations
          mapM_ checkDefaultSuperInterfaceImplementation idecls
          let mnames = map getMName mdecls
+         let fullmnames = map getFullMName mdecls
          ist <- getIState
          let constraintNames = nub $
                  concatMap (namesIn [] ist) (map snd constraints)
 
          mapM_ (checkConstraintName (map (\(x, _, _) -> x) ps)) constraintNames
 
-         logElab 2 $ "Building methods " ++ show mnames
-         ims <- mapM (tdecl impps mnames) mdecls
-         defs <- mapM (defdecl (map (\ (x,y,z) -> z) ims) constraint)
-                      (filter clause ds)
-         let (methods, imethods)
-              = unzip (map (\ (x, y, z) -> (x, y)) ims)
-         let defaults = map (\ (x, (y, z)) -> (x,y)) defs
+         let pre_ddecl = PLaterdecl tn NoFC tty
+         -- Elaborate the interface header, as long as we haven't done it
+         -- in an earlier pass
+         when (what /= EDefns) $
+            elabData info (syn { no_imp = no_imp syn ++ mnames,
+                                 imp_methods = mnames }) doc pDocs fc [] pre_ddecl
+         -- Continue only if we're not in the first pass of a mutual block
+         when (what /= ETypes) $ do
+             dets <- findDets tn (map fst fds)
 
-         -- build implementation constructor type
-         let cty = impbind [(pn, pt) | (pn, _, pt) <- impps ++ ps] $ conbind constraints
-                      $ pibind (map (\ (n, ty) -> (nsroot n, ty)) methods)
-                               constraint
+             logElab 3 $ "Building methods " ++ show fullmnames
+             ims <- mapM (tdecl impps mnames) mdecls
+             defs <- mapM (defdecl (map (\ (x,y,z) -> z) ims) constraint)
+                          (filter clause ds)
+             let (methods, imethods)
+                  = unzip (map (\ (x, y, z) -> (x, y)) ims)
+             let defaults = map (\ (x, (y, z)) -> (x,y)) defs
 
-         let cons = [(cd, pDocs ++ mapMaybe memberDocs ds, cn, NoFC, cty, fc, [])]
-         let ddecl = PDatadecl tn NoFC tty cons
+             addInterface tn (CI cn (map nodoc imethods) defaults idecls
+                                  (map (\(n, _, _) -> n) impps)
+                                  (map (\(n, _, _) -> n) ps)
+                                  (map snd constraints)
+                                  [] dets)
 
-         logElab 5 $ "Interface " ++ show (showDImp verbosePPOption ddecl)
+             -- for each constraint, build a top level function to chase it
+             -- elaborate types now, bodies later (after we've done the constructor
+             -- of the interface)
+             cfns <- mapM (cfun cn constraint syn (map fst imethods)) constraints
+             let (cfnTyDecls, cfnDefs) = unzip cfns
+             mapM_ (rec_elabDecl info EAll info) cfnTyDecls
 
-         -- 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) impps)
-                              (map (\(n, _, _) -> n) ps) 
-                              (map snd constraints)
-                              [] dets)
+             -- for each method, build a top level function
+             -- 'tfun' builds appropriate implicits for the constructor
+             -- declaration
+             fns <- mapM (tfun cn constraint (syn { imp_methods = mnames }) -- mnames })
+                               (map fst imethods)) imethods
+             let (fnTyDecls, fnDefs) = unzip fns
+             mapM_ (rec_elabDecl info EAll info) fnTyDecls
 
-         -- for each constraint, build a top level function to chase it
-         cfns <- mapM (cfun cn constraint syn (map fst imethods)) constraints
-         mapM_ (rec_elabDecl info EAll info) (concat cfns)
+             elabMethTys <- mapM getElabMethTy fullmnames
 
-         -- for each method, build a top level function
-         fns <- mapM (tfun cn constraint (syn { imp_methods = mnames })
-                           (map fst imethods)) imethods
-         logElab 5 $ "Functions " ++ show fns
-         -- Elaborate the the top level methods
-         mapM_ (rec_elabDecl info EAll info) (concat fns)
+             logElab 3 $ "Method types:\n" ++ showSep "\n" (map showTmImpls elabMethTys)
 
-         -- Flag all the top level data declarations as injective
-         mapM_ (\n -> do setInjectivity n True
-                         addIBC (IBCInjective n True))
-               (map fst (filter (\(_, (inj, _, _, _, _)) -> inj) imethods))
+             let cpos = map (\ (n, ty) -> (n, findConstraint ty))
+                            (zip fullmnames elabMethTys)
+             logElab 5 $ "Constraint pos: " ++ show cpos
 
-         -- add the default definitions
-         mapM_ (rec_elabDecl info EAll info) (concatMap (snd.snd) defs)
-         addIBC (IBCInterface tn)
+             -- Method types to store in the IState, taken from the elaborated
+             -- types with the parameter removed
+             let storemeths = map (mkMethTy True cpos) (zip fullmnames elabMethTys)
+             updateIMethods tn storemeths
 
-         sendHighlighting $
-           [(tnfc, AnnName tn Nothing Nothing Nothing)] ++
-           [(pnfc, AnnBoundName pn False) | (pn, pnfc, _) <- ps] ++
-           [(fdfc, AnnBoundName fc False) | (fc, fdfc) <- fds] ++
-           maybe [] (\(conN, conNFC) -> [(conNFC, AnnName conN Nothing Nothing Nothing)]) mcn
+             -- build implementation constructor type
+             let cty = impbind [(pn, pt) | (pn, _, pt) <- impps ++ ps] $
+                             conbind constraints $
+                             pibind (map (mkMethTy False cpos) (zip fullmnames elabMethTys))
+                             constraint
+             logElab 3 $ "Constraint constructor type: " ++ showTmImpls cty
 
+             let cons = [(cd, pDocs ++ mapMaybe memberDocs ds, cn, NoFC, cty, fc, [])]
+             let ddecl = PDatadecl tn NoFC tty cons
+
+             logElab 10 $ "Interface " ++ show (showDImp verbosePPOption ddecl)
+
+
+             -- Elaborate the data declaration
+             elabData info (syn { no_imp = no_imp syn ++ mnames,
+                                  imp_methods = [] }) doc pDocs fc [] ddecl
+
+
+             logElab 5 $ "Function types " ++ show fnTyDecls
+             logElab 5 $ "Method types now: " ++ show imethods
+
+             -- Elaborate the the top level constraint chasers
+             -- (Types elaborated earlier)
+             mapM_ (rec_elabDecl info EAll info) cfnDefs
+             -- Elaborate the the top level method bodies
+             mapM_ (rec_elabDecl info EAll info) fnDefs
+
+             -- Flag all the top level data declarations as injective
+             mapM_ (\n -> do setInjectivity n True
+                             addIBC (IBCInjective n True))
+                   (map fst (filter (\(_, (inj, _, _, _, _)) -> inj) imethods))
+
+             -- add the default definitions
+             mapM_ (rec_elabDecl info EAll info) (concatMap (snd.snd) defs)
+             addIBC (IBCInterface tn)
+
+             sendHighlighting $
+               [(tnfc, AnnName tn Nothing Nothing Nothing)] ++
+               [(pnfc, AnnBoundName pn False) | (pn, pnfc, _) <- ps] ++
+               [(fdfc, AnnBoundName fc False) | (fc, fdfc) <- fds] ++
+               maybe [] (\(conN, conNFC) -> [(conNFC, AnnName conN Nothing Nothing Nothing)]) mcn
+
   where
+    info = info_in { noCaseLift = tn : noCaseLift info_in }
+
+    getElabMethTy :: Name -> Idris PTerm
+    getElabMethTy n = do ist <- getIState
+                         let impls = case lookupCtxtExact n (idris_implicits ist) of
+                                          Just i -> i
+                                          Nothing -> []
+                         case lookupTyExact n (tt_ctxt ist) of
+                              Just ty -> return (delabTy' ist impls ty False False False)
+                              Nothing -> tclift $ tfail (At fc (InternalMsg "Can't happen, elabMethTy"))
+
+    -- Find the argument position of the current interface in a method type
+    -- (we'll use this to update the elaborated top level method types before
+    -- building a data declaration
+    findConstraint :: PTerm -> Int
+    findConstraint = findPos 0
+      where
+        findPos i (PPi _ _ _ (PRef _ _ n) sc)
+            | n == tn = i
+        findPos i (PPi _ _ _ (PApp _ (PRef _ _ n) _) sc)
+            | n == tn = i
+        findPos i (PPi _ _ _ ty sc) = findPos (i + 1) sc
+        findPos i _ = -1 -- Can't happen!
+
+    -- Make the method component of the constructor type by taking the
+    -- elaborated top level method and removing the implicits/constraint
+    mkMethTy :: Bool -> [(Name, Int)] -> (Name, PTerm) -> (Name, PTerm)
+    mkMethTy keepns cpos (n, tm)
+        = (if keepns then n else nsroot n, dropPis num (mapPT dropImp tm))
+      where
+        num = case lookup n cpos of
+                   Just i -> i + 1
+                   Nothing -> 0
+
+        dropPis n (PPi _ _ _ _ sc) | n > 0 = dropPis (n - 1) sc
+        dropPis _ tm = tm
+
+        dropImp (PApp fc (PRef fcr fcs n) args)
+            | Just pos <- lookup n cpos
+                 = PApp fc (PRef fcr fcs (nsroot n))
+                           (filter notConstr (drop (pos + 1) args))
+        dropImp (PApp fc f args)
+                 = PApp fc f (filter notConstr args)
+        dropImp tm = tm
+
+        notConstr (PConstraint {}) = False
+        notConstr _ = True
+
     nodoc (n, (inj, _, _, o, t)) = (n, (inj, o, t))
 
     pibind [] x = x
@@ -205,12 +295,15 @@
     getMName (PTy _ _ _ _ _ n nfc _) = nsroot n
     getMName (PData _ _ _ _ _ (PLaterdecl n nfc _)) = nsroot n
 
+    getFullMName (PTy _ _ _ _ _ n nfc _) = n
+    getFullMName (PData _ _ _ _ _ (PLaterdecl n nfc _)) = n
+
     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'
+                logElab 1 $ "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'))),
+                                              (\ l s p r -> Imp l s p Nothing True r) t'))),
                          (n, (nfc, syn, o, t) ) )
     tdecl impps allmeths (PData doc _ syn _ _ (PLaterdecl n nfc t))
            = do let o = []
@@ -218,7 +311,7 @@
                 logElab 2 $ "Data method " ++ show n ++ " : " ++ showTmImpls t'
                 return ( (n, (toExp (map (\(pn, _, _) -> pn) ps) Exp t')),
                          (n, (True, nfc, doc, o, (toExp (map (\(pn, _, _) -> pn) ps)
-                                              (\ l s p -> Imp l s p Nothing True) t'))),
+                                              (\ l s p r -> Imp l s p Nothing True r) t'))),
                          (n, (nfc, syn, o, t) ) )
     tdecl impps allmeths (PData doc _ syn _ _ _)
          = ierror $ At fc (Msg "Data definitions not allowed in an interface declaration")
@@ -249,7 +342,7 @@
     clause _ = False
 
     -- Generate a function for chasing a dictionary constraint
-    cfun :: Name -> PTerm -> SyntaxInfo -> [a] -> (Name, PTerm) -> Idris [PDecl' PTerm]
+    cfun :: Name -> PTerm -> SyntaxInfo -> [a] -> (Name, PTerm) -> Idris (PDecl, PDecl)
     cfun cn c syn all (cnm, con)
         = do let cfn = SN (ParentN cn (txt (show con)))
              let mnames = take (length all) $ map (\x -> sMN x "meth") [0..]
@@ -269,8 +362,8 @@
              addImplementation False True conn' cfn
              addIBC (IBCImplementation False True conn' cfn)
 --              iputStrLn ("Added " ++ show (conn, cfn, ty))
-             return [PTy emptyDocstring [] syn fc [] cfn NoFC ty,
-                     PClauses fc [Inlinable, Dictionary] cfn [PClause fc cfn lhs [] rhs []]]
+             return (PTy emptyDocstring [] syn fc [] cfn NoFC ty,
+                     PClauses fc [Inlinable, Dictionary] cfn [PClause fc cfn lhs [] rhs []])
 
     -- | Generate a top level function which looks up a method in a given
     -- dictionary (this is inlinable, always)
@@ -279,7 +372,7 @@
          -> SyntaxInfo -> [Name] -- ^ All the method names
          -> (Name, (Bool, FC, Docstring (Either Err PTerm), FnOpts, PTerm))
             -- ^ The present declaration
-         -> Idris [PDecl]
+         -> Idris (PDecl, PDecl)
     tfun cn c syn all (m, (isdata, mfc, doc, o, ty))
         = do let ty' = expandMethNS syn (insertConstraint c all ty)
              let mnames = take (length all) $ map (\x -> sMN x "meth") [0..]
@@ -291,12 +384,19 @@
              logElab 2 ("Top level type: " ++ showTmImpls ty')
              logElab 1 (show (m, ty', capp, margs))
              logElab 2 ("Definition: " ++ showTmImpls lhs ++ " = " ++ showTmImpls rhs)
-             return [PTy doc [] syn fc o m mfc ty',
-                     PClauses fc [Inlinable] m [PClause fc m lhs [] rhs []]]
+             return (PTy doc [] syn fc o m mfc ty',
+                     PClauses fc [Inlinable] m [PClause fc m lhs [] rhs []])
 
-    getMArgs (PPi (Imp _ _ _ _ _) n _ ty sc) = IA n : getMArgs sc
-    getMArgs (PPi (Exp _ _ _) n _ ty sc) = EA n : getMArgs sc
-    getMArgs (PPi (Constraint _ _) n _ ty sc) = CA : getMArgs sc
+    updateIMethod :: [(Name, PTerm)] ->
+                     (Name, (a, b, c, d, PTerm)) ->
+                     (Name, (a, b, c, d, PTerm))
+    updateIMethod ns tm@(n, (isf, mfc, doc, o, ty))
+       | Just ty' <- lookup (nsroot n) ns = (n, (isf, mfc, doc, o, ty'))
+       | otherwise = tm
+
+    getMArgs (PPi (Imp _ _ _ _ _ _) n _ ty sc) = IA n : getMArgs sc
+    getMArgs (PPi (Exp _ _ _ _) n _ ty sc) = EA n : getMArgs sc
+    getMArgs (PPi (Constraint _ _ _) n _ ty sc) = CA : getMArgs sc
     getMArgs _ = []
 
     getMeth :: [Name] -> [Name] -> Name -> PTerm
@@ -337,9 +437,9 @@
        addC _ _ tm = tm
 
     -- make arguments explicit and don't bind interface parameters
-    toExp ns e (PPi (Imp l s p _ _) n fc ty sc)
+    toExp ns e (PPi (Imp l s p _ _ r) n fc ty sc)
         | n `elem` ns = toExp ns e sc
-        | otherwise = PPi (e l s p) n fc ty (toExp ns e sc)
+        | otherwise = PPi (e l s p r) n fc ty (toExp ns e sc)
     toExp ns e (PPi p n fc ty sc) = PPi p n fc ty (toExp ns e sc)
     toExp ns e sc = sc
 
@@ -376,7 +476,7 @@
             Just ty -> getDetPos 0 ns ty
             Nothing -> []
   where
-    getDetPos i ns (Bind n (Pi _ _ _) sc)
+    getDetPos i ns (Bind n (Pi _ _ _ _) sc)
        | n `elem` ns = i : getDetPos (i + 1) ns sc
        | otherwise = getDetPos (i + 1) ns sc
     getDetPos _ _ _ = []
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
@@ -460,10 +460,10 @@
 
 -- | Creates a PArg with a given plicity, name, and term.
 asArg :: Plicity -> Name -> PTerm -> PArg
-asArg (Imp os _ _ _ _) n t = PImp 0 False os n t
-asArg (Exp os _ _) n t = PExp 0 os n t
-asArg (Constraint os _) n t = PConstraint 0 os n t
-asArg (TacImp os _ s) n t = PTacImplicit 0 os n s t
+asArg (Imp os _ _ _ _ _) n t = PImp 0 False os n t
+asArg (Exp os _ _ _) n t = PExp 0 os n t
+asArg (Constraint os _ _) n t = PConstraint 0 os n t
+asArg (TacImp os _ s _) n t = PTacImplicit 0 os n s t
 
 -- | Machine name "rec".
 recName :: Name
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
@@ -77,7 +77,7 @@
                         let pred = PLam fc rname fc Placeholder
                                         (delab ist pred_tt)
                         let rewrite = stripImpls $
-                                        addImplBound ist (map fst env) (PApp fc (PRef fc [] substfn)
+                                        addImplBound ist (map fstEnv env) (PApp fc (PRef fc [] substfn)
                                               [pexp pred, pexp rule, pexp sc])
 --                         trace ("LHS: " ++ show l ++ "\n" ++
 --                                "RHS: " ++ show r ++ "\n" ++
@@ -156,10 +156,10 @@
 
 getParamInfo :: Type -> [PArg] -> Int -> [Int] -> [ParamInfo]
 -- Skip the top level implicits, we just need the explicit ones
-getParamInfo (Bind n (Pi _ _ _) sc) (PExp{} : is) i ps
+getParamInfo (Bind n (Pi _ _ _ _) sc) (PExp{} : is) i ps
     | i `elem` ps = Param : getParamInfo sc is (i + 1) ps
     | otherwise = Index : getParamInfo sc is (i + 1) ps
-getParamInfo (Bind n (Pi _ _ _) sc) (_ : is) i ps
+getParamInfo (Bind n (Pi _ _ _ _) sc) (_ : is) i ps
     | i `elem` ps = ImplicitParam : getParamInfo sc is (i + 1) ps
     | otherwise = ImplicitIndex : getParamInfo sc is (i + 1) ps
 getParamInfo _ _ _ _ = []
@@ -249,13 +249,13 @@
     mkArgs _ _ _ = []
 
     bindIdxs ist [] ty is tm = tm
-    bindIdxs ist (Param : pinfo) (Bind n (Pi _ ty _) sc) is tm
+    bindIdxs ist (Param : pinfo) (Bind n (Pi _ _ ty _) sc) is tm
          = bindIdxs ist pinfo (instantiate (P Bound n ty) sc) is tm
-    bindIdxs ist (Index : pinfo) (Bind n (Pi _ ty _) sc) (i : is) tm
+    bindIdxs ist (Index : pinfo) (Bind n (Pi _ _ ty _) sc) (i : is) tm
         = PPi forall_imp i fc (delab ist ty)
                (bindIdxs ist pinfo (instantiate (P Bound n ty) sc) is tm)
-    bindIdxs ist (ImplicitParam : pinfo) (Bind n (Pi _ ty _) sc) is tm
+    bindIdxs ist (ImplicitParam : pinfo) (Bind n (Pi _ _ ty _) sc) is tm
         = bindIdxs ist pinfo (instantiate (P Bound n ty) sc) is tm
-    bindIdxs ist (ImplicitIndex : pinfo) (Bind n (Pi _ ty _) sc) (i : is) tm
+    bindIdxs ist (ImplicitIndex : pinfo) (Bind n (Pi _ _ ty _) sc) (i : is) tm
         = bindIdxs ist pinfo (instantiate (P Bound n ty) sc) is tm
     bindIdxs _ _ _ _ tm = tm
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
@@ -18,7 +18,7 @@
 import Idris.Core.TT
 import Idris.Core.Typecheck (check, converts, isType, recheck)
 import Idris.Core.Unify
-import Idris.Core.WHNF (whnf,whnfArgs)
+import Idris.Core.WHNF (whnf, whnfArgs)
 import Idris.Coverage (genClauses, recoverableCoverage, validCoverageCase)
 import Idris.Delaborate
 import Idris.DSL
@@ -30,7 +30,7 @@
 import Idris.Output (pshow)
 import Idris.ProofSearch
 import Idris.Reflection
-import Idris.Termination(buildSCG, checkDeclTotality, checkPositive)
+import Idris.Termination (buildSCG, checkDeclTotality, checkPositive)
 
 import qualified Util.Pretty as U
 
@@ -201,7 +201,7 @@
           Nothing -> []
           Just ty -> checkArgs [] [] ty
   where checkArgs :: [Name] -> [[Name]] -> Type -> [Bool]
-        checkArgs env ns (Bind n (Pi _ t _) sc)
+        checkArgs env ns (Bind n (Pi _ _ t _) sc)
             = let env' = case t of
                               TType _ -> n : env
                               _ -> env in
@@ -227,7 +227,7 @@
    do ty <- goal
       case ty of
            P _ n _ -> do env <- get_env
-                         case lookup n env of
+                         case lookupBinder n env of
                               Nothing -> return False
                               _ -> return True
            _ -> return False
@@ -245,19 +245,24 @@
 elab ist info emode opts fn tm
     = do let loglvl = opt_logLevel (idris_options ist)
          when (loglvl > 5) $ unifyLog True
-         whnf_compute_args -- expand type synonyms, etc
+         compute -- expand type synonyms, etc
          let fc = maybe "(unknown)"
          elabE initElabCtxt (elabFC info) tm -- (in argument, guarded, in type, in qquote)
          est <- getAux
          sequence_ (get_delayed_elab est)
          end_unify
+         when (pattern || intransform) $
+              -- convert remaining holes to pattern vars
+              do unify_all
+                 matchProblems False -- only the ones we matched earlier
+                 unifyProblems
+                 mkPat
+                 update_term liftPats
          ptm <- get_term
-         when (pattern || intransform) -- convert remaining holes to pattern vars
-              (do unify_all
-                  matchProblems False -- only the ones we matched earlier
-                  unifyProblems
-                  mkPat
-                  update_term liftPats)
+         when pattern $
+              -- Look for Rig1 (linear) pattern bindings
+              do let pnms = findLinear ist [] ptm
+                 update_term (setLinear pnms)
   where
     pattern = emode == ELHS || emode == EImpossible
     eimpossible = emode == EImpossible
@@ -295,7 +300,7 @@
 
     -- | elabE elaborates an expression, possibly wrapping implicit coercions
     -- and forces/delays.  If you make a recursive call in elab', it is
-    -- normally correct to call elabE - the ones that don't are desugarings
+    -- normally correct to call elabE - the ones that don't are `desugarings
     -- typically
     elabE :: ElabCtxt -> Maybe FC -> PTerm -> ElabD ()
     elabE ina fc' t =
@@ -334,13 +339,13 @@
                               pexp ct]))
 
     forceErr orig env (CantUnify _ (t,_) (t',_) _ _ _)
-       | (P _ (UN ht) _, _) <- unApply (whnf (tt_ctxt ist) env t),
+       | (P _ (UN ht) _, _) <- unApply (normalise (tt_ctxt ist) env t),
             ht == txt "Delayed" = notDelay orig
     forceErr orig env (CantUnify _ (t,_) (t',_) _ _ _)
-       | (P _ (UN ht) _, _) <- unApply (whnf (tt_ctxt ist) env t'),
+       | (P _ (UN ht) _, _) <- unApply (normalise (tt_ctxt ist) env t'),
             ht == txt "Delayed" = notDelay orig
     forceErr orig env (InfiniteUnify _ t _)
-       | (P _ (UN ht) _, _) <- unApply (whnf (tt_ctxt ist) env t),
+       | (P _ (UN ht) _, _) <- unApply (normalise (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
@@ -351,7 +356,7 @@
     notDelay _ = True
 
     local f = do e <- get_env
-                 return (f `elem` map fst e)
+                 return (f `elem` map fstEnv e)
 
     -- | Is a constant a type?
     constType :: Const -> Bool
@@ -372,7 +377,10 @@
          solve
          highlightSource fc' (AnnType "Type" "The type of types")
     elab' ina fc (PUniverse fc' u)   =
-      do apply (RUType u) []
+      do unless (UniquenessTypes `elem` idris_language_extensions ist
+                  || e_qq ina) $
+           lift $ tfail $ At fc' (Msg "You must turn on the UniquenessTypes extension to use UniqueType or AnyType")
+         apply (RUType u) []
          solve
          highlightSource fc' (AnnType (show u) "The type of unique types")
 --  elab' (_,_,inty) (PConstant c)
@@ -389,7 +397,7 @@
                           highlightSource fc' (AnnConst c)
     elab' ina fc (PQuote r)     = do fill r; solve
     elab' ina _ (PTrue fc _)   =
-       do whnf_compute
+       do compute
           g <- goal
           case g of
             TType _ -> elab' ina (Just fc) (PRef fc [] unitTy)
@@ -423,7 +431,7 @@
                     pexp l, pexp r]))
 
     elab' ina _ (PPair fc hls _ l r)
-        = do whnf_compute
+        = do compute
              g <- goal
              let (tc, _) = unApply g
              case g of
@@ -446,7 +454,7 @@
                 IsType -> asType
                 IsTerm -> asValue
                 TypeOrTerm ->
-                   do whnf_compute
+                   do compute
                       g <- goal
                       case g of
                          TType _ -> asType
@@ -536,7 +544,7 @@
                          (trySeq' deferr xs) True
     elab' ina fc (PAlternative ms TryImplicit (orig : alts)) = do
         env <- get_env
-        whnf_compute
+        compute
         ty <- goal
         let doelab = elab' ina fc orig
         tryCatch doelab
@@ -568,7 +576,7 @@
         recoverableErr _ = True
 
         pruneAlts (CantUnify _ (inc, _) (outc, _) _ _ _) alts env
-            = case unApply (whnf (tt_ctxt ist) env inc) of
+            = case unApply (normalise (tt_ctxt ist) env inc) of
                    (P (TCon _ _) n _, _) -> filter (hasArg n env) alts
                    (Constant _, _) -> alts
                    _ -> filter isLend alts -- special case hack for 'Borrowed'
@@ -660,7 +668,7 @@
                do fty <- get_type (Var n) -- check for implicits
                   ctxt <- get_context
                   env <- get_env
-                  let a' = insertScopedImps fc (whnfArgs ctxt env fty) []
+                  let a' = insertScopedImps fc (normalise ctxt env fty) []
                   if null a'
                      then erun fc $
                             do apply (Var n) []
@@ -702,19 +710,30 @@
                solve
                highlightSource nfc (AnnBoundName n False)
     elab' ina fc (PPi p n nfc Placeholder sc)
-          = do attack; arg n (is_scoped p) (sMN 0 "ty")
+          = do attack;
+               case pcount p of
+                    RigW -> return ()
+                    _ -> unless (LinearTypes `elem` idris_language_extensions ist
+                                       || e_qq ina) $
+                           lift $ tfail $ At nfc (Msg "You must turn on the LinearTypes extension to use a count")
+               arg n (pcount p) (is_scoped p) (sMN 0 "phTy")
                addAutoBind p n
                addPSname n -- okay for proof search
                elabE (ina { e_inarg = True, e_intype = True }) fc sc
                solve
                highlightSource nfc (AnnBoundName n False)
     elab' ina fc (PPi p n nfc ty sc)
-          = do attack; tyn <- getNameFrom (sMN 0 "ty")
+          = do attack; tyn <- getNameFrom (sMN 0 "piTy")
                claim tyn RType
                n' <- case n of
                         MN _ _ -> unique_hole n
                         _ -> return n
-               forall n' (is_scoped p) (Var tyn)
+               case pcount p of
+                    RigW -> return ()
+                    _ -> unless (LinearTypes `elem` idris_language_extensions ist
+                                       || e_qq ina) $
+                           lift $ tfail $ At nfc (Msg "You must turn on the LinearTypes extension to use a linear argument")
+               forall n' (pcount p) (is_scoped p) (Var tyn)
                addAutoBind p n'
                addPSname n' -- okay for proof search
                focus tyn
@@ -757,7 +776,7 @@
                          (ivs' \\ ivs)
                -- HACK: If the name leaks into its type, it may leak out of
                -- scope outside, so substitute in the outer scope.
-               expandLet n (case lookup n env of
+               expandLet n (case lookupBinder n env of
                                  Just (Let t v) -> v
                                  other -> error ("Value not a let binding: " ++ show other))
                solve
@@ -807,10 +826,10 @@
                                        ans <- claimArgTys env xs
                                        return ((aval, (True, (Var an))) : ans)
              fnTy [] ret  = forget ret
-             fnTy ((x, (_, xt)) : xs) ret = RBind x (Pi Nothing xt RType) (fnTy xs ret)
+             fnTy ((x, (_, xt)) : xs) ret = RBind x (Pi RigW Nothing xt RType) (fnTy xs ret)
 
              localVar env (PRef _ _ x)
-                           = case lookup x env of
+                           = case lookupBinder x env of
                                   Just _ -> Just x
                                   _ -> Nothing
              localVar env _ = Nothing
@@ -844,7 +863,7 @@
             let dataCon = isDConName f ctxt
             annot <- findHighlight f
             mapM_ checkKnownImplicit args_in
-            let args = insertScopedImps fc (whnfArgs ctxt env fty) args_in
+            let args = insertScopedImps fc (normalise ctxt env fty) args_in
             let unmatchableArgs = if pattern
                                      then getUnmatchable (tt_ctxt ist) f
                                      else []
@@ -853,7 +872,7 @@
                           && isTConName f (tt_ctxt ist)) $
               lift $ tfail $ Msg ("No explicit types on left hand side: " ++ show tm)
 --             trace (show (f, args_in, args)) $
-            if (f `elem` map fst env && length args == 1 && length args_in == 1)
+            if (f `elem` map fstEnv env && length args == 1 && length args_in == 1)
                then -- simple app, as below
                     do simple_app False
                                   (elabE (ina { e_isfn = True }) (Just fc) (PRef ffc hls f))
@@ -901,12 +920,12 @@
                     imp <- if (e_isfn ina) then
                               do guess <- get_guess
                                  env <- get_env
-                                 case safeForgetEnv (map fst env) guess of
+                                 case safeForgetEnv (map fstEnv env) guess of
                                       Nothing ->
                                          return []
                                       Just rguess -> do
                                          gty <- get_type rguess
-                                         let ty_n = whnf ctxt env gty
+                                         let ty_n = normalise ctxt env gty
                                          return $ getReqImps ty_n
                               else return []
                     -- Now we find out how many implicits we needed at the
@@ -954,16 +973,16 @@
                     = lift $ tfail $ UnknownImplicit (pname imp) f
             checkKnownImplicit _ = return ()
 
-            getReqImps (Bind x (Pi (Just i) ty _) sc)
+            getReqImps (Bind x (Pi _ (Just i) ty _) sc)
                  = i : getReqImps sc
             getReqImps _ = []
 
             checkIfInjective n = do
                 env <- get_env
-                case lookup n env of
+                case lookupBinder n env of
                      Nothing -> return ()
                      Just b ->
-                       case unApply (whnf (tt_ctxt ist) env (binderTy b)) of
+                       case unApply (normalise (tt_ctxt ist) env (binderTy b)) of
                             (P _ c _, args) ->
                                 case lookupCtxtExact c (idris_interfaces ist) of
                                    Nothing -> return ()
@@ -1036,6 +1055,9 @@
     elab' ina fc (PElabError e) = lift $ tfail e
     elab' ina mfc (PRewrite fc substfn rule sc newg)
         = elabRewrite (elab' ina mfc) ist fc substfn rule sc newg
+    -- A common error case if trying to typecheck an autogenerated case block
+    elab' ina _ c@(PCase fc Placeholder opts)
+        = lift $ tfail (Msg "No expression for the case to inspect.\nYou need to replace the _ with an expression.")
     elab' ina _ c@(PCase fc scr opts)
         = do attack
 
@@ -1073,13 +1095,13 @@
              -- unnecessarily (can only do this for unique things, since we
              -- assume they don't appear implicitly in types)
              ptm <- get_term
-             let inOpts = (filter (/= scvn) (map fst args)) \\ (concatMap (\x -> allNamesIn (snd x)) opts)
+             let inOpts = (filter (/= scvn) (map fstEnv args)) \\ (concatMap (\x -> allNamesIn (snd x)) opts)
 
-             let argsDropped = filter (isUnique envU)
+             let argsDropped = filter (\t -> isUnique envU t || isNotLift args t)
                                    (nub $ allNamesIn scr ++ inApp ptm ++
                                     inOpts)
 
-             let args' = filter (\(n, _) -> n `notElem` argsDropped) args
+             let args' = filter (\(n, _, _) -> n `notElem` argsDropped) args
 
              attack
              cname' <- defer argsDropped (mkN (mkCaseName fc fn))
@@ -1130,8 +1152,8 @@
                                      Just u -> u
                                      _ -> False
 
-              getKind env (n, _)
-                  = case lookup n env of
+              getKind env (n, _, _)
+                  = case lookupBinder n env of
                          Nothing -> return (n, False) -- can't happen, actually...
                          Just b ->
                             do ty <- get_type (forget (binderTy b))
@@ -1146,6 +1168,14 @@
                          _ -> False
               tcName _ = False
 
+              isNotLift env n
+                 = case lookupBinder n env of
+                        Just ty ->
+                             case unApply (binderTy ty) of
+                                  (P _ n _, _) -> n `elem` noCaseLift info
+                                  _ -> False
+                        _ -> False
+
               usedIn ns (n, b)
                  = n `elem` ns
                      || any (\x -> x `elem` ns) (allTTNames (binderTy b))
@@ -1214,13 +1244,13 @@
              loadState
              updateAux (\aux -> aux { highlighting = hs })
 
-             let quoted = fmap (explicitNames . binderVal) $ lookup nTm env
+             let quoted = fmap (explicitNames . binderVal) $ lookupBinder nTm env
                  isRaw = case unApply (normaliseAll ctxt env finalTy) of
                            (P _ n _, []) | n == reflm "Raw" -> True
                            _ -> False
              case quoted of
                Just q -> do ctxt <- get_context
-                            (q', _, _) <- lift $ recheck (constraintNS info) ctxt [(uq, Lam Erased) | uq <- unquoteNames] (forget q) q
+                            (q', _, _) <- lift $ recheck (constraintNS info) ctxt [(uq, RigW, Lam RigW Erased) | uq <- unquoteNames] (forget q) q
                             if pattern
                               then if isRaw
                                       then reflectRawQuotePattern unquoteNames (forget q')
@@ -1249,7 +1279,7 @@
     elab' ina fc (PQuoteName n True nfc) =
       do ctxt <- get_context
          env <- get_env
-         case lookup n env of
+         case lookupBinder n env of
            Just _ -> do fill $ reflectName n
                         solve
                         highlightSource nfc (AnnBoundName n False)
@@ -1278,7 +1308,9 @@
                                    dotterm
                                    elab' ina fc t
     elab' ina fc (PRunElab fc' tm ns) =
-      do attack
+      do unless (ElabReflection `elem` idris_language_extensions ist) $
+           lift $ tfail $ At fc' (Msg "You must turn on the ElabReflection extension to use %runElab")
+         attack
          n <- getNameFrom (sMN 0 "tacticScript")
          let scriptTy = RApp (Var (sNS (sUN "Elab")
                                   ["Elab", "Reflection", "Language"]))
@@ -1316,7 +1348,7 @@
          env <- get_env
          ctxt <- get_context
          let v = fmap (normaliseAll ctxt env . finalise . binderVal)
-                      (lookup n env)
+                      (lookupBinder n env)
          loadState -- we have the highlighting - re-elaborate the value
          elab' ina fc tm
          case v of
@@ -1339,9 +1371,9 @@
     delayElab pri t
        = updateAux (\e -> e { delayed_elab = delayed_elab e ++ [(pri, t)] })
 
-    isScr :: PTerm -> (Name, Binder Term) -> (Name, (Bool, Binder Term))
-    isScr (PRef _ _ n) (n', b) = (n', (n == n', b))
-    isScr _ (n', b) = (n', (False, b))
+    isScr :: PTerm -> (Name, RigCount, Binder Term) -> (Name, (Bool, Binder Term))
+    isScr (PRef _ _ n) (n', _, b) = (n', (n == n', b))
+    isScr _ (n', _, b) = (n', (False, b))
 
     caseBlock :: FC -> Name
                  -> PTerm -- original scrutinee
@@ -1441,8 +1473,8 @@
         mkDelay env (PAlternative ms b xs) = PAlternative ms b (map (mkDelay env) xs)
         mkDelay env t
             = let fc = fileFC "Delay" in
-                  addImplBound ist (map fst env) (PApp fc (PRef fc [] (sUN "Delay"))
-                                                 [pexp t])
+                  addImplBound ist (map fstEnv env) (PApp fc (PRef fc [] (sUN "Delay"))
+                                                    [pexp t])
 
 
     -- Don't put implicit coercions around applications which are marked
@@ -1467,7 +1499,7 @@
        case fullApp tm of
             -- if f is global, leave it alone because we've already
             -- expanded it to the right arity
-            PApp fc ftm@(PRef _ _ f) args | Just aty <- lookup f env ->
+            PApp fc ftm@(PRef _ _ f) args | Just aty <- lookupBinder f env ->
                do let a = length (getArgTys (normalise (tt_ctxt ist) env (binderTy aty)))
                   return (mkPApp fc a ftm args)
             _ -> return tm
@@ -1476,12 +1508,12 @@
     fullApp (PApp _ (PApp fc f args) xs) = fullApp (PApp fc f (args ++ xs))
     fullApp x = x
 
-    insertScopedImps fc (Bind n (Pi im@(Just i) _ _) sc) xs
+    insertScopedImps fc (Bind n (Pi _ im@(Just i) _ _) sc) xs
       | tcimplementation i && not (toplevel_imp i)
           = pimp n (PResolveTC fc) True : insertScopedImps fc sc xs
       | not (toplevel_imp i)
           = pimp n Placeholder True : insertScopedImps fc sc xs
-    insertScopedImps fc (Bind n (Pi _ _ _) sc) (x : xs)
+    insertScopedImps fc (Bind n (Pi _ _ _ _) sc) (x : xs)
         = x : insertScopedImps fc sc xs
     insertScopedImps _ _ xs = xs
 
@@ -1492,7 +1524,7 @@
            addLam ty' t
       where
         -- just one level at a time
-        addLam (Bind n (Pi (Just _) _ _) sc) t =
+        addLam (Bind n (Pi _ (Just _) _ _) sc) t =
                  do impn <- unique_hole n -- (sMN 0 "scoped_imp")
                     if e_isfn ina -- apply to an implicit immediately
                        then return (PApp emptyFC
@@ -1520,7 +1552,7 @@
          mkCoerce env (PAlternative ms aty tms) n
              = PAlternative ms aty (map (\t -> mkCoerce env t n) tms)
          mkCoerce env t n = let fc = maybe (fileFC "Coercion") id (highestFC t) in
-                                addImplBound ist (map fst env)
+                                addImplBound ist (map fstEnv env)
                                   (PApp fc (PRef fc [] n) [pexp (PCoerced t)])
 
     -- | Elaborate the arguments to a function
@@ -1579,7 +1611,7 @@
       fail $ "Can't elaborate these args: " ++ show arg ++ " " ++ show hole
 
     addAutoBind :: Plicity -> Name -> ElabD ()
-    addAutoBind (Imp _ _ _ _ False) n
+    addAutoBind (Imp _ _ _ _ False _) n
          = updateAux (\est -> est { auto_binds = n : auto_binds est })
     addAutoBind _ _ = return ()
 
@@ -1639,7 +1671,7 @@
     locallyBound [] = Nothing
     locallyBound (t:ts)
        | Just n <- getName t,
-         n `elem` map fst env = Just t
+         n `elem` map fstEnv env = Just t
        | otherwise = locallyBound ts
     getName (PRef _ _ n) = Just n
     getName (PApp _ (PRef _ _ (UN l)) [_, _, arg]) -- ignore Delays
@@ -1681,7 +1713,7 @@
                Just ty -> case unApply (getRetTy ty) of
                             (P _ ctyn _, _) | isTConName ctyn ctxt && not (ctyn == f)
                                      -> False
-                            _ -> let ty' = whnf ctxt [] ty in
+                            _ -> let ty' = normalise 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
@@ -1730,7 +1762,7 @@
          | (P _ fl _, argsl) <- unApply apl,
            (P _ fr _, argsr) <- unApply apr,
            isConName fl ctxt && isConName fr ctxt
-       = fl == fr 
+       = fl == fr
     matchingHead _ _ = True
 
     -- Return whether there is a possible coercion between the return type
@@ -1774,7 +1806,7 @@
    where
      collectConstraints :: [Name] -> [(Term, [Name])] -> Type ->
                                      (Maybe Name, [(Term, [Name])])
-     collectConstraints env tcs (Bind n (Pi _ ty _) sc)
+     collectConstraints env tcs (Bind n (Pi _ _ ty _) sc)
          = let tcs' = case unApply ty of
                            (P _ c _, _) ->
                                case lookupCtxtExact c (idris_interfaces ist) of
@@ -1792,7 +1824,7 @@
 findHighlight :: Name -> ElabD OutputAnnotation
 findHighlight n = do ctxt <- get_context
                      env <- get_env
-                     case lookup n env of
+                     case lookupBinder n env of
                        Just _ -> return $ AnnBoundName n False
                        Nothing -> case lookupTyExact n ctxt of
                                     Just _ -> return $ AnnName n Nothing Nothing Nothing
@@ -1812,7 +1844,7 @@
                         when (not isg) $
                           proofSearch' ist True ambigok 100 True Nothing fn [] [])
              (lift $ Error (addLoc failc
-                   (CantSolveGoal g (map (\(n, b) -> (n, binderTy b)) env))))
+                   (CantSolveGoal g (map (\(n, _, b) -> (n, binderTy b)) env))))
         return ()
   where addLoc (FailContext fc f x : prev) err
            = At fc (ElaboratingArg f x
@@ -1885,7 +1917,7 @@
   focus valn
   elab ist toplevel ERHS [] (sMN 0 "tac") tm
   env <- get_env
-  let (Just binding) = lookup letn env
+  let (Just binding) = lookupBinder letn env
   let val = binderVal binding
   if ind then induction (forget val)
          else casetac (forget val)
@@ -1908,7 +1940,7 @@
     returnUnit = return $ P (DCon 0 0 False) unitCon (P (TCon 0 0) unitTy Erased)
 
     patvars :: [(Name, Term)] -> Term -> ([(Name, Term)], Term)
-    patvars ns (Bind n (PVar t) sc) = patvars ((n, t) : ns) (instantiate (P Bound n t) sc)
+    patvars ns (Bind n (PVar _ t) sc) = patvars ((n, t) : ns) (instantiate (P Bound n t) sc)
     patvars ns tm                   = (ns, tm)
 
     pullVars :: (Term, Term) -> ([(Name, Term)], Term, Term)
@@ -1977,7 +2009,7 @@
 
     -- | Add another argument to a Pi
     mkPi :: RFunArg -> Raw -> Raw
-    mkPi arg rTy = RBind (argName arg) (Pi Nothing (argTy arg) (RUType AllTypes)) rTy
+    mkPi arg rTy = RBind (argName arg) (Pi RigW Nothing (argTy arg) (RUType AllTypes)) rTy
 
     mustBeType ctxt tm ty =
       case normaliseAll ctxt [] (finalise ty) of
@@ -2034,7 +2066,7 @@
                       _ -> n
 
         getRetTy :: Type -> Type
-        getRetTy (Bind _ (Pi _ _ _) sc) = getRetTy sc
+        getRetTy (Bind _ (Pi _ _ _ _) sc) = getRetTy sc
         getRetTy ty = ty
 
     elabScriptStuck :: Term -> ElabD a
@@ -2242,7 +2274,7 @@
       = do ~[n, ty] <- tacTmArgs 2 tac args
            n' <- reifyTTName n
            ty' <- reifyRaw ty
-           forall n' Nothing ty'
+           forall n' RigW Nothing ty'
            returnUnit
       | n == tacN "Prim__PatVar"
       = do ~[n] <- tacTmArgs 1 tac args
@@ -2252,7 +2284,7 @@
       | n == tacN "Prim__PatBind"
       = do ~[n] <- tacTmArgs 1 tac args
            n' <- reifyTTName n
-           patbind n'
+           patbind n' RigW
            returnUnit
       | n == tacN "Prim__LetBind"
       = do ~[n, ty, tm] <- tacTmArgs 3 tac args
@@ -2448,11 +2480,11 @@
 runTac autoSolve ist perhapsFC fn tac
     = do env <- get_env
          g <- goal
-         let tac' = fmap (addImplBound ist (map fst env)) tac
+         let tac' = fmap (addImplBound ist (map fstEnv env)) tac
          if autoSolve
             then runT tac'
             else no_errors (runT tac')
-                   (Just (CantSolveGoal g (map (\(n, b) -> (n, binderTy b)) env)))
+                   (Just (CantSolveGoal g (map (\(n, _, b) -> (n, binderTy b)) env)))
   where
     runT (Intro []) = do g <- goal
                          attack; intro (bname g)
@@ -2482,7 +2514,7 @@
              tryAll tacs
              when autoSolve solveAll
        where envArgs n = do e <- get_env
-                            case lookup n e of
+                            case lookupBinder n e of
                                Just t -> return $ map (const False)
                                                       (getArgTys (binderTy t))
                                _ -> return []
@@ -2500,7 +2532,7 @@
        where isImp (PImp _ _ _ _ _) = True
              isImp _ = False
              envArgs n = do e <- get_env
-                            case lookup n e of
+                            case lookupBinder n e of
                                Just t -> return $ map (const False)
                                                       (getArgTys (binderTy t))
                                _ -> return []
@@ -2609,9 +2641,9 @@
         where tacticTy = Var (reflm "Tactic")
               listTy = Var (sNS (sUN "List") ["List", "Prelude"])
               scriptTy = (RBind (sMN 0 "__pi_arg")
-                                (Pi Nothing (RApp listTy envTupleType) RType)
+                                (Pi RigW Nothing (RApp listTy envTupleType) RType)
                                     (RBind (sMN 1 "__pi_arg")
-                                           (Pi Nothing (Var $ reflm "TT") RType) tacticTy))
+                                           (Pi RigW Nothing (Var $ reflm "TT") RType) tacticTy))
     runT (ByReflection tm) -- run the reflection function 'tm' on the
                            -- goal, then apply the resulting reflected Tactic
         = do tgoal <- goal
@@ -2807,7 +2839,7 @@
          mapM_ (addIBC . IBCDef . cn) ctors
          ctxt <- getContext
          let params = findParams tyn (normalise ctxt [] tyconTy) (map cty ctors)
-         let typeInfo = TI (map cn ctors) False [] params []
+         let typeInfo = TI (map cn ctors) False [] params [] False
          -- implicit precondition to IBCData is that idris_datatypes on the IState is populated.
          -- otherwise writing the IBC just fails silently!
          updateIState $ \i -> i { idris_datatypes =
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
@@ -114,11 +114,11 @@
          return (clhs_tm, crhs_tm)
 
   where
-    depat (Bind n (PVar t) sc) = depat (instantiate (P Bound n t) sc)
+    depat (Bind n (PVar _ t) sc) = depat (instantiate (P Bound n t) sc)
     depat x = x
 
-    renamepats (n' : ns) (Bind n (PVar t) sc)
-       = Bind n' (PVar t) (renamepats ns sc) -- all Vs
+    renamepats (n' : ns) (Bind n (PVar rig t) sc)
+       = Bind n' (PVar rig t) (renamepats ns sc) -- all Vs
     renamepats _ sc = sc
 
     -- names for transformation variables. Need to ensure these don't clash
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
@@ -19,6 +19,7 @@
 import Idris.Core.Execute
 import Idris.Core.TT
 import Idris.Core.Typecheck
+import Idris.Core.WHNF
 import Idris.Coverage
 import Idris.DataOpts
 import Idris.DeepSeq
@@ -133,13 +134,17 @@
              setFnInfo n fninfo
              addIBC (IBCFnInfo n fninfo)
 
+         -- If we use any types with linear constructor arguments, we'd better
+         -- make sure they are use-once
+         tcliftAt fc $ linearCheck ctxt (whnfArgs ctxt [] cty)
+
          return (cty, ckind, ty, inacc)
   where
-    patToImp (Bind n (PVar t) sc) = Bind n (Pi Nothing t (TType (UVar [] 0))) (patToImp sc)
+    patToImp (Bind n (PVar rig t) sc) = Bind n (Pi rig Nothing t (TType (UVar [] 0))) (patToImp sc)
     patToImp (Bind n b sc) = Bind n b (patToImp sc)
     patToImp t = t
 
-    param_pos i ns (Bind n (Pi _ t _) sc)
+    param_pos i ns (Bind n (Pi _ _ t _) sc)
         | n `elem` ns = i : param_pos (i + 1) ns sc
         | otherwise = param_pos (i + 1) ns sc
     param_pos i ns t = []
@@ -192,7 +197,7 @@
          let (fam, _) = unApply (getRetTy nty')
          let corec = case fam of
                         P _ rcty _ -> case lookupCtxt rcty (idris_datatypes i) of
-                                        [TI _ True _ _ _] -> True
+                                        [TI _ True _ _ _ _] -> True
                                         _ -> False
                         _ -> False
          -- Productivity checking now via checking for guarded 'Delay'
@@ -260,7 +265,7 @@
     lst = txt "List"
     errrep = txt "ErrorReportPart"
 
-    tyIsHandler (Bind _ (Pi _ (P _ (NS (UN e) ns1) _) _)
+    tyIsHandler (Bind _ (Pi _ _ (P _ (NS (UN e) ns1) _) _)
                         (App _ (P _ (NS (UN m) ns2) _)
                              (App _ (P _ (NS (UN l) ns3) _)
                                   (P _ (NS (UN r) ns4) _))))
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
@@ -13,6 +13,7 @@
 import Idris.Core.Evaluate
 import Idris.Core.TT
 import Idris.Core.Typecheck
+import Idris.Core.WHNF
 import Idris.DeepSeq
 import Idris.Delaborate
 import Idris.Docstrings
@@ -103,7 +104,7 @@
 -- | Get the list of (index, name) of inaccessible arguments from an elaborated
 -- type
 inaccessibleImps :: Int -> Type -> [Bool] -> [(Int, Name)]
-inaccessibleImps i (Bind n (Pi _ t _) sc) (inacc : ins)
+inaccessibleImps i (Bind n (Pi _ _ t _) sc) (inacc : ins)
     | inacc = (i, n) : inaccessibleImps (i + 1) sc ins
     | otherwise = inaccessibleImps (i + 1) sc ins
 inaccessibleImps _ _ _ = []
@@ -184,8 +185,8 @@
 
 -- if 't' is an interface application, assume its arguments are injective
 pbinds :: IState -> Term -> ElabD ()
-pbinds i (Bind n (PVar t) sc)
-    = do attack; patbind n
+pbinds i (Bind n (PVar rig t) sc)
+    = do attack; patbind n rig
          env <- get_env
          case unApply (normalise (tt_ctxt i) env t) of
               (P _ c _, args) -> case lookupCtxt c (idris_interfaces i) of
@@ -198,26 +199,26 @@
         setinjArg _ = return ()
 pbinds i tm = return ()
 
-pbty (Bind n (PVar t) sc) tm = Bind n (PVTy t) (pbty sc tm)
+pbty (Bind n (PVar _ t) sc) tm = Bind n (PVTy t) (pbty sc tm)
 pbty _ tm = tm
 
-getPBtys (Bind n (PVar t) sc) = (n, t) : getPBtys sc
+getPBtys (Bind n (PVar _ t) sc) = (n, t) : getPBtys sc
 getPBtys (Bind n (PVTy t) sc) = (n, t) : getPBtys sc
 getPBtys _ = []
 
-psolve (Bind n (PVar t) sc) = do solve; psolve sc
+psolve (Bind n (PVar _ t) sc) = do solve; psolve sc
 psolve tm = return ()
 
-pvars ist (Bind n (PVar t) sc) = (n, delab ist t) : pvars ist sc
+pvars ist (Bind n (PVar _ t) sc) = (n, delab ist t) : pvars ist sc
 pvars ist _ = []
 
-getFixedInType i env (PExp _ _ _ _ : is) (Bind n (Pi _ t _) sc)
+getFixedInType i env (PExp _ _ _ _ : is) (Bind n (Pi _ _ t _) sc)
     = nub $ getFixedInType i env [] t ++
             getFixedInType i (n : env) is (instantiate (P Bound n t) sc)
             ++ case unApply t of
                     (P _ n _, _) -> if n `elem` env then [n] else []
                     _ -> []
-getFixedInType i env (_ : is) (Bind n (Pi _ t _) sc)
+getFixedInType i env (_ : is) (Bind n (Pi _ _ t _) sc)
     = getFixedInType i (n : env) is (instantiate (P Bound n t) sc)
 getFixedInType i env is tm@(App _ f a)
     | (P _ tn _, args) <- unApply tm
@@ -231,7 +232,7 @@
                         getFixedInType i env is a
 getFixedInType i _ _ _ = []
 
-getFlexInType i env ps (Bind n (Pi _ t _) sc)
+getFlexInType i env ps (Bind n (Pi _ _ t _) sc)
     = nub $ (if (not (n `elem` ps)) then getFlexInType i env ps t else []) ++
             getFlexInType i (n : env) ps (instantiate (P Bound n t) sc)
 
@@ -260,7 +261,7 @@
                                  flex = getFlexInType i env fix t in
                                  [x | x <- fix, not (x `elem` flex)]
 
-getTCinj i (Bind n (Pi _ t _) sc)
+getTCinj i (Bind n (Pi _ _ t _) sc)
     = getTCinj i t ++ getTCinj i (instantiate (P Bound n t) sc)
 getTCinj i ap@(App _ f a)
     | (P _ n _, args) <- unApply ap,
@@ -292,13 +293,13 @@
   where
     getUniq :: Env -> [(Name, Bool)] -> Term -> State [Name] ()
     getUniq env us (Bind n b sc)
-       = let uniq = case check ctxt env (forgetEnv (map fst env) (binderTy b)) of
+       = let uniq = case check ctxt env (forgetEnv (map fstEnv env) (binderTy b)) of
                          OK (_, UType UniqueType) -> True
                          OK (_, UType NullType) -> True
                          OK (_, UType AllTypes) -> True
                          _ -> False in
              do getUniqB env us b
-                getUniq ((n,b):env) ((n, uniq):us) sc
+                getUniq ((n, RigW, b):env) ((n, uniq):us) sc
     getUniq env us (App _ f a) = do getUniq env us f; getUniq env us a
     getUniq env us (V i)
        | i < length us = if snd (us!!i) then use (fst (us!!i)) else return ()
@@ -310,14 +311,14 @@
 
     getUniqB env us (Let t v) = getUniq env us v
     getUniqB env us (Guess t v) = getUniq env us v
---     getUniqB env us (Pi t v) = do getUniq env us t; getUniq env us v
+--     getUniqB env us (Pi _ _ t v) = do getUniq env us t; getUniq env us v
     getUniqB env us (NLet t v) = getUniq env us v
     getUniqB env us b = return () -- getUniq env us (binderTy b)
 
 -- In a functional application, return the names which are used
 -- directly in a static position
 getStaticNames :: IState -> Term -> [Name]
-getStaticNames ist (Bind n (PVar _) sc)
+getStaticNames ist (Bind n (PVar _ _) sc)
     = getStaticNames ist (instantiate (P Bound n Erased) sc)
 getStaticNames ist tm
     | (P _ fn _, args) <- unApply tm
@@ -331,7 +332,7 @@
 getStaticNames _ _ = []
 
 getStatics :: [Name] -> Term -> [Bool]
-getStatics ns (Bind n (Pi _ _ _) t)
+getStatics ns (Bind n (Pi _ _ _ _) t)
     | n `elem` ns = True : getStatics ns t
     | otherwise = False : getStatics ns t
 getStatics _ _ = []
@@ -407,7 +408,7 @@
     getDataApp f@(App _ _ _)
         | (P _ d _, args) <- unApply f
                = if (d == tyn) then [mParam args args] else []
-    getDataApp (Bind n (Pi _ t _) sc)
+    getDataApp (Bind n (Pi _ _ t _) sc)
         = getDataApp t ++ getDataApp (instantiate (P Bound n t) sc)
     getDataApp _ = []
 
@@ -478,9 +479,9 @@
   where
     op [] (App s f a) = App s f (op [] a) -- for Infer terms
 
-    op ps (Bind n (PVar t) sc) = op ((n, PVar t) : ps) sc
+    op ps (Bind n (PVar r t) sc) = op ((n, PVar r t) : ps) sc
     op ps (Bind n (Hole t) sc) = op ((n, Hole t) : ps) sc
-    op ps (Bind n (Pi i t k) sc) = op ((n, Pi i t k) : ps) sc
+    op ps (Bind n (Pi rig i t k) sc) = op ((n, Pi rig i t k) : ps) sc
     op ps sc = bindAll (sortP ps) sc
 
     -- Keep explicit Pi in the same order, insert others as necessary,
@@ -488,8 +489,8 @@
     sortP ps = let (exps, imps) = partition isExp ps in
                pick (reverse exps) imps
 
-    isExp (_, Pi Nothing _ _) = True
-    isExp (_, Pi (Just i) _ _) = toplevel_imp i && not (machine_gen i)
+    isExp (_, Pi rig Nothing _ _) = True
+    isExp (_, Pi rig (Just i) _ _) = toplevel_imp i && not (machine_gen i)
     isExp _ = False
 
     pick acc [] = acc
@@ -510,13 +511,13 @@
   where
     bindPats []          tm = tm
     bindPats ((n, t):ps) tm
-         | n `notElem` map fst ps = Bind n (PVar t) (bindPats ps tm)
+         | n `notElem` map fst ps = Bind n (PVar RigW t) (bindPats ps tm)
          | otherwise = bindPats ps tm
 
     getPats :: Term -> State [(Name, Type)] Term
-    getPats (Bind n (PVar t) sc) = do ps <- get
-                                      put ((n, t) : ps)
-                                      getPats sc
+    getPats (Bind n (PVar _ t) sc) = do ps <- get
+                                        put ((n, t) : ps)
+                                        getPats sc
     getPats (Bind n (Guess t v) sc) = do t' <- getPats t
                                          v' <- getPats v
                                          sc' <- getPats sc
@@ -525,13 +526,13 @@
                                        v' <- getPats v
                                        sc' <- getPats sc
                                        return (Bind n (Let t' v') sc')
-    getPats (Bind n (Pi i t k) sc) = do t' <- getPats t
-                                        k' <- getPats k
-                                        sc' <- getPats sc
-                                        return (Bind n (Pi i t' k') sc')
-    getPats (Bind n (Lam t) sc) = do t' <- getPats t
-                                     sc' <- getPats sc
-                                     return (Bind n (Lam t') sc')
+    getPats (Bind n (Pi rig i t k) sc) = do t' <- getPats t
+                                            k' <- getPats k
+                                            sc' <- getPats sc
+                                            return (Bind n (Pi rig i t' k') sc')
+    getPats (Bind n (Lam r t) sc) = do t' <- getPats t
+                                       sc' <- getPats sc
+                                       return (Bind n (Lam r t') sc')
     getPats (Bind n (Hole t) sc) = do t' <- getPats t
                                       sc' <- getPats sc
                                       return (Bind n (Hole t') sc')
@@ -544,11 +545,11 @@
 
 isEmpty :: Context -> Ctxt TypeInfo -> Type -> Bool
 isEmpty ctxt tyctxt ty
-    | (P _ tyname _, args) <- unApply (getRetTy ty),
+    | (P _ tyname _, args) <- unApply 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
+      -- clashes 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
@@ -560,7 +561,7 @@
     findClash l r
        | (P _ n _, _) <- unApply l,
          (P _ n' _, _) <- unApply r,
-         isConName n ctxt && isConName n' ctxt, n /= n' 
+         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
@@ -568,6 +569,38 @@
 isEmpty ctxt tyinfo ty = False
 
 hasEmptyPat :: Context -> Ctxt TypeInfo -> Term -> Bool
-hasEmptyPat ctxt tyctxt (Bind n (PVar ty) sc)
+hasEmptyPat ctxt tyctxt (Bind n (PVar _ ty) sc)
     = isEmpty ctxt tyctxt ty || hasEmptyPat ctxt tyctxt sc
 hasEmptyPat ctxt tyctxt _ = False
+
+-- Find names which are applied to a function in a Rig1 position
+findLinear :: IState -> [Name] -> Term -> [(Name, RigCount)]
+findLinear ist env tm | (P _ f _, args) <- unApply tm,
+                        f `notElem` env,
+                        Just ty_in <- lookupTyExact f (tt_ctxt ist)
+    = let ty = whnfArgs (tt_ctxt ist) [] ty_in in
+          nub $ concatMap (findLinear ist env) args ++ findLinArg ty args
+  where
+    findLinArg (Bind n (Pi c _ _ _) sc) (P _ a _ : as)
+         | Rig0 <- c = (a, c) : findLinArg sc as
+         | Rig1 <- c = (a, c) : findLinArg sc as
+    findLinArg (Bind n (Pi _ _ _ _) sc) (a : as)
+          = findLinArg (whnf (tt_ctxt ist) [] (substV a sc)) as
+    findLinArg _ _ = []
+findLinear ist env (App _ f a)
+    = nub $ findLinear ist env f ++ findLinear ist env a
+findLinear ist env (Bind n b sc) = findLinear ist (n : env) sc
+findLinear ist _ _ = []
+
+setLinear :: [(Name, RigCount)] -> Term -> Term
+setLinear ns (Bind n b@(PVar r t) sc)
+   | Just r <- lookup n ns = Bind n (PVar r t) (setLinear ns sc)
+   | otherwise = Bind n b (setLinear ns sc)
+setLinear ns tm = tm
+
+linearArg :: Type -> Bool
+linearArg (Bind n (Pi Rig1 _ _ _) sc) = True
+linearArg (Bind n (Pi _ _ _ _) sc) = linearArg sc
+linearArg _ = False
+
+
diff --git a/src/Idris/ElabDecls.hs b/src/Idris/ElabDecls.hs
--- a/src/Idris/ElabDecls.hs
+++ b/src/Idris/ElabDecls.hs
@@ -68,7 +68,7 @@
 
 -- | Top level elaborator info, supporting recursive elaboration
 recinfo :: FC -> ElabInfo
-recinfo fc = EInfo [] emptyContext id [] (Just fc) (fc_fname fc) 0 id elabDecl'
+recinfo fc = EInfo [] emptyContext id [] (Just fc) (fc_fname fc) 0 [] id elabDecl'
 
 -- | Return the elaborated term which calls 'main'
 elabMain :: Idris Term
@@ -116,9 +116,9 @@
 
           p_believeMe [_,_,x] = Just x
           p_believeMe _ = Nothing
-          believeTy = Bind (sUN "a") (Pi Nothing (TType (UVar [] (-2))) (TType (UVar [] (-1))))
-                       (Bind (sUN "b") (Pi Nothing (TType (UVar [] (-2))) (TType (UVar [] (-1))))
-                         (Bind (sUN "x") (Pi Nothing (V 1) (TType (UVar [] (-1)))) (V 1)))
+          believeTy = Bind (sUN "a") (Pi RigW Nothing (TType (UVar [] (-2))) (TType (UVar [] (-1))))
+                       (Bind (sUN "b") (Pi RigW Nothing (TType (UVar [] (-2))) (TType (UVar [] (-1))))
+                         (Bind (sUN "x") (Pi RigW Nothing (V 1) (TType (UVar [] (-1)))) (V 1)))
           elabBelieveMe
              = do let prim__believe_me = sUN "prim__believe_me"
                   updateContext (addOperator prim__believe_me believeTy 3 p_believeMe)
@@ -141,10 +141,10 @@
           vnNothing = VP (DCon 0 1 False) (sNS (sUN "Nothing") ["Maybe", "Prelude"]) VErased
           vnRefl = VP (DCon 0 2 False) eqCon VErased
 
-          synEqTy = Bind (sUN "a") (Pi Nothing (TType (UVar [] (-3))) (TType (UVar [] (-2))))
-                     (Bind (sUN "b") (Pi Nothing (TType (UVar [] (-3))) (TType (UVar [] (-2))))
-                      (Bind (sUN "x") (Pi Nothing (V 1) (TType (UVar [] (-2))))
-                       (Bind (sUN "y") (Pi Nothing (V 1) (TType (UVar [] (-2))))
+          synEqTy = Bind (sUN "a") (Pi RigW Nothing (TType (UVar [] (-3))) (TType (UVar [] (-2))))
+                     (Bind (sUN "b") (Pi RigW Nothing (TType (UVar [] (-3))) (TType (UVar [] (-2))))
+                      (Bind (sUN "x") (Pi RigW Nothing (V 1) (TType (UVar [] (-2))))
+                       (Bind (sUN "y") (Pi RigW Nothing (V 1) (TType (UVar [] (-2))))
                          (mkApp nMaybe [mkApp (P (TCon 0 4) eqTy Erased)
                                                [V 3, V 2, V 1, V 0]]))))
           elabSynEq
@@ -197,7 +197,12 @@
                     [] -> []
          elabClauses info f (o ++ o') n ps
 elabDecl' what info (PMutual f ps)
-    = do case ps of
+    = do i <- get
+         -- Find the interfaces we're defining in the block so that we can
+         -- inline them appropriately before totality checking
+         let (ufnames, umethss) = unzip (mapMaybe (findTCImpl i) ps)
+
+         case ps of
               [p] -> elabDecl what info p
               _ -> do mapM_ (elabDecl ETypes info) ps
                       mapM_ (elabDecl EDefns info) ps
@@ -210,9 +215,10 @@
          i <- get
          mapM_ (\n -> do logElab 5 $ "Simplifying " ++ show n
                          ctxt' <- do ctxt <- getContext
-                                     tclift $ simplifyCasedef n (getErasureInfo i) ctxt
+                                     tclift $ simplifyCasedef n ufnames umethss (getErasureInfo i) ctxt
                          setContext ctxt')
                  (map snd (idris_totcheck i))
+
          mapM_ buildSCG (idris_totcheck i)
          mapM_ checkDeclTotality (idris_totcheck i)
          -- We've only checked that things are total independently. Given
@@ -223,6 +229,23 @@
   where isDataDecl (PData _ _ _ _ _ _) = True
         isDataDecl _ = False
 
+        findTCImpl :: IState -> PDecl -> Maybe (Name, [Name])
+        findTCImpl ist (PImplementation _ _ _ _ _ _ _ _ n_in _ ps _ _ expn _)
+             = let (n, meths)
+                        = case lookupCtxtName n_in (idris_interfaces ist) of
+                               [(n', ci)] -> (n', map fst (interface_methods ci))
+                               _ -> (n_in, [])
+                   iname = mkiname n (namespace info) ps expn in
+                   Just (iname, meths)
+        findTCImpl ist _ = Nothing
+
+        mkiname n' ns ps' expn' =
+           case expn' of
+                Nothing -> case ns of
+                              [] -> SN (sImplementationN n' (map show ps'))
+                              m -> sNS (SN (sImplementationN n' (map show ps'))) m
+                Just nm -> nm
+
         getDataDecls (PNamespace _ _ ds : decls)
            = getDataDecls ds ++ getDataDecls decls
         getDataDecls (d : decls)
@@ -268,9 +291,8 @@
     ninfo = info { namespace = newNS }
 
 elabDecl' what info (PInterface doc s f cs n nfc ps pdocs fds ds cn cd)
-  | what /= EDefns
     = do logElab 1 $ "Elaborating interface " ++ show n
-         elabInterface info (s { syn_params = [] }) doc f cs n nfc ps pdocs fds ds cn cd
+         elabInterface info (s { syn_params = [] }) doc what f cs n nfc ps pdocs fds ds cn cd
 elabDecl' what info (PImplementation doc argDocs s f cs pnames acc fnopts n nfc ps pextra t expn ds)
     = do logElab 1 $ "Elaborating implementation " ++ show n
          elabImplementation info s doc argDocs what f cs pnames acc fnopts n nfc ps pextra t expn ds
@@ -284,6 +306,8 @@
 -}
 elabDecl' _ info (PDSL n dsl)
     = do i <- getIState
+         unless (DSLNotation `elem` idris_language_extensions i) $
+           ifail "You must turn on the DSLNotation extension to use a dsl block"
          putIState (i { idris_dsls = addDef n dsl (idris_dsls i) })
          addIBC (IBCDSL n)
 elabDecl' what info (PDirective i)
@@ -296,6 +320,9 @@
     = do elabTransform info fc safety old new
          return ()
 elabDecl' what info (PRunElabDecl fc script ns)
-    = do elabRunElab info fc script ns
+    = do i <- getIState
+         unless (ElabReflection `elem` idris_language_extensions i) $
+           ierror $ At fc (Msg "You must turn on the ElabReflection extension to use %runElab")
+         elabRunElab info fc script ns
          return ()
 elabDecl' _ _ _ = return () -- skipped this time
diff --git a/src/Idris/Erasure.hs b/src/Idris/Erasure.hs
--- a/src/Idris/Erasure.hs
+++ b/src/Idris/Erasure.hs
@@ -366,8 +366,8 @@
     getDepsTerm vs bs cd (Bind n bdr body)
         -- here we just push IM.empty on the de bruijn stack
         -- the args will be marked as used at the usage site
-        | Lam ty <- bdr = getDepsTerm vs ((n, const M.empty) : bs) cd body
-        | Pi _ ty _ <- bdr = getDepsTerm vs ((n, const M.empty) : bs) cd body
+        | Lam _ ty <- bdr = getDepsTerm vs ((n, const M.empty) : bs) cd body
+        | Pi _ _ ty _ <- bdr = getDepsTerm vs ((n, const M.empty) : bs) cd body
 
         -- let-bound variables can get partially evaluated
         -- it is sufficient just to plug the Cond in when the bound names are used
@@ -421,11 +421,11 @@
             V i -> snd (bs !! i) cd `union` unconditionalDeps args
 
             -- we interpret applied lambdas as lets in order to reuse code here
-            Bind n (Lam ty) t -> getDepsTerm vs bs cd (lamToLet app)
+            Bind n (Lam _ ty) t -> getDepsTerm vs bs cd (lamToLet app)
 
             -- and we interpret applied lets as lambdas
-            Bind n ( Let ty t') t -> getDepsTerm vs bs cd (App Complete (Bind n (Lam ty) t) t')
-            Bind n (NLet ty t') t -> getDepsTerm vs bs cd (App Complete (Bind n (Lam ty) t) t')
+            Bind n ( Let ty t') t -> getDepsTerm vs bs cd (App Complete (Bind n (Lam RigW ty) t) t')
+            Bind n (NLet ty t') t -> getDepsTerm vs bs cd (App Complete (Bind n (Lam RigW ty) t) t')
 
             Proj t i
                 -> error $ "cannot[0] analyse projection !" ++ show i ++ " of " ++ show t
@@ -504,7 +504,7 @@
         (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' (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: "
@@ -512,7 +512,7 @@
 
     -- split "\x_i -> T(x_i)" into [x_i] and T
     unfoldLams :: Term -> ([Name], Term)
-    unfoldLams (Bind n (Lam ty) t) = let (ns,t') = unfoldLams t in (n:ns, t')
+    unfoldLams (Bind n (Lam _ ty) t) = let (ns,t') = unfoldLams t in (n:ns, t')
     unfoldLams t = ([], t)
 
     union :: Deps -> Deps -> Deps
diff --git a/src/Idris/ErrReverse.hs b/src/Idris/ErrReverse.hs
--- a/src/Idris/ErrReverse.hs
+++ b/src/Idris/ErrReverse.hs
@@ -10,6 +10,7 @@
 module Idris.ErrReverse(errReverse) where
 
 import Idris.AbsSyntax
+import Idris.Core.Evaluate (unfold)
 import Idris.Core.TT
 import Util.Pretty
 
@@ -17,10 +18,17 @@
 import Debug.Trace
 
 -- | For display purposes, apply any 'error reversal' transformations
--- so that errors will be more readable
+-- so that errors will be more readable,
+-- and any 'error reduce' transformations
 errReverse :: IState -> Term -> Term
-errReverse ist t = rewrite 5 t -- (elideLambdas t)
+errReverse ist t = rewrite 5 (do_unfold t) -- (elideLambdas t)
   where
+    do_unfold :: Term -> Term
+    do_unfold t = let ns = idris_errReduce ist in
+                      if null ns then t
+                         else unfold (tt_ctxt ist) []
+                                     (map (\x -> (x, 1000)) (idris_errReduce ist))
+                                     t
 
     rewrite 0 t = t
     rewrite n t = let t' = foldl applyRule t (reverse (idris_errRev ist)) in
@@ -33,7 +41,7 @@
     -- Assume pattern bindings match in l and r (if they don't just treat
     -- the rule as invalid and return t)
 
-    applyNames ns t (Bind n (PVar ty) scl) (Bind n' (PVar ty') scr)
+    applyNames ns t (Bind n (PVar _ ty) scl) (Bind n' (PVar _ ty') scr)
        | n == n' = applyNames (n : ns) t (instantiate (P Ref n ty) scl)
                                          (instantiate (P Ref n' ty') scr)
        | otherwise = t
@@ -70,7 +78,7 @@
     -- it as it won't be very enlightening.
 
     elideLambdas (App s f a) = App s (elideLambdas f) (elideLambdas a)
-    elideLambdas (Bind n (Lam t) sc)
+    elideLambdas (Bind n (Lam _ t) sc)
        | size sc > 200 = P Ref (sUN "...") Erased
     elideLambdas (Bind n b sc)
        = Bind n (fmap elideLambdas b) (elideLambdas sc)
diff --git a/src/Idris/Error.hs b/src/Idris/Error.hs
--- a/src/Idris/Error.hs
+++ b/src/Idris/Error.hs
@@ -79,6 +79,12 @@
 tclift (Error err@(UniverseError fc _ _ _ _)) = do setErrSpan fc; throwError err
 tclift (Error err) = throwError err
 
+tcliftAt :: FC -> TC a -> Idris a
+tcliftAt fc (OK v) = return v
+tcliftAt fc (Error err@(At _ e)) = do setErrSpan fc; throwError err
+tcliftAt fc (Error err@(UniverseError _ _ _ _ _)) = do setErrSpan fc; throwError err
+tcliftAt fc (Error err) = do setErrSpan fc; throwError (At fc err)
+
 tctry :: TC a -> TC a -> Idris a
 tctry tc1 tc2
     = case tc1 of
diff --git a/src/Idris/Help.hs b/src/Idris/Help.hs
--- a/src/Idris/Help.hs
+++ b/src/Idris/Help.hs
@@ -11,6 +11,7 @@
 data CmdArg = ExprArg               -- ^ The command takes an expression
             | NameArg               -- ^ The command takes a name
             | FileArg               -- ^ The command takes a file
+            | ShellCommandArg       -- ^ The command takes a shell command name
             | ModuleArg             -- ^ The command takes a module name
             | PkgArgs               -- ^ The command takes a list of package names
             | NumberArg             -- ^ The command takes a number
@@ -30,6 +31,7 @@
     show ExprArg          = "<expr>"
     show NameArg          = "<name>"
     show FileArg          = "<filename>"
+    show ShellCommandArg  = "<command>"
     show ModuleArg        = "<module>"
     show PkgArgs          = "<package list>"
     show NumberArg        = "<number>"
diff --git a/src/Idris/IBC.hs b/src/Idris/IBC.hs
--- a/src/Idris/IBC.hs
+++ b/src/Idris/IBC.hs
@@ -47,7 +47,7 @@
 import System.FilePath
 
 ibcVersion :: Word16
-ibcVersion = 155
+ibcVersion = 160
 
 -- | When IBC is being loaded - we'll load different things (and omit
 -- different structures/definitions) depending on which phase we're in.
@@ -86,6 +86,7 @@
   , ibc_moduledocs             :: ![(Name, Docstring D.DocTerm)]
   , ibc_transforms             :: ![(Name, (Term, Term))]
   , ibc_errRev                 :: ![(Term, Term)]
+  , ibc_errReduce              :: ![Name]
   , ibc_coercions              :: ![Name]
   , ibc_lineapps               :: ![(FilePath, Int, PTerm)]
   , ibc_namehints              :: ![(Name, Name)]
@@ -114,7 +115,7 @@
 !-}
 
 initIBC :: IBCFile
-initIBC = IBCFile ibcVersion "" [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] Nothing [] [] [] [] [] [] [] [] [] []
+initIBC = IBCFile ibcVersion "" [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] Nothing [] [] [] [] [] [] [] [] [] []
 
 hasValidIBCVersion :: FilePath -> Idris Bool
 hasValidIBCVersion fp = do
@@ -191,6 +192,7 @@
                        makeEntry "ibc_moduledocs"  (ibc_moduledocs i),
                        makeEntry "ibc_transforms"  (ibc_transforms i),
                        makeEntry "ibc_errRev"  (ibc_errRev i),
+                       makeEntry "ibc_errReduce"  (ibc_errReduce i),
                        makeEntry "ibc_coercions"  (ibc_coercions i),
                        makeEntry "ibc_lineapps"  (ibc_lineapps i),
                        makeEntry "ibc_namehints"  (ibc_namehints i),
@@ -220,7 +222,9 @@
 
 writeIBC :: FilePath -> FilePath -> Idris ()
 writeIBC src f
-    = do logIBC 1 $ "Writing ibc " ++ show f
+    = do
+         logIBC  1 $ "Writing IBC for: " ++ show f
+         iReport 2 $ "Writing IBC for: " ++ show f
          i <- getIState
 --          case (Data.List.map fst (idris_metavars i)) \\ primDefs of
 --                 (_:_) -> ifail "Can't write ibc when there are unsolved metavariables"
@@ -313,7 +317,7 @@
                         _ -> 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) 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"
@@ -322,6 +326,7 @@
 ibc i (IBCInjective n a) f = return f { ibc_injective = (n,a) : ibc_injective f }
 ibc i (IBCTrans n t) f = return f { ibc_transforms = (n, t) : ibc_transforms f }
 ibc i (IBCErrRev t) f = return f { ibc_errRev = t : ibc_errRev f }
+ibc i (IBCErrReduce t) f = return f { ibc_errReduce = t : ibc_errReduce f }
 ibc i (IBCLineApp fp l t) f
      = return f { ibc_lineapps = (fp,l,t) : ibc_lineapps f }
 ibc i (IBCNameHint (n, ty)) f
@@ -414,6 +419,7 @@
                 processCoercions archive
                 processTransforms archive
                 processErrRev archive
+                processErrReduce archive
                 processLineApps archive
                 processNameHints archive
                 processMetaInformation archive
@@ -795,6 +801,11 @@
     ts <- getEntry [] "ibc_errRev" ar
     mapM_ addErrRev ts
 
+processErrReduce :: Archive -> Idris ()
+processErrReduce ar = do
+    ts <- getEntry [] "ibc_errReduce" ar
+    mapM_ addErrReduce ts
+
 processLineApps :: Archive -> Idris ()
 processLineApps ar = do
     ls <- getEntry [] "ibc_lineapps" ar
@@ -1227,9 +1238,7 @@
                 PEGenerated -> putWord8 16
                 StaticFn -> putWord8 17
                 OverlappingDictionary -> putWord8 18
-                UnfoldIface x ns -> do putWord8 19
-                                       put x
-                                       put ns
+                ErrorReduce -> putWord8 20
         get
           = do i <- getWord8
                case i of
@@ -1254,9 +1263,7 @@
                    16 -> return PEGenerated
                    17 -> return StaticFn
                    18 -> return OverlappingDictionary
-                   19 -> do x <- get
-                            ns <- get
-                            return (UnfoldIface x ns)
+                   20 -> return ErrorReduce
                    _ -> error "Corrupted binary data for FnOpt"
 
 instance Binary Fixity where
@@ -1326,26 +1333,30 @@
 instance Binary Plicity where
         put x
           = case x of
-                Imp x1 x2 x3 x4 _ ->
+                Imp x1 x2 x3 x4 _ x5 ->
                              do putWord8 0
                                 put x1
                                 put x2
                                 put x3
                                 put x4
-                Exp x1 x2 x3 ->
+                                put x5
+                Exp x1 x2 x3 x4 ->
                              do putWord8 1
                                 put x1
                                 put x2
                                 put x3
-                Constraint x1 x2 ->
+                                put x4
+                Constraint x1 x2 x3 ->
                                     do putWord8 2
                                        put x1
                                        put x2
-                TacImp x1 x2 x3 ->
+                                       put x3
+                TacImp x1 x2 x3 x4 ->
                                    do putWord8 3
                                       put x1
                                       put x2
                                       put x3
+                                      put x4
         get
           = do i <- getWord8
                case i of
@@ -1353,18 +1364,22 @@
                            x2 <- get
                            x3 <- get
                            x4 <- get
-                           return (Imp x1 x2 x3 x4 False)
+                           x5 <- get
+                           return (Imp x1 x2 x3 x4 False x5)
                    1 -> do x1 <- get
                            x2 <- get
                            x3 <- get
-                           return (Exp x1 x2 x3)
+                           x4 <- get
+                           return (Exp x1 x2 x3 x4)
                    2 -> do x1 <- get
                            x2 <- get
-                           return (Constraint x1 x2)
+                           x3 <- get
+                           return (Constraint x1 x2 x3)
                    3 -> do x1 <- get
                            x2 <- get
                            x3 <- get
-                           return (TacImp x1 x2 x3)
+                           x4 <- get
+                           return (TacImp x1 x2 x3 x4)
                    _ -> error "Corrupted binary data for Plicity"
 
 
@@ -2414,17 +2429,19 @@
                return (FnInfo x1)
 
 instance Binary TypeInfo where
-        put (TI x1 x2 x3 x4 x5) = do put x1
-                                     put x2
-                                     put x3
-                                     put x4
-                                     put x5
+        put (TI x1 x2 x3 x4 x5 x6) = do put x1
+                                        put x2
+                                        put x3
+                                        put x4
+                                        put x5
+                                        put x6
         get = do x1 <- get
                  x2 <- get
                  x3 <- get
                  x4 <- get
                  x5 <- get
-                 return (TI x1 x2 x3 x4 x5)
+                 x6 <- get
+                 return (TI x1 x2 x3 x4 x5 x6)
 
 instance Binary SynContext where
         put x
diff --git a/src/Idris/IdrisDoc.hs b/src/Idris/IdrisDoc.hs
--- a/src/Idris/IdrisDoc.hs
+++ b/src/Idris/IdrisDoc.hs
@@ -19,7 +19,7 @@
 import Idris.Docstrings (nullDocstring)
 import qualified Idris.Docstrings as Docstrings
 import Idris.Parser.Helpers (opChars)
-import IRTS.System (getDataFileName)
+import IRTS.System (getIdrisDataFileByName)
 
 import Control.Applicative ((<|>))
 import Control.Monad (forM_)
@@ -46,7 +46,6 @@
 import Text.Blaze.Html5 (preEscapedToHtml, toHtml, (!))
 import qualified Text.Blaze.Html5 as H
 import Text.Blaze.Html5.Attributes as A
-import Text.Blaze.Internal (MarkupM(Empty))
 import Text.Blaze.Renderer.String (renderMarkup)
 import Text.PrettyPrint.Annotated.Leijen (displayDecorated, renderCompact)
 
@@ -543,7 +542,7 @@
 createFunDoc ist fd@(FD name docstring args ftype fixity) = do
   H.dt ! (A.id $ toValue $ show name) $ genTypeHeader ist fd
   H.dd $ do
-    (if nullDocstring docstring then Empty else Docstrings.renderHtml docstring)
+    (if nullDocstring docstring then mempty else Docstrings.renderHtml docstring)
     let args'             = filter (\(_, _, _, d) -> isJust d) args
     if (not $ null args') || (isJust fixity)
        then H.dl $ do
@@ -551,9 +550,9 @@
              H.dt ! class_ "fixity" $ "Fixity"
              let f = fromJust fixity
              H.dd ! class_ "fixity" ! title (toValue $ show f) $ genFix f
-           else Empty
+           else mempty
          forM_ args' genArg
-       else Empty
+       else mempty
 
   where genFix (Infixl {prec=p})  =
           toHtml $ "Left associative, precedence " ++ show p
@@ -563,7 +562,7 @@
           toHtml $ "Non-associative, precedence " ++ show p
         genFix (PrefixN {prec=p}) =
           toHtml $ "Prefix, precedence " ++ show p
-        genArg (_, _, _, Nothing)           = Empty
+        genArg (_, _, _, Nothing)           = mempty
         genArg (name, _, _, Just docstring) = do
           H.dt $ toHtml $ show name
           H.dd $ Docstrings.renderHtml docstring
@@ -584,7 +583,7 @@
            $ toHtml $ name $ nsroot n
     H.span ! class_ "signature" $ nbsp
   H.dd $ do
-    (if nullDocstring docstring then Empty else Docstrings.renderHtml docstring)
+    (if nullDocstring docstring then mempty else Docstrings.renderHtml docstring)
     H.dl ! class_ "decls" $ (forM_ (maybeToList c ++ fds) (createFunDoc ist))
 
   where name (NS n ns) = show (NS (sUN $ name n) ns)
@@ -601,10 +600,10 @@
            $ toHtml $ name $ nsroot n
     H.span ! class_ "type" $ do nbsp ; prettyParameters
   H.dd $ do
-    (if nullDocstring doc then Empty else Docstrings.renderHtml doc)
+    (if nullDocstring doc then mempty else Docstrings.renderHtml doc)
     if not $ null params
        then H.dl $ forM_ params genParam
-       else Empty
+       else mempty
     H.dl ! class_ "decls" $ createFunDoc ist ctor
     H.dl ! class_ "decls" $ forM_ projs (createFunDoc ist)
   where name (NS n ns) = show (NS (sUN $ name n) ns)
@@ -624,14 +623,14 @@
     H.span ! class_ "word" $ do "data"; nbsp
     genTypeHeader ist fd
   H.dd $ do
-    (if nullDocstring docstring then Empty else Docstrings.renderHtml docstring)
+    (if nullDocstring docstring then mempty else Docstrings.renderHtml docstring)
     let args' = filter (\(_, _, _, d) -> isJust d) args
     if not $ null args'
        then H.dl $ forM_ args' genArg
-       else Empty
+       else mempty
     H.dl ! class_ "decls" $ forM_ fds (createFunDoc ist)
 
-  where genArg (_, _, _, Nothing)           = Empty
+  where genArg (_, _, _, Nothing)           = mempty
         genArg (name, _, _, Just docstring) = do
           H.dt $ toHtml $ show name
           H.dd $ Docstrings.renderHtml docstring
@@ -663,7 +662,7 @@
       H.div ! class_ "wrapper" $ do
         H.header $ do
           H.strong "IdrisDoc"
-          if index then Empty else do
+          if index then mempty else do
             ": "
             toHtml str
           H.nav $ H.a ! href (toValue indexPage) $ "Index"
@@ -708,5 +707,5 @@
                              --   dependencies should be written
                  -> IO ()
 copyDependencies dir =
-  do styles <- getDataFileName $ "idrisdoc" </> "styles.css"
+  do styles <- getIdrisDataFileByName $ "idrisdoc" </> "styles.css"
      copyFile styles (dir </> "styles.css")
diff --git a/src/Idris/Info.hs b/src/Idris/Info.hs
--- a/src/Idris/Info.hs
+++ b/src/Idris/Info.hs
@@ -22,6 +22,7 @@
   , getIdrisHistoryFile
   , getIdrisInstalledPackages
   , getIdrisLoggingCategories
+  , getIdrisDataFileByName
   ) where
 
 import Idris.AbsSyntax (loggingCatsStr)
@@ -34,6 +35,7 @@
 import Data.Version
 import System.Directory
 import System.FilePath
+
 getIdrisDataDir :: IO String
 getIdrisDataDir = S.getIdrisDataDir
 
@@ -88,3 +90,6 @@
 
 getIdrisLoggingCategories :: IO [String]
 getIdrisLoggingCategories = return $ words loggingCatsStr
+
+getIdrisDataFileByName :: String -> IO FilePath
+getIdrisDataFileByName = S.getIdrisDataFileByName
diff --git a/src/Idris/Interactive.hs b/src/Idris/Interactive.hs
--- a/src/Idris/Interactive.hs
+++ b/src/Idris/Interactive.hs
@@ -32,10 +32,7 @@
 
 import Data.Char
 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 ()
@@ -60,8 +57,8 @@
     ist <- getIState
     cl <- getInternalApp fn l
     let fulln = getAppName cl
-
-    case lookup fulln (idris_metavars ist) of
+    let metavars = lookup fulln (idris_metavars ist)
+    case metavars of
       Nothing -> addMissing fn updatefile l n
       Just _ -> do
         src <- runIO $ readSource fn
@@ -164,22 +161,25 @@
 
 
 makeWith :: FilePath -> Bool -> Int -> Name -> Idris ()
-makeWith fn updatefile l n
-   = do src <- runIO $ readSource fn
-        let (before, tyline : later) = splitAt (l-1) (lines src)
-        let ind = getIndent tyline
-        let with = mkWith tyline n
-        -- add clause before first blank line in 'later',
-        -- or (TODO) before first line with same indentation as tyline
-        let (nonblank, rest) = span (\x -> not (all isSpace x) &&
-                                           not (ind == getIndent x)) later
-        if updatefile then
-           do let fb = fn ++ "~"
-              runIO $ writeSource fb (unlines (before ++ nonblank)
-                                        ++ with ++ "\n" ++
-                                    unlines rest)
-              runIO $ copyFile fb fn
-           else iPrintResult (with ++ "\n")
+makeWith fn updatefile l n = do
+  src <- runIO $ readSource fn
+  i <- getIState
+  indentWith <- getIndentWith
+  let (before, tyline : later) = splitAt (l-1) (lines src)
+  let ind = getIndent tyline
+--  runIO . traceIO $ "indentWith = " ++ show indentWith
+  let with = mkWith tyline n indentWith
+  -- add clause before first blank line in 'later',
+  -- or (TODO) before first line with same indentation as tyline
+  let (nonblank, rest) = span (\x -> not (all isSpace x) &&
+                                     not (ind == getIndent x)) later
+  if updatefile
+    then do
+      let fb = fn ++ "~"
+      runIO $ writeSource fb (unlines (before ++ nonblank) ++
+                              with ++ "\n" ++ unlines rest)
+      runIO $ copyFile fb fn
+    else iPrintResult (with ++ "\n")
   where getIndent s = length (takeWhile isSpace s)
 
 -- Replace the given metavariable on the given line with a 'case'
@@ -221,9 +221,6 @@
         findSubstr' acc i n (x : xs) = findSubstr' (x : acc) (i + 1) n xs
 
 
-
-
-
 doProofSearch :: FilePath -> Bool -> Bool ->
                  Int -> Name -> [Name] -> Maybe Int -> Idris ()
 doProofSearch fn updatefile rec l n hints Nothing
@@ -390,10 +387,10 @@
   where getIndent s = length (takeWhile isSpace s)
 
         appArgs skip 0 _ = ""
-        appArgs skip i (Bind n@(UN c) (Pi _ _ _) sc)
+        appArgs skip i (Bind n@(UN c) (Pi _ _ _ _) sc)
            | (thead c /= '_' && n `notElem` skip)
                 = " " ++ show n ++ appArgs skip (i - 1) sc
-        appArgs skip i (Bind _ (Pi _ _ _) sc) = appArgs skip (i - 1) sc
+        appArgs skip i (Bind _ (Pi _ _ _ _) sc) = appArgs skip (i - 1) sc
         appArgs skip i _ = ""
 
         stripMNBind _ args t | args <= 0 = stripImp t
@@ -416,7 +413,7 @@
         constraints i [n] ty = showSep ", " (showConstraints i [n] ty) ++ " => "
         constraints i ns ty = "(" ++ showSep ", " (showConstraints i ns ty) ++ ") => "
 
-        showConstraints i ns (Bind n (Pi _ ty _) sc)
+        showConstraints i ns (Bind n (Pi _ _ ty _) sc)
             | n `elem` ns = show (delab i ty) :
                               showConstraints i ns (substV (P Bound n Erased) sc)
             | otherwise = showConstraints i ns (substV (P Bound n Erased) sc)
@@ -428,9 +425,9 @@
         -- Also, make interface implementations implicit
         guessImps :: IState -> Context -> Term -> [Name]
         -- machine names aren't lifted
-        guessImps ist ctxt (Bind n@(MN _ _) (Pi _ ty _) sc)
+        guessImps ist ctxt (Bind n@(MN _ _) (Pi _ _ ty _) sc)
            = n : guessImps ist ctxt sc
-        guessImps ist ctxt (Bind n (Pi _ ty _) sc)
+        guessImps ist ctxt (Bind n (Pi _ _ ty _) sc)
            | guarded ctxt n (substV (P Bound n Erased) sc)
                 = n : guessImps ist ctxt sc
            | isInterface ist ty
@@ -441,7 +438,7 @@
         guessImps ist ctxt _ = []
 
         paramty (TType _) = True
-        paramty (Bind _ (Pi _ (TType _) _) sc) = paramty sc
+        paramty (Bind _ (Pi _ _ (TType _) _) sc) = paramty sc
         paramty _ = False
 
         -- TMP HACK unusable name so don't lift
@@ -450,7 +447,7 @@
                             _ -> False
 
         guessInterfaces :: IState -> Context -> [Name] -> [Name] -> Term -> [Name]
-        guessInterfaces ist ctxt binders usednames (Bind n (Pi _ ty _) sc)
+        guessInterfaces ist ctxt binders usednames (Bind n (Pi _ _ ty _) sc)
            | isParamInterface ist ty && any (\x -> elem x usednames)
                                             (paramNames binders ty)
                 = n : guessInterfaces ist ctxt (n : binders) usednames sc
@@ -485,7 +482,7 @@
               isConName f ctxt = any (guarded ctxt n) args
 --         guarded ctxt n (Bind (UN cn) (Pi t) sc) -- ignore shadows
 --             | thead cn /= '_' = guarded ctxt n t || guarded ctxt n sc
-        guarded ctxt n (Bind _ (Pi _ t _) sc)
+        guarded ctxt n (Bind _ (Pi _ _ t _) sc)
             = guarded ctxt n t || guarded ctxt n sc
         guarded ctxt n _ = False
 
diff --git a/src/Idris/Main.hs b/src/Idris/Main.hs
--- a/src/Idris/Main.hs
+++ b/src/Idris/Main.hs
@@ -31,8 +31,6 @@
 
 import Util.System
 
-import Prelude hiding (id, (.), (<$>))
-
 import Control.Category
 import Control.DeepSeq
 import Control.Monad
@@ -40,22 +38,26 @@
 import Control.Monad.Trans.Except (runExceptT)
 import Control.Monad.Trans.State.Strict (execStateT)
 import Data.Maybe
+import Prelude hiding (id, (.), (<$>))
 import System.Console.Haskeline as H
 import System.Directory
 import System.Exit
 import System.FilePath
 import System.IO
+import System.IO.CodePage (withCP65001)
 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 -> do
-                         putStrLn $ "Uncaught error: " ++ show err
-                         exitFailure
-                       Right _ -> return ()
-
+runMain prog = withCP65001 $ do
+               -- Run in codepage 65001 on Windows so that UTF-8 characters can
+               -- be displayed properly. See #3000.
+  res <- runExceptT $ execStateT prog idrisInit
+  case res of
+       Left err -> do
+         putStrLn $ "Uncaught error: " ++ show err
+         exitFailure
+       Right _ -> return ()
 
 -- | The main function of Idris that when given a set of Options will
 -- launch Idris into the desired interaction mode either: REPL;
@@ -68,7 +70,6 @@
        let nobanner = NoBanner `elem` opts
        let idesl = Idemode `elem` opts || IdemodeSocket `elem` opts
        let runrepl = not (NoREPL `elem` opts)
-       let verbose = runrepl || Verbose `elem` opts
        let output = opt getOutput opts
        let ibcsubdir = opt getIBCSubDir opts
        let importdirs = opt getImportDir opts
@@ -78,7 +79,7 @@
        let pkgdirs = opt getPkgDir opts
        -- Set default optimisations
        let optimise = case opt getOptLevel opts of
-                        [] -> 2
+                        [] -> 1
                         xs -> last xs
 
        setOptLevel optimise
@@ -116,13 +117,16 @@
        mapM_ addLangExt (opt getLanguageExt opts)
        setREPL runrepl
        setQuiet (quiet || isJust script || not (null immediate))
-       setVerbose verbose
+
        setCmdLine opts
        setOutputTy outty
        setNoBanner nobanner
        setCodegen cgn
        mapM_ (addFlag cgn) cgFlags
        mapM_ makeOption opts
+       vlevel <- verbose
+       when (runrepl && vlevel == 0) $ setVerbose 1
+
        -- if we have the --bytecode flag, drop into the bytecode assembler
        case bcs of
          [] -> return ()
@@ -213,13 +217,16 @@
        ok <- noErrors
        when (not ok) $ runIO (exitWith (ExitFailure 1))
   where
-    makeOption (OLogging i)  = setLogLevel i
-    makeOption (OLogCats cs) = setLogCats cs
-    makeOption TypeCase      = setTypeCase True
-    makeOption TypeInType    = setTypeInType True
-    makeOption NoCoverage    = setCoverage False
-    makeOption ErrContext    = setErrContext True
-    makeOption _             = return ()
+    makeOption (OLogging i)     = setLogLevel i
+    makeOption (OLogCats cs)    = setLogCats cs
+    makeOption (Verbose v)      = setVerbose v
+    makeOption TypeCase         = setTypeCase True
+    makeOption TypeInType       = setTypeInType True
+    makeOption NoCoverage       = setCoverage False
+    makeOption ErrContext       = setErrContext True
+    makeOption (IndentWith n)   = setIndentWith n
+    makeOption (IndentClause n) = setIndentClause n
+    makeOption _                = return ()
 
     processOptimisation :: (Bool,Optimisation) -> Idris ()
     processOptimisation (True,  p) = addOptimise p
diff --git a/src/Idris/Package.hs b/src/Idris/Package.hs
--- a/src/Idris/Package.hs
+++ b/src/Idris/Package.hs
@@ -8,6 +8,26 @@
 {-# LANGUAGE CPP #-}
 module Idris.Package where
 
+import System.Directory
+import System.Directory (copyFile, createDirectoryIfMissing)
+import System.Exit
+import System.FilePath (addExtension, addTrailingPathSeparator, dropExtension,
+                        hasExtension, normalise, takeDirectory, takeExtension,
+                        takeFileName, (</>))
+import System.IO
+import System.Process
+
+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.Either (partitionEithers)
+import Data.List
+import Data.List.Split (splitOn)
+import Data.Maybe (fromMaybe)
+
 import Idris.AbsSyntax
 import Idris.Core.TT
 import Idris.Error (ifail)
@@ -17,28 +37,13 @@
 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 Idris.Package.Common
+import Idris.Package.Parser
 
-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
+import IRTS.System
 
 -- To build a package:
 -- * read the package description
@@ -71,18 +76,22 @@
       make (makefile pkgdesc)
       case (execout pkgdesc) of
         Nothing -> do
-          case mergeOptions copts (idx : NoREPL : Verbose : idris_opts pkgdesc) of
+          case mergeOptions copts (idx : NoREPL : Verbose 1 : idris_opts pkgdesc) of
             Left emsg -> do
               putStrLn emsg
               exitWith (ExitFailure 1)
-            Right opts -> buildMods opts (modules pkgdesc)
+            Right opts -> do
+              auditPackage (AuditIPkg `elem` opts) pkgdesc
+              buildMods opts (modules pkgdesc)
         Just o -> do
           let exec = dir </> o
-          case mergeOptions copts (idx : NoREPL : Verbose : Output exec : idris_opts pkgdesc) of
+          case mergeOptions copts (idx : NoREPL : Verbose 1 : Output exec : idris_opts pkgdesc) of
             Left emsg -> do
               putStrLn emsg
               exitWith (ExitFailure 1)
-            Right opts -> buildMain opts (idris_main pkgdesc)
+            Right opts -> do
+              auditPackage (AuditIPkg `elem` opts) pkgdesc
+              buildMain opts (idris_main pkgdesc)
     case m_ist of
       Nothing  -> exitWith (ExitFailure 1)
       Just ist -> do
@@ -115,11 +124,12 @@
     res <- inPkgDir pkgdesc $ do
       make (makefile pkgdesc)
 
-      case mergeOptions copts (NoREPL : Verbose : idris_opts pkgdesc) of
+      case mergeOptions copts (NoREPL : Verbose 1 : idris_opts pkgdesc) of
         Left emsg -> do
           putStrLn emsg
           exitWith (ExitFailure 1)
         Right opts -> do
+          auditPackage (AuditIPkg `elem` opts) pkgdesc
           buildMods opts (modules pkgdesc)
     when quit $ case res of
                   Nothing -> exitWith (ExitFailure 1)
@@ -145,7 +155,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
@@ -195,7 +205,7 @@
   cd             <- getCurrentDirectory
   let pkgDir      = cd </> takeDirectory fp
       outputDir   = cd </> pkgname pkgdesc ++ "_doc"
-      popts       = NoREPL : Verbose : idris_opts pkgdesc
+      popts       = NoREPL : Verbose 1 : idris_opts pkgdesc
       mods        = modules pkgdesc
       fs          = map (foldl1' (</>) . splitOn "." . showCG) mods
   setCurrentDirectory $ pkgDir </> sourcedir pkgdesc
@@ -259,14 +269,15 @@
         hClose tmph
         (tmpn', tmph') <- tempfile ""
         hClose tmph'
-        let popts = (Filename tmpn : NoREPL : Verbose : Output tmpn' : idris_opts pkgdesc)
+        let popts = (Filename tmpn : NoREPL : Verbose 1 : 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' []
+            let texe = if isWindows then addExtension tmpn' ".exe" else tmpn'
+            exitCode <- rawSystem texe []
             return (m_ist, exitCode)
       case m_ist of
         Nothing  -> exitWith (ExitFailure 1)
@@ -300,10 +311,55 @@
 -- Methods for building, testing, installing, and removal of idris
 -- packages.
 
+auditPackage :: Bool -> PkgDesc -> IO ()
+auditPackage False _    = return ()
+auditPackage True  ipkg = do
+    cwd <- getCurrentDirectory
+
+    let ms = map (sourcedir ipkg </>) $ map (toPath . showCG) (modules ipkg)
+    ms' <- mapM makeAbsolute ms
+
+    ifiles <- getIdrisFiles cwd
+
+    let ifiles' = map dropExtension ifiles
+
+    not_listed <- mapM makeRelativeToCurrentDirectory (ifiles' \\ ms')
+
+    putStrLn $ unlines $
+         ["Warning: The following modules are not listed in your iPkg file:\n"]
+      ++ map (\m -> unwords ["-", m]) not_listed
+      ++ ["\nModules that are not listed, are not installed."]
+
+  where
+    toPath n = foldl1' (</>) $ splitOn "." n
+
+    getIdrisFiles :: FilePath -> IO [FilePath]
+    getIdrisFiles dir = do
+      contents <- getDirectoryContents dir
+      let contents' = filter (\fname -> fname /= "." && fname /= "..") contents
+
+      -- [ NOTE ] Directory >= 1.2.5.0 introduced `listDirectory` but later versions of directory appear to be causing problems with ghc 7.10.3 and cabal 1.22 in travis. Let's reintroduce the old ranges for directory to be sure.
+
+
+      files <- forM contents (findRest dir)
+      return $ filter (isIdrisFile) (concat files)
+
+    isIdrisFile :: FilePath -> Bool
+    isIdrisFile fp = takeExtension fp == ".idr" || takeExtension fp == ".lidr"
+
+    findRest :: FilePath -> FilePath -> IO [FilePath]
+    findRest dir fn = do
+      path <- makeAbsolute (dir </> fn)
+      isDir <- doesDirectoryExist path
+      if isDir
+        then getIdrisFiles path
+        else return [path]
+
 buildMods :: [Opt] -> [Name] -> IO (Maybe IState)
 buildMods opts ns = do let f = map (toPath . showCG) ns
                        idris (map Filename f ++ opts)
-    where toPath n = foldl1' (</>) $ splitOn "." n
+    where
+      toPath n = foldl1' (</>) $ splitOn "." n
 
 testLib :: Bool -> String -> String -> IO Bool
 testLib warn p f
@@ -441,13 +497,15 @@
     chkOpt o@(IBCSubDir _)    = Right o
     chkOpt o@(ImportDir _ )   = Right o
     chkOpt o@(UseCodegen _)   = Right o
+    chkOpt o@(Verbose _)      = Right o
+    chkOpt o@(AuditIPkg)      = Right o
     chkOpt o                  = Left (unwords ["\t", show o, "\n"])
 
     genErrMsg :: [String] -> String
     genErrMsg es = unlines
         [ "Not all command line options can be used to override package options."
         , "\nThe only changeable options are:"
-        , "\t--log <lvl>, --total, --warnpartial, --warnreach"
+        , "\t--log <lvl>, --total, --warnpartial, --warnreach, --warnipkg"
         , "\t--ibcsubdir <path>, -i --idrispath <path>"
         , "\t--logging-categories <cats>"
         , "\nThe options need removing are:"
diff --git a/src/Idris/Parser.hs b/src/Idris/Parser.hs
--- a/src/Idris/Parser.hs
+++ b/src/Idris/Parser.hs
@@ -688,6 +688,8 @@
                     return ErrorHandler
         <|> do try (lchar '%' *> reserved "error_reverse");
                     return ErrorReverse
+        <|> do try (lchar '%' *> reserved "error_reduce");
+                    return ErrorReduce
         <|> do try (lchar '%' *> reserved "reflection");
                     return Reflection
         <|> do try (lchar '%' *> reserved "hint");
@@ -763,7 +765,7 @@
 params :: SyntaxInfo -> IdrisParser [PDecl]
 params syn =
     do reservedHL "parameters"; lchar '('; ns <- typeDeclList syn; lchar ')'
-       let ns' = [(n, ty) | (n, _, ty) <- ns]
+       let ns' = [(n, ty) | (_, n, _, ty) <- ns]
        openBlock
        let pvars = syn_params syn
        ds <- many (decl syn { syn_params = pvars ++ ns' })
@@ -903,7 +905,7 @@
                                  return (doc, argDocs, acc))
                     fc <- getFC
                     cons <- constraintList syn
-                    let cons' = [(c, ty) | (c, _, ty) <- cons]
+                    let cons' = [(c, ty) | (_, c, _, ty) <- cons]
                     (n_in, nfc) <- fnName
                     let n = expandNS syn n_in
                     cs <- many carg
@@ -953,11 +955,11 @@
                         fc <- getFC
                         en <- optional implementationName
                         cs <- constraintList syn
-                        let cs' = [(c, ty) | (c, _, ty) <- cs]
+                        let cs' = [(c, ty) | (_, c, _, ty) <- cs]
                         (cn, cnfc) <- fnName
                         args <- many (simpleExpr syn)
                         let sc = PApp fc (PRef cnfc [cnfc] cn) (map pexp args)
-                        let t = bindList (PPi constraint) cs sc
+                        let t = bindList (\r -> PPi constraint { pcount = r }) cs sc
                         pnames <- implementationUsing
                         ds <- implementationBlock syn
                         return [PImplementation doc argDocs syn fc cs' pnames acc opts cn cnfc args [] t en ds]
@@ -1429,6 +1431,11 @@
 pLangExt :: IdrisParser LanguageExt
 pLangExt = (reserved "TypeProviders" >> return TypeProviders)
        <|> (reserved "ErrorReflection" >> return ErrorReflection)
+       <|> (reserved "UniquenessTypes" >> return UniquenessTypes)
+       <|> (reserved "LinearTypes" >> return LinearTypes)
+       <|> (reserved "DSLNotation" >> return DSLNotation)
+       <|> (reserved "ElabReflection" >> return ElabReflection)
+       <|> (reserved "FirstClassReflection" >> return FCReflection)
 
 {-| Parses a totality
 
@@ -1696,6 +1703,7 @@
 loadSource :: Bool -> FilePath -> Maybe Int -> Idris ()
 loadSource lidr f toline
              = do logParser 1 ("Reading " ++ f)
+                  iReport   2 ("Reading " ++ f)
                   i <- getIState
                   let def_total = default_total i
                   file_in <- runIO $ readSource f
@@ -1783,8 +1791,7 @@
                   logLvl 10 (show (toAlist (idris_implicits i)))
                   logLvl 3 (show (idris_infixes i))
                   -- Now add all the declarations to the context
-                  v <- verbose
-                  when v $ iputStrLn $ "Type checking " ++ f
+                  iReport 1 $ "Type checking " ++ f
                   -- we totality check after every Mutual block, so if
                   -- anything is a single definition, wrap it in a
                   -- mutual block on its own
@@ -1795,11 +1802,12 @@
                   mapM_ (\n -> do logLvl 5 $ "Simplifying " ++ show n
                                   ctxt' <-
                                     do ctxt <- getContext
-                                       tclift $ simplifyCasedef n (getErasureInfo i) ctxt
+                                       tclift $ simplifyCasedef n [] [] (getErasureInfo i) ctxt
                                   setContext ctxt')
                            (map snd (idris_totcheck i))
                   -- build size change graph from simplified definitions
-                  logLvl 1 "Totality checking"
+                  iReport 3 $ "Totality checking " ++ f
+                  logLvl 1 $ "Totality checking " ++ f
                   i <- getIState
                   mapM_ buildSCG (idris_totcheck i)
                   mapM_ checkDeclTotality (idris_totcheck i)
@@ -1822,7 +1830,8 @@
 
                   logLvl 1 ("Finished " ++ f)
                   ibcsd <- valIBCSubDir i
-                  logLvl 1 "Universe checking"
+                  logLvl  1 $ "Universe checking " ++ f
+                  iReport 3 $ "Universe checking " ++ f
                   iucheck
                   let ibc = ibcPathNoFallback ibcsd f
                   i <- getIState
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
@@ -5,38 +5,39 @@
 License     : BSD3
 Maintainer  : The Idris Community.
 -}
-{-# LANGUAGE GeneralizedNewtypeDeriving, ConstraintKinds #-}
-{-# LANGUAGE PatternGuards, TupleSections                #-}
+{-# LANGUAGE ConstraintKinds, GeneralizedNewtypeDeriving, PatternGuards,
+             TupleSections #-}
 module Idris.Parser.Expr where
 
 import Idris.AbsSyntax
+import Idris.Core.TT
+import Idris.DSL
 import Idris.Parser.Helpers
 import Idris.Parser.Ops
-import Idris.DSL
-import Idris.Core.TT
 
 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 Control.Applicative
 import Control.Monad
 import Control.Monad.State.Strict
+import qualified Data.ByteString.UTF8 as UTF8
+import Data.Char
 import Data.Function (on)
-import Data.Maybe
-import qualified Data.List.Split as Spl
+import qualified Data.HashSet as HS
 import Data.List
+import qualified Data.List.Split as Spl
+import Data.Maybe
 import Data.Monoid
-import Data.Char
-import qualified Data.HashSet as HS
 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
 
 -- | Allow implicit type declarations
 allowImp :: SyntaxInfo -> SyntaxInfo
@@ -261,8 +262,8 @@
     updTactic ns (TDocStr (Left n)) = TDocStr . Left . fst $ updateB ns (n, NoFC)
     updTactic ns t = fmap (update ns) t
 
-    updTacImp ns (TacImp o st scr)  = TacImp o st (update ns scr)
-    updTacImp _  x                  = x
+    updTacImp ns (TacImp o st scr r) = TacImp o st (update ns scr) r
+    updTacImp _  x                   = x
 
     dropn :: Name -> [(Name, a)] -> [(Name, a)]
     dropn n [] = []
@@ -678,16 +679,16 @@
                                f
                                (PMatchApp fc ff)
                                (PRef fc [] (sMN 0 "match")))
-              <?> "matching application expression") <|> (do
-             fc <- getFC
-             i <- get
-             args <- many (do notEndApp; arg syn)
-             wargs <- if withAppAllowed syn && not (inPattern syn)
-                         then many (do notEndApp; reservedOp "|"; expr' syn)
-                         else return []
-             case args of
-               [] -> return f
-               _  -> return (withApp fc (flattenFromInt fc f args) wargs))
+                   <?> "matching application expression") <|>
+               (do fc <- getFC
+                   i <- get
+                   args <- many (do notEndApp; arg syn)
+                   wargs <- if withAppAllowed syn && not (inPattern syn)
+                              then many (do notEndApp; reservedOp "|"; expr' syn)
+                              else return []
+                   case args of
+                     [] -> return f
+                     _  -> return (withApp fc (flattenFromInt fc f args) wargs))
        <?> "function application"
    where
     -- bit of a hack to deal with the situation where we're applying a
@@ -914,7 +915,7 @@
 typeExpr :: SyntaxInfo -> IdrisParser PTerm
 typeExpr syn = do cs <- if implicitAllowed syn then constraintList syn else return []
                   sc <- expr (allowConstr syn)
-                  return (bindList (PPi constraint) cs sc)
+                  return (bindList (\r -> PPi (constraint { pcount = r })) cs sc)
                <?> "type signature"
 
 {- | Parses a lambda expression
@@ -941,7 +942,7 @@
                 ((do xt <- try $ tyOptDeclList (disallowImp syn)
                      fc <- getFC
                      sc <- lambdaTail
-                     return (bindList (PLam fc) xt sc))
+                     return (bindList (\r -> PLam fc) xt sc))
                  <|>
                  (do ps <- sepBy (do fc <- getFC
                                      e <- simpleExpr (disallowImp (syn { inPattern = True }))
@@ -1072,13 +1073,13 @@
 
 bindsymbol opts st syn
      = do symbol "->"
-          return (Exp opts st False)
+          return (Exp opts st False RigW)
 
 explicitPi opts st syn
    = do xt <- try (lchar '(' *> typeDeclList syn <* lchar ')')
         binder <- bindsymbol opts st syn
         sc <- expr (allowConstr syn)
-        return (bindList (PPi binder) xt sc)
+        return (bindList (\r -> PPi (binder { pcount = r })) xt sc)
 
 autoImplicit opts st syn
    = do kw <- reservedFC "auto"
@@ -1088,8 +1089,8 @@
         symbol "->"
         sc <- expr (allowConstr syn)
         highlightP kw AnnKeyword
-        return (bindList (PPi
-          (TacImp [] Dynamic (PTactics [ProofSearch True True 100 Nothing [] []]))) xt sc)
+        return (bindList (\r -> PPi
+          (TacImp [] Dynamic (PTactics [ProofSearch True True 100 Nothing [] []]) r)) xt sc)
 
 defaultImplicit opts st syn = do
    kw <- reservedFC "default"
@@ -1102,7 +1103,7 @@
    symbol "->"
    sc <- expr (allowConstr syn)
    highlightP kw AnnKeyword
-   return (bindList (PPi (TacImp [] Dynamic script)) xt sc)
+   return (bindList (\r -> PPi (TacImp [] Dynamic script r)) xt sc)
 
 normalImplicit opts st syn = do
    xt <- typeDeclList syn <* lchar '}'
@@ -1111,19 +1112,19 @@
    sc <- expr syn
    let (im,cl)
           = if implicitAllowed syn
-               then (Imp opts st False (Just (Impl False True False)) True,
+               then (Imp opts st False (Just (Impl False True False)) True RigW,
                       constraint)
-               else (Imp opts st False (Just (Impl False False False)) True,
-                     Imp opts st False (Just (Impl True False False)) True)
-   return (bindList (PPi im) xt
-           (bindList (PPi cl) cs sc))
+               else (Imp opts st False (Just (Impl False False False)) True RigW,
+                     Imp opts st False (Just (Impl True False False)) True RigW)
+   return (bindList (\r -> PPi (im { pcount = r })) xt
+           (bindList (\r -> PPi (cl { pcount = r })) cs sc))
 
 constraintPi opts st syn =
    do cs <- constraintList1 syn
       sc <- expr syn
       if implicitAllowed syn
-         then return (bindList (PPi constraint) cs sc)
-         else return (bindList (PPi (Imp opts st False (Just (Impl True False False)) True))
+         then return (bindList (\r -> PPi constraint { pcount = r }) cs sc)
+         else return (bindList (\r -> PPi (Imp opts st False (Just (Impl True False False)) True r))
                                cs sc)
 
 implicitPi opts st syn =
@@ -1181,11 +1182,11 @@
   ;
 @
 -}
-constraintList :: SyntaxInfo -> IdrisParser [(Name, FC, PTerm)]
+constraintList :: SyntaxInfo -> IdrisParser [(RigCount, Name, FC, PTerm)]
 constraintList syn = try (constraintList1 syn)
                      <|> return []
 
-constraintList1 :: SyntaxInfo -> IdrisParser [(Name, FC, PTerm)]
+constraintList1 :: SyntaxInfo -> IdrisParser [(RigCount, Name, FC, PTerm)]
 constraintList1 syn = try (do lchar '('
                               tys <- sepBy1 nexpr (lchar ',')
                               lchar ')'
@@ -1193,13 +1194,13 @@
                               return tys)
                   <|> try (do t <- opExpr (disallowImp syn)
                               reservedOp "=>"
-                              return [(defname, NoFC, t)])
+                              return [(RigW, defname, NoFC, t)])
                   <?> "type constraint list"
   where nexpr = try (do (n, fc) <- name; lchar ':'
                         e <- expr (disallowImp syn)
-                        return (n, fc, e))
+                        return (RigW, n, fc, e))
                 <|> do e <- expr (disallowImp syn)
-                       return (defname, NoFC, e)
+                       return (RigW, defname, NoFC, e)
         defname = sMN 0 "constraint"
 
 {- | Parses a type declaration list
@@ -1217,17 +1218,21 @@
   ;
 @
 -}
-typeDeclList :: SyntaxInfo -> IdrisParser [(Name, FC, PTerm)]
-typeDeclList syn = try (sepBy1 (do (x, xfc) <- fnName
+typeDeclList :: SyntaxInfo -> IdrisParser [(RigCount, Name, FC, PTerm)]
+typeDeclList syn = try (sepBy1 (do rig <- option RigW rigCount
+                                   (x, xfc) <- fnName
                                    lchar ':'
                                    t <- typeExpr (disallowImp syn)
-                                   return (x, xfc, t))
+                                   return (rig, x, xfc, t))
                            (lchar ','))
                    <|> do ns <- sepBy1 name (lchar ',')
                           lchar ':'
                           t <- typeExpr (disallowImp syn)
-                          return (map (\(x, xfc) -> (x, xfc, t)) ns)
+                          return (map (\(x, xfc) -> (RigW, x, xfc, t)) ns)
                    <?> "type declaration list"
+  where
+    rigCount = do lchar '1'; return Rig1
+           <|> do lchar '0'; return Rig0
 
 {- | Parses a type declaration list with optional parameters
 @
@@ -1241,11 +1246,11 @@
 NameOrPlaceHolder ::= Name | '_';
 @
 -}
-tyOptDeclList :: SyntaxInfo -> IdrisParser [(Name, FC, PTerm)]
+tyOptDeclList :: SyntaxInfo -> IdrisParser [(RigCount, Name, FC, PTerm)]
 tyOptDeclList syn = sepBy1 (do (x, fc) <- nameOrPlaceholder
                                t <- option Placeholder (do lchar ':'
                                                            expr syn)
-                               return (x, fc, t))
+                               return (RigW, x, fc, t))
                            (lchar ',')
                     <?> "type declaration list"
     where  nameOrPlaceholder :: IdrisParser (Name, FC)
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
@@ -455,9 +455,9 @@
 
 {-* Syntax helpers-}
 -- | Bind constraints to term
-bindList :: (Name -> FC -> PTerm -> PTerm -> PTerm) -> [(Name, FC, PTerm)] -> PTerm -> PTerm
-bindList b []              sc = sc
-bindList b ((n, fc, t):bs) sc = b n fc t (bindList b bs sc)
+bindList :: (RigCount -> Name -> FC -> PTerm -> PTerm -> PTerm) -> [(RigCount, Name, FC, PTerm)] -> PTerm -> PTerm
+bindList b []                 sc = sc
+bindList b ((r, n, fc, t):bs) sc = b r n fc t (bindList b bs sc)
 
 {- | @commaSeparated p@ parses one or more occurences of `p`,
      separated by commas and optional whitespace. -}
diff --git a/src/Idris/PartialEval.hs b/src/Idris/PartialEval.hs
--- a/src/Idris/PartialEval.hs
+++ b/src/Idris/PartialEval.hs
@@ -97,37 +97,37 @@
   where
     -- Specialise static argument in type by let-binding provided value instead
     -- of expecting it as a function argument
-    st ((ExplicitS, v) : xs) (Bind n (Pi _ t _) sc)
+    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)
+    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 ((UnifiedD, _) : xs) (Bind n (Pi _ _ t _) sc)
          = st xs sc
     -- Keep types as is
-    st (_ : xs) (Bind n (Pi i t k) sc)
-         = Bind n (Pi i t k) (st xs sc)
+    st (_ : xs) (Bind n (Pi rig i t k) sc)
+         = Bind n (Pi rig i t k) (st xs sc)
     st _ t = t
 
     -- 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 rig i t k) sc)
          = do amap <- get
               case lookup imp amap of
                    Just n' ->
                         do put (amap ++ [((UnifiedD, Erased), n)])
                            sc' <- unifyEq xs (subst n (P Bound n' Erased) sc)
-                           return (Bind n (Pi i t k) sc') -- erase later
+                           return (Bind n (Pi rig i t k) sc') -- erase later
                    _ -> do put (amap ++ [(imp, n)])
                            sc' <- unifyEq xs sc
-                           return (Bind n (Pi i t k) sc')
-    unifyEq (x : xs) (Bind n (Pi i t k) sc)
+                           return (Bind n (Pi rig i t k) sc')
+    unifyEq (x : xs) (Bind n (Pi rig i t k) sc)
          = do args <- get
               put (args ++ [(x, n)])
               sc' <- unifyEq xs sc
-              return (Bind n (Pi i t k) sc')
+              return (Bind n (Pi rig i t k) sc')
     unifyEq xs t = do args <- get
                       put (args ++ (zip xs (repeat (sUN "_"))))
                       return t
@@ -141,13 +141,13 @@
 mkPE_TyDecl :: IState -> [(PEArgType, Term)] -> Type -> PTerm
 mkPE_TyDecl ist args ty = mkty args ty
   where
-    mkty ((ExplicitD, v) : xs) (Bind n (Pi _ t k) sc)
+    mkty ((ExplicitD, v) : xs) (Bind n (Pi rig _ t k) sc)
        = PPi expl n NoFC (delab ist (generaliseIn t)) (mkty xs sc)
-    mkty ((ConstraintD, v) : xs) (Bind n (Pi _ t k) sc)
+    mkty ((ConstraintD, v) : xs) (Bind n (Pi rig _ t k) sc)
          | concreteInterface ist t = mkty xs sc
          | interfaceConstraint ist t
              = PPi constraint n NoFC (delab ist (generaliseIn t)) (mkty xs sc)
-    mkty ((ImplicitD _, v) : xs) (Bind n (Pi _ t k) sc)
+    mkty ((ImplicitD _, v) : xs) (Bind n (Pi rig _ t k) sc)
          = PPi impl n NoFC (delab ist (generaliseIn t)) (mkty xs sc)
 
     mkty (_ : xs) t
@@ -276,7 +276,7 @@
               -> [(PEArgType, Term)]
               -> PEDecl
 mkPE_TermDecl ist newname sname specty ns
-      {- We need to erase the *dynamic* arguments 
+      {- 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
@@ -285,12 +285,12 @@
          on the RHS.
          -}
     = let deps = getDepNames (eraseRet specty)
-          lhs = eraseDeps deps $ 
+          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) $ 
+                   --      ++ showTmImpls rhs) $
                    lookupCtxtExact sname (idris_patdefs ist)
           newpats = case patdef of
                          Nothing -> PEDecl lhs rhs [(lhs, rhs)] True
@@ -305,7 +305,7 @@
 
   -- 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) 
+  getDepNames (PPi _ n _ _ sc)
         | n `elem` allNamesIn sc = n : getDepNames sc
         | otherwise = getDepNames sc
   getDepNames tm = []
@@ -337,7 +337,7 @@
          | 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)
diff --git a/src/Idris/Primitives.hs b/src/Idris/Primitives.hs
--- a/src/Idris/Primitives.hs
+++ b/src/Idris/Primitives.hs
@@ -32,7 +32,7 @@
 
 ty :: [Const] -> Const -> Type
 ty []     x = Constant x
-ty (t:ts) x = Bind (sMN 0 "T") (Pi Nothing (Constant t) (TType (UVar [] (-3)))) (ty ts x)
+ty (t:ts) x = Bind (sMN 0 "T") (Pi RigW Nothing (Constant t) (TType (UVar [] (-3)))) (ty ts x)
 
 total, partial, iopartial :: Totality
 total = Total []
@@ -455,8 +455,8 @@
 
 strToInt :: IntTy -> [Const] -> Maybe Const
 strToInt ity [Str x] = case reads x of
-                         [(n,"")] -> Just $ toInt ity (n :: Integer)
-                         _        -> Just $ I 0
+                         [(n,s)] -> Just $ if all isSpace s then toInt ity (n :: Integer) else I 0
+                         _       -> Just $ I 0
 strToInt _ _ = Nothing
 
 intToFloat :: [Const] -> Maybe Const
@@ -481,8 +481,8 @@
 c_floatToStr [Fl x] = Just $ Str (show x)
 c_floatToStr _ = Nothing
 c_strToFloat [Str x] = case reads x of
-                         [(n,"")] -> Just $ Fl n
-                         _ -> Just $ Fl 0
+                         [(n,s)] -> Just $ Fl (if all isSpace s then n else 0)
+                         _       -> Just $ Fl 0
 c_strToFloat _ = Nothing
 
 p_fPrim :: (Double -> Double) -> [Const] -> Maybe Const
diff --git a/src/Idris/ProofSearch.hs b/src/Idris/ProofSearch.hs
--- a/src/Idris/ProofSearch.hs
+++ b/src/Idris/ProofSearch.hs
@@ -49,7 +49,7 @@
                 return ()) True
       where
         tryAll []     = fail "No trivial solution"
-        tryAll ((x, b):xs)
+        tryAll ((x, _, b):xs)
            = do -- if type of x has any holes in it, move on
                 hs <- get_holes
                 let badhs = hs -- filter (flip notElem holesOK) hs
@@ -85,7 +85,7 @@
                 return ()) True
       where
         tryAll []     = fail "No trivial solution"
-        tryAll ((x, b):xs)
+        tryAll ((x, _, b):xs)
            = do -- if type of x has any holes in it, move on
                 hs <- get_holes
                 let badhs = hs -- filter (flip notElem holesOK) hs
@@ -123,7 +123,7 @@
 cantSolveGoal = do g <- goal
                    env <- get_env
                    lift $ tfail $
-                      CantSolveGoal g (map (\(n,b) -> (n, binderTy b)) env)
+                      CantSolveGoal g (map (\(n,_,b) -> (n, binderTy b)) env)
 
 proofSearch :: Bool -- ^ recursive search (False for 'refine')
             -> Bool -- ^ invoked from a tactic proof. If so, making new metavariables is meaningless, and there should be an error reported instead.
@@ -300,7 +300,7 @@
              tryLocals d locs tys env
 
     tryLocals d locs tys [] = fail "Locals failed"
-    tryLocals d locs tys ((x, t) : xs)
+    tryLocals d locs tys ((x, _, t) : xs)
        | x `elem` locs || x `notElem` psnames = tryLocals d locs tys xs
        | otherwise = try' (tryLocal d (x : locs) tys x t)
                           (tryLocals d locs tys xs) True
@@ -346,7 +346,7 @@
         TermPart ty,
         TextPart "using proof search, but proof search only works on datatypes with constructors."] ++
        case ty of
-         (Bind _ (Pi _ _ _) _) -> [TextPart "In particular, function types are not supported."]
+         (Bind _ (Pi _ _ _ _) _) -> [TextPart "In particular, function types are not supported."]
          _ -> []
 
 -- | Resolve interfaces. This will only pick up 'normal'
@@ -475,9 +475,9 @@
 
     introImps = do g <- goal
                    case g of
-                        (Bind _ (Pi _ _ _) sc) -> do attack; intro Nothing
-                                                     num <- introImps
-                                                     return (num + 1)
+                        (Bind _ (Pi _ _ _ _) sc) -> do attack; intro Nothing
+                                                       num <- introImps
+                                                       return (num + 1)
                         _ -> return 0
 
     solven n = replicateM_ n solve
diff --git a/src/Idris/Prover.hs b/src/Idris/Prover.hs
--- a/src/Idris/Prover.hs
+++ b/src/Idris/Prover.hs
@@ -82,8 +82,8 @@
   = case envAtFocus (proof e) of
          OK env -> names env
   where names [] = []
-        names ((MN _ _, _) : bs) = names bs
-        names ((n, _) : bs) = show n : names bs
+        names ((MN _ _, _, _) : bs) = names bs
+        names ((n, _, _) : bs) = show n : names bs
 
 prove :: Bool -> ElabInfo -> Ctxt OptInfo -> Context -> Bool -> Name -> Type -> Idris ()
 prove mode info opt ctxt lit n ty
@@ -174,18 +174,18 @@
                     delab ist t
 
     assumptionNames :: Env -> [Name]
-    assumptionNames = map fst
+    assumptionNames = map fstEnv
 
     prettyPs :: Bool -> Binder Type -> [(Name, Bool)] -> Env -> Doc OutputAnnotation
     prettyPs all g bnd [] = empty
-    prettyPs all g bnd ((n@(MN _ r), _) : bs)
+    prettyPs all g bnd ((n@(MN _ r), _, _) : bs)
         | not all && r == txt "rewrite_rule" = prettyPs all g ((n, False):bnd) bs
-    prettyPs all g bnd ((n@(MN _ _), _) : bs)
+    prettyPs all g bnd ((n@(MN _ _), _, _) : bs)
         | not (all || n `elem` freeEnvNames bs || n `elem` goalNames g) = prettyPs all g bnd bs
-    prettyPs all g bnd ((n, Let t v) : bs) =
+    prettyPs all g bnd ((n, _, Let t v) : bs) =
       line <> bindingOf n False <+> text "=" <+> tPretty bnd v <+> colon <+>
         align (tPretty bnd t) <> prettyPs all g ((n, False):bnd) bs
-    prettyPs all g bnd ((n, b) : bs) =
+    prettyPs all g bnd ((n, _, b) : bs) =
       line <> bindingOf n False <+> colon <+>
       align (tPretty bnd (binderTy b)) <> prettyPs all g ((n, False):bnd) bs
 
@@ -227,7 +227,7 @@
         nest nestingSize (align . cat . punctuate (text ",") . map (`bindingOf` False) $ hs)
 
     freeEnvNames :: Env -> [Name]
-    freeEnvNames = concatMap (\(n, b) -> freeNames (Bind n b Erased))
+    freeEnvNames = concatMap (\(n, _, b) -> freeNames (Bind n b Erased))
 
 lifte :: ElabState EState -> ElabD a -> Idris a
 lifte st e = do (v, _) <- elabStep st e
@@ -468,7 +468,7 @@
                              (ploop fn d prompt prf e h')
 
 
-envCtxt env ctxt = foldl (\c (n, b) -> addTyDecl n Bound (binderTy b) c) ctxt env
+envCtxt env ctxt = foldl (\c (n, _, b) -> addTyDecl n Bound (binderTy b) c) ctxt env
 
 checkNameType :: ElabState EState -> [String] -> Name -> Idris (Bool, ElabState EState, Bool, [String], Either Err (Idris ()))
 checkNameType e prf n = do
@@ -478,7 +478,7 @@
     idrisCatch (do
         let OK env = envAtFocus (proof e)
             ctxt'  = envCtxt env ctxt
-            bnd    = map (\x -> (fst x, False)) env
+            bnd    = map (\x -> (fstEnv x, False)) env
             ist'   = ist { tt_ctxt = ctxt' }
         putIState ist'
         -- Unlike the REPL, metavars have no special treatment, to
@@ -505,7 +505,7 @@
             action = case tm of
               TType _ ->
                 iPrintTermWithType (prettyImp ppo (PType emptyFC)) type1Doc
-              _ -> let bnd = map (\x -> (fst x, False)) env in
+              _ -> let bnd = map (\x -> (fstEnv x, False)) env in
                    iPrintTermWithType (pprintPTerm ppo bnd [] infixes (delab ist tm))
                                        (pprintPTerm ppo bnd [] infixes (delab ist ty))
         putIState ist
@@ -522,7 +522,7 @@
          let OK env = envAtFocus (proof e)
              ctxt'  = envCtxt env ctxt
              ist'   = ist { tt_ctxt = ctxt' }
-             bnd    = map (\x -> (fst x, False)) env
+             bnd    = map (\x -> (fstEnv x, False)) env
          putIState ist'
          (tm, ty) <- elabVal (recinfo proverfc) ERHS t
          let tm'     = force (normaliseAll ctxt' env tm)
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,9 @@
 License     : BSD3
 Maintainer  : The Idris Community.
 -}
-{-# LANGUAGE CPP, DeriveFunctor, FlexibleInstances, MultiParamTypeClasses,
-             PatternGuards #-}
+
+{-# LANGUAGE PatternGuards #-}
+
 module Idris.REPL
   ( idemodeStart
   , startServer
@@ -16,6 +17,23 @@
   , proofs
   ) where
 
+import Control.Category
+import Control.Concurrent
+import Control.Concurrent.Async (race)
+import Control.DeepSeq
+import qualified Control.Exception as X
+import Control.Monad
+import Control.Monad.Trans (lift)
+import Control.Monad.Trans.Except (runExceptT)
+import Control.Monad.Trans.State.Strict (evalStateT, 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 Idris.AbsSyntax
 import Idris.Apropos (apropos, aproposModules)
 import Idris.ASTUtils
@@ -28,8 +46,9 @@
 import Idris.Core.Unify
 import Idris.Core.WHNF
 import Idris.Coverage
+import Idris.DataOpts
 import Idris.Delaborate
-import Idris.Docs hiding (Doc)
+import Idris.Docs
 import Idris.Docstrings (overview, renderDocTerm, renderDocstring)
 import Idris.Elab.Clause
 import Idris.Elab.Term
@@ -55,36 +74,8 @@
 import Idris.TypeSearch (searchByType)
 import Idris.WhoCalls
 import IRTS.Compiler
-
-import Util.DynamicLinker
-import Util.Net (listenOnLocalhost, listenOnLocalhostAnyPort)
-import Util.Pretty hiding ((</>))
-import Util.System
-
-import Version_idris (gitHash)
-
-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 Control.Monad
-import Control.Monad.Trans (lift)
-import Control.Monad.Trans.Except (ExceptT, runExceptT)
-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 Network
+import Prelude hiding (id, (.), (<$>))
 import System.Console.Haskeline as H
 import System.Directory
 import System.Environment
@@ -96,6 +87,11 @@
 import System.IO
 import System.Process
 import Text.Trifecta.Result (ErrInfo(..), Result(..))
+import Util.DynamicLinker
+import Util.Net (listenOnLocalhost, listenOnLocalhostAnyPort)
+import Util.Pretty hiding ((</>))
+import Util.System
+import Version_idris (gitHash)
 
 -- | Run the REPL
 repl :: IState -- ^ The initial state
@@ -194,7 +190,7 @@
            setErrContext True
            setOutH h
            setQuiet True
-           setVerbose False
+           setVerbose 0
            mods <- loadInputs [f] toline
            ist <- getIState
            return (ist, f)
@@ -396,10 +392,15 @@
      runIO . hPutStrLn h $ IdeMode.convSExp "return" msg id
 runIdeModeCommand h id orig fn mods (IdeMode.Metavariables cols) =
   do ist <- getIState
-     let mvs = reverse $ map fst (idris_metavars ist) \\ primDefs
+     let mvs = reverse $ [ (n, i)
+                         | (n, (_, i, _, _, _)) <- idris_metavars ist
+                         , not (n `elem` primDefs)
+                         ]
      let ppo = ppOptionIst ist
      -- splitMvs is a list of pairs of names and their split types
-     let splitMvs = mapSnd (splitPi ist) (mvTys ist mvs)
+     let splitMvs = [ (n, (premises, concl, tm))
+                    | (n, i, ty) <- mvTys ist mvs
+                    , let (premises, concl, tm) = splitPi ist i ty]
      -- mvOutput is the pretty-printed version ready for conversion to SExpr
      let mvOutput = map (\(n, (hs, c)) -> (n, hs, c)) $
                     mapPair show
@@ -413,20 +414,24 @@
      runIO . hPutStrLn h $
        IdeMode.convSExp "return" (IdeMode.SymbolAtom "ok", mvOutput) id
   where mapPair f g xs = zip (map (f . fst) xs) (map (g . snd) xs)
-        mapSnd f xs = zip (map fst xs) (map (f . snd) xs)
+        firstOfThree (x, y, z) = x
+        mapThird f xs = map (\(x, y, z) -> (x, y, f z)) xs
 
         -- | Split a function type into a pair of premises, conclusion.
         -- Each maintains both the original and delaborated versions.
-        splitPi :: IState -> Type -> ([(Name, Type, PTerm)], Type, PTerm)
-        splitPi ist (Bind n (Pi _ t _) rest) =
-          let (hs, c, pc) = splitPi ist rest in
+        splitPi :: IState -> Int -> Type -> ([(Name, Type, PTerm)], Type, PTerm)
+        splitPi ist i (Bind n (Pi _ _ t _) rest) | i > 0 =
+          let (hs, c, pc) = splitPi ist (i - 1) rest in
             ((n, t, delabTy' ist [] t False False True):hs,
              c, delabTy' ist [] c False False True)
-        splitPi ist tm = ([], tm, delabTy' ist [] tm False False True)
+        splitPi ist i tm = ([], tm, delabTy' ist [] tm False False True)
 
         -- | Get the types of a list of metavariable names
-        mvTys :: IState -> [Name] -> [(Name, Type)]
-        mvTys ist = mapSnd vToP . mapMaybe (flip lookupTyNameExact (tt_ctxt ist))
+        mvTys :: IState -> [(Name, Int)] -> [(Name, Int, Type)]
+        mvTys ist mvs = [ (n, i, ty)
+                        | (n, i) <- mvs
+                        , ty <- maybeToList (fmap (vToP . snd) (lookupTyNameExact n (tt_ctxt ist)))
+                        ]
 
         -- | Show a type and its corresponding PTerm in a format suitable
         -- for the IDE - that is, pretty-printed and annotated.
@@ -586,6 +591,8 @@
 idemodeProcess :: FilePath -> Command -> Idris ()
 idemodeProcess fn Warranty = process fn Warranty
 idemodeProcess fn Help = process fn Help
+idemodeProcess fn (RunShellCommand cmd) =
+  iPrintError ":! is not currently supported in IDE mode."
 idemodeProcess fn (ChangeDirectory f) =
   do process fn (ChangeDirectory f)
      dir <- runIO $ getCurrentDirectory
@@ -813,6 +820,7 @@
 process :: FilePath -> Command -> Idris ()
 process fn Help = iPrintResult displayHelp
 process fn Warranty = iPrintResult warranty
+process fn (RunShellCommand cmd) = runIO $ system cmd >> return ()
 process fn (ChangeDirectory f)
                  = do runIO $ setCurrentDirectory f
                       return ()
@@ -1229,7 +1237,8 @@
 process fn (Execute tm)
                    = idrisCatch
                        (do ist <- getIState
-                           (m, _) <- elabVal (recinfo (fileFC "toplevel")) ERHS (elabExec fc tm)
+                           (m_in, _) <- elabVal (recinfo (fileFC "toplevel")) ERHS (elabExec fc tm)
+                           m <- applyOpts m_in
                            (tmpn, tmph) <- runIO $ tempfile ""
                            runIO $ hClose tmph
                            t <- codegen
@@ -1273,7 +1282,7 @@
          case lookupCtxt n (idris_patdefs i) of
            [] -> iPrintError $ "Unknown name " ++ show n
            [(_, tms)] ->
-             iRenderResult (vsep (map (pprintPTerm ppOpts 
+             iRenderResult (vsep (map (pprintPTerm ppOpts
                                                    []
                                                    []
                                                    (idris_infixes i))
@@ -1448,7 +1457,6 @@
             ty' = normaliseC ctxt [] ty
         iPrintResult =<< renderExternal fmt width (pprintDelab ist tm)
 
-
 showTotal :: Totality -> IState -> Doc OutputAnnotation
 showTotal t@(Partial (Other ns)) i
    = text "possibly not total due to:" <$>
@@ -1517,7 +1525,7 @@
         ppMissing _ = empty
 
         ppTy :: Bool -> IState -> (Name, TypeInfo) -> Doc OutputAnnotation
-        ppTy amb ist (n, TI constructors isCodata _ _ _)
+        ppTy amb ist (n, TI constructors isCodata _ _ _ _)
           = kwd key <+> prettyName True amb [] n <+> colon <+>
             align (pprintDelabTy ist n) <+> kwd "where" <$>
             indent 2 (vsep (map (ppCon False ist) constructors))
@@ -1538,4 +1546,3 @@
 replSettings hFile = setComplete replCompletion $ defaultSettings {
                        historyFile = hFile
                      }
-
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
@@ -17,6 +17,7 @@
              | Reload
              | Watch
              | Load FilePath (Maybe Int) -- up to maximum line number
+             | RunShellCommand FilePath
              | ChangeDirectory FilePath
              | ModImport String
              | Edit
@@ -32,6 +33,7 @@
              | Universes
              | LogLvl Int
              | LogCategory [LogCat]
+             | Verbosity Int
              | Spec PTerm
              | WHNF PTerm
              | TestInline PTerm
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
@@ -78,6 +78,7 @@
   , noArgCmd ["w", "watch"] Watch "Watch the current file for changes"
   , (["l", "load"], FileArg, "Load a new file"
     , strArg (\f -> Load f Nothing))
+  , (["!"], ShellCommandArg, "Run a shell command", strArg RunShellCommand)
   , (["cd"], FileArg, "Change working directory"
     , strArg ChangeDirectory)
   , (["module"], ModuleArg, "Import an extra module", moduleArg ModImport) -- NOTE: dragons
@@ -118,9 +119,12 @@
   , (["pp", "pprint"], (SeqArgs OptionArg (SeqArgs NumberArg NameArg))
     , "Pretty prints an Idris function in either LaTeX or HTML and for a specified width."
     , cmd_pprint)
+  , (["verbosity"], NumberArg, "Set verbosity level", cmd_verb)
   ]
   where optionsList = intercalate ", " $ map fst setOptions
 
+
+parserCommands :: CommandTable
 parserCommands =
   [ noArgCmd ["u", "universes"] Universes "Display universe constraints"
   , noArgCmd ["errorhandlers"] ListErrorHandlers "List registered error handlers"
@@ -146,7 +150,7 @@
   , proofArgCmd ["mc", "makecase"] MakeCase
       ":mc <line> <name> adds a case block for the definition of the metavariable on the line"
   , proofArgCmd ["ml", "makelemma"] MakeLemma "?"
-  , (["log"], NumberArg, "Set logging verbosity level", cmd_log)
+  , (["log"], NumberArg, "Set logging level", cmd_log)
   , ( ["logcats"]
     , ManyArgs NameArg
     , "Set logging categories"
@@ -238,8 +242,6 @@
           return $ Right (cmd t)
     try noArg <|> try justOperator <|> properArg
 
-
-
 genArg :: String -> P.IdrisParser a -> (a -> Command)
            -> String -> P.IdrisParser (Either String Command)
 genArg argName argParser cmd name = do
@@ -336,16 +338,13 @@
   where
     maintm = PRef (fileFC "(repl)") [] (sNS (sUN "main") ["Main"])
 
-
 cmd_dynamic :: String -> P.IdrisParser (Either String Command)
 cmd_dynamic name = do
     let optArg = do l <- many anyChar
                     if (l /= "")
                         then return $ Right (DynamicLink l)
                         else return $ Right ListDynamic
-
     let failure = return $ Left $ "Usage is :" ++ name ++ " [<library>]"
-
     try optArg <|> failure
 
 cmd_pprint :: String -> P.IdrisParser (Either String Command)
@@ -362,8 +361,6 @@
         ppFormat = (discard (P.symbol "html") >> return HTMLOutput)
                <|> (discard (P.symbol "latex") >> return LaTeXOutput)
 
-
-
 cmd_compile :: String -> P.IdrisParser (Either String Command)
 cmd_compile name = do
     let defaultCodegen = Via IBCFormat "c"
@@ -404,6 +401,12 @@
     i <- fmap (fromIntegral . fst) P.natural
     eof
     return (Right (LogLvl i))
+
+cmd_verb :: String -> P.IdrisParser (Either String Command)
+cmd_verb name = do
+    i <- fmap (fromIntegral . fst) P.natural
+    eof
+    return (Right (Verbosity i))
 
 cmd_cats :: String -> P.IdrisParser (Either String Command)
 cmd_cats name = do
diff --git a/src/Idris/Reflection.hs b/src/Idris/Reflection.hs
--- a/src/Idris/Reflection.hs
+++ b/src/Idris/Reflection.hs
@@ -314,9 +314,9 @@
 
 reifyTTBinderApp :: (Term -> ElabD a) -> Name -> [Term] -> ElabD (Binder a)
 reifyTTBinderApp reif f [t]
-                      | f == reflm "Lam" = liftM Lam (reif t)
+                      | f == reflm "Lam" = liftM (Lam RigW) (reif t)
 reifyTTBinderApp reif f [t, k]
-                      | f == reflm "Pi" = liftM2 (Pi Nothing) (reif t) (reif k)
+                      | f == reflm "Pi" = liftM2 (Pi RigW Nothing) (reif t) (reif k)
 reifyTTBinderApp reif f [x, y]
                       | f == reflm "Let" = liftM2 Let (reif x) (reif y)
 reifyTTBinderApp reif f [t]
@@ -326,7 +326,7 @@
 reifyTTBinderApp reif f [x, y]
                       | f == reflm "Guess" = liftM2 Guess (reif x) (reif y)
 reifyTTBinderApp reif f [t]
-                      | f == reflm "PVar" = liftM PVar (reif t)
+                      | f == reflm "PVar" = liftM (PVar RigW) (reif t)
 reifyTTBinderApp reif f [t]
                       | f == reflm "PVTy" = liftM PVTy (reif t)
 reifyTTBinderApp _ f args = fail ("Unknown reflection binder: " ++ show (f, args))
@@ -577,12 +577,12 @@
      fill (reflectConstant c); solve
 
 reflectBinderQuotePattern :: ([Name] -> a -> ElabD ()) -> Raw -> [Name] -> Binder a -> ElabD ()
-reflectBinderQuotePattern q ty unq (Lam t)
+reflectBinderQuotePattern q ty unq (Lam _ t)
    = do t' <- claimTy (sMN 0 "ty") ty; movelast t'
         fill $ reflCall "Lam" [ty, Var t']
         solve
         focus t'; q unq t
-reflectBinderQuotePattern q ty unq (Pi _ t k)
+reflectBinderQuotePattern q ty unq (Pi _ _ t k)
    = do t' <- claimTy (sMN 0 "ty") ty; movelast t'
         k' <- claimTy (sMN 0 "k") ty; movelast k';
         fill $ reflCall "Pi" [ty, Var t', Var k']
@@ -619,7 +619,7 @@
         solve
         focus x'; q unq x
         focus y'; q unq y
-reflectBinderQuotePattern q ty unq (PVar t)
+reflectBinderQuotePattern q ty unq (PVar _ t)
    = do t' <- claimTy (sMN 0 "ty") ty; movelast t'
         fill $ reflCall "PVar" [ty, Var t']
         solve
@@ -749,9 +749,9 @@
 reflectBinder = reflectBinderQuote reflectTTQuote (reflm "TT") []
 
 reflectBinderQuote :: ([Name] -> a -> Raw) -> Name -> [Name] -> Binder a -> Raw
-reflectBinderQuote q ty unq (Lam t)
+reflectBinderQuote q ty unq (Lam _ t)
    = reflCall "Lam" [Var ty, q unq t]
-reflectBinderQuote q ty unq (Pi _ t k)
+reflectBinderQuote q ty unq (Pi _ _ t k)
    = reflCall "Pi" [Var ty, q unq t, q unq k]
 reflectBinderQuote q ty unq (Let x y)
    = reflCall "Let" [Var ty, q unq x, q unq y]
@@ -763,7 +763,7 @@
    = reflCall "GHole" [Var ty, q unq t]
 reflectBinderQuote q ty unq (Guess x y)
    = reflCall "Guess" [Var ty, q unq x, q unq y]
-reflectBinderQuote q ty unq (PVar t)
+reflectBinderQuote q ty unq (PVar _ t)
    = reflCall "PVar" [Var ty, q unq t]
 reflectBinderQuote q ty unq (PVTy t)
    = reflCall "PVTy" [Var ty, q unq t]
@@ -804,7 +804,7 @@
 
 -- | Reflect the environment of a proof into a List (TTName, Binder TT)
 reflectEnv :: Env -> Raw
-reflectEnv = foldr consToEnvList emptyEnvList
+reflectEnv = foldr consToEnvList emptyEnvList . envBinders
   where
     consToEnvList :: (Name, Binder Term) -> Raw -> Raw
     consToEnvList (n, b) l
@@ -823,8 +823,10 @@
     emptyEnvList = raw_apply (Var (sNS (sUN "Nil") ["List", "Prelude"]))
                              [envTupleType]
 
+-- Reflected environments don't get the RigCount (for the moment, at least)
 reifyEnv :: Term -> ElabD Env
-reifyEnv = reifyList (reifyPair reifyTTName (reifyTTBinder reifyTT (reflm "TT")))
+reifyEnv tm = do preEnv <- reifyList (reifyPair reifyTTName (reifyTTBinder reifyTT (reflm "TT"))) tm
+                 return $ map (\(n, b) -> (n, RigW, b)) preEnv
 
 -- | Reflect an error into the internal datatype of Idris -- TODO
 rawBool :: Bool -> Raw
@@ -1088,7 +1090,7 @@
 -- come from a lookup in idris_implicits on IState.
 getArgs :: [PArg] -> Raw -> ([RFunArg], Raw)
 getArgs []     r = ([], r)
-getArgs (a:as) (RBind n (Pi _ ty _) sc) =
+getArgs (a:as) (RBind n (Pi _ _ ty _) sc) =
   let (args, res) = getArgs as sc
       erased = if InaccessibleArg `elem` argopts a then RErased else RNotErased
       arg' = case a of
@@ -1119,7 +1121,7 @@
         mkFunClause ([], lhs, rhs) = RMkFunClause lhs rhs
         mkFunClause (((n, ty) : ns), lhs, rhs) = mkFunClause (ns, bind lhs, bind rhs) where
           bind Impossible = Impossible
-          bind tm = Bind n (PVar ty) tm
+          bind tm = Bind n (PVar RigW ty) tm
 
 -- | Build the reflected datatype definition(s) that correspond(s) to
 -- a provided unqualified name
diff --git a/src/Idris/Termination.hs b/src/Idris/Termination.hs
--- a/src/Idris/Termination.hs
+++ b/src/Idris/Termination.hs
@@ -48,7 +48,7 @@
 --
 -- If so, set the 'AllGuarded' flag which can be used by the productivity check
 checkIfGuarded :: Name -> Idris ()
-checkIfGuarded n 
+checkIfGuarded n
    = do i <- get
         let ctxt = tt_ctxt i
         case lookupDefExact n ctxt of
@@ -65,9 +65,9 @@
                            Nothing -> False
                            Just fs -> AllGuarded `elem` fs
 
-    -- Top level thing always needs to be a constructor application if 
+    -- 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) 
+    allGuarded names i (STerm t)
           | (P _ fn _, args) <- unApply t,
             guard fn i
             = and (map (guardedTerm names i) args)
@@ -86,7 +86,7 @@
                 = 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
@@ -112,13 +112,13 @@
   where
     args t = [0..length (getArgTys t)-1]
 
-    cp i (Bind n (Pi _ aty _) sc)
+    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 (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)
@@ -163,7 +163,7 @@
         t <- getTotality n
         i <- getIState
         ctxt' <- do ctxt <- getContext
-                    tclift $ simplifyCasedef n (getErasureInfo i) ctxt
+                    tclift $ simplifyCasedef n [] [] (getErasureInfo i) ctxt
         setContext ctxt'
         ctxt <- getContext
         i <- getIState
@@ -185,7 +185,7 @@
                             case unApply (getRetTy ty) of
                               (P _ tyn _, _) -> do
                                  let ms = case lookupCtxt tyn (idris_datatypes i) of
-                                       [TI _ _ _ _ xs@(_:_)] -> xs
+                                       [TI _ _ _ _ xs@(_:_) _] -> xs
                                        ts -> [tyn]
                                  checkPositive ms (n, ty)
                               _-> return $ Total []
@@ -239,7 +239,7 @@
                  case getPartial ist [] ns of
                       Nothing -> return ()
                       Just bad -> do let t' = Partial (Other bad)
-                                     logCoverage 2 $ "Set to " ++ show t'
+                                     logCoverage 2 $ "Set in verify to " ++ show t'
                                      setTotality n t'
                                      addIBC (IBCTotal n t')
               _ -> return ()
@@ -270,8 +270,8 @@
 buildSCG :: (FC, Name) -> Idris ()
 buildSCG (_, n) = do
    ist <- getIState
-   case lookupCtxt n (idris_callgraph ist) of
-       [cg] -> case lookupDefExact n (tt_ctxt ist) of
+   case lookupCtxtExact n (idris_callgraph ist) of
+       Just 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"
@@ -280,8 +280,7 @@
                   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)
+       _ -> logCoverage 5 $ "Could not build SCG for " ++ show n ++ "\n"
 
 delazy = delazy' False -- not lazy codata
 delazy' all t@(App _ f a)
@@ -369,7 +368,7 @@
         = 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 Unguarded v pvs pargs ++
           -- Substitute in the scope since this might reveal some useful
           -- structure
           findCalls cases guarded (substV v e) pvs pargs
@@ -429,8 +428,8 @@
      = 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 []
+     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))]
@@ -471,15 +470,15 @@
 
       isInductive (P _ nty _) (P _ nty' _) =
           let (co, muts) = case lookupCtxt nty (idris_datatypes ist) of
-                                [TI _ x _ _ muts] -> (x, muts)
+                                [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 (Bind x (PVar _ ty) sc) = dePat (instantiate (P Bound x ty) sc)
   dePat t = t
 
-  patvars (Bind x (PVar _) sc) = x : patvars sc
+  patvars (Bind x (PVar _ _) sc) = x : patvars sc
   patvars _ = []
 
   allGuarded n ist = case lookupCtxtExact n (idris_flags ist) of
@@ -634,16 +633,16 @@
 -- 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
+-- 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/Transforms.hs b/src/Idris/Transforms.hs
--- a/src/Idris/Transforms.hs
+++ b/src/Idris/Transforms.hs
@@ -86,7 +86,7 @@
 -- (In general, this would not be true, but when we elaborate transformation
 -- rules we mangle the names so that it is true. While this feels a bit
 -- hacky, it's much easier to think about than mangling de Bruijn indices).
-  where depat ms (Bind n (PVar t) sc)
+  where depat ms (Bind n (PVar _ t) sc)
           = case lookup n ms of
                  Just tm -> depat ms (subst n tm sc)
                  _ -> depat ms sc -- no occurrence? Shouldn't happen
@@ -95,7 +95,7 @@
 matchTerm :: Term -> Term -> Maybe [(Name, Term)]
 matchTerm lhs tm = matchVars [] lhs tm
    where
-      matchVars acc (Bind n (PVar t) sc) tm
+      matchVars acc (Bind n (PVar _ t) sc) tm
            = matchVars (n : acc) (instantiate (P Bound n t) sc) tm
       matchVars acc sc tm
           = -- trace (show acc ++ ": " ++ show (sc, tm)) $
diff --git a/src/Idris/TypeSearch.hs b/src/Idris/TypeSearch.hs
--- a/src/Idris/TypeSearch.hs
+++ b/src/Idris/TypeSearch.hs
@@ -104,8 +104,8 @@
   matcher = matchTypesBulk istate maxScore ty1
 
 
-typeFromDef :: (Def, i, b, c, d) -> Maybe Type
-typeFromDef (def, _, _, _, _) = get def where
+typeFromDef :: (Def, r, i, b, c, d) -> Maybe Type
+typeFromDef (def, _, _, _, _, _) = get def where
   get :: Def -> Maybe Type
   get (Function ty _) = Just ty
   get (TyDecl _ ty) = Just ty
@@ -142,7 +142,7 @@
   (arguments, theRemovedArgs, retTy) = go [] [] t
 
   -- NOTE : args are in reverse order
-  go args removedArgs (Bind n (Pi _ ty _) sc) = let arg = (n, ty) in
+  go args removedArgs (Bind n (Pi _ _ ty _) sc) = let arg = (n, ty) in
     if removePred ty
       then go args (arg : removedArgs) sc
       else go (arg : args) removedArgs sc
@@ -439,7 +439,7 @@
   unifyQueue state [] = return state
   unifyQueue state ((ty1, ty2) : queue) = do
     --trace ("go: \n" ++ show state) True `seq` return ()
-    res <- tcToMaybe $ match_unify ctxt [ (n, Pi Nothing ty (TType (UVar [] 0))) | (n, ty) <- holes state]
+    res <- tcToMaybe $ match_unify ctxt [ (n, RigW, Pi RigW Nothing ty (TType (UVar [] 0))) | (n, ty) <- holes state]
                                    (ty1, Nothing)
                                    (ty2, Nothing) [] (map fst $ holes state) []
     (state', queueAdditions) <- resolveUnis res state
diff --git a/src/Util/System.hs b/src/Util/System.hs
--- a/src/Util/System.hs
+++ b/src/Util/System.hs
@@ -38,6 +38,11 @@
 import Tools_idris
 #endif
 
+#ifdef mingw32_HOST_OS
+import Graphics.Win32.Misc (getStdHandle, sTD_OUTPUT_HANDLE)
+import System.Console.MinTTY (isMinTTYHandle)
+#endif
+
 catchIO :: IO a -> (IOError -> IO a) -> IO a
 catchIO = CE.catch
 
@@ -67,8 +72,23 @@
 
 isATTY :: IO Bool
 isATTY = do
-            tty <- isATTYRaw 1 -- fd stdout
-            return $ tty /= 0
+            tty    <- isATTYRaw 1 -- fd stdout
+            mintty <- isMinTTY
+            return $ (tty /= 0) || mintty
+
+-- | Return 'True' if the process's standard output is attached to a MinTTY
+-- console (e.g., Cygwin or MSYS) on Windows. Return 'False' otherwise.
+--
+-- Unfortunately, we must check this separately since 'isATTY' always returns
+-- 'False' on MinTTY consoles.
+isMinTTY :: IO Bool
+#ifdef mingw32_HOST_OS
+isMinTTY = do
+  h <- getStdHandle sTD_OUTPUT_HANDLE
+  isMinTTYHandle h
+#else
+isMinTTY = return False
+#endif
 
 withTempdir :: String -> (FilePath -> IO a) -> IO a
 withTempdir subdir callback
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_10.ghc;
+  resolver = haskell.packages.lts-7_19.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.10
+resolver: lts-7.19
 
 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/stylize.sh b/stylize.sh
new file mode 100644
--- /dev/null
+++ b/stylize.sh
@@ -0,0 +1,39 @@
+#!/usr/bin/env bash
+
+set -e
+
+if [ -n "$TRAVIS" ];
+then
+    mkdir -p ~/.local/bin
+    export PATH=$HOME/.local/bin:/opt/ghc/$GHCVER/bin:$PATH
+    curl --retry 3 -L https://www.stackage.org/stack/linux-x86_64 | tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack'
+    stack config set system-ghc --global true
+    stack install --resolver "lts-$STACKVER" stylish-haskell --no-terminal
+fi
+
+
+find . -name \*.hs -and \( -not \( -name Setup.hs -or -path ./.cabal-sandbox/\* -or -path ./dist/\* \) \) | xargs stylish-haskell -i > stylish-out 2>&1
+
+# It doesn't do exit codes properly, so we just check if it outputted anything.
+if [ -s stylish-out ];
+then
+    echo "Stylish-haskell reported an error :("
+    cat stylish-out
+    exit 1
+fi
+
+rm stylish-out
+
+if git status --porcelain|grep .; # true if there was any output
+then
+    echo "Git tree is dirty after stylizing.";
+    if [ -n "$TRAVIS" ];
+    then
+        echo "Since we're on Travis, this is a build failure."
+        echo "Run ./stylize.sh to stylize your tree and push the changes."
+        exit 1
+    fi
+else
+    echo "Stylish didn't change anything :)"
+    exit 0;
+fi
diff --git a/test/TestData.hs b/test/TestData.hs
--- a/test/TestData.hs
+++ b/test/TestData.hs
@@ -70,7 +70,8 @@
       ( 15, ANY  ),
       ( 16, ANY  ),
       ( 17, ANY  ),
-      ( 18, ANY  )]),
+      ( 18, ANY  ),
+      ( 19, ANY  )]),
   ("bignum",          "Bignum",
     [ (  1, ANY  ),
       (  2, ANY  )]),
@@ -157,7 +158,8 @@
       (  3, ANY  ),
       (  4, ANY  ),
       (  5, ANY  ),
-      (  6, ANY  )]),
+      (  6, ANY  ),
+      (  7, ANY  )]),
   ("io",              "IO monad",
     [ (  1, C_CG ),
       (  2, ANY  ),
@@ -178,7 +180,8 @@
       (  4, ANY  ),
       (  5, ANY  ),
       (  6, ANY  ),
-      (  7, ANY  )]),
+      (  7, ANY  ),
+      (  8, ANY  )]),
   ("prelude",         "Prelude",
     [ (  1, ANY  )]),
   ("primitives",      "Primitive types",
@@ -277,7 +280,8 @@
       ( 16, ANY  ),
       ( 17, ANY  ),
       ( 18, ANY  ),
-      ( 19, ANY  )]),
+      ( 19, ANY  ),
+      ( 20, 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
@@ -107,11 +107,17 @@
       normalise [] = []
 
 main :: IO ()
-main =
-  defaultMainWithIngredients ingredients $
-    askOption $ \(NodeOpt node) ->
-      let (codegen, flags) = if node then (JS, ["--codegen", "node"])
-                                     else (C , [])
-       in
-        mkGoldenTests (testFamiliesForCodegen codegen)
-                    (flags ++ idrisFlags)
+main = do
+  node <- findExecutable "node"
+  case node of
+    Nothing -> do
+      putStrLn "For running the test suite against Node, node must be installed."
+      exitFailure
+    Just _  -> do
+      defaultMainWithIngredients ingredients $
+        askOption $ \(NodeOpt node) ->
+          let (codegen, flags) = if node then (JS, ["--codegen", "node"])
+                                         else (C , [])
+           in
+            mkGoldenTests (testFamiliesForCodegen codegen)
+                        (flags ++ idrisFlags)
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 = S (fromIntegerNat 41) (Expected type)
+        thing = 42 (Expected type)
 
 Specifically:
         Type mismatch between
diff --git a/test/basic019/basic019.idr b/test/basic019/basic019.idr
new file mode 100644
--- /dev/null
+++ b/test/basic019/basic019.idr
@@ -0,0 +1,10 @@
+printRange : (t : Type) -> (Show t, Num t, Enum t) => IO ()
+printRange t = do printLn [(the t 1)..10]
+                  printLn [(the t 10),9..1]
+                  printLn (take 10 [(the t 1)..])
+                  printLn (take 10 [(the t 1),3..])
+
+main : IO ()
+main = do printRange Nat
+          printRange Int
+          printRange Integer
diff --git a/test/basic019/expected b/test/basic019/expected
new file mode 100644
--- /dev/null
+++ b/test/basic019/expected
@@ -0,0 +1,12 @@
+[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
+[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
+[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
+[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
+[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
+[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
diff --git a/test/basic019/run b/test/basic019/run
new file mode 100644
--- /dev/null
+++ b/test/basic019/run
@@ -0,0 +1,4 @@
+#!/usr/bin/env bash
+${IDRIS:-idris} $@ basic019.idr -o basic019
+./basic019
+rm -f basic019 *.ibc
diff --git a/test/dsl001/expected b/test/dsl001/expected
--- a/test/dsl001/expected
+++ b/test/dsl001/expected
@@ -1,13 +1,13 @@
 24
 12
 testFac : Int
-testFac = PE_interp_f79b3e31 [] (PE_fromInteger_d6648df 4)
-PE_interp_f79b3e31 : Env G -> Int -> Int
-PE_interp_f79b3e31 (3arg) = \x =>
+testFac = PE_interp_e04a79ff [] (PE_fromInteger_d6648df 4)
+PE_interp_e04a79ff : Env G -> Int -> Int
+PE_interp_e04a79ff (3arg) = \x =>
                               ifThenElse (PE_==_ba2f651f x
                                                          (PE_fromInteger_d6648df 0))
                                          (Delay (PE_fromInteger_d6648df 1))
-                                         (Delay (PE_*_ba2f651f (PE_interp_f79b3e31 (x ::
+                                         (Delay (PE_*_ba2f651f (PE_interp_e04a79ff (x ::
                                                                                     (3arg))
                                                                                    (PE_-_ba2f651f x
                                                                                                   (PE_fromInteger_d6648df 1)))
diff --git a/test/dsl001/input b/test/dsl001/input
--- a/test/dsl001/input
+++ b/test/dsl001/input
@@ -1,2 +1,2 @@
 :printdef testFac
-:printdef PE_interp_f79b3e31
+:printdef PE_interp_e04a79ff
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
+${IDRIS:-idris} $@ test001.idr -o test001 --partial-eval
 ./test001
-${IDRIS:-idris} $@ test001.idr --quiet --port none < input
+${IDRIS:-idris} $@ test001.idr --partial-eval --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
@@ -3,6 +3,8 @@
 import Data.Vect
 import Data.Fin
 
+%language DSLNotation
+
 data Ty = TyInt | TyBool| TyFun Ty Ty
 
 interpTy : Ty -> Type
diff --git a/test/dsl002/Resimp.idr b/test/dsl002/Resimp.idr
--- a/test/dsl002/Resimp.idr
+++ b/test/dsl002/Resimp.idr
@@ -3,6 +3,7 @@
 import public Data.Vect
 import public Data.Fin
 
+%language DSLNotation
 %access public export
 
 -- IO operations which read a resource
diff --git a/test/dsl003/DSLPi.idr b/test/dsl003/DSLPi.idr
--- a/test/dsl003/DSLPi.idr
+++ b/test/dsl003/DSLPi.idr
@@ -3,6 +3,8 @@
 import Data.Fin
 import Data.Vect
 
+%language DSLNotation
+
 data Ty = BOOL | INT | UNIT | ARR Ty Ty
 
 arr_ : _ -> Ty -> Ty -> Ty
diff --git a/test/dsl004/Door0.idr b/test/dsl004/Door0.idr
--- a/test/dsl004/Door0.idr
+++ b/test/dsl004/Door0.idr
@@ -1,6 +1,8 @@
 import IOu
 
-data Result : (a : Type) -> (a -> Type) -> Type* where
+%language UniquenessTypes
+
+data Result : (a : Type) -> (a -> Type) -> AnyType where
      Res : {k : a -> Type} -> (val : a) -> k val -> Result a k
 
 
diff --git a/test/dsl004/Door1.idr b/test/dsl004/Door1.idr
--- a/test/dsl004/Door1.idr
+++ b/test/dsl004/Door1.idr
@@ -2,6 +2,8 @@
 
 import Data.Vect
 
+%language UniquenessTypes
+
 data Result : (a : AnyType) -> (a -> AnyType) -> AnyType where
      Res : {k : a -> AnyType} -> (val : a) -> (h : k val) -> Result a k
 
diff --git a/test/dsl004/Door2.idr b/test/dsl004/Door2.idr
--- a/test/dsl004/Door2.idr
+++ b/test/dsl004/Door2.idr
@@ -1,5 +1,7 @@
 import IOu
 
+%language UniquenessTypes
+
 data DoorState = OPEN | CLOSED
 
 data DoorH : DoorState -> UniqueType where
diff --git a/test/dsl004/Door3.idr b/test/dsl004/Door3.idr
--- a/test/dsl004/Door3.idr
+++ b/test/dsl004/Door3.idr
@@ -1,5 +1,7 @@
 import IOu
 
+%language UniquenessTypes
+
 data DoorState = OPEN | CLOSED
 
 data DoorH : DoorState -> UniqueType where
diff --git a/test/dsl004/IOu.idr b/test/dsl004/IOu.idr
--- a/test/dsl004/IOu.idr
+++ b/test/dsl004/IOu.idr
@@ -1,5 +1,7 @@
 module IOu
 
+%language UniquenessTypes
+
 -------- An IO type supporting possibly unique values
 
 data IOu : AnyType -> AnyType where
diff --git a/test/interactive001/expected b/test/interactive001/expected
--- a/test/interactive001/expected
+++ b/test/interactive001/expected
@@ -5,7 +5,7 @@
 
 f x :: map f xs
 isElem2 x (y :: ys) with (_)
-  isElem2 x (y :: ys) | with_pat = ?isElem2_rhs
+        isElem2 x (y :: ys) | with_pat = ?isElem2_rhs
 
   isElem3 y (y :: ys) | (Yes Refl) = ?isElem3_rhs_3
 
diff --git a/test/interactive001/input b/test/interactive001/input
--- a/test/interactive001/input
+++ b/test/interactive001/input
@@ -1,8 +1,8 @@
-:cs 12 xs
-:cs 18 ys
-:ps 22 maprhs
-:mw 26 isElem2
-:cs 31 p
-:cs 36 xs'
-:cs 39 x
-:cs 43 case_val
+:casesplit 12 xs
+:casesplit 18 ys
+:proofsearch 22 maprhs
+:makewith 26 isElem2
+:casesplit 31 p
+:casesplit 36 xs'
+:casesplit 39 x
+:casesplit 43 case_val
diff --git a/test/interactive001/interactive001.idr b/test/interactive001/interactive001.idr
new file mode 100644
--- /dev/null
+++ b/test/interactive001/interactive001.idr
@@ -0,0 +1,45 @@
+module elem
+
+import Decidable.Equality
+import Data.Vect
+
+using (xs : List a)
+  data Elem  : a -> List a -> Type where
+       Here  : Elem x (x :: xs)
+       There : Elem x xs -> Elem x (y :: xs)
+
+isElem : (x : Nat) -> (xs : List Nat) -> Maybe (Elem x xs)
+isElem x xs = ?isElem_rhs
+
+vadd : Num a => Vect n a -> Vect n a -> Vect n a
+vadd xs ys = localZipWith (+) xs ys where
+   localZipWith : (a -> b -> c) -> Vect n a -> Vect n b -> Vect n c
+   localZipWith f [] [] = []
+   localZipWith f (_ :: _) ys = ?localZipWith_rhs
+
+map : (a -> b) -> Vect n a -> Vect n b
+map f [] = []
+map f (x :: xs) = ?maprhs
+
+isElem2 : (x : Nat) -> (xs : List Nat) -> Maybe (Elem x xs)
+isElem2 x [] = Nothing
+isElem2 x (y :: ys) = ?isElem_rhs_2
+
+isElem3 : (x : Nat) -> (xs : List Nat) -> Maybe (Elem x xs)
+isElem3 x [] = Nothing
+isElem3 x (y :: ys) with (decEq x y)
+  isElem3 x (y :: ys) | (Yes p) = ?isElem3_rhs_1
+  isElem3 x (y :: ys) | (No _) = ?isElem3_rhs_2
+
+foo : List a -> List a
+foo xs = case xs of
+              xs' => ?bar
+
+elemVoid1 : elem.Elem x [] -> Void
+elemVoid1 x = ?elemVoid1_rhs
+
+elemVoid2 : elem.Elem x [] -> Void
+elemVoid2 x = case x of
+                   case_val => ?elemVoid2_rhs
+
+
diff --git a/test/interactive001/run b/test/interactive001/run
--- a/test/interactive001/run
+++ b/test/interactive001/run
@@ -1,3 +1,5 @@
 #!/usr/bin/env bash
-${IDRIS:-idris} $@ --quiet --port none test032.idr < input
+
+${IDRIS:-idris} $@ --quiet --port none --indent-with 8 interactive001.idr < input
+
 rm -f *.ibc
diff --git a/test/interactive001/test032.idr b/test/interactive001/test032.idr
deleted file mode 100644
--- a/test/interactive001/test032.idr
+++ /dev/null
@@ -1,45 +0,0 @@
-module elem
-
-import Decidable.Equality
-import Data.Vect
-
-using (xs : List a)
-  data Elem  : a -> List a -> Type where
-       Here  : Elem x (x :: xs)
-       There : Elem x xs -> Elem x (y :: xs)
-
-isElem : (x : Nat) -> (xs : List Nat) -> Maybe (Elem x xs)
-isElem x xs = ?isElem_rhs
-
-vadd : Num a => Vect n a -> Vect n a -> Vect n a
-vadd xs ys = localZipWith (+) xs ys where
-   localZipWith : (a -> b -> c) -> Vect n a -> Vect n b -> Vect n c
-   localZipWith f [] [] = []
-   localZipWith f (_ :: _) ys = ?localZipWith_rhs
-
-map : (a -> b) -> Vect n a -> Vect n b
-map f [] = []
-map f (x :: xs) = ?maprhs
-
-isElem2 : (x : Nat) -> (xs : List Nat) -> Maybe (Elem x xs)
-isElem2 x [] = Nothing
-isElem2 x (y :: ys) = ?isElem_rhs_2
-
-isElem3 : (x : Nat) -> (xs : List Nat) -> Maybe (Elem x xs)
-isElem3 x [] = Nothing
-isElem3 x (y :: ys) with (decEq x y)
-  isElem3 x (y :: ys) | (Yes p) = ?isElem3_rhs_1
-  isElem3 x (y :: ys) | (No _) = ?isElem3_rhs_2
-
-foo : List a -> List a
-foo xs = case xs of
-              xs' => ?bar
-
-elemVoid1 : elem.Elem x [] -> Void
-elemVoid1 x = ?elemVoid1_rhs
-
-elemVoid2 : elem.Elem x [] -> Void
-elemVoid2 x = case x of
-                   case_val => ?elemVoid2_rhs
-
-
diff --git a/test/interactive010/expected b/test/interactive010/expected
--- a/test/interactive010/expected
+++ b/test/interactive010/expected
@@ -4,9 +4,9 @@
 Usage is :doc <functionname>
 Usage is :wc <functionname>
 Usage is :printdef <functionname>
-pat {ty504} : Type toplevel.u. pat {__interface505} : Prelude.Interfaces.Fractional {ty504}. Prelude.Interfaces./ {ty504} {__interface505}
+pat {ty503} : Type toplevel.u. pat {__interface504} : Prelude.Interfaces.Fractional {ty503}. Prelude.Interfaces./ {ty503} {__interface504}
 
- : pty {ty504} : Type toplevel.u. pty {__interface505} : Prelude.Interfaces.Fractional {ty504}. {ty504} -> {ty504} -> {ty504}
+ : pty {ty503} : Type toplevel.u. pty {__interface504} : Prelude.Interfaces.Fractional {ty503}. {ty503} -> {ty503} -> {ty503}
 (input):1:1: error: expected: ":",
     dependent type signature,
     end of input
diff --git a/test/interactive011/.gitignore b/test/interactive011/.gitignore
new file mode 100644
--- /dev/null
+++ b/test/interactive011/.gitignore
@@ -0,0 +1,1 @@
+interactive011
diff --git a/test/interactive011/input b/test/interactive011/input
--- a/test/interactive011/input
+++ b/test/interactive011/input
@@ -1,2 +1,2 @@
-:ac 5 Show
-:ac 7 append
+:addclause 8 Show
+:addclause 10 append
diff --git a/test/interactive011/interactive011.idr b/test/interactive011/interactive011.idr
deleted file mode 100644
--- a/test/interactive011/interactive011.idr
+++ /dev/null
@@ -1,11 +0,0 @@
-import Data.Vect
-
-data Foo = Bar | Baz
-
-implementation Show Foo where
-
-append : Vect n a -> Vect m a -> Vect (n + m) a
-append (x :: xs) ys = ?append_rhs_2
-
-
-
diff --git a/test/interactive011/interactive011.ipkg b/test/interactive011/interactive011.ipkg
new file mode 100644
--- /dev/null
+++ b/test/interactive011/interactive011.ipkg
@@ -0,0 +1,8 @@
+package interactive011
+
+opts = "--quiet --indent-clause 4 --indent-with 8"
+
+sourcedir = src
+modules = Foo
+main = Main
+executable = interactive011
diff --git a/test/interactive011/run b/test/interactive011/run
--- a/test/interactive011/run
+++ b/test/interactive011/run
@@ -1,3 +1,6 @@
 #!/usr/bin/env bash
-${IDRIS:-idris} $@ --quiet --port none interactive011.idr < input
+
+cd src
+${IDRIS:-idris} "$@" --quiet --port none --indent-clause 4 Main.idr <../input
+
 rm -f *.ibc
diff --git a/test/interactive011/src/Foo.idr b/test/interactive011/src/Foo.idr
new file mode 100644
--- /dev/null
+++ b/test/interactive011/src/Foo.idr
@@ -0,0 +1,5 @@
+module Foo
+
+export
+foo : IO ()
+foo = putStrLn "Hello foo"
diff --git a/test/interactive011/src/Main.idr b/test/interactive011/src/Main.idr
new file mode 100644
--- /dev/null
+++ b/test/interactive011/src/Main.idr
@@ -0,0 +1,14 @@
+module Main
+
+import Data.Vect
+import Foo
+
+data Foo = Bar | Baz
+
+implementation Show Foo where
+
+append : Vect n a -> Vect m a -> Vect (n + m) a
+append (x :: xs) ys = ?append_rhs_2
+
+main : IO ()
+main = foo
diff --git a/test/interfaces002/interfaces002.idr b/test/interfaces002/interfaces002.idr
--- a/test/interfaces002/interfaces002.idr
+++ b/test/interfaces002/interfaces002.idr
@@ -1,10 +1,9 @@
 import Data.Vect
 
 %default total
-  
+
 interface ArrayM where
   Array : (n : Nat) -> (a : Type) -> Type
-  
   create : (n : Nat) -> a -> Array n a
 
   lkp : (i : Nat) -> (prf : LTE (S i) n) -> Array n a -> a
@@ -37,5 +36,3 @@
 
 main : IO ()
 main = printLn (testSum (upd 11 1 (LTESucc (LTESucc LTEZero)) (create 4 10)))
-
-
diff --git a/test/interfaces007/expected b/test/interfaces007/expected
new file mode 100644
--- /dev/null
+++ b/test/interfaces007/expected
@@ -0,0 +1,1 @@
+(2, 6)
diff --git a/test/interfaces007/interfaces007.idr b/test/interfaces007/interfaces007.idr
new file mode 100644
--- /dev/null
+++ b/test/interfaces007/interfaces007.idr
@@ -0,0 +1,52 @@
+data State : (stateType : Type) -> Type -> Type where
+     Get : State stateType stateType
+     Put : stateType -> State stateType ()
+
+     Pure : ty -> State stateType ty
+     Bind : State stateType a -> (a -> State stateType b) ->
+             State stateType b
+
+get : State stateType stateType
+get = Get
+
+put : stateType -> State stateType ()
+put = Put
+
+-- Test is that mutually defined implementations work and get past the
+-- totality checker as they should
+mutual
+  Functor (State stateType) where
+      map func x = do val <- x
+                      pure (func val)
+
+  Applicative (State stateType) where
+      pure = Pure
+      (<*>) f a = do f' <- f
+                     a' <- a
+                     pure (f' a')
+
+  Monad (State stateType) where
+      (>>=) = Bind
+
+runState : State stateType a -> (st : stateType) -> (a, stateType)
+runState Get st = (st, st)
+runState (Put newState) st = ((), newState)
+
+runState (Pure x) st = (x, st)
+runState (Bind cmd prog) st = let (val, nextState) = runState cmd st in
+                                  runState (prog val) nextState
+
+addIfPositive : Integer -> State Integer Bool
+addIfPositive val = do when (val > 0) $
+                            do current <- get
+                               put (current + val)
+                       pure (val > 0)
+
+addPositives : List Integer -> State Integer Nat
+addPositives vals = do added <- traverse addIfPositive vals
+                       pure (length (filter id added))
+
+main : IO ()
+main = printLn $ runState (addPositives [-1,2,-3,4]) 0
+
+
diff --git a/test/interfaces007/run b/test/interfaces007/run
new file mode 100644
--- /dev/null
+++ b/test/interfaces007/run
@@ -0,0 +1,4 @@
+#!/usr/bin/env bash
+${IDRIS:-idris} $@ interfaces007.idr -o interfaces007
+./interfaces007
+rm -f interfaces007 *.ibc
diff --git a/test/meta001/Finite.idr b/test/meta001/Finite.idr
--- a/test/meta001/Finite.idr
+++ b/test/meta001/Finite.idr
@@ -4,6 +4,8 @@
 import Language.Reflection.Elab
 import Language.Reflection.Utils
 
+%language ElabReflection
+
 -- Test various features of reflected elaboration, including looking
 -- up datatypes, defining functions, and totality checking
 
diff --git a/test/meta002/AgdaStyleReflection.idr b/test/meta002/AgdaStyleReflection.idr
--- a/test/meta002/AgdaStyleReflection.idr
+++ b/test/meta002/AgdaStyleReflection.idr
@@ -13,7 +13,7 @@
 import Pruviloj
 
 %default total
-
+%language ElabReflection
 
 
 ||| Function arguments as provided at the application site
diff --git a/test/meta002/DataDef.idr b/test/meta002/DataDef.idr
--- a/test/meta002/DataDef.idr
+++ b/test/meta002/DataDef.idr
@@ -1,5 +1,7 @@
 module DataDef
 
+%language ElabReflection
+
 foo : Elab ()
 foo = do declareDatatype $ Declare `{{DataDef.N}} [MkFunArg `{{n}} `(Nat) Explicit NotErased] `(Type)
          defineDatatype $ DefineDatatype `{{DataDef.N}} [
diff --git a/test/meta002/Deriving.idr b/test/meta002/Deriving.idr
--- a/test/meta002/Deriving.idr
+++ b/test/meta002/Deriving.idr
@@ -1,6 +1,8 @@
 ||| Test some deriving features
 module Deriving
 
+%language ElabReflection
+
 -- NB: test disabled due to excess memory consumption
 
 import Pruviloj
diff --git a/test/meta002/Tacs.idr b/test/meta002/Tacs.idr
--- a/test/meta002/Tacs.idr
+++ b/test/meta002/Tacs.idr
@@ -16,6 +16,7 @@
 import Pruviloj.Core
 
 %default total
+%language ElabReflection
 
 -- Tactics can now query the elaborator and bind variables
 
diff --git a/test/meta002/expected b/test/meta002/expected
--- a/test/meta002/expected
+++ b/test/meta002/expected
@@ -1,7 +1,7 @@
-DataDef.idr:72:1-9:
+DataDef.idr:74:1-9:
 While running an elaboration script, the following error occurred:
 Prelude.Either.Either is already defined as a datatype.
-Tacs.idr:298:15:
+Tacs.idr:299:15:
 When checking right hand side of testElab3 with expected type
         DPair Ty (Tm [])
 
diff --git a/test/meta003/BadDef.idr b/test/meta003/BadDef.idr
--- a/test/meta003/BadDef.idr
+++ b/test/meta003/BadDef.idr
@@ -2,6 +2,8 @@
 
 import Language.Reflection.Elab
 
+%language ElabReflection
+
 mkN : String -> TTName
 mkN n = NS (UN n) ["BadDef"]
 
diff --git a/test/meta003/expected b/test/meta003/expected
--- a/test/meta003/expected
+++ b/test/meta003/expected
@@ -1,4 +1,4 @@
-BadDef.idr:12:1-9:
+BadDef.idr:14:1-9:
 While running an elaboration script, the following error occurred:
 Type mismatch between
         ()
diff --git a/test/meta004/expected b/test/meta004/expected
--- a/test/meta004/expected
+++ b/test/meta004/expected
@@ -1,3 +1,3 @@
-meta004.idr:48:1-9:
+meta004.idr:50:1-9:
 While running an elaboration script, the following error occurred:
 Not an impossible case
diff --git a/test/meta004/meta004.idr b/test/meta004/meta004.idr
--- a/test/meta004/meta004.idr
+++ b/test/meta004/meta004.idr
@@ -2,6 +2,8 @@
 import Language.Reflection.Utils
 import Pruviloj.Core
 
+%language ElabReflection
+
 rename : TTName -> TTName -> Raw -> Raw
 rename old new (RBind name b body) = RBind name (map (rename old new) b) (rename old new body)
 rename old new (RApp f arg) = RApp (rename old new f) (rename old new arg)
diff --git a/test/pkg001/expected b/test/pkg001/expected
--- a/test/pkg001/expected
+++ b/test/pkg001/expected
@@ -1,7 +1,7 @@
 Not all command line options can be used to override package options.
 
 The only changeable options are:
-	--log <lvl>, --total, --warnpartial, --warnreach
+	--log <lvl>, --total, --warnpartial, --warnreach, --warnipkg
 	--ibcsubdir <path>, -i --idrispath <path>
 	--logging-categories <cats>
 
diff --git a/test/pkg008/expected b/test/pkg008/expected
new file mode 100644
--- /dev/null
+++ b/test/pkg008/expected
@@ -0,0 +1,13 @@
+Entering directory `./src'
+Type checking ./NumOps.idr
+Type checking ./Test.idr
+Leaving directory `./src'
+Test Passed
+Test Passed
+Entering directory `./src'
+Leaving directory `./src'
+Entering directory `./src'
+Removed: NumOps.ibc
+Removed: Test.ibc
+Removed: 00maths-idx.ibc
+Leaving directory `./src'
diff --git a/test/pkg008/maths.ipkg b/test/pkg008/maths.ipkg
new file mode 100644
--- /dev/null
+++ b/test/pkg008/maths.ipkg
@@ -0,0 +1,9 @@
+package maths
+
+sourcedir = src
+
+modules = NumOps
+        , Test
+
+tests = Test.testDouble
+      , Test.testTriple
diff --git a/test/pkg008/run b/test/pkg008/run
new file mode 100644
--- /dev/null
+++ b/test/pkg008/run
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+
+${IDRIS:-idris} $@ --build maths.ipkg
+${IDRIS:-idris} $@ --testpkg maths.ipkg | grep -v -e "idris"
+
+# Idris only appears in the randomly generated name of test so we grep
+# to remove it to make output consistent.
+
+${IDRIS:-idris} $@ --clean maths.ipkg
diff --git a/test/pkg008/src/NumOps.idr b/test/pkg008/src/NumOps.idr
new file mode 100644
--- /dev/null
+++ b/test/pkg008/src/NumOps.idr
@@ -0,0 +1,9 @@
+module NumOps
+
+%access export -- to make functions under test visible
+
+double : Num a => a -> a
+double a = a + a
+
+triple : Num a => a -> a
+triple a = a + double a
diff --git a/test/pkg008/src/Test.idr b/test/pkg008/src/Test.idr
new file mode 100644
--- /dev/null
+++ b/test/pkg008/src/Test.idr
@@ -0,0 +1,21 @@
+module Test
+
+import NumOps
+
+%access export  -- to make the test functions visible
+
+assertEq : Eq a => (given : a) -> (expected : a) -> IO ()
+assertEq g e = if g == e
+    then putStrLn "Test Passed"
+    else putStrLn "Test Failed"
+
+assertNotEq : Eq a => (given : a) -> (expected : a) -> IO ()
+assertNotEq g e = if not (g == e)
+    then putStrLn "Test Passed"
+    else putStrLn "Test Failed"
+
+testDouble : IO ()
+testDouble = assertEq (double 2) 4
+
+testTriple : IO ()
+testTriple = assertNotEq (triple 2) 5
diff --git a/test/proof002/Reflect.idr b/test/proof002/Reflect.idr
--- a/test/proof002/Reflect.idr
+++ b/test/proof002/Reflect.idr
@@ -4,6 +4,7 @@
 
 %access public export
 %default total
+%language FirstClassReflection
 
 using (xs : List a, ys : List a, G : List (List a))
 
diff --git a/test/proof002/expected b/test/proof002/expected
--- a/test/proof002/expected
+++ b/test/proof002/expected
@@ -1,8 +1,8 @@
-Reflect.idr:174:21-26:
+Reflect.idr:175:21-26:
 This style of tactic proof is deprecated. See %runElab for the replacement.
-Reflect.idr:183:21-26:
+Reflect.idr:184:21-26:
 This style of tactic proof is deprecated. See %runElab for the replacement.
-Reflect.idr:191:15-20:
+Reflect.idr:192:15-20:
 This style of tactic proof is deprecated. See %runElab for the replacement.
 test030a.idr:12:26-14:1:
 When checking right hand side of testReflect1 with expected type
diff --git a/test/pruviloj001/pruviloj001.idr b/test/pruviloj001/pruviloj001.idr
--- a/test/pruviloj001/pruviloj001.idr
+++ b/test/pruviloj001/pruviloj001.idr
@@ -5,6 +5,7 @@
 import Pruviloj.Induction
 
 %default total
+%language ElabReflection
 
 ||| Try some simplification and rewriting heuristics, then attempt to
 ||| solve the goal
diff --git a/test/regression001/reg002.idr b/test/regression001/reg002.idr
new file mode 100644
--- /dev/null
+++ b/test/regression001/reg002.idr
@@ -0,0 +1,8 @@
+mutual
+  interface MyInterface a where
+    foo : a -> b
+    foo = bar
+
+  bar : MyInterface a => a -> b
+  bar = ?bar_rhs
+
diff --git a/test/regression001/run b/test/regression001/run
--- a/test/regression001/run
+++ b/test/regression001/run
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 ${IDRIS:-idris} $@ --check \
-    reg001.idr reg036.idr reg037.idr reg038.idr reg046.idr \
+    reg001.idr reg002.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 \
diff --git a/test/sourceLocation001/SourceLoc.idr b/test/sourceLocation001/SourceLoc.idr
--- a/test/sourceLocation001/SourceLoc.idr
+++ b/test/sourceLocation001/SourceLoc.idr
@@ -6,6 +6,7 @@
 import Language.Reflection.Utils
 
 %default total
+%language DSLNotation
 
 ||| A "function" that returns where it is called in the source
 getLoc : {default tactics { sourceLocation } x : SourceLocation} -> SourceLocation
diff --git a/test/sourceLocation001/expected b/test/sourceLocation001/expected
--- a/test/sourceLocation001/expected
+++ b/test/sourceLocation001/expected
@@ -1,19 +1,19 @@
-SourceLoc.idr:11:19-26:
+SourceLoc.idr:12:19-26:
 This style of tactic proof is deprecated. See %runElab for the replacement.
-SourceLoc.idr:20:19-24:
+SourceLoc.idr:21:19-24:
 This style of tactic proof is deprecated. See %runElab for the replacement.
-SourceLoc.idr:40:20-27:
+SourceLoc.idr:41:20-27:
 This style of tactic proof is deprecated. See %runElab for the replacement.
-SourceLoc.idr:98:18-23:
+SourceLoc.idr:99:18-23:
 This style of tactic proof is deprecated. See %runElab for the replacement.
 Testing using definition
-FileLoc "SourceLoc.idr" (16, 11) (16, 17)
+FileLoc "SourceLoc.idr" (17, 11) (17, 17)
 Testing using inline tactics
-FileLoc "SourceLoc.idr" (20, 17) (20, 17)
+FileLoc "SourceLoc.idr" (21, 17) (21, 17)
 Testing using metavariable with later definition
-FileLoc "SourceLoc.idr" (98, 16) (98, 16)
+FileLoc "SourceLoc.idr" (99, 16) (99, 16)
 -----------------------
 Success!
-Error at FileLoc "SourceLoc.idr" (72, 23) (72, 26)
+Error at FileLoc "SourceLoc.idr" (73, 23) (73, 26)
 Success!
 Success!
diff --git a/test/tactics001/Tactics.idr b/test/tactics001/Tactics.idr
--- a/test/tactics001/Tactics.idr
+++ b/test/tactics001/Tactics.idr
@@ -4,7 +4,7 @@
 
 import Data.Vect
 
-
+%language ElabReflection
 %default total
 
 -- Test that basic proofs with new-style tactics work
diff --git a/test/totality020/expected b/test/totality020/expected
new file mode 100644
--- /dev/null
+++ b/test/totality020/expected
@@ -0,0 +1,1 @@
+totality020.idr:4:5:bug _ _ Refl is a valid case
diff --git a/test/totality020/run b/test/totality020/run
new file mode 100644
--- /dev/null
+++ b/test/totality020/run
@@ -0,0 +1,3 @@
+#!/usr/bin/env bash
+${IDRIS:-idris} $@ totality020.idr --check
+rm -f *.ibc
diff --git a/test/totality020/totality020.idr b/test/totality020/totality020.idr
new file mode 100644
--- /dev/null
+++ b/test/totality020/totality020.idr
@@ -0,0 +1,4 @@
+%default total
+
+bug : (n, m : Nat) -> n + m = n -> Void
+bug _ _ Refl impossible
diff --git a/test/unique001/unique001.idr b/test/unique001/unique001.idr
--- a/test/unique001/unique001.idr
+++ b/test/unique001/unique001.idr
@@ -1,5 +1,7 @@
 module Main
 
+%language UniquenessTypes
+
 data UList : Type -> UniqueType where
      Nil   : UList a
      (::)  : a -> UList a -> UList a
diff --git a/test/unique004/expected b/test/unique004/expected
--- a/test/unique004/expected
+++ b/test/unique004/expected
@@ -1,26 +1,26 @@
-unique001a.idr:33:11:Type mismatch between
+unique001a.idr:35:11:Type mismatch between
         Int -> String
 and
         UniqueType (Int -> String)
-unique001a.idr:44:12:Type mismatch between
+unique001a.idr:46:12:Type mismatch between
         Int -> String
 and
         UniqueType (Int -> String)
-unique001a.idr:55:12:Type mismatch between
+unique001a.idr:57:12:Type mismatch between
         UniqueType (Int -> String)
 and
         Int -> String
-unique001b.idr:16:7:Borrowed name xs must not be used on RHS
-unique001c.idr:46:6:Unique name f is used more than once
-unique001d.idr:3:7:Borrowed name x must not be used on RHS
-unique001e.idr:3:10:
+unique001b.idr:18:7:Borrowed name xs must not be used on RHS
+unique001c.idr:47:6:Unique name f is used more than once
+unique001d.idr:4:7:Borrowed name x must not be used on RHS
+unique001e.idr:4:10:
 Constructor Main.Nil has a UniqueType, but the data type does not
-unique002.idr:15:5:Unique name xs is used more than once
-unique002a.idr:15:5:Type mismatch between
+unique002.idr:17:5:Unique name xs is used more than once
+unique002a.idr:17:5:Type mismatch between
         Int -> String
 and
         UniqueType (Int -> String)
-unique003.idr:18:5:Type mismatch between
+unique003.idr:20:5:Type mismatch between
         Int -> String
 and
         UniqueType (Int -> String)
diff --git a/test/unique004/unique001a.idr b/test/unique004/unique001a.idr
--- a/test/unique004/unique001a.idr
+++ b/test/unique004/unique001a.idr
@@ -1,5 +1,7 @@
 module Main
 
+%language UniquenessTypes
+
 data UList : Type -> UniqueType where
      Nil   : UList a
      (::)  : a -> UList a -> UList a
diff --git a/test/unique004/unique001b.idr b/test/unique004/unique001b.idr
--- a/test/unique004/unique001b.idr
+++ b/test/unique004/unique001b.idr
@@ -1,5 +1,7 @@
 module Main
 
+%language UniquenessTypes
+
 data UList : Type -> UniqueType where
      Nil   : UList a
      (::)  : a -> UList a -> UList a
diff --git a/test/unique004/unique001c.idr b/test/unique004/unique001c.idr
--- a/test/unique004/unique001c.idr
+++ b/test/unique004/unique001c.idr
@@ -1,3 +1,4 @@
+%language UniquenessTypes
 
 data UList : Type -> UniqueType where
      UNil : UList a
diff --git a/test/unique004/unique001d.idr b/test/unique004/unique001d.idr
--- a/test/unique004/unique001d.idr
+++ b/test/unique004/unique001d.idr
@@ -1,3 +1,4 @@
+%language UniquenessTypes
 
 steal : {a : UniqueType} -> Borrowed a -> a
 steal (Read x) = x
diff --git a/test/unique004/unique001e.idr b/test/unique004/unique001e.idr
--- a/test/unique004/unique001e.idr
+++ b/test/unique004/unique001e.idr
@@ -1,3 +1,4 @@
+%language UniquenessTypes
 
 data BadList : UniqueType -> Type where
      Nil : {a : UniqueType} -> BadList a
diff --git a/test/unique004/unique002.idr b/test/unique004/unique002.idr
--- a/test/unique004/unique002.idr
+++ b/test/unique004/unique002.idr
@@ -1,3 +1,5 @@
+%language UniquenessTypes
+
 data UList : Type -> UniqueType where
      Nil   : UList a
      (::)  : a -> UList a -> UList a
diff --git a/test/unique004/unique002a.idr b/test/unique004/unique002a.idr
--- a/test/unique004/unique002a.idr
+++ b/test/unique004/unique002a.idr
@@ -1,3 +1,5 @@
+%language UniquenessTypes
+
 data UList : Type -> UniqueType where
      Nil   : UList a
      (::)  : a -> UList a -> UList a
diff --git a/test/unique004/unique003.idr b/test/unique004/unique003.idr
--- a/test/unique004/unique003.idr
+++ b/test/unique004/unique003.idr
@@ -1,5 +1,7 @@
 module Main
 
+%language UniquenessTypes
+
 data UList : Type -> UniqueType where
      Nil   : UList a
      (::)  : a -> UList a -> UList a
