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 test_c test 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_c test lib_doc lib_doc_clean user_doc_html user_doc_pdf user_docs
 
 include config.mk
 -include custom.mk
@@ -65,6 +65,9 @@
 
 user_doc_pdf:
 	$(MAKE) -C docs latexpdf
+
+fast:
+	$(CABAL) install $(CABALFLAGS) --ghc-option=-O0
 
 dist/setup-config:
 	$(CABAL) configure $(CABALFLAGS)
diff --git a/idris.cabal b/idris.cabal
--- a/idris.cabal
+++ b/idris.cabal
@@ -1,5 +1,5 @@
 Name:           idris
-Version:        0.9.18.1
+Version:        0.9.19
 License:        BSD3
 License-file:   LICENSE
 Author:         Edwin Brady
@@ -114,8 +114,11 @@
                        libs/contrib/Classes/*.idr
                        libs/contrib/Control/*.idr
                        libs/contrib/Control/Isomorphism/*.idr
-		       libs/contrib/Control/Algebra/*.idr
+                       libs/contrib/Control/Algebra/*.idr
                        libs/contrib/Data/*.idr
+                       libs/contrib/Data/Nat/*.idr
+                       libs/contrib/Data/Nat/DivMod/*.idr
+                       libs/contrib/Data/Matrix/*.idr
                        libs/contrib/Decidable/*.idr
                        libs/contrib/Network/*.idr
                        libs/contrib/System/Concurrency/*.idr
@@ -123,6 +126,7 @@
                        libs/effects/Makefile
                        libs/effects/effects.ipkg
                        libs/effects/Effect/*.idr
+		       libs/effects/Effect/Logging/*.idr
                        libs/effects/*.idr
 
                        test/Makefile
@@ -317,6 +321,9 @@
                        test/reg065/run
                        test/reg065/*.idr
                        test/reg065/expected
+                       test/reg066/run
+                       test/reg066/*.idr
+                       test/reg066/expected
 
                        test/basic001/run
                        test/basic001/*.idr
@@ -383,9 +390,6 @@
                        test/delab001/expected
                        test/delab001/input
 
-                       test/disambig001/run
-                       test/disambig001/*.idr
-                       test/disambig001/expected
                        test/disambig002/run
                        test/disambig002/*.idr
                        test/disambig002/expected
@@ -400,6 +404,9 @@
                        test/dsl003/run
                        test/dsl003/*.idr
                        test/dsl003/expected
+                       test/dsl004/run
+                       test/dsl004/*.idr
+                       test/dsl004/expected
 
                        test/effects001/run
                        test/effects001/*.idr
@@ -416,7 +423,11 @@
                        test/effects004/*.idr
                        test/effects004/expected
                        test/effects004/input
+                       test/effects005/run
+                       test/effects005/*.idr
+                       test/effects005/expected
 
+
                        test/error001/run
                        test/error001/*.idr
                        test/error001/expected
@@ -526,6 +537,13 @@
                        test/interactive007/run
                        test/interactive007/input
                        test/interactive007/expected
+                       test/interactive008/run
+                       test/interactive008/input
+                       test/interactive008/expected
+                       test/interactive009/run
+                       test/interactive009/input
+                       test/interactive009/*.idr
+                       test/interactive009/expected
 
                        test/io001/run
                        test/io001/*.idr
@@ -638,6 +656,13 @@
                        test/sugar005/*.idr
                        test/sugar005/expected
 
+                       test/syntax001/run
+                       test/syntax001/*.idr
+                       test/syntax001/expected
+                       test/syntax002/run
+                       test/syntax002/*.idr
+                       test/syntax002/expected
+
                        test/tactics001/run
                        test/tactics001/*.idr
                        test/tactics001/expected
@@ -770,6 +795,7 @@
                 , Idris.Core.TT
                 , Idris.Core.Typecheck
                 , Idris.Core.Unify
+                , Idris.Core.WHNF
 
                 , Idris.Elab.Utils
                 , Idris.Elab.Type
@@ -780,6 +806,7 @@
                 , Idris.Elab.Class
                 , Idris.Elab.Instance
                 , Idris.Elab.Provider
+                , Idris.Elab.RunElab
                 , Idris.Elab.Transform
                 , Idris.Elab.Value
                 , Idris.Elab.Term
@@ -858,7 +885,6 @@
   Other-modules:
                   Util.Pretty
                 , Util.Net
-                , Util.Zlib
 
                 , Pkg.PParser
 
@@ -868,22 +894,21 @@
                 , Tools_idris
 
   Build-depends:  base >=4 && <5
-                , annotated-wl-pprint >= 0.5.3 && < 0.7
+                , annotated-wl-pprint >= 0.7 && < 0.8
                 , ansi-terminal < 0.7
                 , ansi-wl-pprint < 0.7
                 , base64-bytestring < 1.1
                 , binary >= 0.7 && < 0.8
-                , blaze-html >= 0.6.1.3 && < 0.8
-                , blaze-markup >= 0.5.2.1 && < 0.6.3.0
+                , blaze-html >= 0.6.1.3 && < 0.9
+                , blaze-markup >= 0.5.2.1 && < 0.8
                 , bytestring < 0.11
                 , cheapskate < 0.2
                 , containers >= 0.5 && < 0.6
                 , deepseq < 1.5
-                , directory >= 1.2.2.0 && < 1.3
+                , directory >= 1.2.2.0 && < 1.2.3.0 || > 1.2.3.0
                 , filepath < 1.5
                 , fingertree >= 0.1 && < 0.2
                 , haskeline >= 0.7 && < 0.8
-                , lens >= 4.1.1 && < 4.10
                 , mtl >= 2.1 && < 2.3
                 , network < 2.7
                 , optparse-applicative >= 0.11 && < 0.12
@@ -898,10 +923,9 @@
                 , trifecta >= 1.1 && < 1.6
                 , uniplate >=1.6 && < 1.7
                 , unordered-containers < 0.3
-                , utf8-string < 0.4
+                , utf8-string <= 1
                 , vector < 0.11
                 , vector-binary-instances < 0.3
-                , xml < 1.4
                 , zip-archive > 0.2.3.5 && < 0.2.4
                 , zlib < 0.6
                 , safe
@@ -984,7 +1008,7 @@
                 , transformers
 
   ghc-prof-options: -auto-all -caf-all
-  ghc-options:      -threaded -rtsopts -funbox-strict-fields -O2
+  ghc-options:      -threaded -rtsopts -funbox-strict-fields
 
 Executable idris-node
   Main-is:        Main.hs
@@ -997,4 +1021,4 @@
                 , transformers
 
   ghc-prof-options: -auto-all -caf-all
-  ghc-options:      -threaded -rtsopts -funbox-strict-fields -O2
+  ghc-options:      -threaded -rtsopts -funbox-strict-fields
diff --git a/jsrts/Runtime-browser.js b/jsrts/Runtime-browser.js
--- a/jsrts/Runtime-browser.js
+++ b/jsrts/Runtime-browser.js
@@ -2,7 +2,6 @@
   console.log(s);
 };
 
-
 var i$systemInfo = function(index) {
   switch(index) {
     case 0:
diff --git a/jsrts/Runtime-common.js b/jsrts/Runtime-common.js
--- a/jsrts/Runtime-common.js
+++ b/jsrts/Runtime-common.js
@@ -1,6 +1,6 @@
 /** @constructor */
 var i$VM = function() {
-  this.valstack = [];
+  this.valstack = {};
   this.valstack_top = 0;
   this.valstack_base = 0;
 
@@ -63,26 +63,29 @@
 
 var i$ffiWrap = function(fid,oldbase,myoldbase) {
   return function() {
+    var oldstack = i$callstack;
     i$callstack = [];
 
     var res = fid;
 
     for(var i = 0; i < (arguments.length ? arguments.length : 1); ++i) {
-      i$valstack_top += 1;
-      i$valstack[i$valstack_top] = res;
-      i$valstack[i$valstack_top + 1] = arguments[i];
-      i$SLIDE(2);
-      i$valstack_top = i$valstack_base + 2;
-      i$CALL(_idris__123_APPLY0_125_,[oldbase])
-      while (i$callstack.length) {
-        var func = i$callstack.pop();
-        var args = i$callstack.pop();
-        func.apply(this,args);
+      while (res instanceof i$CON) {
+        i$valstack_top += 1;
+        i$valstack[i$valstack_top] = res;
+        i$valstack[i$valstack_top + 1] = arguments[i];
+        i$SLIDE(2);
+        i$valstack_top = i$valstack_base + 2;
+        i$CALL(_idris__123_APPLY0_125_,[oldbase])
+        while (i$callstack.length) {
+          var func = i$callstack.pop();
+          var args = i$callstack.pop();
+          func.apply(this,args);
+        }
+        res = i$ret;
       }
-      res = i$ret;
     }
 
-    i$callstack = i$vm.callstack;
+    i$callstack = oldstack;
 
     return i$ret;
   }
@@ -100,4 +103,15 @@
     return chr;
   else
     return String.fromCharCode(chr);
+}
+
+var i$RUN = function () {
+  for (var i = 0; i < 10000 && i$callstack.length; i++) {
+    var func = i$callstack.pop();
+    var args = i$callstack.pop();
+    func.apply(this,args);
+  };
+
+  if (i$callstack.length)
+    setTimeout(i$RUN, 0);
 }
diff --git a/jsrts/Runtime-node.js b/jsrts/Runtime-node.js
--- a/jsrts/Runtime-node.js
+++ b/jsrts/Runtime-node.js
@@ -5,6 +5,25 @@
   };
 })();
 
+var i$getLine = (function() {
+  var fs = require( "fs" )
+
+  return function() {
+    var ret = "";
+
+    while(true) {
+      var b = new Buffer(1);
+      fs.readSync(0, b, 0, 1 )
+      if (b[0] == 10)
+        break;
+      else
+        ret += String.fromCharCode(b[0]);
+    }
+
+    return ret;
+  };
+})();
+
 var i$systemInfo = function(index) {
   var os = require('os')
     switch(index) {
diff --git a/libs/base/Control/Monad/State.idr b/libs/base/Control/Monad/State.idr
--- a/libs/base/Control/Monad/State.idr
+++ b/libs/base/Control/Monad/State.idr
@@ -1,7 +1,7 @@
 module Control.Monad.State
 
 import public Control.Monad.Identity
-import Control.Monad.Trans
+import public Control.Monad.Trans
 
 %access public
 
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
@@ -22,8 +22,9 @@
     (==) a b = realPart a == realPart b && imagPart a == imagPart b
 
 instance Show a => Show (Complex a) where
-    show (r:+i) = "("++show r++":+"++show i++")"
-
+    showPrec d (r :+ i) = showParens (d >= plus_i) $ showPrec plus_i r ++ " :+ " ++ showPrec plus_i i
+      where plus_i : Prec
+            plus_i = User 6
 
 
 -- when we have a type class 'Fractional' (which contains Float and Double),
@@ -58,6 +59,12 @@
 
 conjugate : Num a => Complex a -> Complex a
 conjugate (r:+i) = (r :+ (0-i))
+
+instance Functor Complex where
+  map f (r :+ i) = f r :+ f i
+
+instance Neg a => Neg (Complex a) where
+  negate = map negate
 
 -- We can't do "instance Num a => Num (Complex a)" because
 -- we need "abs" which needs "magnitude" which needs "sqrt" which needs Float
diff --git a/libs/base/Data/Fin.idr b/libs/base/Data/Fin.idr
--- a/libs/base/Data/Fin.idr
+++ b/libs/base/Data/Fin.idr
@@ -129,6 +129,8 @@
                           | Nothing = Nothing
 natToFin _ _ = Nothing
 
+||| Convert an `Integer` to a `Fin`, provided the integer is within bounds.
+||| @n The upper bound of the Fin
 integerToFin : Integer -> (n : Nat) -> Maybe (Fin n)
 integerToFin x Z = Nothing -- make sure 'n' is concrete, to save reduction!
 integerToFin x n = if x >= 0 then natToFin (cast x) n else Nothing
diff --git a/libs/base/Data/HVect.idr b/libs/base/Data/HVect.idr
--- a/libs/base/Data/HVect.idr
+++ b/libs/base/Data/HVect.idr
@@ -1,7 +1,6 @@
 module Data.HVect
 
-import Data.Fin
-import Data.Vect
+import public Data.Vect
 
 %access public
 %default total
@@ -42,6 +41,24 @@
 instance (Eq t, Eq (HVect ts)) => Eq (HVect (t::ts)) where
   (x::xs) == (y::ys) = x == y && xs == ys
 
+total
+hvectInjective1 : {xs, ys: HVect ts} -> {x, y:a} -> x :: xs = y :: ys -> x = y
+hvectInjective1 Refl = Refl
+
+total
+hvectInjective2 : {xs, ys: HVect ts} -> {x, y:a} -> x :: xs = y :: ys -> xs = ys
+hvectInjective2 Refl = Refl
+
+instance DecEq (HVect []) where
+  decEq [] [] = Yes Refl
+
+instance (DecEq t, DecEq (HVect ts)) => DecEq (HVect (t::ts)) where
+  decEq (x::xs) (y::ys) with (decEq x y)
+    decEq (z::xs) (z::ys) | Yes Refl with (decEq xs ys)
+      decEq (z::zs) (z::zs) | Yes Refl | Yes Refl = Yes Refl
+      decEq (z::xs) (z::ys) | Yes Refl | No ctr = No (ctr . hvectInjective2)
+    decEq (x::xs) (y::ys) | No ctr = No (ctr . hvectInjective1)
+
 class Shows (k : Nat) (ts : Vect k Type) where
   shows : HVect ts -> Vect k String
 
@@ -56,17 +73,17 @@
 
 ||| Extract an arbitrary element of the correct type.
 ||| @ t the goal type
-get : {default tactics { search 100; } p : Elem t ts} -> HVect ts -> t
+get : {auto p : Elem t ts} -> HVect ts -> t
 get {p = Here} (x::xs) = x
 get {p = There p'} (x::xs) = get {p = p'} xs
 
 ||| Replace an element with the correct type.
-put : {default tactics { search 100; } p : Elem t ts} -> t -> HVect ts -> HVect ts
+put : {auto p : Elem t ts} -> t -> HVect ts -> HVect ts
 put {p = Here} y (x::xs) = y :: xs
 put {p = There p'} y (x::xs) = x :: put {p = p'} y xs
 
 ||| Update an element with the correct type.
-update : {default tactics { search 100; } p : Elem t ts} -> (t -> u) -> HVect ts -> HVect (replaceByElem ts p u)
+update : {auto p : Elem t ts} -> (t -> u) -> HVect ts -> HVect (replaceByElem ts p u)
 update {p = Here} f (x::xs) = f x :: xs
 update {p = There p'} f (x::xs) = x :: update {p = p'} f xs
 
diff --git a/libs/base/Data/List.idr b/libs/base/Data/List.idr
--- a/libs/base/Data/List.idr
+++ b/libs/base/Data/List.idr
@@ -37,6 +37,14 @@
         mkNo f g Here = f Refl
         mkNo f g (There x) = g x
 
+||| Remove the element at the given position.
+|||
+||| @xs The list to be removed from
+||| @p A proof that the element to be removed is in the list
+dropElem : (xs : List a) -> (p : Elem x xs) -> List a
+dropElem (x :: ys) Here = ys 
+dropElem (x :: ys) (There p) = x :: dropElem ys p
+
 ||| The intersectBy function returns the intersect of two lists by user-supplied equality predicate.
 intersectBy : (a -> a -> Bool) -> List a -> List a -> List a
 intersectBy eq xs ys = [x | x <- xs, any (eq x) ys]
diff --git a/libs/base/Data/Vect.idr b/libs/base/Data/Vect.idr
--- a/libs/base/Data/Vect.idr
+++ b/libs/base/Data/Vect.idr
@@ -52,3 +52,30 @@
 mapElem Here = Here
 mapElem (There e) = There (mapElem e)
 
+-- Some convenience functions for testing lengths
+
+||| If the given Vect is the required length, return a Vect with that
+||| length in its type, otherwise return Nothing
+||| @len the required length
+||| @xs the vector with the desired length
+-- Needs to be Maybe rather than Dec, because if 'n' is unequal to m, we 
+-- only know we don't know how to make a Vect n a, not that one can't exist.
+isLength : {m : Nat} -> -- expected at run-time
+           (len : Nat) -> (xs : Vect m a) -> Maybe (Vect len a)
+isLength {m} len xs with (decEq m len)
+  isLength {m = m} m xs | (Yes Refl) = Just xs
+  isLength {m = m} len xs | (No contra) = Nothing
+
+||| If the given Vect is at least the required length, return a Vect with
+||| at least that length in its type, otherwise return Nothing
+||| @len the required length
+||| @xs the vector with the desired length
+overLength : {m : Nat} -> -- expected at run-time
+             (len : Nat) -> (xs : Vect m a) -> Maybe (p ** Vect (plus p len) a)
+overLength {m} n xs with (cmp m n)
+  overLength {m = m} (plus m (S y)) xs | (CmpLT y) = Nothing
+  overLength {m = m} m xs | CmpEQ
+         = Just (0 ** xs)
+  overLength {m = plus n (S x)} n xs | (CmpGT x)
+         = Just (S x ** rewrite plusCommutative (S x) n in xs)
+
diff --git a/libs/base/Data/VectType.idr b/libs/base/Data/VectType.idr
--- a/libs/base/Data/VectType.idr
+++ b/libs/base/Data/VectType.idr
@@ -1,6 +1,6 @@
 module Data.VectType
 
-import Data.Fin
+import public Data.Fin
 
 %access public
 %default total
@@ -9,9 +9,14 @@
 
 infixr 7 ::
 
-%elim data Vect : Nat -> Type -> Type where
+||| Vectors: Generic lists with explicit length in the type
+%elim 
+data Vect : Nat -> Type -> Type where
+  ||| Empty vector 
   Nil  : Vect Z a
-  (::) : (x : a) -> (xs : Vect n a) -> Vect (S n) a
+  ||| A non-empty vector of length `S k`, consisting of a head element and 
+  ||| the rest of the list, of length `k`.
+  (::) : (x : a) -> (xs : Vect k a) -> Vect (S k) a
 
 -- Hints for interactive editing
 %name Vect xs,ys,zs,ws
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
@@ -64,23 +64,23 @@
 
 mutual
   instance Show SpecialName where
-    show (WhereN i n1 n2) = "(WhereN " ++ show i ++ " " ++
-                            show n1 ++ " " ++ show n2 ++ ")"
-    show (WithN i n) = "(WithN " ++ show i ++ " " ++ show n ++ ")"
-    show (InstanceN i ss) = "(InstanceN " ++ show i ++ " " ++ show ss ++ ")"
-    show (ParentN n s) = "(ParentN " ++ show n ++ " " ++ show s ++ ")"
-    show (MethodN n) = "(MethodN " ++ show n ++ ")"
-    show (CaseN n) = "(CaseN " ++ show n ++ ")"
-    show (ElimN n) = "(ElimN " ++ show n ++ ")"
-    show (InstanceCtorN n) = "(InstanceCtorN " ++ show n ++ ")"
-    show (MetaN parent meta) = "(MetaN " ++ show parent ++ " " ++ show meta ++ ")"
+    showPrec d (WhereN i n1 n2) = showCon d "WhereN" $ showArg i ++
+                            showArg n1 ++ showArg n2
+    showPrec d (WithN i n) = showCon d "WithN" $ showArg i ++ showArg n
+    showPrec d (InstanceN i ss) = showCon d "InstanceN" $ showArg i ++ showArg ss
+    showPrec d (ParentN n s) = showCon d "ParentN" $ showArg n ++ showArg s
+    showPrec d (MethodN n) = showCon d "MethodN" $ showArg n
+    showPrec d (CaseN n) = showCon d "CaseN" $ showArg n
+    showPrec d (ElimN n) = showCon d "ElimN" $ showArg n
+    showPrec d (InstanceCtorN n) = showCon d "InstanceCtorN" $ showArg n
+    showPrec d (MetaN parent meta) = showCon d "MetaN" $ showArg parent ++ showArg meta
 
   instance Show TTName where
-    show (UN str)   = "(UN " ++ show str ++ ")"
-    show (NS n ns)  = "(NS " ++ show n ++ " " ++ show ns ++ ")"
-    show (MN i str) = "(MN " ++ show i ++ " " ++ show str ++ ")"
-    show (SN sn)    = "(SN " ++ assert_total (show sn) ++ ")"
-    show NErased    = "NErased"
+    showPrec d (UN str)   = showCon d "UN" $ showArg str
+    showPrec d (NS n ns)  = showCon d "NS" $ showArg n ++ showArg ns
+    showPrec d (MN i str) = showCon d "MN" $ showArg i ++ showArg str
+    showPrec d (SN sn)    = showCon d "SN" $ assert_total (showArg sn)
+    showPrec d NErased    = "NErased"
 
 mutual
   instance Eq TTName where
@@ -104,28 +104,44 @@
     _                   == _                     = False
 
 instance Show TTUExp where
-  show (UVar i) = "(UVar " ++ show i ++ ")"
-  show (UVal i) = "(UVal " ++ show i ++ ")"
+  showPrec d (UVar i) = showCon d "UVar" $ showArg i
+  showPrec d (UVal i) = showCon d "UVal" $ showArg i
 
 instance Eq TTUExp where
   (UVar i) == (UVar j) = i == j
   (UVal i) == (UVal j) = i == j
   x        == y        = False
 
+instance Show NativeTy where
+  show IT8  = "IT8"
+  show IT16 = "IT16"
+  show IT32 = "IT32"
+  show IT64 = "IT64"
+
+instance Show IntTy where
+  showPrec d (ITFixed t) = showCon d "ITFixed" $ showArg t
+  showPrec d ITNative    = "ITNative"
+  showPrec d ITBig       = "ITBig"
+  showPrec d ITChar      = "ITChar"
+
+instance Show ArithTy where
+  showPrec d (ATInt t) = showCon d "ATInt" $ showArg t
+  showPrec d ATFloat   = "ATFloat"
+
 instance Show Const where
-  show (I i)      = "(I " ++ show i ++ ")"
-  show (BI n)     = "(BI " ++ show n ++ ")"
-  show (Fl f)     = "(Fl " ++ show f ++ ")"
-  show (Ch c)     = "(Ch " ++ show c ++ ")"
-  show (Str str)  = "(Str " ++ show str ++ ")"
-  show (B8 b)     = "(B8 ...)"
-  show (B16 b)    = "(B16 ...)"
-  show (B32 b)    = "(B32 ...)"
-  show (B64 b)    = "(B64 ...)"
-  show (AType x) = "(AType ...)"
-  show StrType = "StrType"
-  show VoidType = "VoidType"
-  show Forgot = "Forgot"
+  showPrec d (I i)      = showCon d "I" $ showArg i
+  showPrec d (BI n)     = showCon d "BI" $ showArg n
+  showPrec d (Fl f)     = showCon d "Fl" $ showArg f
+  showPrec d (Ch c)     = showCon d "Ch" $ showArg c
+  showPrec d (Str str)  = showCon d "Str" $ showArg str
+  showPrec d (B8 b)     = showCon d "B8" $ showArg b
+  showPrec d (B16 b)    = showCon d "B16" $ showArg b
+  showPrec d (B32 b)    = showCon d "B32" $ showArg b
+  showPrec d (B64 b)    = showCon d "B64" $ showArg b
+  showPrec d (AType x)  = showCon d "AType" $ showArg x
+  showPrec d StrType    = "StrType"
+  showPrec d VoidType   = "VoidType"
+  showPrec d Forgot     = "Forgot"
 
 instance Eq NativeTy where
   IT8  == IT8  = True
@@ -164,10 +180,10 @@
 
 
 instance Show NameType where
-  show Bound = "Bound"
-  show Ref = "Ref"
-  show (DCon t ar) = "(DCon " ++ show t ++ " " ++ show ar ++ ")"
-  show (TCon t ar) = "(TCon " ++ show t ++ " " ++ show ar ++ ")"
+  showPrec d Bound = "Bound"
+  showPrec d Ref = "Ref"
+  showPrec d (DCon t ar) = showCon d "DCon" $ showArg t ++ showArg ar
+  showPrec d (TCon t ar) = showCon d "TCon" $ showArg t ++ showArg ar
 
 instance Eq NameType where
   Bound       == Bound          = True
@@ -177,15 +193,15 @@
   x           == y              = False
 
 instance (Show a) => Show (Binder a) where
-  show (Lam t) = "(Lam " ++ show t ++ ")"
-  show (Pi t _) = "(Pi " ++ show t ++ ")"
-  show (Let t1 t2) = "(Let " ++ show t1 ++ " " ++ show t2 ++ ")"
-  show (NLet t1 t2) = "(NLet " ++ show t1 ++ " " ++ show t2 ++ ")"
-  show (Hole t) = "(Hole " ++ show t ++ ")"
-  show (GHole t) = "(GHole " ++ show t ++ ")"
-  show (Guess t1 t2) = "(Guess " ++ show t1 ++ " " ++ show t2 ++ ")"
-  show (PVar t) = "(PVar " ++ show t ++ ")"
-  show (PVTy t) = "(PVTy " ++ show t ++ ")"
+  showPrec d (Lam t) = showCon d "Lam" $ showArg t
+  showPrec d (Pi t1 t2) = showCon d "Pi" $ showArg t1 ++ showArg t2
+  showPrec d (Let t1 t2) = showCon d "Let" $ showArg t1 ++ showArg t2
+  showPrec d (NLet t1 t2) = showCon d "NLet" $ showArg t1 ++ showArg t2
+  showPrec d (Hole t) = showCon d "Hole" $ showArg t
+  showPrec d (GHole t) = showCon d "GHole" $ showArg t
+  showPrec d (Guess t1 t2) = showCon d "Guess" $ showArg t1 ++ showArg t2
+  showPrec d (PVar t) = showCon d "PVar" $ showArg t
+  showPrec d (PVTy t) = showCon d "PVTy" $ showArg t
 
 instance (Eq a) => Eq (Binder a) where
   (Lam t)       == (Lam t')         = t == t'
@@ -200,17 +216,17 @@
   x             == y                = False
 
 instance Show TT where
-  show = my_show
-    where %assert_total my_show : TT -> String
-          my_show (P nt n t) = "(P " ++ show nt ++ " " ++ show n ++ " " ++ show t ++ ")"
-          my_show (V i) = "(V " ++ show i ++ ")"
-          my_show (Bind n b t) = "(Bind " ++ show n ++ " " ++ show b ++ " " ++ show t ++ ")"
-          my_show (App t1 t2) = "(App " ++ show t1 ++ " " ++ show t2 ++ ")"
-          my_show (TConst c) = "(TConst " ++ show c ++ ")"
-          my_show (Proj tm i) = "(Proj " ++ show tm ++ " " ++ show i ++ ")"
-          my_show Erased = "Erased"
-          my_show Impossible = "Impossible"
-          my_show (TType u) = "(TType " ++ show u ++ ")"
+  showPrec = my_show
+    where %assert_total my_show : Prec -> TT -> String
+          my_show d (P nt n t) = showCon d "P" $ showArg nt ++ showArg n ++ showArg t
+          my_show d (V i) = showCon d "V" $ showArg i
+          my_show d (Bind n b t) = showCon d "Bind" $ showArg n ++ showArg b ++ showArg t
+          my_show d (App t1 t2) = showCon d "App" $ showArg t1 ++ showArg t2
+          my_show d (TConst c) = showCon d "TConst" $ showArg c
+          my_show d (Proj tm i) = showCon d "Proj" $ showArg tm ++ showArg i
+          my_show d Erased = "Erased"
+          my_show d Impossible = "Impossible"
+          my_show d (TType u) = showCon d "TType" $ showArg u
 
 instance Eq TT where
   a == b = equalp a b
@@ -226,6 +242,12 @@
           equalp (TType u)    (TType u')       = u == u'
           equalp x            y                = False
 
+instance Eq Universe where
+  Reflection.NullType   == Reflection.NullType   = True
+  Reflection.UniqueType == Reflection.UniqueType = True
+  Reflection.AllTypes   == Reflection.AllTypes   = True
+  _                     == _                     = False
+
 total
 forget : TT -> Maybe Raw
 forget tm = fe [] tm
@@ -251,53 +273,54 @@
     fe env Impossible    = Nothing
 
 instance Show Raw where
-  show r = my_show r
-    where %assert_total my_show : Raw -> String
-          my_show (Var n) = "(Var " ++ show n ++ ")"
-          my_show (RBind n b tm) = "(RBind " ++ show n ++ " " ++ show b ++ " " ++ my_show tm ++ ")"
-          my_show (RApp tm tm') = "(RApp " ++ my_show tm ++ " " ++ my_show tm' ++ ")"
-          my_show RType = "RType"
-          my_show (RForce tm) = "(RForce " ++ my_show tm ++ ")"
-          my_show (RConstant c) = "(RConstant " ++ show c ++ ")"
+  showPrec = my_show
+    where %assert_total my_show : Prec -> Raw -> String
+          my_show d (Var n) = showCon d "Var" $ showArg n
+          my_show d (RBind n b tm) = showCon d "RBind" $ showArg n ++ showArg b ++ " " ++ my_show App tm
+          my_show d (RApp tm tm') = showCon d "RApp" $ " " ++ my_show App tm ++ " " ++ my_show App tm'
+          my_show d RType = "RType"
+          my_show d (RForce tm) = showCon d "RForce" $ " " ++ my_show App tm
+          my_show d (RConstant c) = showCon d "RConstant" $ showArg c
 
 instance Show SourceLocation where
-  show (FileLoc filename line col) = "FileLoc \"" ++ filename ++ "\" " ++ show line ++ " " ++ show col
+  showPrec d (FileLoc filename line col) = showCon d "FileLoc" $ showArg filename ++ showArg line ++ showArg col
 
 instance Show Err where
-  show (Msg x) = "Msg \"" ++ x ++ "\""
-  show (InternalMsg x) = "InternalMsg \"" ++ x ++ "\""
-  show (CantUnify x tm tm' err xs y) = "CantUnify " ++ show x ++
-                                       " ( " ++ show tm ++ ") (" ++ show tm' ++ ") (" ++ show err ++ ") " ++
-                                       show xs ++ " " ++ show y
-  show (InfiniteUnify n tm xs) = "InfiniteUnify " ++ show n ++ show tm ++ show xs
-  show (CantConvert tm tm' xs) = "CantConvert " ++ show tm ++ show tm' ++ show xs
-  show (CantSolveGoal tm ctxt) = "CantSolveGoal " ++ show tm ++ " " ++ show ctxt
-  show (UnifyScope n n' tm xs) = "UnifyScope " ++ show n ++ " " ++ show n' ++ " " ++ show tm ++ " " ++ show xs
-  show (CantInferType x) = "CantInferType " ++ show x
-  show (NonFunctionType tm tm') = "NonFunctionType " ++ show tm ++ show tm'
-  show (NotEquality tm tm') = "NotEquality " ++ show tm ++ " " ++ show tm'
-  show (TooManyArguments n) = "TooManyArguments " ++ show n
-  show (CantIntroduce tm) = "CantIntroduce " ++ show tm
-  show (NoSuchVariable n) = "NoSuchVariable " ++ show n
-  show (WithFnType tm) = "WithFnType " ++ show tm
-  show (CantMatch tm) = "CantMatch " ++ show tm
-  show (NoTypeDecl n) = "NoTypeDecl " ++ show n
-  show (NotInjective tm tm' x) = "NotInjective " ++ show tm ++ " " ++ show tm'
-  show (CantResolve tm) = "CantResolve " ++ show tm
-  show (InvalidTCArg n tm) = "InvalidTCName " ++ show n ++ " (" ++ show tm ++ ")"
-  show (CantResolveAlts xs) = "CantResolveAlts " ++ show xs
-  show (IncompleteTerm tm) = "IncompleteTerm " ++ show tm
-  show (NoEliminator s tm) = "NoEliminator " ++ show s ++ " " ++ show tm
-  show UniverseError = "UniverseError"
-  show ProgramLineComment = "ProgramLineComment"
-  show (Inaccessible n) = "Inaccessible " ++ show n
-  show (UnknownImplicit n f) = "UnknownImplicit " ++ show n ++ " "  ++ show f
-  show (NonCollapsiblePostulate n) = "NonCollapsiblePostulate " ++ show n
-  show (AlreadyDefined n) = "AlreadyDefined " ++ show n
-  show (ProofSearchFail err) = "ProofSearchFail " ++ show err
-  show (NoRewriting tm) = "NoRewriting " ++ show tm
-  show (ProviderError x) = "ProviderError \"" ++ show x ++ "\""
-  show (LoadingFailed x err) = "LoadingFailed " ++ show x ++ " (" ++ show err ++ ")"
+  showPrec d (Msg x) = showCon d "Msg" $ showArg x
+  showPrec d (InternalMsg x) = showCon d "InternalMsg" $ showArg x
+  showPrec d (CantUnify x tm tm' err xs y) = showCon d "CantUnify" $ showArg x ++
+                                       showArg tm ++ showArg tm' ++ showArg err ++
+                                       showArg xs ++ showArg y
+  showPrec d (InfiniteUnify n tm xs) = showCon d "InfiniteUnify" $ showArg n ++ showArg tm ++ showArg xs
+  showPrec d (CantConvert tm tm' xs) = showCon d "CantConvert" $ showArg tm ++ showArg tm' ++ showArg xs
+  showPrec d (CantSolveGoal tm ctxt) = showCon d "CantSolveGoal" $ showArg tm ++ showArg ctxt
+  showPrec d (UnifyScope n n' tm xs) = showCon d "UnifyScope" $ showArg n ++ showArg n' ++ showArg tm ++ showArg xs
+  showPrec d (CantInferType x) = showCon d "CantInferType" $ showArg x
+  showPrec d (NonFunctionType tm tm') = showCon d "NonFunctionType" $ showArg tm ++ showArg tm'
+  showPrec d (NotEquality tm tm') = showCon d "NotEquality" $ showArg tm ++ showArg tm'
+  showPrec d (TooManyArguments n) = showCon d "TooManyArguments" $ showArg n
+  showPrec d (CantIntroduce tm) = showCon d "CantIntroduce" $ showArg tm
+  showPrec d (NoSuchVariable n) = showCon d "NoSuchVariable" $ showArg n
+  showPrec d (WithFnType tm) = showCon d "WithFnType" $ showArg tm
+  showPrec d (CantMatch tm) = showCon d "CantMatch" $ showArg tm
+  showPrec d (NoTypeDecl n) = showCon d "NoTypeDecl" $ showArg n
+  showPrec d (NotInjective tm tm' x) = showCon d "NotInjective" $ showArg tm ++ showArg tm'
+  showPrec d (CantResolve tm) = showCon d "CantResolve" $ showArg tm
+  showPrec d (InvalidTCArg n tm) = showCon d "InvalidTCName" $ showArg n ++ showArg tm
+  showPrec d (CantResolveAlts xs) = showCon d "CantResolveAlts" $ showArg xs
+  showPrec d (NoValidAlts xs) = showCon d "NoValidAlts" $ showArg xs
+  showPrec d (IncompleteTerm tm) = showCon d "IncompleteTerm" $ showArg tm
+  showPrec d (NoEliminator s tm) = showCon d "NoEliminator" $ showArg s ++ showArg tm
+  showPrec d UniverseError = "UniverseError"
+  showPrec d ProgramLineComment = "ProgramLineComment"
+  showPrec d (Inaccessible n) = showCon d "Inaccessible" $ showArg n
+  showPrec d (UnknownImplicit n f) = showCon d "UnknownImplicit" $ showArg n ++ showArg f
+  showPrec d (NonCollapsiblePostulate n) = showCon d "NonCollapsiblePostulate" $ showArg n
+  showPrec d (AlreadyDefined n) = showCon d "AlreadyDefined" $ showArg n
+  showPrec d (ProofSearchFail err) = showCon d "ProofSearchFail" $ showArg err
+  showPrec d (NoRewriting tm) = showCon d "NoRewriting" $ showArg tm
+  showPrec d (ProviderError x) = showCon d "ProviderError" $ showArg x
+  showPrec d (LoadingFailed x err) = showCon d "LoadingFailed" $ showArg x ++ showArg err
 
 -------------------------
 -- Idiom brackets for Raw
@@ -312,11 +335,23 @@
 --------------------------------------
 -- Instances for definition reflection
 --------------------------------------
-instance Show Arg where
-  show (Explicit n t) = "(Explicit " ++ show n ++ " " ++ show t ++ ")"
-  show (Implicit n t) = "(Implicit " ++ show n ++ " " ++ show t ++ ")"
-  show (Constraint n t) = "(Constraint " ++ show n ++ " " ++ show t ++ ")"
+instance Show Erasure where
+  show Erased    = "Erased"
+  show NotErased = "NotErased"
 
+instance Show Plicity where
+  show Explicit = "Explicit"
+  show Implicit = "Implicit"
+  show Constraint = "Constraint"
+
+instance Show FunArg where
+  showPrec d (MkFunArg n ty plic era) = showCon d "MkFunArg" $ showArg n ++
+                                        showArg ty ++ showArg plic ++ showArg era
+
+instance Show CtorArg where
+  showPrec d (CtorParameter fa) = showCon d "CtorParameter" $ showArg fa
+  showPrec d (CtorField fa) = showCon d "CtorField" $ showArg fa
+
 instance Show TyDecl where
-  show (Declare fn args ret) = "(Declare " ++ show fn ++ " " ++
-                               show args ++ " " ++ show ret ++ ")"
+  showPrec d (Declare fn args ret) = showCon d "Declare" $ showArg fn ++
+                                     showArg args ++ showArg ret
diff --git a/libs/base/System.idr b/libs/base/System.idr
--- a/libs/base/System.idr
+++ b/libs/base/System.idr
@@ -4,23 +4,7 @@
 %default partial
 %access public
 
-||| Get the command-line arguments that the program was called with.
-getArgs : IO (List String)
-getArgs = do n <- numArgs
-             ga' [] 0 n
-  where
-    numArgs : IO Int
-    numArgs = foreign FFI_C "idris_numArgs" (IO Int)
-
-    getArg : Int -> IO String
-    getArg x = foreign FFI_C "idris_getArg" (Int -> IO String) x
-
-    ga' : List String -> Int -> Int -> IO (List String)
-    ga' acc i n = if (i == n) then (return $ reverse acc) else
-                    do arg <- getArg i
-                       ga' (arg :: acc) (i+1) n
-
-||| Retrieves an value from the environment, if the given key is present,
+||| Retrieves a value from the environment if the given key is present,
 ||| otherwise it returns Nothing.
 getEnv : String -> IO (Maybe String)
 getEnv key = do
@@ -73,8 +57,9 @@
 exit code = foreign FFI_C "exit" (Int -> IO ()) code
 
 ||| Get the Unix time
-time : IO Int
-time = foreign FFI_C "idris_time" (IO Int)
+time : IO Integer
+time = do MkRaw t <- foreign FFI_C "idris_time" (IO (Raw Integer))
+          return t
 
 usleep : Int -> IO ()
 usleep i = foreign FFI_C "usleep" (Int -> IO ()) i
diff --git a/libs/base/System/Concurrency/Raw.idr b/libs/base/System/Concurrency/Raw.idr
--- a/libs/base/System/Concurrency/Raw.idr
+++ b/libs/base/System/Concurrency/Raw.idr
@@ -7,15 +7,25 @@
 import System
 
 ||| Send a message of any type to the thread with the given thread id
-sendToThread : (thread_id : Ptr) -> a -> IO ()
+||| Returns 1 if the message was sent successfully, 0 otherwise
+sendToThread : (thread_id : Ptr) -> a -> IO Int
 sendToThread {a} dest val
-   = foreign FFI_C "idris_sendMessage" (Ptr -> Ptr -> Raw a -> IO ())
+   = foreign FFI_C "idris_sendMessage" (Ptr -> Ptr -> Raw a -> IO Int)
                 prim__vm dest (MkRaw val)
 
 ||| Check for messages in the process inbox
 checkMsgs : IO Bool
 checkMsgs = do msgs <- foreign FFI_C "idris_checkMessages" (Ptr -> IO Ptr)
                             prim__vm
+               null <- nullPtr msgs
+               return (not null)
+
+||| Check for messages in the process inbox
+||| If no messages, waits for the given number of seconds
+checkMsgsTimeout : Int -> IO Bool
+checkMsgsTimeout timeout
+          = do msgs <- foreign FFI_C "idris_checkMessagesTimeout" 
+                            (Ptr -> Int -> IO Ptr) prim__vm timeout
                null <- nullPtr msgs
                return (not null)
 
diff --git a/libs/base/base.ipkg b/libs/base/base.ipkg
--- a/libs/base/base.ipkg
+++ b/libs/base/base.ipkg
@@ -5,7 +5,7 @@
 
           Debug.Error, Debug.Trace,
 
-          System.Info,
+          System.Info, 
 
           Language.Reflection.Utils,
 
diff --git a/libs/contrib/Control/Algebra.idr b/libs/contrib/Control/Algebra.idr
--- a/libs/contrib/Control/Algebra.idr
+++ b/libs/contrib/Control/Algebra.idr
@@ -54,7 +54,7 @@
 |||     forall a,     inverse a <+> a == neutral
 ||| + Associativity of `<.>`:
 |||     forall a b c, a <.> (b <.> c) == (a <.> b) <.> c
-||| + Distributivity of `<.>` and `<->`:
+||| + Distributivity of `<.>` and `<+>`:
 |||     forall a b c, a <.> (b <+> c) == (a <.> b) <+> (a <.> c)
 |||     forall a b c, (a <+> b) <.> c == (a <.> c) <+> (b <.> c)
 class AbelianGroup a => Ring a where
@@ -80,7 +80,7 @@
 ||| + Neutral for `<.>`:
 |||     forall a,     a <.> unity     == a
 |||     forall a,     unity <.> a     == a
-||| + Distributivity of `<.>` and `<->`:
+||| + Distributivity of `<.>` and `<+>`:
 |||     forall a b c, a <.> (b <+> c) == (a <.> b) <+> (a <.> c)
 |||     forall a b c, (a <+> b) <.> c == (a <.> c) <+> (b <.> c)
 class Ring a => RingWithUnity a where
@@ -109,21 +109,21 @@
 ||| + InverseM of `<.>`, except for neutral
 |||     forall a /= neutral,  a <.> inverseM a == unity
 |||     forall a /= neutral,  inverseM a <.> a == unity
-||| + Distributivity of `<.>` and `<->`:
+||| + Distributivity of `<.>` and `<+>`:
 |||     forall a b c, a <.> (b <+> c) == (a <.> b) <+> (a <.> c)
 |||     forall a b c, (a <+> b) <.> c == (a <.> c) <+> (b <.> c)
 class RingWithUnity a => Field a where
   inverseM : (x : a) -> Not (x = neutral) -> a
 
-sum : (Foldable t, Monoid a) => t a -> a
-sum = foldr (<+>) neutral
+sum' : (Foldable t, Monoid a) => t a -> a
+sum' = concat
 
-product : (Foldable t, RingWithUnity a) => t a -> a
-product = foldr (<.>) unity
+product' : (Foldable t, RingWithUnity a) => t a -> a
+product' = foldr (<.>) unity
 
-power : RingWithUnity a => a -> Nat -> a
-power _ Z     = unity
-power x (S n) = x <.> (Algebra.power x n)
+pow' : RingWithUnity a => a -> Nat -> a
+pow' _ Z     = unity
+pow' x (S n) = x <.> pow' x n
 
 
 -- XXX todo:
diff --git a/libs/contrib/Control/Algebra/NumericInstances.idr b/libs/contrib/Control/Algebra/NumericInstances.idr
--- a/libs/contrib/Control/Algebra/NumericInstances.idr
+++ b/libs/contrib/Control/Algebra/NumericInstances.idr
@@ -1,6 +1,9 @@
+||| Instances of algebraic classes (group, ring, etc) for numeric data types,
+||| and Complex number types.
 module Control.Algebra.NumericInstances
 
 import Control.Algebra
+import Control.Algebra.VectorSpace
 import Data.Complex
 import Data.ZZ
 
@@ -102,3 +105,9 @@
 
 instance RingWithUnity a => RingWithUnity (Complex a) where
   unity = (unity :+ neutral)
+
+instance RingWithUnity a => Module a (Complex a) where
+  (<#>) x = map (x <.>)
+
+instance RingWithUnity a => InnerProductSpace a (Complex a) where
+  (x :+ y) <||> z = realPart $ (x :+ inverse y) <.> z
diff --git a/libs/contrib/Data/Fun.idr b/libs/contrib/Data/Fun.idr
--- a/libs/contrib/Data/Fun.idr
+++ b/libs/contrib/Data/Fun.idr
@@ -1,6 +1,6 @@
 module Data.Fun
 
-import Data.Vect
+import public Data.Vect
 
 %default total
 
diff --git a/libs/contrib/Data/Heap.idr b/libs/contrib/Data/Heap.idr
--- a/libs/contrib/Data/Heap.idr
+++ b/libs/contrib/Data/Heap.idr
@@ -114,8 +114,8 @@
 --------------------------------------------------------------------------------
 
 instance Show a => Show (MaxiphobicHeap a) where
-  show Empty = "Empty"
-  show (Node s l e r) = "Node (" ++ show l ++ " " ++ show e ++ " " ++ show r ++ ")"
+  showPrec d Empty = "Empty"
+  showPrec d (Node s l e r) = showCon d "Node" $ " _" ++ showArg l ++ showArg e ++ showArg r
 
 instance Eq a => Eq (MaxiphobicHeap a) where
   Empty              == Empty              = True
diff --git a/libs/contrib/Data/Matrix.idr b/libs/contrib/Data/Matrix.idr
--- a/libs/contrib/Data/Matrix.idr
+++ b/libs/contrib/Data/Matrix.idr
@@ -1,150 +1,58 @@
+||| Basic matrix operations with dimensionalities enforced
+||| at the type level
 module Data.Matrix
 
-import        Control.Algebra
-import        Control.Algebra.VectorSpace
-import public Control.Algebra.NumericInstances
-
-import Data.Complex
-import Data.ZZ
-import Data.Fin
-import Data.Vect
+import public Data.Vect
 
 %default total
 
-infixr 2 <:>  -- vector inner product
-infixr 2 ><   -- vector outer product
-infixr 2 <<>> -- matrix commutator
-infixr 2 >><< -- matrix anticommutator
-infixl 3 <\>  -- row times a matrix
-infixr 4 </>  -- matrix times a column
-infixr 5 <>   -- matrix multiplication
-infixr 7 \&\  -- vector tensor product
-infixr 7 <&>  -- matrix tensor product
-
------------------------------------------------------------------------
---               Vectors as members of algebraic classes
------------------------------------------------------------------------
-
-instance Semigroup a => Semigroup (Vect n a) where
-  (<+>) v w = zipWith (<+>) v w
-
-instance Monoid a => Monoid (Vect n a) where
-  neutral {n} = replicate n neutral
-
-instance Group a => Group (Vect n a) where
-  inverse = map inverse
-
-instance AbelianGroup a => AbelianGroup (Vect n a) where {}
-
-instance Ring a => Ring (Vect n a) where
-  (<.>) v w = zipWith (<.>) v w
-
-instance RingWithUnity a => RingWithUnity (Vect n a) where
-  unity {n} = replicate n unity
-
---instance Field a => Field (Vect n a) where
-
-instance RingWithUnity a => Module a (Vect n a) where
-  (<#>) r v = map (r <.>) v
-
-instance RingWithUnity a => Module a (Vect n (Vect l a)) where
-  (<#>) r m = map (r <#>) m
--- should be Module a b => Module a (Vect n b), but results in 'overlapping instance'
-
------------------------------------------------------------------------
---                       (Ring) Vector functions
------------------------------------------------------------------------
-
-||| Inner product of ring vectors
-(<:>) : Ring a => Vect n a -> Vect n a -> a
-(<:>) w v = foldr (<+>) neutral (zipWith (<.>) w v)
-
-||| Tensor multiply (⊗) ring vectors
-(\&\) : Ring a => Vect n a -> Vect m a -> Vect (n * m) a
-(\&\) {n} {m} v w = zipWith (<.>) (oextend m v) (orep n w) where
-  orep : (n : Nat) -> Vect m a -> Vect (n * m) a
-  orep n v = concat $ replicate n v
-  oextend : (n : Nat) -> Vect k a -> Vect (k * n) a
-  oextend n w = concat $ map (replicate n) w
-
-||| Standard basis vector with one nonzero entry, ring data type and vector-length unfixed
-basis : RingWithUnity a => {d : Nat} -> (Fin d) -> Vect d a
-basis i = replaceAt i unity $ neutral
-
------------------------------------------------------------------------
---                          Matrix functions
------------------------------------------------------------------------
-
 ||| Matrix with n rows and m columns
 Matrix : Nat -> Nat -> Type -> Type
 Matrix n m a = Vect n (Vect m a)
 
-||| Gets the specified column of a matrix. For rows use the vector function 'index'
+||| Get the specified column of a matrix
 getCol : Fin m -> Matrix n m a -> Vect n a
-getCol fm q = map (index fm) q
+getCol f = map (index f)
 
-||| Deletes the specified column of a matrix. For rows use the vector function 'deleteAt'
-deleteCol : Fin (S m) -> Matrix n (S m) a -> Matrix n m a
-deleteCol f m = map (deleteAt f) m
+||| Get the specified row of a matrix
+getRow : Fin n -> Matrix n m a -> Vect m a
+getRow = index
 
-||| Matrix element at specified row and column indices
-indices : Fin n -> Fin m -> Matrix n m a -> a
-indices f1 f2 m = index f2 (index f1 m)
+||| Delete the specified column of a matrix
+deleteCol : Fin (S m) -> Matrix n (S m) a -> Matrix n m a
+deleteCol f = map (deleteAt f)
 
-||| Matrix times a column vector
-(</>) : Ring a => Matrix n m a -> Vect m a -> Vect n a
-(</>) m v = map (v <:>) m
+||| Delete the specified row of a matrix
+deleteRow : Fin (S n) -> Matrix (S n) m a -> Matrix n m a
+deleteRow = deleteAt
 
-||| Matrix times a row vector
-(<\>) : Ring a => Vect n a -> Matrix n m a -> Vect m a
-(<\>) r m = map (r <:>) $ transpose m
+insertRow : Fin (S n) -> Vect m a -> Matrix n m a -> Matrix (S n) m a
+insertRow = insertAt
 
-||| Matrix multiplication
-(<>) : Ring a => Matrix n k a ->
-                 Matrix k m a ->
-                 Matrix n m a
-(<>) m1 m2 = map (<\> m2) m1
+insertCol : Fin (S m) -> Vect n a -> Matrix n m a -> Matrix n (S m) a
+insertCol f = zipWith (insertAt f)
 
-||| Tensor multiply (⊗) for ring matrices
-(<&>) : Ring a => Matrix h1 w1 a -> Matrix h2 w2 a -> Matrix (h1 * h2) (w1 * w2) a
-(<&>) m1 m2 = zipWith (\&\) (stepOne m1 m2) (stepTwo m1 m2) where
-  stepOne : Matrix h1 w1 a -> Matrix h2 w2 a -> Matrix (h1 * h2) w1 a
-  stepOne {h2} m1 m2 = concat $ map (replicate h2) m1
-  stepTwo : Matrix h1 w1 a -> Matrix h2 w2 a -> Matrix (h1 * h2) w2 a
-  stepTwo {h1} m1 m2 = concat $ (Vect.replicate h1) m2
+||| Matrix element at specified row and column indices
+indices : Fin n -> Fin m -> Matrix n m a -> a
+indices f1 f2 = index f2 . index f1
 
 ||| Cast a vector from a standard Vect to a proper n x 1 matrix
 col : Vect n a -> Matrix n 1 a
-col v = map (\x => [x]) v
+col = map (\x => [x])
 
 ||| Cast a row from a standard Vect to a proper 1 x n matrix
 row : Vect n a -> Matrix 1 n a
 row r = [r]
 
-||| Outer product between ring vectors
-(><) : Ring a => Vect n a -> Vect m a -> Matrix n m a
-(><) x y = (col x) <> (row y)
-
-||| All finite numbers up to the given bound
-allN : (n : Nat) -> Vect n (Fin n)
-allN Z     = Nil
-allN (S n) = FZ :: (map FS $ allN n)
-
-||| Identity matrix
-Id : RingWithUnity a => {d : Nat} -> Matrix d d a
-Id {d} = map (\n => basis n) $ allN d
-
-||| Matrix commutator
-(<<>>) : Ring a => Matrix n n a -> Matrix n n a -> Matrix n n a
-(<<>>) m1 m2 = (m1 <> m2) <-> (m2 <> m1)
-
-||| Matrix anti-commutator
-(>><<) : Ring a => Matrix n n a -> Matrix n n a -> Matrix n n a
-(>><<) m1 m2 = (m1 <> m2) <+> (m2 <> m1)
-
------------------------------------------------------------------------
---                      Matrix Algebra Properties
------------------------------------------------------------------------
+||| Matrix formed by deleting specified row and col
+subMatrix : Fin (S n) -> Fin (S m) -> Matrix (S n) (S m) a -> Matrix n m a
+subMatrix r c = deleteRow r . deleteCol c
 
--- TODO: Prove properties of matrix algebra for 'Verified' algebraic classes
+||| Flatten a matrix of matrices
+concatMatrix : Matrix n m (Matrix x y a) -> Matrix (n * x) (m * y) a
+concatMatrix = Vect.concat . map (map Vect.concat) . map transpose
 
+||| All finite numbers of the specified level
+fins : (n : Nat) -> Vect n (Fin n)
+fins Z     = Nil
+fins (S n) = FZ :: (map FS $ fins n)
diff --git a/libs/contrib/Data/Matrix/Algebraic.idr b/libs/contrib/Data/Matrix/Algebraic.idr
new file mode 100644
--- /dev/null
+++ b/libs/contrib/Data/Matrix/Algebraic.idr
@@ -0,0 +1,149 @@
+||| Matrix operations with vector space dimensionalities enforced
+||| at the type level. Uses operations from classes in `Control.Algebra`
+||| and `Control.Algebra.VectorSpace`.
+module Data.Matrix.Algebraic
+
+import public Control.Algebra
+import public Control.Algebra.VectorSpace
+import public Control.Algebra.NumericInstances
+
+import public Data.Matrix
+
+
+%default total
+
+infixr 2 <:>  -- vector inner product
+infixr 2 ><   -- vector outer product
+infixr 2 <<>> -- matrix commutator
+infixr 2 >><< -- matrix anticommutator
+infixl 3 <\>  -- row times a matrix
+infixr 4 </>  -- matrix times a column
+infixr 5 <>   -- matrix multiplication
+infixr 7 \&\  -- vector tensor product
+infixr 7 <&>  -- matrix tensor product
+
+-----------------------------------------------------------------------
+--               Vectors as members of algebraic classes
+-----------------------------------------------------------------------
+
+instance Semigroup a => Semigroup (Vect n a) where
+  (<+>)= zipWith (<+>)
+
+instance Monoid a => Monoid (Vect n a) where
+  neutral {n} = replicate n neutral
+
+instance Group a => Group (Vect n a) where
+  inverse = map inverse
+
+instance AbelianGroup a => AbelianGroup (Vect n a) where {}
+
+instance Ring a => Ring (Vect n a) where
+  (<.>) = zipWith (<.>)
+
+instance RingWithUnity a => RingWithUnity (Vect n a) where
+  unity {n} = replicate n unity
+
+instance RingWithUnity a => Module a (Vect n a) where
+  (<#>) r = map (r <.>)
+
+instance RingWithUnity a => Module a (Vect n (Vect l a)) where
+  (<#>) r = map (r <#>)
+-- should be Module a b => Module a (Vect n b), but results in 'overlapping instance'
+
+-----------------------------------------------------------------------
+--                        (Ring) Vector functions
+-----------------------------------------------------------------------
+
+||| Inner product of ring vectors
+(<:>) : Ring a => Vect n a -> Vect n a -> a
+(<:>) w v = foldr (<+>) neutral (zipWith (<.>) w v)
+
+||| Tensor multiply (⊗) ring vectors
+(\&\) : Ring a => Vect n a -> Vect m a -> Vect (n * m) a
+(\&\) {n} {m} v w = zipWith (<.>) (oextend m v) (orep n w) where
+  orep : (n : Nat) -> Vect m a -> Vect (n * m) a
+  orep n v = concat $ replicate n v
+  oextend : (n : Nat) -> Vect k a -> Vect (k * n) a
+  oextend n w = concat $ map (replicate n) w
+
+||| Standard basis vector with one nonzero entry, ring data type and vector-length unfixed
+basis : RingWithUnity a => (Fin d) -> Vect d a
+basis i = replaceAt i unity neutral
+
+-----------------------------------------------------------------------
+--                         Ring Matrix functions
+-----------------------------------------------------------------------
+
+||| Matrix times a column vector
+(</>) : Ring a => Matrix n m a -> Vect m a -> Vect n a
+(</>) m v = map (v <:>) m
+
+||| Matrix times a row vector
+(<\>) : Ring a => Vect n a -> Matrix n m a -> Vect m a
+(<\>) r m = map (r <:>) $ transpose m
+
+||| Matrix multiplication
+(<>) : Ring a => Matrix n k a ->
+                 Matrix k m a ->
+                 Matrix n m a
+(<>) m1 m2 = map (<\> m2) m1
+
+||| Tensor multiply (⊗) for ring matrices
+(<&>) : Ring a => Matrix h1 w1 a -> Matrix h2 w2 a -> Matrix (h1 * h2) (w1 * w2) a
+(<&>) m1 m2 = zipWith (\&\) (stepOne m1 m2) (stepTwo m1 m2) where
+  stepOne : Matrix h1 w1 a -> Matrix h2 w2 a -> Matrix (h1 * h2) w1 a
+  stepOne {h2} m1 m2 = concat $ map (replicate h2) m1
+  stepTwo : Matrix h1 w1 a -> Matrix h2 w2 a -> Matrix (h1 * h2) w2 a
+  stepTwo {h1} m1 m2 = concat $ replicate h1 m2
+
+||| Outer product between ring vectors
+(><) : Ring a => Vect n a -> Vect m a -> Matrix n m a
+(><) x y = col x <> row y
+
+||| Matrix commutator
+(<<>>) : Ring a => Matrix n n a -> Matrix n n a -> Matrix n n a
+(<<>>) m1 m2 = (m1 <> m2) <-> (m2 <> m1)
+
+||| Matrix anti-commutator
+(>><<) : Ring a => Matrix n n a -> Matrix n n a -> Matrix n n a
+(>><<) m1 m2 = (m1 <> m2) <+> (m2 <> m1)
+
+||| Identity matrix
+Id : RingWithUnity a => Matrix d d a
+Id = map (\n => basis n) (fins _)
+
+||| Square matrix from diagonal elements
+diag_ : Monoid a => Vect n a -> Matrix n n a
+diag_ = zipWith (\f => \x => replaceAt f x neutral) (fins _)
+
+||| Combine two matrices to make a new matrix in block diagonal form
+blockDiag : Monoid a => Matrix n n a -> Matrix m m a -> Matrix (n+m) (n+m) a
+blockDiag g h = map (++ replicate _ neutral) g ++ map ((replicate _ neutral) ++) h
+
+
+-----------------------------------------------------------------------
+--                           Determinants
+-----------------------------------------------------------------------
+
+||| Alternating sum
+altSum : Group a => Vect n a -> a
+altSum (x::y::zs) = (x <-> y) <+> altSum zs
+altSum [x]        = x
+altSum []         = neutral
+
+||| Determinant of a 2-by-2 matrix
+det2 : Ring a => Matrix 2 2 a -> a
+det2 [[x1,x2],[y1,y2]] = x1 <.> y2 <-> x2 <.> y1
+
+||| Determinant of a square matrix
+det : Ring a => Matrix (S (S n)) (S (S n)) a -> a
+det {n} m = case n of
+  Z     => det2 m
+  (S k) => altSum . map (\c => indices FZ c m <.> det (subMatrix FZ c m))
+         $ fins (S (S (S k)))
+
+-----------------------------------------------------------------------
+--                      Matrix Algebra Properties
+-----------------------------------------------------------------------
+
+-- TODO: Prove properties of matrix algebra for 'Verified' algebraic classes
diff --git a/libs/contrib/Data/Matrix/Numeric.idr b/libs/contrib/Data/Matrix/Numeric.idr
new file mode 100644
--- /dev/null
+++ b/libs/contrib/Data/Matrix/Numeric.idr
@@ -0,0 +1,129 @@
+||| Matrix operations with vector space dimensionalities enforced
+||| at the type level. Uses operations from the Num type class.
+module Data.Matrix.Numeric
+
+import public Data.Matrix
+
+%default total
+
+infixr 2 <:>  -- vector inner product
+infixr 2 ><   -- vector outer product
+infixr 2 <<>> -- matrix commutator
+infixr 2 >><< -- matrix anticommutator
+infixl 3 <\>  -- row times a matrix
+infixr 4 </>  -- matrix times a column
+infixr 5 <>   -- matrix multiplication
+infixl 5 <#>  -- matrix rescale
+infixl 5 <#   -- vector rescale
+infixr 7 \&\  -- vector tensor product
+infixr 7 <&>  -- matrix tensor product
+
+-----------------------------------------------------------------------
+--                   Vectors as members of Num
+-----------------------------------------------------------------------
+
+instance Num a => Num (Vect n a) where
+  (+) = zipWith (+)
+  (-) = zipWith (+)
+  (*) = zipWith (*)
+  abs = id
+  fromInteger n = replicate _ (fromInteger n)
+
+-----------------------------------------------------------------------
+--                        Vector functions
+-----------------------------------------------------------------------
+
+||| Inner product of ring vectors
+(<:>) : Num a => Vect n a -> Vect n a -> a
+(<:>) w v = sum $ zipWith (*) w v
+
+||| Scale a numeric vector by a scalar
+(<#) : Num a => a -> Vect n a -> Vect n a
+(<#) r = map (r *)
+
+||| Tensor multiply (⊗) numeric vectors
+(\&\) : Num a => Vect n a -> Vect m a -> Vect (n * m) a
+(\&\) {n} {m} v w = zipWith (*) (oextend m v) (orep n w) where
+  orep : (n : Nat) -> Vect m a -> Vect (n * m) a
+  orep n v = concat $ replicate n v
+  oextend : (n : Nat) -> Vect k a -> Vect (k * n) a
+  oextend n w = concat $ map (replicate n) w
+
+||| Standard basis vector with one nonzero entry, numeric data type and vector-length unfixed
+basis : Num a => (Fin d) -> Vect d a
+basis i = replaceAt i 1 0
+
+-----------------------------------------------------------------------
+--                          Matrix functions
+-----------------------------------------------------------------------
+
+||| Matrix times a column vector
+(</>) : Num a => Matrix n m a -> Vect m a -> Vect n a
+(</>) m v = map (v <:>) m
+
+||| Matrix times a row vector
+(<\>) : Num a => Vect n a -> Matrix n m a -> Vect m a
+(<\>) r m = map (r <:>) $ transpose m
+
+||| Matrix multiplication
+(<>) : Num a => Matrix n k a ->
+                Matrix k m a ->
+                Matrix n m a
+(<>) m1 m2 = map (<\> m2) m1
+
+||| Scale matrix by a scalar
+(<#>) : Num a => a -> Matrix n m a -> Matrix n m a
+(<#>) r = map (r <#)
+
+||| Tensor multiply (⊗) for numeric matrices
+(<&>) : Num a => Matrix h1 w1 a -> Matrix h2 w2 a -> Matrix (h1 * h2) (w1 * w2) a
+(<&>) m1 m2 = zipWith (\&\) (stepOne m1 m2) (stepTwo m1 m2) where
+  stepOne : Matrix h1 w1 a -> Matrix h2 w2 a -> Matrix (h1 * h2) w1 a
+  stepOne {h2} m1 m2 = concat $ map (replicate h2) m1
+  stepTwo : Matrix h1 w1 a -> Matrix h2 w2 a -> Matrix (h1 * h2) w2 a
+  stepTwo {h1} m1 m2 = concat $ replicate h1 m2
+
+||| Outer product between numeric vectors
+(><) : Num a => Vect n a -> Vect m a -> Matrix n m a
+(><) x y = col x <> row y
+
+||| Matrix commutator
+(<<>>) : Num a => Matrix n n a -> Matrix n n a -> Matrix n n a
+(<<>>) m1 m2 = (m1 <> m2) - (m2 <> m1)
+
+||| Matrix anti-commutator
+(>><<) : Num a => Matrix n n a -> Matrix n n a -> Matrix n n a
+(>><<) m1 m2 = (m1 <> m2) + (m2 <> m1)
+
+||| Identity matrix
+Id : Num a => Matrix d d a
+Id = map (\n => basis n) (fins _)
+
+||| Square matrix from diagonal elements
+diag_ : Num a => Vect n a -> Matrix n n a
+diag_ = zipWith (\f => \x => replaceAt f x 0) (fins _)
+
+||| Combine two matrices to make a new matrix in block diagonal form
+blockDiag : Num a => Matrix n n a -> Matrix m m a -> Matrix (n+m) (n+m) a
+blockDiag {n} {m} g h = map (++ replicate m 0) g ++ map ((replicate n 0) ++) h
+
+-----------------------------------------------------------------------
+--                           Determinants
+-----------------------------------------------------------------------
+
+||| Alternating sum
+altSum : Num a => Vect n a -> a
+altSum (x::y::zs) = (x - y) + altSum zs
+altSum [x]        = x
+altSum []         = 0
+
+||| Determinant of a 2-by-2 matrix
+det2 : Num a => Matrix 2 2 a -> a
+det2 [[x1,x2],[y1,y2]] = x1*y2 - x2*y1
+
+||| Determinant of a square matrix
+det : Num a => Matrix (S (S n)) (S (S n)) a -> a
+det {n} m = case n of
+  Z     => det2 m
+  (S k) => altSum . map (\c => indices FZ c m * det (subMatrix FZ c m))
+         $ fins (S (S (S k)))
diff --git a/libs/contrib/Data/Nat.idr b/libs/contrib/Data/Nat.idr
deleted file mode 100644
--- a/libs/contrib/Data/Nat.idr
+++ /dev/null
@@ -1,166 +0,0 @@
-||| Extra utilities for working with Nats
-module Data.Nat
-
-import Data.Fin
-import Data.So
-
-import Control.WellFounded
-
-%default total
-%access public
-
-||| A strict less-than relation on `Nat`.
-|||
-||| @ n the smaller number
-||| @ m the larger number
-data LT' : (n,m : Nat) -> Type where
-  ||| n < 1 + n
-  LTSucc : LT' n (S n)
-  ||| n < m implies that n < m + 1
-  LTStep : LT' n m -> LT' n (S m)
-
-%name LT' lt, lt'
-
-||| Nothing is strictly less than zero
-instance Uninhabited (LT' n 0) where
-  uninhabited LTSucc impossible
-
-||| Zero is less than any non-zero number.
-LTZeroLeast : LT' Z (S n)
-LTZeroLeast {n = Z}   = LTSucc
-LTZeroLeast {n = S n} = LTStep LTZeroLeast
-
-||| If n < m, then 1 + n < 1 + m
-ltSuccSucc : LT' n m -> LT' (S n) (S m)
-ltSuccSucc LTSucc      = LTSucc
-ltSuccSucc (LTStep lt) = LTStep $ ltSuccSucc lt
-
-||| If n + 1 < m, then n < m
-lteToLt' : LTE (S n) m -> LT' n m
-lteToLt' {n = Z}   (LTESucc x) = LTZeroLeast
-lteToLt' {n = S k} (LTESucc x) = ltSuccSucc $ lteToLt' x
-
-||| Convert from LT' to LTE
-ltToLTE : LT' n m -> LTE (S n) m
-ltToLTE LTSucc      = lteRefl
-ltToLTE (LTStep lt) = lteSuccRight $ ltToLTE lt
-
-||| Subtraction gives a result that is actually smaller.
-minusLT' : (x,y : Nat) -> x - y `LT'` S x
-minusLT' Z     y = LTSucc
-minusLT' (S k) Z = LTSucc
-minusLT' (S k) (S j) = LTStep (minusLT' k j)
-
-||| Strict less-than is well-founded, with the cascade stopping at
-||| zero (because there's nothing less than zero). This can't be done
-||| for LTE, because that one doesn't stop at zero (because `LTE 0 0`
-||| is inhabited).
-instance WellFounded LT' where
-  wellFounded x = Access (acc x)
-    where
-      ||| Show accessibility by induction on the structure of the LT' witness
-      acc : (x, y : Nat) -> LT' y x -> Accessible LT' y
-      -- Zero is vacuously accessible: there's nothing smaller to check
-      acc Z     y lt = absurd lt
-      -- If the element being accessed is one smaller, we're done
-      acc (S y) y LTSucc = Access (acc y)
-      -- If the element is more than one smaller, we need to go further
-      acc (S k) y (LTStep smaller) = acc k y smaller
-
-||| The result of division on natural numbers.
-|||
-||| @ dividend the dividend
-||| @ divisor the divisor
-data DivMod : (dividend, divisor : Nat) -> Type where
-  ||| The result of division, with a quotient and a remainder.
-  |||
-  ||| @ dividend the dividend
-  ||| @ divisor the divisor
-  ||| @ quotient the quotient
-  ||| @ remainder the remainder (bounded by the divisor)
-  ||| @ ok the fact that this is, in fact, a result of division
-  DivModRes : {dividend, divisor : Nat} ->
-              (quotient : Nat) -> (remainder : Fin divisor) ->
-              (ok : dividend = finToNat remainder + quotient * divisor) ->
-              DivMod dividend divisor
-
-
-||| Any natural number can be a `Fin` where the bound is itself plus some difference.
-private
-toFin : (x : Nat) -> (diff : Nat) -> Fin (plus x (S diff))
-toFin Z diff = FZ
-toFin (S k) diff = FS $ toFin k diff
-
-||| Converting to a `Fin` and back to `Nat` preserves the input. This is a correctness proof for `toFin`.
-private
-toFinAndBack : (x : Nat) -> (diff : Nat) -> finToNat (toFin x diff) = x
-toFinAndBack Z diff = Refl
-toFinAndBack (S k) diff = cong (toFinAndBack k diff)
-
-
-||| The accessibilty predicate used for division.
-private
-accPlusLT' : LT' (S j) (S (plus k (S j)))
-accPlusLT' {j = Z}   {k = Z}   = LTSucc
-accPlusLT' {j = Z}   {k = S k} = LTStep (accPlusLT' {j = Z} {k = k})
-accPlusLT' {j = S j} {k = k}   = rewrite sym $ plusSuccRightSucc k (S j) in
-                                 ltSuccSucc accPlusLT'
-
-
-||| Division and modulus on `Nat`, inspired by the definition in the
-||| Agda standard library.
-|||
-||| This uses well-founded recursion on `LT'`.
-|||
-||| @ dividend the dividend
-||| @ divisor the divisor
-||| @ nonzero division by zero is nonsense
-total -- yay!
-divMod : (dividend, divisor : Nat) ->
-         {auto nonzero : So (not (decAsBool (decEq divisor Z)))} ->
-         DivMod dividend divisor
-divMod _     Z     {nonzero} = absurd nonzero
-divMod Z     (S k)           = DivModRes 0 FZ Refl
-divMod (S j) (S k) {nonzero} = wfInd {P=P} stepDiv (S j) (S k) nonzero
-  where
-    ||| The goal passed to the accessibility eliminator.
-    |||
-    ||| This is responsible for generating the goal in the
-    ||| well-founded fixed point.
-    |||
-    ||| @ dividend the dividend to recurse over
-    P : (dividend : Nat) -> Type
-    P dividend = (divisor : Nat) -> (nonzero : So (not (decAsBool (decEq divisor Z)))) -> DivMod dividend divisor
-
-
-    ||| Well-founded recursion needs a recursion operator.
-    |||
-    ||| @ dividend the dividend we are recursing over
-    ||| @ rec the recursive call provided by the well-founded induction operator
-    stepDiv : (dividend : Nat) -> (rec : (d' : Nat) -> LT' d' dividend -> P d') -> P dividend
-    -- We need not consider division by zero
-    stepDiv dividend rec   Z     nonzero = absurd nonzero
-    -- Dividing zero by anyting else gives 0, with 0 remainder
-    stepDiv Z rec (S k) nonzero = DivModRes 0 0 Refl
-    -- To divide two non-zero values, we must know which is larger
-    stepDiv (S j) rec (S k) nonzero with (cmp j k)
-      -- n / n = 1 remainder 0
-      stepDiv (S j)                 rec (S j)                 nonzero | CmpEQ      =
-        DivModRes 1 0 (sym $ cong (plusZeroRightNeutral j))
-      -- if n < m, then m = n + r, and the quotient is 0 with remainder r
-      stepDiv (S j)                 rec (S (plus j (S diff))) nonzero | CmpLT diff =
-        DivModRes 0 (toFin (S j) diff) $
-          rewrite toFinAndBack j diff
-          in sym $ cong (plusZeroRightNeutral j)
-      -- if n > m, then n = m + d, and the quotient is 1 + ((n - m) / m) with the same remainder
-      stepDiv (S (plus k (S diff))) rec (S k)                 nonzero | CmpGT diff =
-        let res = rec (S diff) accPlusLT' (S k) Oh
-        in case res of
-             DivModRes quotient remainder ok =>
-               DivModRes (S quotient) remainder $
-                 rewrite plusAssociative (finToNat remainder) (S k) (mult quotient (S k)) in
-                 rewrite plusCommutative (finToNat remainder) (S k) in
-                 rewrite sym $ plusAssociative (S k) (finToNat remainder) (mult quotient (S k)) in
-                 rewrite ok in Refl
-
-
diff --git a/libs/contrib/Data/Nat/DivMod.idr b/libs/contrib/Data/Nat/DivMod.idr
new file mode 100644
--- /dev/null
+++ b/libs/contrib/Data/Nat/DivMod.idr
@@ -0,0 +1,60 @@
+||| Euclidean division using primitive recursion/induction.
+module Data.Nat.DivMod
+
+%default total
+
+||| The result of euclidean division of natural numbers
+|||
+||| @ dividend the dividend
+||| @ divisor the divisor
+data DivMod : (dividend, divisor : Nat) -> Type where
+  ||| The result of division. The order of operations and operands in the
+  ||| result type was picked to not require any explicit proofs.
+  |||
+  ||| @ quotient the quotient
+  ||| @ remainder the remainder
+  ||| @ divisor the divisor
+  ||| @ remainderSmall proof that the remainder is in the range
+  ||| `[0 .. divisor - 1]`
+  MkDivMod : (quotient, remainder : Nat) ->
+             (remainderSmall : remainder `LT` divisor) ->
+             DivMod (remainder + quotient * divisor) divisor
+
+||| The base case, dividing zero by a successor.
+|||
+||| @ n the predecessor of the divisor
+ZDivModSn : Z `DivMod` S n
+ZDivModSn = MkDivMod 0 0 (LTESucc LTEZero)
+
+||| Given a number less than or equal to a bound, is it equal, or less?
+|||
+||| @ m the lesser or equal number
+||| @ n the greater or equal number
+||| @ mLten proof that `m` is less than or equal to `n`
+stepLT : (mLten : m `LTE` n) -> Either (m = n) (m `LT` n)
+stepLT {m = Z} {n = Z} LTEZero = Left Refl
+stepLT {m = Z} {n = (S n)} LTEZero = Right (LTESucc LTEZero)
+stepLT {m = (S m)} {n = (S n)} (LTESucc mLten) with (stepLT mLten)
+  stepLT {m = (S m)} {n = (S n)} (LTESucc mLten) | (Left mEqn) = Left $ cong mEqn
+  stepLT {m = (S m)} {n = (S n)} (LTESucc mLten) | (Right mLtn) = Right $ LTESucc mLtn
+
+||| The inductive step, taking a division of `m` to a division of `S m`
+|||
+||| @ m the dividend in the inductive hypothesis
+||| @ n the divisor
+||| @ hyp the inductive hypothesis
+SmDivModn : (hyp : m `DivMod` n) -> (S m) `DivMod` n
+SmDivModn (MkDivMod q r rLtn) with (stepLT rLtn)
+  SmDivModn (MkDivMod q r rLtn) | (Left Refl) = MkDivMod (S q) 0 (LTESucc LTEZero)
+  SmDivModn (MkDivMod q r rLtn) | (Right srLtn) = MkDivMod q (S r) srLtn
+
+||| Euclidean division. Note that this takes the predecessor of the divisor to
+||| avoid division by zero.
+|||
+||| @ dividend the dividend
+||| @ predDivisor the predecessor of the desired divisor
+divMod : (dividend, predDivisor : Nat) -> dividend `DivMod` S predDivisor
+divMod Z n = ZDivModSn
+divMod (S m) n = SmDivModn (m `divMod` n)
+
+
diff --git a/libs/contrib/Data/Nat/DivMod/IteratedSubtraction.idr b/libs/contrib/Data/Nat/DivMod/IteratedSubtraction.idr
new file mode 100644
--- /dev/null
+++ b/libs/contrib/Data/Nat/DivMod/IteratedSubtraction.idr
@@ -0,0 +1,167 @@
+||| Division of natural numbers, by iterated subtraction using well-founded
+||| recursion
+module Data.Nat.DivMod.IteratedSubtraction
+
+import Data.Fin
+import Data.So
+
+import Control.WellFounded
+
+%default total
+%access public
+
+||| A strict less-than relation on `Nat`.
+|||
+||| @ n the smaller number
+||| @ m the larger number
+data LT' : (n,m : Nat) -> Type where
+  ||| n < 1 + n
+  LTSucc : LT' n (S n)
+  ||| n < m implies that n < m + 1
+  LTStep : LT' n m -> LT' n (S m)
+
+%name LT' lt, lt'
+
+||| Nothing is strictly less than zero
+instance Uninhabited (LT' n 0) where
+  uninhabited LTSucc impossible
+
+||| Zero is less than any non-zero number.
+LTZeroLeast : LT' Z (S n)
+LTZeroLeast {n = Z}   = LTSucc
+LTZeroLeast {n = S n} = LTStep LTZeroLeast
+
+||| If n < m, then 1 + n < 1 + m
+ltSuccSucc : LT' n m -> LT' (S n) (S m)
+ltSuccSucc LTSucc      = LTSucc
+ltSuccSucc (LTStep lt) = LTStep $ ltSuccSucc lt
+
+||| If n + 1 < m, then n < m
+lteToLt' : LTE (S n) m -> LT' n m
+lteToLt' {n = Z}   (LTESucc x) = LTZeroLeast
+lteToLt' {n = S k} (LTESucc x) = ltSuccSucc $ lteToLt' x
+
+||| Convert from LT' to LTE
+ltToLTE : LT' n m -> LTE (S n) m
+ltToLTE LTSucc      = lteRefl
+ltToLTE (LTStep lt) = lteSuccRight $ ltToLTE lt
+
+||| Subtraction gives a result that is actually smaller.
+minusLT' : (x,y : Nat) -> x - y `LT'` S x
+minusLT' Z     y = LTSucc
+minusLT' (S k) Z = LTSucc
+minusLT' (S k) (S j) = LTStep (minusLT' k j)
+
+||| Strict less-than is well-founded, with the cascade stopping at
+||| zero (because there's nothing less than zero). This can't be done
+||| for LTE, because that one doesn't stop at zero (because `LTE 0 0`
+||| is inhabited).
+instance WellFounded LT' where
+  wellFounded x = Access (acc x)
+    where
+      ||| Show accessibility by induction on the structure of the LT' witness
+      acc : (x, y : Nat) -> LT' y x -> Accessible LT' y
+      -- Zero is vacuously accessible: there's nothing smaller to check
+      acc Z     y lt = absurd lt
+      -- If the element being accessed is one smaller, we're done
+      acc (S y) y LTSucc = Access (acc y)
+      -- If the element is more than one smaller, we need to go further
+      acc (S k) y (LTStep smaller) = acc k y smaller
+
+||| The result of division on natural numbers.
+|||
+||| @ dividend the dividend
+||| @ divisor the divisor
+data DivMod : (dividend, divisor : Nat) -> Type where
+  ||| The result of division, with a quotient and a remainder.
+  |||
+  ||| @ dividend the dividend
+  ||| @ divisor the divisor
+  ||| @ quotient the quotient
+  ||| @ remainder the remainder (bounded by the divisor)
+  ||| @ ok the fact that this is, in fact, a result of division
+  DivModRes : {dividend, divisor : Nat} ->
+              (quotient : Nat) -> (remainder : Fin divisor) ->
+              (ok : dividend = finToNat remainder + quotient * divisor) ->
+              DivMod dividend divisor
+
+
+||| Any natural number can be a `Fin` where the bound is itself plus some difference.
+private
+toFin : (x : Nat) -> (diff : Nat) -> Fin (plus x (S diff))
+toFin Z diff = FZ
+toFin (S k) diff = FS $ toFin k diff
+
+||| Converting to a `Fin` and back to `Nat` preserves the input. This is a correctness proof for `toFin`.
+private
+toFinAndBack : (x : Nat) -> (diff : Nat) -> finToNat (toFin x diff) = x
+toFinAndBack Z diff = Refl
+toFinAndBack (S k) diff = cong (toFinAndBack k diff)
+
+
+||| The accessibilty predicate used for division.
+private
+accPlusLT' : LT' (S j) (S (plus k (S j)))
+accPlusLT' {j = Z}   {k = Z}   = LTSucc
+accPlusLT' {j = Z}   {k = S k} = LTStep (accPlusLT' {j = Z} {k = k})
+accPlusLT' {j = S j} {k = k}   = rewrite sym $ plusSuccRightSucc k (S j) in
+                                 ltSuccSucc accPlusLT'
+
+
+||| Division and modulus on `Nat`, inspired by the definition in the
+||| Agda standard library.
+|||
+||| This uses well-founded recursion on `LT'`.
+|||
+||| @ dividend the dividend
+||| @ divisor the divisor
+||| @ nonzero division by zero is nonsense
+total -- yay!
+divMod : (dividend, divisor : Nat) ->
+         {auto nonzero : So (not (decAsBool (decEq divisor Z)))} ->
+         DivMod dividend divisor
+divMod _     Z     {nonzero} = absurd nonzero
+divMod Z     (S k)           = DivModRes 0 FZ Refl
+divMod (S j) (S k) {nonzero} = wfInd {P=P} stepDiv (S j) (S k) nonzero
+  where
+    ||| The goal passed to the accessibility eliminator.
+    |||
+    ||| This is responsible for generating the goal in the
+    ||| well-founded fixed point.
+    |||
+    ||| @ dividend the dividend to recurse over
+    P : (dividend : Nat) -> Type
+    P dividend = (divisor : Nat) -> (nonzero : So (not (decAsBool (decEq divisor Z)))) -> DivMod dividend divisor
+
+
+    ||| Well-founded recursion needs a recursion operator.
+    |||
+    ||| @ dividend the dividend we are recursing over
+    ||| @ rec the recursive call provided by the well-founded induction operator
+    stepDiv : (dividend : Nat) -> (rec : (d' : Nat) -> LT' d' dividend -> P d') -> P dividend
+    -- We need not consider division by zero
+    stepDiv dividend rec   Z     nonzero = absurd nonzero
+    -- Dividing zero by anyting else gives 0, with 0 remainder
+    stepDiv Z rec (S k) nonzero = DivModRes 0 0 Refl
+    -- To divide two non-zero values, we must know which is larger
+    stepDiv (S j) rec (S k) nonzero with (cmp j k)
+      -- n / n = 1 remainder 0
+      stepDiv (S j)                 rec (S j)                 nonzero | CmpEQ      =
+        DivModRes 1 0 (sym $ cong (plusZeroRightNeutral j))
+      -- if n < m, then m = n + r, and the quotient is 0 with remainder r
+      stepDiv (S j)                 rec (S (plus j (S diff))) nonzero | CmpLT diff =
+        DivModRes 0 (toFin (S j) diff) $
+          rewrite toFinAndBack j diff
+          in sym $ cong (plusZeroRightNeutral j)
+      -- if n > m, then n = m + d, and the quotient is 1 + ((n - m) / m) with the same remainder
+      stepDiv (S (plus k (S diff))) rec (S k)                 nonzero | CmpGT diff =
+        let res = rec (S diff) accPlusLT' (S k) Oh
+        in case res of
+             DivModRes quotient remainder ok =>
+               DivModRes (S quotient) remainder $
+                 rewrite plusAssociative (finToNat remainder) (S k) (mult quotient (S k)) in
+                 rewrite plusCommutative (finToNat remainder) (S k) in
+                 rewrite sym $ plusAssociative (S k) (finToNat remainder) (mult quotient (S k)) in
+                 rewrite ok in Refl
+
+
diff --git a/libs/contrib/System/Concurrency/Process.idr b/libs/contrib/System/Concurrency/Process.idr
--- a/libs/contrib/System/Concurrency/Process.idr
+++ b/libs/contrib/System/Concurrency/Process.idr
@@ -34,8 +34,10 @@
 myID = Lift (return (MkPID prim__vm))
 
 ||| Send a message to another process
-send : ProcID msg -> msg -> Process msg ()
-send (MkPID p) m = Lift (sendToThread p (prim__vm, m))
+||| Returns whether the send was unsuccessful.
+send : ProcID msg -> msg -> Process msg Bool
+send (MkPID p) m = Lift (do x <- sendToThread p (prim__vm, m)
+                            return (x == 1))
 
 ||| Return whether a message is waiting in the queue
 msgWaiting : Process msg Bool
diff --git a/libs/contrib/contrib.ipkg b/libs/contrib/contrib.ipkg
--- a/libs/contrib/contrib.ipkg
+++ b/libs/contrib/contrib.ipkg
@@ -9,8 +9,9 @@
           Control.WellFounded,
           Classes.Verified,
           Data.Fun, Data.Rel,
-          Data.Hash, Data.Matrix,
-          Data.Nat,
+          Data.Hash,
+          Data.Matrix, Data.Matrix.Algebraic, Data.Matrix.Numeric,
+          Data.Nat.DivMod, Data.Nat.DivMod.IteratedSubtraction,
           Data.ZZ, Data.Sign,
           Data.BoundedList,
           Data.Heap,
diff --git a/libs/effects/Effect/Logging/Default.idr b/libs/effects/Effect/Logging/Default.idr
new file mode 100644
--- /dev/null
+++ b/libs/effects/Effect/Logging/Default.idr
@@ -0,0 +1,57 @@
+-- ------------------------------------------------------------- [ Default.idr ]
+-- Module    : Default.idr
+-- Copyright : (c) The Idris Community
+-- License   : see LICENSE
+-- --------------------------------------------------------------------- [ EOH ]
+
+||| A logging effect that allows messages to be logged using both
+||| numerical levels and user specified categories. The higher the
+||| logging level the grater in verbosity the logging.
+|||
+||| In this effect the resource we are computing over is the logging
+||| level itself and the list of categories to show.
+|||
+module Effect.Logging.Default
+
+import Effects
+import public Effect.Logging.Level
+
+import Control.IOExcept -- TODO Add IOExcept Logger.
+
+||| A Logging effect to log levels and categories.
+data Logging : Effect where
+    Log : (Eq a, Show a) =>
+          (lvl : Nat)
+       -> (cats : List a)
+       -> (msg : String)
+       -> Logging () (Nat,List a) (\v => (Nat,List a))
+
+||| The Logging effect.
+|||
+||| @cTy The type used to differentiate categories.
+LOG : (cTy : Type) -> EFFECT
+LOG a = MkEff (Nat, List a) Logging
+
+instance Handler Logging IO where
+    handle (l,cs) (Log lvl cs' msg) k = do
+      case lvl <= l  of
+        False => k () (l,cs)
+        True  =>  do
+          let res = and $ map (\x => elem x cs') cs
+          let prompt = if isNil cs then "" else show cs
+          if res || isNil cs
+            then do
+              printLn $ unwords [show lvl, ":", prompt, ":", msg]
+              k () (l,cs)
+            else k () (l,cs)
+
+||| Log the given message at the given level and assign it the list of categories.
+|||
+||| @l The logging level.
+||| @cs The logging categories.
+||| @m THe message to be logged.
+log : (Show a, Eq a) => (l : Nat)
+    -> (cs : List a) -> (m : String) -> Eff () [LOG a]
+log lvl cs msg = call $ Log lvl cs msg
+
+-- --------------------------------------------------------------------- [ EOF ]
diff --git a/libs/effects/Effect/Logging/Level.idr b/libs/effects/Effect/Logging/Level.idr
new file mode 100644
--- /dev/null
+++ b/libs/effects/Effect/Logging/Level.idr
@@ -0,0 +1,49 @@
+-- -------------------------------------------------------------- [ Levels.idr ]
+-- Module    : Levels.idr
+-- Copyright : (c) Jan de Muijnck-Hughes
+-- License   : see LICENSE
+-- --------------------------------------------------------------------- [ EOH ]
+||| Common aliases and definitions of Logging Levels.
+module Effect.Logging.Level
+
+%access public
+-- ---------------------------------------------- [ Nat Derived Logging Levels ]
+--
+-- Several aliases have been defined to aide in semantic use of the
+-- logging levels. These aliases have come from the Log4j family of
+-- loggers.
+
+||| No events will be logged.
+OFF : Nat
+OFF = 0
+
+||| A severe error that will prevent the application from continuing.
+FATAL : Nat
+FATAL = 1
+
+||| An error in the application, possibly recoverable.
+ERROR : Nat
+ERROR = 2
+
+||| An event that might possible lead to an error.
+WARN : Nat
+WARN = 3
+
+|||  An event for informational purposes.
+INFO : Nat
+INFO = 4
+
+||| A general debugging event.
+DEBUG : Nat
+DEBUG = 5
+
+||| A fine-grained debug message, typically capturing the flow through
+||| the application.
+TRACE : Nat
+TRACE = 6
+
+||| All events should be logged.
+ALL : Nat
+ALL = 7
+
+-- --------------------------------------------------------------------- [ EOF ]
diff --git a/libs/effects/Effect/Logging/Simple.idr b/libs/effects/Effect/Logging/Simple.idr
new file mode 100644
--- /dev/null
+++ b/libs/effects/Effect/Logging/Simple.idr
@@ -0,0 +1,48 @@
+-- -------------------------------------------------------------- [ Simple.idr ]
+-- Module    : Logging.idr
+-- Copyright : (c) The Idris Community
+-- License   : see LICENSE
+--------------------------------------------------------------------- [ EOH ]
+
+||| A simple logging effect that allows messages to be logged at
+||| different numerical level. The higher the number the grater in
+||| verbosity the logging.
+|||
+||| In this effect the resource we are computing over is the logging
+||| level itself.
+|||
+module Effect.Logging.Simple
+
+import Effects
+import public Effect.Logging.Level
+
+import Control.IOExcept -- TODO Add IO Logging Handler
+
+||| A Logging effect that displays a logging message to be logged at a
+||| certain level.
+data Logging : Effect where
+    Log : (lvl : Nat)
+       -> (msg : String)
+       -> Logging () Nat (\v => Nat)
+
+||| A Logging Effect.
+LOG : EFFECT
+LOG = MkEff Nat Logging
+
+-- For logging in the IO context
+instance Handler Logging IO where
+    handle l (Log lvl msg) k = do
+      case lvl <= l  of
+        False   => k () l
+        True  =>  do
+          printLn $ unwords [show lvl, ":", msg]
+          k () l
+
+||| Log `msg` at the given level.
+|||
+||| @l The level to log.
+||| @m The message to log.
+log : (l : Nat) -> (m : String) -> Eff () [LOG]
+log lvl msg = call $ Log lvl msg
+
+-- --------------------------------------------------------------------- [ EOF ]
diff --git a/libs/effects/Effect/Monad.idr b/libs/effects/Effect/Monad.idr
--- a/libs/effects/Effect/Monad.idr
+++ b/libs/effects/Effect/Monad.idr
@@ -2,20 +2,27 @@
 
 import Effects
 
--- Eff is a monad too, so we can happily use it in a monad transformer.
+data MonadEffT : List EFFECT -> (Type -> Type) -> Type -> Type where
+     MkMonadEffT : EffM m a xs (\v => xs) -> MonadEffT xs m a
 
-using (xs : List EFFECT, m : Type -> Type)
-  instance Functor (\a => EffM m a xs (\v => xs)) where
-    map f prog = do t <- prog
-                    value (f t)
+instance Functor (MonadEffT xs f) where
+    map f (MkMonadEffT x) = MkMonadEffT (do x' <- x
+                                            pure (f x'))
 
-  instance Applicative (\a => EffM m a xs (\v => xs)) where
-    pure = value
-    (<*>) f a = do f' <- f
-                   a' <- a
-                   value (f' a')
+instance Applicative (MonadEffT xs f) where
+    pure x = MkMonadEffT (pure x)
+    (<*>) (MkMonadEffT f) (MkMonadEffT x) 
+          = MkMonadEffT (do f' <- f
+                            x' <- x
+                            pure (f' x'))
 
-  instance Monad (\a => Eff m a xs (\v => xs)) where
-    (>>=) = Effects.(>>=)
+instance Monad (MonadEffT xs f) where
+    (>>=) (MkMonadEffT x) f = MkMonadEffT (do x' <- x
+                                              let MkMonadEffT fx = f x'
+                                              fx)
 
+implicit monadEffT : EffM m a xs (\v => xs) -> MonadEffT xs m a
+monadEffT = MkMonadEffT
 
+MonadEff : List EFFECT -> Type -> Type
+MonadEff xs = MonadEffT xs id
diff --git a/libs/effects/Effect/Random.idr b/libs/effects/Effect/Random.idr
--- a/libs/effects/Effect/Random.idr
+++ b/libs/effects/Effect/Random.idr
@@ -2,7 +2,6 @@
 
 import Effects
 import Data.Vect
-import Data.Fin
 
 data Random : Effect where 
      getRandom : sig Random Integer Integer
diff --git a/libs/effects/Effect/System.idr b/libs/effects/Effect/System.idr
--- a/libs/effects/Effect/System.idr
+++ b/libs/effects/Effect/System.idr
@@ -9,7 +9,7 @@
 
 data System : Effect where
      Args : sig System (List String)
-     Time : sig System Int
+     Time : sig System Integer
      GetEnv : String -> sig System (Maybe String)
      CSystem : String -> sig System Int
 
@@ -33,7 +33,7 @@
 getArgs : Eff (List String) [SYSTEM]
 getArgs = call Args
 
-time : Eff Int [SYSTEM]
+time : Eff Integer [SYSTEM]
 time = call Time
 
 getEnv : String -> Eff (Maybe String) [SYSTEM]
diff --git a/libs/effects/Effect/Trans.idr b/libs/effects/Effect/Trans.idr
new file mode 100644
--- /dev/null
+++ b/libs/effects/Effect/Trans.idr
@@ -0,0 +1,20 @@
+module Effect.Trans
+
+import Effects
+
+%access public
+
+data Trans : (Type -> Type) -> Effect where
+  Lift : m a -> sig (Trans m) a
+
+-- using (m : Type -> Type)
+instance Monad m => Handler (Trans m) m where
+     handle st (Lift op) k = do x <- op
+                                k x ()
+
+TRANS : (Type -> Type) -> EFFECT
+TRANS m = MkEff () (Trans m)
+
+lift : m a -> Eff a [TRANS m]
+lift op = call $ Lift op
+
diff --git a/libs/effects/Effects.idr b/libs/effects/Effects.idr
--- a/libs/effects/Effects.idr
+++ b/libs/effects/Effects.idr
@@ -293,15 +293,13 @@
 
 call : {a, b: _} -> {e : Effect} ->
        (eff : e t a b) ->
-       {default tactics { search 100; }
-          prf : EffElem e a xs} ->
+       {auto prf : EffElem e a xs} ->
       EffM m t xs (\v => updateResTy v xs prf eff)
 call e {prf} = callP prf e
 
 implicit
 lift : EffM m t ys ys' ->
-       {default tactics { search 100; }
-          prf : SubList ys xs} ->
+       {auto prf : SubList ys xs} ->
        EffM m t xs (\v => updateWith (ys' v) xs prf)
 lift e {prf} = liftP prf e
 
diff --git a/libs/effects/effects.ipkg b/libs/effects/effects.ipkg
--- a/libs/effects/effects.ipkg
+++ b/libs/effects/effects.ipkg
@@ -1,9 +1,20 @@
 package effects
 
 opts    = "--nobasepkgs -i ../prelude -i ../base"
-modules = Effects, Effect.Default,
 
-          Effect.Exception, Effect.File, Effect.State,
-          Effect.Random, Effect.StdIO, Effect.Select,
-          Effect.Memory, Effect.System
+modules = Effects
+        , Effect.Default
+        , Effect.Monad
 
+        , Effect.Exception
+        , Effect.File
+        , Effect.State
+        , Effect.Random
+        , Effect.StdIO
+        , Effect.Select
+        , Effect.Memory
+        , Effect.System
+        , Effect.Trans
+        , Effect.Logging.Level
+        , Effect.Logging.Simple
+        , Effect.Logging.Default
diff --git a/libs/prelude/Builtins.idr b/libs/prelude/Builtins.idr
--- a/libs/prelude/Builtins.idr
+++ b/libs/prelude/Builtins.idr
@@ -119,7 +119,8 @@
 
   ||| Make a read-only version of a unique value, which can be passed to another
   ||| function without the unique value being consumed.
-  implicit
+  implicit -- needs a special case in the coercion code, since implicits need
+           -- a concrete type to coerce!
   lend : {a : UniqueType} -> a -> Borrowed a
   lend x = Read x
 
@@ -170,6 +171,8 @@
 %extern prim__stderr : Ptr
 
 %extern prim__null : Ptr
+%extern prim__eqPtr : Ptr -> Ptr -> Int
+%extern prim__eqManagedPtr : ManagedPtr -> ManagedPtr -> Int
 %extern prim__registerPtr : Ptr -> Int -> ManagedPtr
 
 
diff --git a/libs/prelude/Decidable/Equality.idr b/libs/prelude/Decidable/Equality.idr
--- a/libs/prelude/Decidable/Equality.idr
+++ b/libs/prelude/Decidable/Equality.idr
@@ -123,7 +123,7 @@
 -- List
 --------------------------------------------------------------------------------
 
-lemma_val_not_nil : {x : t, xs : List t} -> ((x :: xs) = Prelude.List.Nil {a = t} -> Void)
+lemma_val_not_nil : {x : t, xs : List t} -> ((x :: xs) = Prelude.List.Nil {elem = t} -> Void)
 lemma_val_not_nil Refl impossible
 
 lemma_x_eq_xs_neq : {x : t, xs : List t, y : t, ys : List t} -> (x = y) -> (xs = ys -> Void) -> ((x :: xs) = (y :: ys) -> Void)
@@ -191,5 +191,26 @@
        where primitiveEq : x = y
              primitiveEq = believe_me (Refl {x})
              postulate primitiveNotEq : x = y -> Void
+
+--------------------------------------------------------------------------------
+-- Ptr
+--------------------------------------------------------------------------------
+
+instance DecEq Ptr where
+    decEq x y = if x == y then Yes primitiveEq else No primitiveNotEq
+       where primitiveEq : x = y
+             primitiveEq = believe_me (Refl {x})
+             postulate primitiveNotEq : x = y -> Void
+
+--------------------------------------------------------------------------------
+-- ManagedPtr
+--------------------------------------------------------------------------------
+
+instance DecEq ManagedPtr where
+    decEq x y = if x == y then Yes primitiveEq else No primitiveNotEq
+       where primitiveEq : x = y
+             primitiveEq = believe_me (Refl {x})
+             postulate primitiveNotEq : x = y -> Void
+
 
 
diff --git a/libs/prelude/IO.idr b/libs/prelude/IO.idr
--- a/libs/prelude/IO.idr
+++ b/libs/prelude/IO.idr
@@ -6,7 +6,7 @@
 %access public
 
 ||| Idris's primitive IO, for building abstractions on top of
-abstract 
+abstract
 data PrimIO : Type -> Type where
      prim__IO : a -> PrimIO a
 
@@ -20,13 +20,22 @@
 abstract WorldRes : Type -> Type
 WorldRes x = x
 
+||| An FFI specifier, which describes how a particular compiler
+||| backend handles foreign function calls.
 record FFI where
   constructor MkFFI
+  ||| A family describing which types are available in the FFI
   ffi_types : Type -> Type
+
+  ||| The type used to specify the names of foreign functions in this FFI
   ffi_fn : Type
+
+  ||| How this FFI describes exported datatypes
   ffi_data : Type
 
-abstract 
+||| The IO type, parameterised over the FFI that is available within
+||| it.
+abstract
 data IO' : (lang : FFI) -> Type -> Type where
      MkIO : (World -> PrimIO (WorldRes a)) -> IO' lang a
 
@@ -64,6 +73,19 @@
 foreign_prim f fname (FFun arg sc) env
         = \x => foreign_prim f fname sc ((arg, x) :: env)
 
+||| Call a foreign function.
+|||
+||| The particular semantics of foreign function calls depend on the
+||| Idris compiler backend in use. For the default C backend, see the
+||| documentation for `FFI_C`.
+|||
+||| For more details, please consult [the Idris documentation](http://docs.idris-lang.org/en/latest/reference/ffi.html).
+|||
+||| @ f     an FFI descriptor, which is specific to the compiler backend.
+||| @ fname the name of the foreign function
+||| @ ty    the Idris type for the foreign function
+||| @ fty   an automatically-found proof that the Idris type works with
+|||         the FFI in question
 %inline
 foreign : (f : FFI) -> (fname : ffi_fn f) -> (ty : Type) ->
           {auto fty : FTy f [] ty} -> ty
@@ -128,7 +150,7 @@
   -- Tell erasure analysis not to erase the argument
   %used MkRaw x
 
-  -- Supported C integer types
+  ||| Supported C integer types
   data C_IntTypes : Type -> Type where
        C_IntChar   : C_IntTypes Char
        C_IntNative : C_IntTypes Int
@@ -137,7 +159,7 @@
        C_IntBits32 : C_IntTypes Bits32
        C_IntBits64 : C_IntTypes Bits64
 
-  -- Supported C foreign types
+  ||| Supported C foreign types
   data C_Types : Type -> Type where
        C_Str   : C_Types String
        C_Float : C_Types Float
@@ -147,6 +169,8 @@
        C_Any   : C_Types (Raw a)
        C_IntT  : C_IntTypes i -> C_Types i
 
+  ||| A descriptor for the C FFI. See the constructors of `C_Types`
+  ||| and `C_IntTypes` for the concrete types that are available.
   FFI_C : FFI
   FFI_C = MkFFI C_Types String String
 
@@ -201,14 +225,17 @@
 -- pass we only have 'JsFn' and not the constructor.
 %used MkJsFn x
 
-FFI_JS : FFI                                     
+||| The JavaScript FFI. The strings naming functions in this API are
+||| JavaScript code snippets, into which the arguments are substituted
+||| for the placeholders `%0`, `%1`, etc.
+FFI_JS : FFI
 FFI_JS = MkFFI JS_Types String String
 
 JS_IO : Type -> Type
 JS_IO = IO' FFI_JS
 
 
---------- Foreign Exports 
+--------- Foreign Exports
 
 namespace FFI_Export
 -- It's just like Data.List.Elem, but we don't need all the other stuff
@@ -226,7 +253,7 @@
   %used FFI_Prim prim
 
   data FFI_Exportable : (f : FFI) -> List (Type, ffi_data f) -> Type -> Type where
-       FFI_IO : (b : FFI_Base f xs t) -> FFI_Exportable f xs (IO t)
+       FFI_IO : (b : FFI_Base f xs t) -> FFI_Exportable f xs (IO' f t)
        FFI_Fun : (b : FFI_Base f xs s) -> (a : FFI_Exportable f xs t) -> FFI_Exportable f xs (s -> t)
        FFI_Ret : (b : FFI_Base f xs t) -> FFI_Exportable f xs t
 
diff --git a/libs/prelude/Language/Reflection.idr b/libs/prelude/Language/Reflection.idr
--- a/libs/prelude/Language/Reflection.idr
+++ b/libs/prelude/Language/Reflection.idr
@@ -215,6 +215,8 @@
                      NamePart TTName |
                      ||| An Idris term, to be pretty printed
                      TermPart TT |
+                     ||| A Raw term to be displayed by the compiler
+                     RawPart Raw |
                      ||| An indented sub-report, to provide more details
                      SubReport (List ErrorReportPart)
 %name ErrorReportPart part, p
@@ -399,13 +401,13 @@
 
 instance Quotable a TT => Quotable (List a) TT where
   quotedTy = `(List ~(quotedTy {a}))
-  quote [] = `(List.Nil {a=~(quotedTy {a})})
-  quote (x :: xs) = `(List.(::) {a=~(quotedTy {a})} ~(quote x) ~(quote xs))
+  quote [] = `(List.Nil {elem=~(quotedTy {a})})
+  quote (x :: xs) = `(List.(::) {elem=~(quotedTy {a})} ~(quote x) ~(quote xs))
 
 instance Quotable a Raw => Quotable (List a) Raw where
   quotedTy = `(List ~(quotedTy {a}))
-  quote [] = `(List.Nil {a=~(quotedTy {a})})
-  quote (x :: xs) = `(List.(::) {a=~(quotedTy {a})} ~(quote x) ~(quote xs))
+  quote [] = `(List.Nil {elem=~(quotedTy {a})})
+  quote (x :: xs) = `(List.(::) {elem=~(quotedTy {a})} ~(quote x) ~(quote xs))
 
 mutual
   instance Quotable TTName TT where
@@ -576,42 +578,71 @@
     quote (PVar x) = `(PVar {a=TT} ~(assert_total (quote x)))
     quote (PVTy x) = `(PVTy {a=TT} ~(assert_total (quote x)))
 
-
-instance Quotable ErrorReportPart TT where
-  quotedTy = `(ErrorReportPart)
-  quote (TextPart x) = `(TextPart ~(quote x))
-  quote (NamePart n) = `(NamePart ~(quote n))
-  quote (TermPart tm) = `(TermPart ~(quote tm))
-  quote (SubReport xs) = `(SubReport ~(assert_total $ quote xs))
-
 mutual
-  quoteRaw : Raw -> TT
-  quoteRaw (Var n) = `(Var ~(quote n))
-  quoteRaw (RBind n b tm) = `(RBind ~(quote n) ~(assert_total $ quoteRawBinder b) ~(quoteRaw tm))
-  quoteRaw (RApp tm tm') = `(RApp ~(quoteRaw tm) ~(quoteRaw tm'))
-  quoteRaw RType = `(RType)
-  quoteRaw (RUType u) = `(RUType ~(quote u))
-  quoteRaw (RForce tm) = `(RForce ~(quoteRaw tm))
-  quoteRaw (RConstant c) = `(RConstant ~(quote c))
+  quoteRawTT : Raw -> TT
+  quoteRawTT (Var n) = `(Var ~(quote n))
+  quoteRawTT (RBind n b tm) = `(RBind ~(quote n) ~(assert_total $ quoteRawBinderTT b) ~(quoteRawTT tm))
+  quoteRawTT (RApp tm tm') = `(RApp ~(quoteRawTT tm) ~(quoteRawTT tm'))
+  quoteRawTT RType = `(RType)
+  quoteRawTT (RUType u) = `(RUType ~(quote u))
+  quoteRawTT (RForce tm) = `(RForce ~(quoteRawTT tm))
+  quoteRawTT (RConstant c) = `(RConstant ~(quote c))
 
-  quoteRawBinder : Binder Raw -> TT
-  quoteRawBinder (Lam x) = `(Lam {a=Raw} ~(quoteRaw x))
-  quoteRawBinder (Pi x k) = `(Pi {a=Raw} ~(quoteRaw x) ~(quoteRaw k))
-  quoteRawBinder (Let x y) = `(Let {a=Raw} ~(quoteRaw x) ~(quoteRaw y))
-  quoteRawBinder (NLet x y) = `(NLet {a=Raw} ~(quoteRaw x) ~(quoteRaw y))
-  quoteRawBinder (Hole x) = `(Hole {a=Raw} ~(quoteRaw x))
-  quoteRawBinder (GHole x) = `(GHole {a=Raw} ~(quoteRaw x))
-  quoteRawBinder (Guess x y) = `(Guess {a=Raw} ~(quoteRaw x) ~(quoteRaw y))
-  quoteRawBinder (PVar x) = `(PVar {a=Raw} ~(quoteRaw x))
-  quoteRawBinder (PVTy x) = `(PVTy {a=Raw} ~(quoteRaw x))
+  quoteRawBinderTT : Binder Raw -> TT
+  quoteRawBinderTT (Lam x) = `(Lam {a=Raw} ~(quoteRawTT x))
+  quoteRawBinderTT (Pi x k) = `(Pi {a=Raw} ~(quoteRawTT x) ~(quoteRawTT k))
+  quoteRawBinderTT (Let x y) = `(Let {a=Raw} ~(quoteRawTT x) ~(quoteRawTT y))
+  quoteRawBinderTT (NLet x y) = `(NLet {a=Raw} ~(quoteRawTT x) ~(quoteRawTT y))
+  quoteRawBinderTT (Hole x) = `(Hole {a=Raw} ~(quoteRawTT x))
+  quoteRawBinderTT (GHole x) = `(GHole {a=Raw} ~(quoteRawTT x))
+  quoteRawBinderTT (Guess x y) = `(Guess {a=Raw} ~(quoteRawTT x) ~(quoteRawTT y))
+  quoteRawBinderTT (PVar x) = `(PVar {a=Raw} ~(quoteRawTT x))
+  quoteRawBinderTT (PVTy x) = `(PVTy {a=Raw} ~(quoteRawTT x))
 
 instance Quotable Raw TT where
   quotedTy = `(Raw)
-  quote = quoteRaw
+  quote = quoteRawTT
 
 instance Quotable (Binder Raw) TT where
   quotedTy = `(Binder Raw)
-  quote = quoteRawBinder
+  quote = quoteRawBinderTT
+
+mutual
+  quoteRawRaw : Raw -> Raw
+  quoteRawRaw (Var n) = `(Var ~(quote n))
+  quoteRawRaw (RBind n b tm) = `(RBind ~(quote n) ~(assert_total $ quoteRawBinderRaw b) ~(quoteRawRaw tm))
+  quoteRawRaw (RApp tm tm') = `(RApp ~(quoteRawRaw tm) ~(quoteRawRaw tm'))
+  quoteRawRaw RType = `(RType)
+  quoteRawRaw (RUType u) = `(RUType ~(quote u))
+  quoteRawRaw (RForce tm) = `(RForce ~(quoteRawRaw tm))
+  quoteRawRaw (RConstant c) = `(RConstant ~(quote c))
+
+  quoteRawBinderRaw : Binder Raw -> Raw
+  quoteRawBinderRaw (Lam x) = `(Lam {a=Raw} ~(quoteRawRaw x))
+  quoteRawBinderRaw (Pi x k) = `(Pi {a=Raw} ~(quoteRawRaw x) ~(quoteRawRaw k))
+  quoteRawBinderRaw (Let x y) = `(Let {a=Raw} ~(quoteRawRaw x) ~(quoteRawRaw y))
+  quoteRawBinderRaw (NLet x y) = `(NLet {a=Raw} ~(quoteRawRaw x) ~(quoteRawRaw y))
+  quoteRawBinderRaw (Hole x) = `(Hole {a=Raw} ~(quoteRawRaw x))
+  quoteRawBinderRaw (GHole x) = `(GHole {a=Raw} ~(quoteRawRaw x))
+  quoteRawBinderRaw (Guess x y) = `(Guess {a=Raw} ~(quoteRawRaw x) ~(quoteRawRaw y))
+  quoteRawBinderRaw (PVar x) = `(PVar {a=Raw} ~(quoteRawRaw x))
+  quoteRawBinderRaw (PVTy x) = `(PVTy {a=Raw} ~(quoteRawRaw x))
+
+instance Quotable Raw Raw where
+  quotedTy = `(Raw)
+  quote = quoteRawRaw
+
+instance Quotable (Binder Raw) Raw where
+  quotedTy = `(Binder Raw)
+  quote = quoteRawBinderRaw
+
+instance Quotable ErrorReportPart TT where
+  quotedTy = `(ErrorReportPart)
+  quote (TextPart x) = `(TextPart ~(quote x))
+  quote (NamePart n) = `(NamePart ~(quote n))
+  quote (TermPart tm) = `(TermPart ~(quote tm))
+  quote (RawPart tm) = `(RawPart ~(quote tm))
+  quote (SubReport xs) = `(SubReport ~(assert_total $ quote xs))
 
 instance Quotable Tactic TT where
   quotedTy = `(Tactic)
diff --git a/libs/prelude/Language/Reflection/Elab.idr b/libs/prelude/Language/Reflection/Elab.idr
--- a/libs/prelude/Language/Reflection/Elab.idr
+++ b/libs/prelude/Language/Reflection/Elab.idr
@@ -7,24 +7,52 @@
 
 import Builtins
 import Prelude.Applicative
+import Prelude.Basics
+import Prelude.Bool
 import Prelude.Functor
 import Prelude.List
 import Prelude.Maybe
 import Prelude.Monad
+import Prelude.Nat
 import Language.Reflection
 
-||| Arguments, with plicity.
-data Arg : Type where
-  ||| An explicit argument
-  Explicit : TTName -> Raw -> Arg
+data Fixity = Infixl Nat | Infixr Nat | Infix Nat | Prefix Nat
 
-  ||| An implicit argument, to be solved by unification
-  Implicit : TTName -> Raw -> Arg
+||| Erasure annotations reflect Idris's idea of what is intended to be
+||| erased.
+data Erasure = Erased | NotErased
 
-  ||| A type-class constraint argument, to be solved by type class
-  ||| resolution
-  Constraint : TTName -> Raw -> Arg
+||| How an argument is provided in high-level Idris
+data Plicity =
+  ||| The argument is directly provided at the application site
+  Explicit |
+  ||| The argument is found by Idris at the application site
+  Implicit |
+  ||| The argument is solved using type class resolution
+  Constraint
 
+||| Function arguments
+|||
+||| These are the simplest representation of argument lists, and are
+||| used for functions.
+record FunArg where
+  constructor MkFunArg
+  argName : TTName
+  argTy   : Raw
+  plicity : Plicity
+  erasure : Erasure
+
+||| Type constructor arguments
+|||
+||| Each argument is identified as being either a parameter that is
+||| consistent in all constructors, or an index that varies based on
+||| which constructor is selected.
+data TyConArg =
+  ||| Parameters are uniform across the constructors
+  TyConParameter FunArg |
+  ||| Indices are not uniform
+  TyConIndex FunArg
+
 ||| A type declaration
 data TyDecl : Type where
   ||| A type declaration.
@@ -36,38 +64,35 @@
   ||| @ fn the name to be declared, fully-qualified
   ||| @ args the arguments to the function
   ||| @ ret the final return type
-  Declare : (fn : TTName) -> (args : List Arg) -> (ret : Raw) -> TyDecl
+  Declare : (fn : TTName) -> (args : List FunArg) -> (ret : Raw) -> TyDecl
 
 ||| A single pattern-matching clause
 data FunClause : Type where
   MkFunClause : (lhs, rhs : Raw) -> FunClause
-  MkImpossibleClause : (lhs : Raw) -> FunClause
 
 ||| A reflected function definition.
 data FunDefn : Type where
   DefineFun : TTName -> List FunClause -> FunDefn
 
-||| An argument to a type constructor.
-data TyConArg : Type where
-  ||| Parameters are consistent across all constructors of the type
-  Parameter : TTName -> Raw -> TyConArg
 
-  ||| Indices are allowed to vary across constructors
-  Index : TTName -> Raw -> TyConArg
+data CtorArg = CtorParameter FunArg | CtorField FunArg
 
 ||| A reflected datatype definition
-data Datatype : Type where
-  ||| A reflected datatype definition
-  |||
-  ||| @ familyName the name of the type constructor
-  ||| @ tyConArgs the arguments to the type constructor
-  ||| @ tyConRes the result of the type constructor
-  ||| @ constrs the constructors, with their types
-  MkDatatype : (familyName : TTName) ->
-               (tyConArgs : List TyConArg) -> (tyConRes : Raw) ->
-               (constrs : List (TTName, Raw)) ->
-               Datatype
+record Datatype where
+  constructor MkDatatype
 
+  ||| The name of the type constructor
+  familyName : TTName
+
+  ||| The arguments to the type constructor
+  tyConArgs : List TyConArg
+
+  ||| The result of the type constructor
+  tyConRes : Raw
+
+  ||| The constructors for the family
+  constructors : List (TTName, List CtorArg, Raw)
+
 ||| A reflected elaboration script.
 abstract
 data Elab : Type -> Type where
@@ -85,7 +110,10 @@
   prim__LookupTy : TTName -> Elab (List (TTName, NameType, TT))
   prim__LookupDatatype : TTName -> Elab (List Datatype)
 
+  prim__Check : Raw -> Elab (TT, TT)
+
   prim__SourceLocation : Elab SourceLocation
+  prim__Namespace : Elab (List String)
 
   prim__Forget : TT -> Elab Raw
 
@@ -93,7 +121,8 @@
 
   prim__Solve : Elab ()
   prim__Fill : Raw -> Elab ()
-  prim__Apply : Raw -> Elab ()
+  prim__Apply : Raw -> List (Bool, Int) -> Elab (List (TTName, TTName))
+  prim__MatchApply : Raw -> List (Bool, Int) -> Elab (List (TTName, TTName))
   prim__Focus : TTName -> Elab ()
   prim__Unfocus : TTName -> Elab ()
   prim__Attack : Elab ()
@@ -105,18 +134,24 @@
   prim__Forall : TTName -> Raw -> Elab ()
   prim__PatVar : TTName -> Elab ()
   prim__PatBind : TTName -> Elab ()
+  prim__LetBind : TTName -> Raw -> Raw -> Elab ()
 
   prim__Compute : Elab ()
+  prim__Normalise : (List (TTName, Binder TT)) -> TT -> Elab TT
+  prim__Whnf : TT -> Elab TT
 
   prim__DeclareType : TyDecl -> Elab ()
   prim__DefineFunction : FunDefn -> Elab ()
   prim__AddInstance : TTName -> TTName -> Elab ()
 
   prim__ResolveTC : TTName -> Elab ()
+  prim__Search : Int -> List TTName -> Elab ()
   prim__RecursiveElab : Raw -> Elab () -> Elab (TT, TT)
 
-  prim__Debug : {a : Type} -> Maybe String -> Elab a
+  prim__Fixity : String -> Elab Fixity
 
+  prim__Debug : {a : Type} -> List ErrorReportPart -> Elab a
+  prim__Metavar : TTName -> Elab ()
 
 -------------
 -- Public API
@@ -186,11 +221,21 @@
                             []    => fail [TextPart "No datatype named", NamePart n]
                             xs    => fail [TextPart "More than one datatype named", NamePart n]
 
+  ||| Attempt to type-check a term, getting back itself and its type
+  check : (tm : Raw) -> Elab (TT, TT)
+  check tm = prim__Check tm
+
   ||| Convert a type-annotated reflected term to its untyped
   ||| equivalent
   forgetTypes : TT -> Elab Raw
   forgetTypes tt = prim__Forget tt
 
+  ||| Get the goal type as a Raw term
+  goalType : Elab Raw
+  goalType = do g <- getGoal
+                forgetTypes (snd g)
+
+
   ||| Generate a unique name based on some hint.
   |||
   ||| **NB**: the generated name is unique _for this run of the
@@ -206,10 +251,50 @@
   fill : Raw -> Elab ()
   fill tm = prim__Fill tm
 
-  ||| Fill with unification
-  apply : Raw -> Elab ()
-  apply tm = prim__Apply tm
+  ||| Attempt to apply an operator to fill the current hole,
+  ||| potentially solving arguments by unification.
+  |||
+  ||| The return value is a list of pairs of names, one for each input
+  ||| argument. The first projection of these pairs is the original
+  ||| name of the argument, from the type declaration, and the second
+  ||| projection is the hole into which it is placed.
+  |||
+  ||| Note that not all of the returned hole names still exist, as
+  ||| they may have been solved.
+  |||
+  ||| @ op the term to apply
+  |||
+  ||| @ argSpec instructions for finding the arguments to the term,
+  |||     where the Boolean states whether or not to attempt to solve
+  |||     the argument and the Int gives the priority in which to do
+  |||     so
+  apply : (op : Raw) ->
+          (argSpec : List (Bool, Int)) ->
+          Elab (List (TTName, TTName))
+  apply tm argSpec = prim__Apply tm argSpec
 
+  ||| Attempt to apply an operator to fill the current hole,
+  ||| potentially solving arugments by matching.
+  |||
+  ||| The return value is a list of pairs of names, one for each input
+  ||| argument. The first projection of these pairs is the original
+  ||| name of the argument, from the type declaration, and the second
+  ||| projection is the hole into which it is placed.
+  |||
+  ||| Note that not all of the returned hole names still exist, as
+  ||| they may have been solved.
+  |||
+  ||| @ op the term to apply
+  |||
+  ||| @ argSpec instructions for finding the arguments to the term,
+  |||     where the Boolean states whether or not to attempt to solve
+  |||     the argument and the Int gives the priority in which to do
+  |||     so
+  matchApply : (op : Raw) ->
+               (argSpec : List (Bool, Int)) ->
+               Elab (List (TTName, TTName))
+  matchApply tm argSpec = prim__Apply tm argSpec
+
   ||| Move the focus to the specified hole
   |||
   ||| @ hole the hole to focus on
@@ -241,11 +326,15 @@
   ||| the body. Requires that the hole be in binding form (use
   ||| `attack`).
   |||
-  ||| @ n the name to use for the argument, or `Nothing` to use the name
-  |||   in the corresponding hole type (a dependent function)
-  intro : (n : Maybe TTName) -> Elab ()
-  intro n = prim__Intro n
+  ||| @ n the name to use for the argument
+  intro : (n : TTName) -> Elab ()
+  intro n = prim__Intro (Just n)
 
+  ||| Introduce a lambda binding around the current hole and focus on
+  ||| the body, using the name provided by the type of the hole.
+  intro' : Elab ()
+  intro' = prim__Intro Nothing
+
   ||| Introduce a dependent function type binding into the current hole,
   ||| and focus on the body.
   forall : TTName -> Raw -> Elab ()
@@ -259,10 +348,31 @@
   patbind : TTName -> Elab ()
   patbind n = prim__PatBind n
 
+  ||| Introduce a new let binding
+  |||
+  ||| @ n the name to let bind
+  ||| @ ty the type of the term to be let-bound
+  ||| @ tm the term to be bound
+  letbind : (n : TTName) -> (ty, tm : Raw) -> Elab ()
+  letbind n ty tm = prim__LetBind n ty tm
+
   ||| Normalise the goal.
   compute : Elab ()
   compute = prim__Compute
 
+  ||| Normalise a term in some lexical environment
+  |||
+  ||| @ env the environment in which to compute (get one of these from `getEnv`)
+  ||| @ term the term to normalise
+  normalise : (env : List (TTName, Binder TT)) -> (term : TT) -> Elab TT
+  normalise env term = prim__Normalise env term
+
+  ||| Reduce a closed term to weak-head normal form
+  |||
+  ||| @ term the term to reduce
+  whnf : (term : TT) -> Elab TT
+  whnf term = prim__Whnf term
+
   ||| Find the source context for the elaboration script
   getSourceLocation : Elab SourceLocation
   getSourceLocation = prim__SourceLocation
@@ -273,6 +383,14 @@
                       fill (quote loc)
                       solve
 
+  ||| Get the current namespace at the point of tactic execution. This
+  ||| allows scripts to define top-level names conveniently.
+  |||
+  ||| The namespace is represented as a reverse-order list of strings,
+  ||| just as in the representation of names.
+  currentNamespace : Elab (List String)
+  currentNamespace = prim__Namespace
+
   ||| Attempt to rewrite the goal using an equality.
   |||
   ||| The tactic searches the goal for applicable subterms, and
@@ -306,12 +424,32 @@
   resolveTC : (fn : TTName) -> Elab ()
   resolveTC fn = prim__ResolveTC fn
 
+  ||| Use Idris's internal proof search.
+  search : Elab ()
+  search = prim__Search 100 []
+
+  ||| Use Idris's internal proof search, with more control.
+  |||
+  ||| @ depth the search depth
+  ||| @ hints additional names to try
+  search' : (depth : Int) -> (hints : List TTName) -> Elab ()
+  search' depth hints = prim__Search depth hints
+
+  ||| Look up the declared fixity for an operator.
+  |||
+  ||| The lookup fails if the operator does not yet have a fixity or
+  ||| if the string is not a valid operator.
+  |||
+  ||| @ operator the operator string to look up
+  operatorFixity : (operator : String) -> Elab Fixity
+  operatorFixity operator = prim__Fixity operator
+
   ||| Halt elaboration, dumping the internal state for inspection.
   |||
   ||| This is intended for elaboration script developers, not for
   ||| end-users. Use `fail` for final scripts.
   debug : Elab a
-  debug = prim__Debug Nothing
+  debug = prim__Debug []
 
   ||| Halt elaboration, dumping the internal state and displaying a
   ||| message.
@@ -320,8 +458,14 @@
   ||| end-users. Use `fail` for final scripts.
   |||
   ||| @ msg the message to display
-  debugMessage : (msg : String) -> Elab a
-  debugMessage msg = prim__Debug (Just msg)
+  debugMessage : (msg : List ErrorReportPart) -> Elab a
+  debugMessage msg = prim__Debug msg
+
+  ||| Create a new top-level metavariable to solve the current hole.
+  |||
+  ||| @ name the name for the top-level variable
+  metavar : (name : TTName) -> Elab ()
+  metavar name = prim__Metavar name
 
   ||| Recursively invoke the reflected elaborator with some goal.
   |||
diff --git a/libs/prelude/Language/Reflection/Errors.idr b/libs/prelude/Language/Reflection/Errors.idr
--- a/libs/prelude/Language/Reflection/Errors.idr
+++ b/libs/prelude/Language/Reflection/Errors.idr
@@ -31,6 +31,7 @@
          | CantResolve TT
          | InvalidTCArg TTName TT
          | CantResolveAlts (List TTName)
+         | NoValidAlts (List TTName)
          | IncompleteTerm TT
          | NoEliminator String TT
          | UniverseError
diff --git a/libs/prelude/Prelude.idr b/libs/prelude/Prelude.idr
--- a/libs/prelude/Prelude.idr
+++ b/libs/prelude/Prelude.idr
@@ -24,6 +24,9 @@
 import public Prelude.Pairs
 import public Prelude.Stream
 import public Prelude.Providers
+import public Prelude.Show
+import public Prelude.Interactive
+import public Prelude.File
 import public Decidable.Equality
 import public Language.Reflection
 import public Language.Reflection.Errors
@@ -37,114 +40,11 @@
 decAsBool (No _)  = False
 
 
--- Show and instances
-
-class Show a where
-    partial show : a -> String
-
-instance Show Int where
-    show = prim__toStrInt
-
-instance Show Integer where
-    show = prim__toStrBigInt
-
-instance Show Float where
-    show = prim__floatToStr
-
-
-firstCharIs : (Char -> Bool) -> String -> Bool
-firstCharIs p s with (strM s)
-  firstCharIs p ""             | StrNil = False
-  firstCharIs p (strCons c cs) | StrCons c cs = p c
-
-protectEsc : (Char -> Bool) -> String -> String -> String
-protectEsc p f s = f ++ (if firstCharIs p s then "\\&" else "") ++ s
-
-showLitChar : Char -> String -> String
-showLitChar '\a'   = ("\\a" ++)
-showLitChar '\b'   = ("\\b" ++)
-showLitChar '\f'   = ("\\f" ++)
-showLitChar '\n'   = ("\\n" ++)
-showLitChar '\r'   = ("\\r" ++)
-showLitChar '\t'   = ("\\t" ++)
-showLitChar '\v'   = ("\\v" ++)
-showLitChar '\SO'  = protectEsc (== 'H') "\\SO"
-showLitChar '\DEL' = ("\\DEL" ++)
-showLitChar '\\'   = ("\\\\" ++)
-showLitChar c      = case getAt (cast (cast {to=Int} c)) asciiTab of
-                          Just k => strCons '\\' . (k ++)
-                          Nothing => if (c > '\DEL')
-                                        then strCons '\\' . protectEsc isDigit (show (cast {to=Int} c))
-                                        else strCons c
-  where asciiTab : List String
-        asciiTab = ["NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
-                    "BS",  "HT",  "LF",  "VT",  "FF",  "CR",  "SO",  "SI",
-                    "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
-                    "CAN", "EM",  "SUB", "ESC", "FS",  "GS",  "RS",  "US"]
-
-        getAt : Nat -> List String -> Maybe String
-        getAt Z     (x :: xs) = Just x
-        getAt (S k) (x :: xs) = getAt k xs
-        getAt _     []        = Nothing
-
-showLitString : List Char -> String -> String
-showLitString []        = id
-showLitString ('"'::cs) = ("\\\"" ++) . showLitString cs
-showLitString (c  ::cs) = showLitChar c . showLitString cs
-
-instance Show Char where
-  show '\'' = "'\\''"
-  show c    = strCons '\'' (showLitChar c "'")
-
-instance Show String where
-  show cs = strCons '"' (showLitString (cast cs) "\"")
-
-instance Show Nat where
-    show n = show (the Integer (cast n))
-
-instance Show Bool where
-    show True = "True"
-    show False = "False"
-
-instance Show () where
-  show () = "()"
-
-instance Show Bits8 where
-  show b = b8ToString b
-
-instance Show Bits16 where
-  show b = b16ToString b
-
-instance Show Bits32 where
-  show b = b32ToString b
-
-instance Show Bits64 where
-  show b = b64ToString b
-
-instance (Show a, Show b) => Show (a, b) where
-    show (x, y) = "(" ++ show x ++ ", " ++ show y ++ ")"
-
-instance Show a => Show (List a) where
-    show xs = "[" ++ show' "" xs ++ "]" where
-        show' acc []        = acc
-        show' acc [x]       = acc ++ show x
-        show' acc (x :: xs) = show' (acc ++ show x ++ ", ") xs
-
-instance Show a => Show (Maybe a) where
-    show Nothing = "Nothing"
-    show (Just x) = "Just " ++ show x
-
-instance (Show a, {y : a} -> Show (p y)) => Show (Sigma a p) where
-    show (y ** prf) = "(" ++ show y ++ " ** " ++ show prf ++ ")"
-      
 ---- Functor instances
 
 instance Functor PrimIO where
     map f io = prim_io_bind io (prim_io_return . f)
 
-instance Functor (IO' ffi) where
-    map f io = io_bind io (\b => io_return (f b))
-
 instance Functor Maybe where
     map f (Just x) = Just (f x)
     map f Nothing  = Nothing
@@ -160,12 +60,6 @@
 
     am <*> bm = prim_io_bind am (\f => prim_io_bind bm (prim_io_return . f))
 
-instance Applicative (IO' ffi) where
-    pure x = io_return x
-    f <*> a = io_bind f (\f' =>
-                io_bind a (\a' =>
-                  io_return (f' a')))
-
 instance Applicative Maybe where
     pure = Just
 
@@ -202,9 +96,6 @@
 instance Monad PrimIO where
     b >>= k = prim_io_bind b k
 
-instance Monad (IO' ffi) where
-    b >>= k = io_bind b k
-
 instance Monad Maybe where
     Nothing  >>= k = Nothing
     (Just x) >>= k = k x
@@ -328,183 +219,6 @@
 uncurry : (a -> b -> c) -> (a, b) -> c
 uncurry f (a, b) = f a b
 
----- some basic io
-
-||| Output a string to stdout without a trailing newline
-putStr : String -> IO' ffi ()
-putStr x = do prim_write x
-              return ()
-
-||| Output a string to stdout with a trailing newline
-putStrLn : String -> IO' ffi ()
-putStrLn x = putStr (x ++ "\n")
-
-||| Output something showable to stdout, without a trailing newline
-partial
-print : Show a => a -> IO' ffi ()
-print x = putStr (show x)
-
-||| Output something showable to stdout, with a trailing newline
-partial
-printLn : Show a => a -> IO' ffi ()
-printLn x = putStrLn (show x)
-
-||| Read one line of input from stdin, without the trailing newline
-partial
-getLine : IO' ffi String
-getLine = do x <- prim_read
-             return (reverse (trimNL (reverse x)))
-  where trimNL : String -> String
-        trimNL str with (strM str)
-          trimNL "" | StrNil = ""
-          trimNL (strCons '\n' xs) | StrCons _ _ = xs
-          trimNL (strCons x xs)    | StrCons _ _ = strCons x xs
-
-||| Write a single character to stdout
-partial
-putChar : Char -> IO ()
-putChar c = foreign FFI_C "putchar" (Int -> IO ()) (cast c)
-
-||| Write a singel character to stdout, with a trailing newline
-partial
-putCharLn : Char -> IO ()
-putCharLn c = putStrLn (singleton c)
-
-||| Read a single character from stdin
-partial
-getChar : IO Char
-getChar = map cast $ foreign FFI_C "getchar" (IO Int)
-
----- some basic file handling
-
-||| A file handle
-abstract
-data File = FHandle Ptr
-
-||| Standard input
-stdin : File
-stdin = FHandle prim__stdin
-
-||| Standard output
-stdout : File
-stdout = FHandle prim__stdout
-
-||| Standard output
-stderr : File
-stderr = FHandle prim__stderr
-
-||| Call the RTS's file opening function
-do_fopen : String -> String -> IO Ptr
-do_fopen f m
-   = foreign FFI_C "fileOpen" (String -> String -> IO Ptr) f m
-
-||| Open a file
-||| @ f the filename
-||| @ m the mode as a String (`"r"`, `"w"`, or `"r+"`)
-fopen : (f : String) -> (m : String) -> IO File
-fopen f m = do h <- do_fopen f m
-               return (FHandle h)
-
-||| Modes for opening files
-data Mode = Read | Write | ReadWrite
-
-||| Open a file
-||| @ f the filename
-||| @ m the mode
-partial
-openFile : (f : String) -> (m : Mode) -> IO File
-openFile f m = fopen f (modeStr m) where
-  modeStr Read  = "r"
-  modeStr Write = "w"
-  modeStr ReadWrite = "r+"
-
-partial
-do_fclose : Ptr -> IO ()
-do_fclose h = foreign FFI_C "fileClose" (Ptr -> IO ()) h
-
-partial
-closeFile : File -> IO ()
-closeFile (FHandle h) = do_fclose h
-
-partial
-do_fread : Ptr -> IO' l String
-do_fread h = prim_fread h
-
-fgetc : File -> IO Char
-fgetc (FHandle h) = return (cast !(foreign FFI_C "fgetc" (Ptr -> IO Int) h))
-
-fgetc' : File -> IO (Maybe Char)
-fgetc' (FHandle h)
-   = do x <- foreign FFI_C "fgetc" (Ptr -> IO Int) h
-        if (x < 0) then return Nothing
-                   else return (Just (cast x))
-
-fflush : File -> IO ()
-fflush (FHandle h) = foreign FFI_C "fflush" (Ptr -> IO ()) h
-
-do_popen : String -> String -> IO Ptr
-do_popen f m = foreign FFI_C "do_popen" (String -> String -> IO Ptr) f m
-
-popen : String -> Mode -> IO File
-popen f m = do ptr <- do_popen f (modeStr m)
-               return (FHandle ptr)
-  where
-    modeStr Read  = "r"
-    modeStr Write = "w"
-    modeStr ReadWrite = "r+"
-
-pclose : File -> IO ()
-pclose (FHandle h) = foreign FFI_C "pclose" (Ptr -> IO ()) h
-
--- mkForeign (FFun "idris_readStr" [FPtr, FPtr] (FAny String))
---                        prim__vm h
-
-partial
-fread : File -> IO' l String
-fread (FHandle h) = do_fread h
-
-partial
-do_fwrite : Ptr -> String -> IO ()
-do_fwrite h s = do prim_fwrite h s
-                   return ()
-
-partial
-fwrite : File -> String -> IO ()
-fwrite (FHandle h) s = do_fwrite h s
-
-partial
-do_feof : Ptr -> IO Int
-do_feof h = foreign FFI_C "fileEOF" (Ptr -> IO Int) h
-
-||| Check if a file handle has reached the end
-feof : File -> IO Bool
-feof (FHandle h) = do eof <- do_feof h
-                      return (not (eof == 0))
-
-partial
-do_ferror : Ptr -> IO Int
-do_ferror h = foreign FFI_C "fileError" (Ptr -> IO Int) h
-
-ferror : File -> IO Bool
-ferror (FHandle h) = do err <- do_ferror h
-                        return (not (err == 0))
-
-fpoll : File -> IO Bool
-fpoll (FHandle h) = do p <- foreign FFI_C "fpoll" (Ptr -> IO Int) h
-                       return (p > 0)
-
-||| Check if a foreign pointer is null
-partial
-nullPtr : Ptr -> IO Bool
-nullPtr p = do ok <- foreign FFI_C "isNull" (Ptr -> IO Int) p
-               return (ok /= 0)
-
-||| Check if a supposed string was actually a null pointer
-partial
-nullStr : String -> IO Bool
-nullStr p = do ok <- foreign FFI_C "isNull" (String -> IO Int) p
-               return (ok /= 0)
-
 namespace JSNull
   ||| Check if a foreign pointer is null
   partial
@@ -524,12 +238,6 @@
 eqPtr x y = do eq <- foreign FFI_C "idris_eqPtr" (Ptr -> Ptr -> IO Int) x y
                return (eq /= 0)
 
-||| Check whether a file handle is actually a null pointer
-partial
-validFile : File -> IO Bool
-validFile (FHandle h) = do x <- nullPtr h
-                           return (not x)
-
 ||| Loop while some test is true
 |||
 ||| @ test the condition of the loop
@@ -541,18 +249,27 @@
                             while t b
                     else return ()
 
-||| Read the contents of a file into a string
-partial -- no error checking!
-readFile : String -> IO String
-readFile fn = do h <- openFile fn Read
-                 c <- readFile' h ""
-                 closeFile h
-                 return c
-  where
-    partial
-    readFile' : File -> String -> IO String
-    readFile' h contents =
-       do x <- feof h
-          if not x then do l <- fread h
-                           readFile' h (contents ++ l)
-                   else return contents
+------- Some error rewriting
+
+%language ErrorReflection
+  
+private
+cast_part : TT -> ErrorReportPart
+cast_part (P Bound n t) = TextPart "unknown type"
+cast_part x = TermPart x
+  
+%error_handler
+cast_error : Err -> Maybe (List ErrorReportPart)
+cast_error (CantResolve `(Cast ~x ~y))
+     = Just [TextPart "Can't cast from",
+             cast_part x,
+             TextPart "to",
+             cast_part y]
+cast_error _ = Nothing
+
+%error_handler
+num_error : Err -> Maybe (List ErrorReportPart)
+num_error (CantResolve `(Num ~x))
+     = Just [TermPart x, TextPart "is not a numeric type"]
+num_error _ = Nothing
+
diff --git a/libs/prelude/Prelude/Applicative.idr b/libs/prelude/Prelude/Applicative.idr
--- a/libs/prelude/Prelude/Applicative.idr
+++ b/libs/prelude/Prelude/Applicative.idr
@@ -5,6 +5,7 @@
 import Prelude.Basics
 import Prelude.Bool
 import Prelude.Classes
+import Prelude.Foldable
 import Prelude.Functor
 
 ---- Applicative functors/Idioms
@@ -48,3 +49,26 @@
 when : Applicative f => Bool -> Lazy (f ()) -> f ()
 when True f = Force f
 when False f = pure ()
+
+||| Fold using Alternative
+|||
+||| If you have a left-biased alternative operator `<|>`, then `choice`
+||| performs left-biased choice from a list of alternatives, which means that
+||| it evaluates to the left-most non-`empty` alternative.
+|||
+||| If the list is empty, or all values in it are `empty`, then it
+||| evaluates to `empty`.
+|||
+||| Example:
+|||
+||| ```
+||| -- given a parser expression like:
+||| expr = literal <|> keyword <|> funcall
+|||
+||| -- choice lets you write this as:
+||| expr = choice [literal, keyword, funcall]
+||| ```
+|||
+||| Note: In Haskell, `choice` is called `asum`.
+choice : (Foldable t, Alternative f) => t (f a) -> f a
+choice x = foldr (<|>) empty x
diff --git a/libs/prelude/Prelude/Basics.idr b/libs/prelude/Prelude/Basics.idr
--- a/libs/prelude/Prelude/Basics.idr
+++ b/libs/prelude/Prelude/Basics.idr
@@ -11,8 +11,8 @@
 
 ||| Manually assign a type to an expression.
 ||| @ a the type to assign
-||| @ x the element to get the type
-the : (a : Type) -> (x : a) -> a
+||| @ value the element to get the type
+the : (a : Type) -> (value : a) -> a
 the _ = id
 
 ||| Constant function. Ignores its second argument.
@@ -20,7 +20,7 @@
 const x = \v => x
 
 ||| Return the first element of a pair.
-fst : (s, t) -> s
+fst : (a, b) -> a
 fst (x, y) = x
 
 ||| Return the second element of a pair.
diff --git a/libs/prelude/Prelude/Cast.idr b/libs/prelude/Prelude/Cast.idr
--- a/libs/prelude/Prelude/Cast.idr
+++ b/libs/prelude/Prelude/Cast.idr
@@ -15,7 +15,7 @@
 instance Cast String Int where
     cast = prim__fromStrInt
 
-instance Cast String Float where
+instance Cast String Double where
     cast = prim__strToFloat
 
 instance Cast String Integer where
@@ -26,24 +26,30 @@
 instance Cast Int String where
     cast = prim__toStrInt
 
-instance Cast Int Float where
+instance Cast Int Double where
     cast = prim__toFloatInt
 
 instance Cast Int Integer where
     cast = prim__sextInt_BigInt
 
--- Float casts
+-- Double casts
 
-instance Cast Float String where
+instance Cast Double String where
     cast = prim__floatToStr
 
-instance Cast Float Int where
+instance Cast Double Int where
     cast = prim__fromFloatInt
 
+instance Cast Double Integer where
+    cast = prim__fromFloatBigInt
+
 -- Integer casts
 
 instance Cast Integer String where
     cast = prim__toStrBigInt
+
+instance Cast Integer Double where
+    cast = prim__toFloatBigInt
 
 -- Char casts
 
diff --git a/libs/prelude/Prelude/Classes.idr b/libs/prelude/Prelude/Classes.idr
--- a/libs/prelude/Prelude/Classes.idr
+++ b/libs/prelude/Prelude/Classes.idr
@@ -46,6 +46,12 @@
 instance Eq String where
     (==) = boolOp prim__eqString
 
+instance Eq Ptr where
+    (==) = boolOp prim__eqPtr
+
+instance Eq ManagedPtr where
+    (==) = boolOp prim__eqManagedPtr
+
 instance Eq Bool where
     True  == True  = True
     True  == False = False
diff --git a/libs/prelude/Prelude/File.idr b/libs/prelude/Prelude/File.idr
new file mode 100644
--- /dev/null
+++ b/libs/prelude/Prelude/File.idr
@@ -0,0 +1,156 @@
+module Prelude.File
+
+import Builtins
+import Prelude.List
+import Prelude.Maybe
+import Prelude.Monad
+import Prelude.Chars
+import Prelude.Strings
+import Prelude.Cast
+import Prelude.Bool
+import Prelude.Basics
+import Prelude.Classes
+import Prelude.Monad
+import IO
+
+%access public
+
+||| A file handle
+abstract
+data File = FHandle Ptr
+
+||| Standard input
+stdin : File
+stdin = FHandle prim__stdin
+
+||| Standard output
+stdout : File
+stdout = FHandle prim__stdout
+
+||| Standard output
+stderr : File
+stderr = FHandle prim__stderr
+
+||| Call the RTS's file opening function
+do_fopen : String -> String -> IO Ptr
+do_fopen f m
+   = foreign FFI_C "fileOpen" (String -> String -> IO Ptr) f m
+
+||| Open a file
+||| @ f the filename
+||| @ m the mode as a String (`"r"`, `"w"`, or `"r+"`)
+fopen : (f : String) -> (m : String) -> IO File
+fopen f m = do h <- do_fopen f m
+               return (FHandle h)
+
+||| Check whether a file handle is actually a null pointer
+partial
+validFile : File -> IO Bool
+validFile (FHandle h) = do x <- nullPtr h
+                           return (not x)
+
+||| Modes for opening files
+data Mode = Read | Write | ReadWrite
+
+||| Open a file
+||| @ f the filename
+||| @ m the mode
+partial
+openFile : (f : String) -> (m : Mode) -> IO File
+openFile f m = fopen f (modeStr m) where
+  modeStr Read  = "r"
+  modeStr Write = "w"
+  modeStr ReadWrite = "r+"
+
+partial
+do_fclose : Ptr -> IO ()
+do_fclose h = foreign FFI_C "fileClose" (Ptr -> IO ()) h
+
+partial
+closeFile : File -> IO ()
+closeFile (FHandle h) = do_fclose h
+
+partial
+do_fread : Ptr -> IO' l String
+do_fread h = prim_fread h
+
+fgetc : File -> IO Char
+fgetc (FHandle h) = return (cast !(foreign FFI_C "fgetc" (Ptr -> IO Int) h))
+
+fgetc' : File -> IO (Maybe Char)
+fgetc' (FHandle h)
+   = do x <- foreign FFI_C "fgetc" (Ptr -> IO Int) h
+        if (x < 0) then return Nothing
+                   else return (Just (cast x))
+
+fflush : File -> IO ()
+fflush (FHandle h) = foreign FFI_C "fflush" (Ptr -> IO ()) h
+
+do_popen : String -> String -> IO Ptr
+do_popen f m = foreign FFI_C "do_popen" (String -> String -> IO Ptr) f m
+
+popen : String -> Mode -> IO File
+popen f m = do ptr <- do_popen f (modeStr m)
+               return (FHandle ptr)
+  where
+    modeStr Read  = "r"
+    modeStr Write = "w"
+    modeStr ReadWrite = "r+"
+
+pclose : File -> IO ()
+pclose (FHandle h) = foreign FFI_C "pclose" (Ptr -> IO ()) h
+
+-- mkForeign (FFun "idris_readStr" [FPtr, FPtr] (FAny String))
+--                        prim__vm h
+
+partial
+fread : File -> IO' l String
+fread (FHandle h) = do_fread h
+
+partial
+do_fwrite : Ptr -> String -> IO ()
+do_fwrite h s = do prim_fwrite h s
+                   return ()
+
+partial
+fwrite : File -> String -> IO ()
+fwrite (FHandle h) s = do_fwrite h s
+
+partial
+do_feof : Ptr -> IO Int
+do_feof h = foreign FFI_C "fileEOF" (Ptr -> IO Int) h
+
+||| Check if a file handle has reached the end
+feof : File -> IO Bool
+feof (FHandle h) = do eof <- do_feof h
+                      return (not (eof == 0))
+
+partial
+do_ferror : Ptr -> IO Int
+do_ferror h = foreign FFI_C "fileError" (Ptr -> IO Int) h
+
+ferror : File -> IO Bool
+ferror (FHandle h) = do err <- do_ferror h
+                        return (not (err == 0))
+
+fpoll : File -> IO Bool
+fpoll (FHandle h) = do p <- foreign FFI_C "fpoll" (Ptr -> IO Int) h
+                       return (p > 0)
+
+||| Read the contents of a file into a string
+partial -- no error checking!
+readFile : String -> IO String
+readFile fn = do h <- openFile fn Read
+                 c <- readFile' h ""
+                 closeFile h
+                 return c
+  where
+    partial
+    readFile' : File -> String -> IO String
+    readFile' h contents =
+       do x <- feof h
+          if not x then do l <- fread h
+                           readFile' h (contents ++ l)
+                   else return contents
+
+
diff --git a/libs/prelude/Prelude/Interactive.idr b/libs/prelude/Prelude/Interactive.idr
new file mode 100644
--- /dev/null
+++ b/libs/prelude/Prelude/Interactive.idr
@@ -0,0 +1,142 @@
+||| Various helper functions for creating simple interactive systems.
+||| 
+||| These are mostly intended for helping with teaching, in that they will allow
+||| the easy creation of interactive programs without needing to teach IO
+||| or Effects first, but they also capture some common patterns of interactive
+||| programming.
+module Prelude.Interactive
+
+import Builtins
+import Prelude.List
+import Prelude.File
+import Prelude.Bool
+import Prelude.Classes
+import Prelude.Strings
+import Prelude.Chars
+import Prelude.Show
+import Prelude.Cast
+import Prelude.Maybe
+import Prelude.Functor
+import Prelude.Monad
+import IO
+
+%access public
+
+---- some basic io
+
+||| Output a string to stdout without a trailing newline
+putStr : String -> IO' ffi ()
+putStr x = do prim_write x
+              return ()
+
+||| Output a string to stdout with a trailing newline
+putStrLn : String -> IO' ffi ()
+putStrLn x = putStr (x ++ "\n")
+
+||| Output something showable to stdout, without a trailing newline
+print : Show a => a -> IO' ffi ()
+print x = putStr (show x)
+
+||| Output something showable to stdout, with a trailing newline
+printLn : Show a => a -> IO' ffi ()
+printLn x = putStrLn (show x)
+
+||| Read one line of input from stdin, without the trailing newline
+getLine : IO' ffi String
+getLine = do x <- prim_read
+             return (reverse (trimNL (reverse x)))
+  where trimNL : String -> String
+        trimNL str with (strM str)
+          trimNL "" | StrNil = ""
+          trimNL (strCons '\n' xs) | StrCons _ _ = xs
+          trimNL (strCons x xs)    | StrCons _ _ = strCons x xs
+
+||| Write a single character to stdout
+putChar : Char -> IO ()
+putChar c = foreign FFI_C "putchar" (Int -> IO ()) (cast c)
+
+||| Write a singel character to stdout, with a trailing newline
+putCharLn : Char -> IO ()
+putCharLn c = putStrLn (singleton c)
+
+||| Read a single character from stdin
+getChar : IO Char
+getChar = map cast $ foreign FFI_C "getchar" (IO Int)
+
+||| Get the command-line arguments that the program was called with.
+partial
+getArgs : IO (List String)
+getArgs = do n <- numArgs
+             ga' [] 0 n
+  where
+    numArgs : IO Int
+    numArgs = foreign FFI_C "idris_numArgs" (IO Int)
+
+    getArg : Int -> IO String
+    getArg x = foreign FFI_C "idris_getArg" (Int -> IO String) x
+
+    partial
+    ga' : List String -> Int -> Int -> IO (List String)
+    ga' acc i n = if (i == n) then (return $ reverse acc) else
+                    do arg <- getArg i
+                       ga' (arg :: acc) (i+1) n
+
+
+||| Process input from an open file handle, while maintaining a state.
+||| @ state the input state
+||| @ onRead the function to run on reading a line, returning a String to
+||| output and a new state
+||| @ onEOF the function to run on reaching end of file, returning a String
+||| to output
+partial
+processHandle : File -> 
+                (state : a) ->
+                (onRead : a -> String -> (String, a)) -> 
+                (onEOF : a -> String) -> 
+                IO ()
+processHandle h acc onRead onEOF 
+   = if !(feof h)
+        then putStr (onEOF acc)
+        else do x <- fread h
+                let (out, acc') = onRead acc x
+                putStr out
+                processHandle h acc' onRead onEOF    
+
+||| Process input from the standard input stream, while maintaining a state.
+||| @ state the input state
+||| @ onRead the function to run on reading a line, returning a String to
+||| output and a new state
+||| @ onEOI the function to run on reaching end of input, returning a String
+||| to output
+partial
+processStdin : (state : a) -> 
+               (onRead : a -> String -> (String, a)) -> 
+               (onEOI : a -> String) -> IO ()
+processStdin = processHandle stdin
+
+||| A basic read-eval-print loop, maintaining a state
+||| @ state the input state
+||| @ prompt the prompt to show 
+||| @ onInput the function to run on reading input, returning a String to
+||| output and a new state. Returns Nothing if the repl should exit
+partial
+replWith : (state : a) -> (prompt : String) -> 
+           (onInput : a -> String -> Maybe (String, a)) -> IO ()
+replWith acc prompt fn 
+   = do putStr prompt
+        x <- getLine
+        case fn acc x of
+             Just (out, acc') => do putStr out 
+                                    replWith acc' prompt fn
+             Nothing => return ()
+
+||| A basic read-eval-print loop
+||| @ prompt the prompt to show 
+||| @ onInput the function to run on reading input, returning a String to
+||| output 
+partial
+repl : (prompt : String) -> 
+       (onInput : String -> String) -> IO ()
+repl prompt fn 
+   = replWith () prompt (\x, s => Just (fn s, ()))
+
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
@@ -9,6 +9,7 @@
 import Prelude.Foldable
 import Prelude.Functor
 import Prelude.Maybe
+import Prelude.Uninhabited
 import Prelude.Nat
 
 %access public
@@ -17,12 +18,13 @@
 infix 5 \\
 infixr 7 ::,++
 
-||| Linked lists
-%elim data List a =
-  ||| The empty list
+||| Generic lists
+%elim data List elem =
+  ||| Empty list
   Nil |
-  ||| Cons cell
-  (::) a (List a)
+  ||| A non-empty list, consisting of a head element and the rest of
+  ||| the list.
+  (::) elem (List elem)
 
 -- Name hints for interactive editing
 %name List xs, ys, zs, ws
@@ -42,6 +44,47 @@
 isCons (x::xs) = True
 
 --------------------------------------------------------------------------------
+-- Decidable Predicates
+--------------------------------------------------------------------------------
+
+||| Satisfiable if `xs` is non-empty (e.g., if `xs` is a cons).
+data NonEmpty : (xs : List a) -> Type where
+    ||| The proof that a cons cell is non-empty
+    IsNonEmpty : NonEmpty (x :: xs)
+
+private
+nonEmptyNil : NonEmpty [] -> Void
+nonEmptyNil IsNonEmpty impossible
+
+||| Decide whether a list is non-empty
+nonEmpty : (xs : List a) -> Dec (NonEmpty xs)
+nonEmpty [] = No nonEmptyNil
+nonEmpty (x :: xs) = Yes IsNonEmpty
+
+||| Satisfiable if `k` is a valid index into `xs`
+|||
+||| @ k the potential index
+||| @ xs the list into which k may be an index
+data InBounds : (k : Nat) -> (xs : List a) -> Type where
+    ||| Z is a valid index into any cons cell
+    InFirst : InBounds Z (x :: xs)
+    ||| Valid indices can be extended
+    InLater : InBounds k xs -> InBounds (S k) (x :: xs)
+
+instance Uninhabited (InBounds k []) where
+    uninhabited InFirst impossible
+
+||| Decide whether `k` is a valid index into `xs`
+inBounds : (k : Nat) -> (xs : List a) -> Dec (InBounds k xs)
+inBounds k [] = No uninhabited
+inBounds Z (x :: xs) = Yes InFirst
+inBounds (S k) (x :: xs) with (inBounds k xs)
+  inBounds (S k) (x :: xs) | (Yes prf) = Yes (InLater prf)
+  inBounds (S k) (x :: xs) | (No contra)
+      = No (\p => case p of
+                       InLater y => contra y)
+
+--------------------------------------------------------------------------------
 -- Length
 --------------------------------------------------------------------------------
 
@@ -59,10 +102,9 @@
 ||| Find a particular element of a list.
 |||
 ||| @ ok a proof that the index is within bounds
-index : (n : Nat) -> (l : List a) -> (ok : lt n (length l) = True) -> a
-index Z     (x::xs) p    = x
-index (S n) (x::xs) p    = index n xs ?indexTailProof
-index _     []      Refl   impossible
+index : (n : Nat) -> (xs : List a) -> {auto ok : InBounds n xs} -> a
+index Z     (x :: xs) {ok} = x
+index (S k) (x :: xs) {ok = InLater p} = index k xs
 
 ||| Attempt to find a particular element of a list.
 |||
@@ -74,8 +116,8 @@
 
 ||| Get the first element of a non-empty list
 ||| @ ok proof that the list is non-empty
-head : (l : List a) -> {auto ok : isCons l = True} -> a
-head []      {ok=Refl}   impossible
+head : (l : List a) -> {auto ok : NonEmpty l} -> a
+head []      {ok=IsNonEmpty} impossible
 head (x::xs) {ok=p}    = x
 
 ||| Attempt to get the first element of a list. If the list is empty, return
@@ -86,8 +128,8 @@
 
 ||| Get the tail of a non-empty list.
 ||| @ ok proof that the list is non-empty
-tail : (l : List a) -> {auto ok : isCons l = True} -> List a
-tail []      {ok=Refl}   impossible
+tail : (l : List a) -> {auto ok : NonEmpty l} -> List a
+tail []      {ok=IsNonEmpty} impossible
 tail (x::xs) {ok=p}    = xs
 
 ||| Attempt to get the tail of a list.
@@ -99,10 +141,10 @@
 
 ||| Retrieve the last element of a non-empty list.
 ||| @ ok proof that the list is non-empty
-last : (l : List a) -> {auto ok : isCons l = True} -> a
-last []         {ok=Refl}   impossible
+last : (l : List a) -> {auto ok : NonEmpty l} -> a
+last []         {ok=IsNonEmpty} impossible
 last [x]        {ok=p}    = x
-last (x::y::ys) {ok=p}    = last (y::ys) {ok=Refl}
+last (x::y::ys) {ok=p}    = last (y::ys) {ok=IsNonEmpty}
 
 ||| Attempt to retrieve the last element of a non-empty list.
 |||
@@ -116,10 +158,10 @@
 
 ||| Return all but the last element of a non-empty list.
 ||| @ ok proof that the list is non-empty
-init : (l : List a) -> {auto ok : isCons l = True} -> List a
-init []         {ok=Refl}   impossible
+init : (l : List a) -> {auto ok : NonEmpty l} -> List a
+init []         {ok=IsNonEmpty} impossible
 init [x]        {ok=p}    = []
-init (x::y::ys) {ok=p}    = x :: init (y::ys) {ok=Refl}
+init (x::y::ys) {ok=p}    = x :: init (y::ys) {ok=IsNonEmpty}
 
 ||| Attempt to Return all but the last element of a list.
 |||
@@ -129,8 +171,7 @@
 init' (x::xs) =
   case xs of
     []    => Just []
-    y::ys =>
-      -- XXX: Problem with typechecking a "do" block here
+    y::ys => 
       case init' $ y::ys of
         Nothing => Nothing
         Just j  => Just $ x :: j
@@ -242,42 +283,38 @@
 -- Zips and unzips
 --------------------------------------------------------------------------------
 
-||| Combine two lists of the same length elementwise using some function.
+||| Combine two lists elementwise using some function. If they are different
+||| lengths, the result is truncated to the length of the shorter list.
 ||| @ f the function to combine elements with
 ||| @ l the first list
 ||| @ r the second list
-||| @ ok a proof that the lengths of the inputs are equal
-zipWith : (f : a -> b -> c) -> (l : List a) -> (r : List b) ->
-  (ok : length l = length r) -> List c
-zipWith f []      (y::ys) Refl   impossible
-zipWith f (x::xs) []      Refl   impossible
-zipWith f []      []      p    = []
-zipWith f (x::xs) (y::ys) p    = f x y :: (zipWith f xs ys ?zipWithTailProof)
+zipWith : (f : a -> b -> c) -> (l : List a) -> (r : List b) -> List c
+zipWith f []      (y::ys) = []
+zipWith f (x::xs) []      = []
+zipWith f []      []      = []
+zipWith f (x::xs) (y::ys) = f x y :: zipWith f xs ys
 
-||| Combine three lists of the same length elementwise using some function.
+||| Combine three lists elementwise using some function. If they are different
+||| lengths, the result is truncated to the length of the shortest list.
 ||| @ f the function to combine elements with
 ||| @ x the first list
 ||| @ y the second list
 ||| @ z the third list
-||| @ ok a proof that the lengths of the first two inputs are equal
-||| @ ok' a proof that the lengths of the second and third inputs are equal
 zipWith3 : (f : a -> b -> c -> d) -> (x : List a) -> (y : List b) ->
-  (z : List c) -> (ok : length x = length y) -> (ok' : length y = length z) -> List d
-zipWith3 f _       []      (z::zs) p    Refl   impossible
-zipWith3 f _       (y::ys) []      p    Refl   impossible
-zipWith3 f []      (y::ys) _       Refl q      impossible
-zipWith3 f (x::xs) []      _       Refl q      impossible
-zipWith3 f []      []      []      p    q    = []
-zipWith3 f (x::xs) (y::ys) (z::zs) p    q    =
-  f x y z :: (zipWith3 f xs ys zs ?zipWith3TailProof ?zipWith3TailProof')
+           (z : List c) -> List d
+zipWith3 f _       []      (z::zs) = [] 
+zipWith3 f _       (y::ys) []      = []
+zipWith3 f []      (y::ys) _       = []
+zipWith3 f (x::xs) []      _       = []
+zipWith3 f []      []      []      = []
+zipWith3 f (x::xs) (y::ys) (z::zs) = f x y z :: zipWith3 f xs ys zs
 
 ||| Combine two lists elementwise into pairs
-zip : (l : List a) -> (r : List b) -> (length l = length r) -> List (a, b)
+zip : (l : List a) -> (r : List b) -> List (a, b)
 zip = zipWith (\x,y => (x, y))
 
 ||| Combine three lists elementwise into tuples
-zip3 : (x : List a) -> (y : List b) -> (z : List c) -> (length x = length y) ->
-  (length y = length z) -> List (a, b, c)
+zip3 : (x : List a) -> (y : List b) -> (z : List c) -> List (a, b, c)
 zip3 = zipWith3 (\x,y,z => (x, y, z))
 
 ||| Split a list of pairs into two lists
@@ -312,7 +349,7 @@
 instance Foldable List where
   foldr c n [] = n
   foldr c n (x::xs) = c x (foldr c n xs)
-  
+
   foldl f q [] = q
   foldl f q (x::xs) = foldl f (f q x) xs
 
@@ -350,8 +387,13 @@
     intersperse' sep []      = []
     intersperse' sep (y::ys) = sep :: y :: intersperse' sep ys
 
-intercalate : List a -> List (List a) -> List a
-intercalate sep l = concat $ intersperse sep l
+||| Given a separator list and some more lists, produce a new list by
+||| placing the separator between each of the lists.
+|||
+||| @ sep the separator
+||| @ xss the lists between which the separator will be placed
+intercalate : (sep : List a) -> (xss : List (List a)) -> List a
+intercalate sep xss = concat $ intersperse sep xss
 
 ||| Transposes rows and columns of a list of lists.
 |||
@@ -456,15 +498,20 @@
       else
         findIndices' (S cnt) p xs
 
+||| Find the index of the first occurrence of an element in a list, using a custom equality test.
 elemIndexBy : (a -> a -> Bool) -> a -> List a -> Maybe Nat
 elemIndexBy p e = findIndex $ p e
 
+||| Find the index of the first occurrence of an element in a list,
+||| using the default equality test for the type of list elements.
 elemIndex : Eq a => a -> List a -> Maybe Nat
 elemIndex = elemIndexBy (==)
 
+||| Find all indices for an element in a list, using a custom equality test.
 elemIndicesBy : (a -> a -> Bool) -> a -> List a -> List Nat
 elemIndicesBy p e = findIndices $ p e
 
+||| Find all indices for an element in a list, using the default equality test for the type of list elements.
 elemIndices : Eq a => a -> List a -> List Nat
 elemIndices = elemIndicesBy (==)
 
@@ -655,7 +702,12 @@
 -- Predicates
 --------------------------------------------------------------------------------
 
-isPrefixOfBy : (a -> a -> Bool) -> List a -> List a -> Bool
+||| Check whether a list is a prefix of another according to a user-supplied equality test.
+|||
+||| @ eq the equality comparison
+||| @ left the potential prefix
+||| @ right the list that may have `left` as its prefix
+isPrefixOfBy : (eq : a -> a -> Bool) -> (left, right : List a) -> Bool
 isPrefixOfBy p [] right        = True
 isPrefixOfBy p left []         = False
 isPrefixOfBy p (x::xs) (y::ys) =
@@ -691,6 +743,7 @@
 -- Sorting
 --------------------------------------------------------------------------------
 
+||| Check whether a list is sorted with respect to the default ordering for the type of its elements.
 sorted : Ord a => List a -> Bool
 sorted []      = True
 sorted (x::xs) =
@@ -698,6 +751,9 @@
     Nil     => True
     (y::ys) => x <= y && sorted (y::ys)
 
+||| Merge two sorted lists using an arbitrary comparison
+||| predicate. Note that the lists must have been sorted using this
+||| predicate already.
 mergeBy : (a -> a -> Ordering) -> List a -> List a -> List a
 mergeBy order []      right   = right
 mergeBy order left    []      = left
@@ -706,15 +762,21 @@
      then x :: mergeBy order xs (y::ys)
      else y :: mergeBy order (x::xs) ys
 
+||| Merge two sorted lists using the default ordering for the type of their elements.
 merge : Ord a => List a -> List a -> List a
 merge = mergeBy compare
 
-sort : Ord a => List a -> List a
-sort []  = []
-sort [x] = [x]
-sort xs  = let (x, y) = split xs in
-    merge (sort (assert_smaller xs x)) 
-          (sort (assert_smaller xs y)) -- not structurally smaller, hence assert
+||| Sort a list using some arbitrary comparison predicate.
+|||
+||| @ cmp how to compare elements
+||| @ xs the list to sort
+sortBy : (cmp : a -> a -> Ordering) -> (xs : List a) -> List a
+sortBy cmp []  = []
+sortBy cmp [x] = [x]
+sortBy cmp xs  = let (x, y) = split xs in
+    mergeBy cmp
+          (sortBy cmp (assert_smaller xs x))
+          (sortBy cmp (assert_smaller xs y)) -- not structurally smaller, hence assert
   where
     splitRec : List a -> List a -> (List a -> List a) -> (List a, List a)
     splitRec (_::_::xs) (y::ys) zs = splitRec xs ys (zs . ((::) y))
@@ -723,6 +785,10 @@
     split : List a -> (List a, List a)
     split xs = splitRec xs xs id
 
+||| Sort a list using the default ordering for the type of its elements.
+sort : Ord a => List a -> List a
+sort = sortBy compare
+
 --------------------------------------------------------------------------------
 -- Conversions
 --------------------------------------------------------------------------------
@@ -736,6 +802,7 @@
 -- Misc
 --------------------------------------------------------------------------------
 
+||| Keep the `Just` elements in a list, discarding the `Nothing` elements.
 catMaybes : List (Maybe a) -> List a
 catMaybes []      = []
 catMaybes (x::xs) =
@@ -753,7 +820,7 @@
 appendNilRightNeutral []      = Refl
 appendNilRightNeutral (x::xs) =
   let inductiveHypothesis = appendNilRightNeutral xs in
-    ?appendNilRightNeutralStepCase
+    rewrite inductiveHypothesis in Refl
 
 ||| Appending lists is associative.
 appendAssociative : (l : List a) -> (c : List a) -> (r : List a) ->
@@ -761,7 +828,7 @@
 appendAssociative []      c r = Refl
 appendAssociative (x::xs) c r =
   let inductiveHypothesis = appendAssociative xs c r in
-    ?appendAssociativeStepCase
+    rewrite inductiveHypothesis in Refl
 
 ||| The length of two lists that are appended is the sum of the lengths
 ||| of the input lists.
@@ -770,7 +837,7 @@
 lengthAppend []      right = Refl
 lengthAppend (x::xs) right =
   let inductiveHypothesis = lengthAppend xs right in
-    ?lengthAppendStepCase
+    rewrite inductiveHypothesis in Refl
 
 ||| Mapping a function over a list doesn't change its length.
 mapPreservesLength : (f : a -> b) -> (l : List a) ->
@@ -778,7 +845,7 @@
 mapPreservesLength f []      = Refl
 mapPreservesLength f (x::xs) =
   let inductiveHypothesis = mapPreservesLength f xs in
-    ?mapPreservesLengthStepCase
+    rewrite inductiveHypothesis in Refl
 
 ||| Mapping a function over two lists and appending them is equivalent
 ||| to appending them and then mapping the function.
@@ -787,7 +854,7 @@
 mapDistributesOverAppend f []      r = Refl
 mapDistributesOverAppend f (x::xs) r =
   let inductiveHypothesis = mapDistributesOverAppend f xs r in
-    ?mapDistributesOverAppendStepCase
+    rewrite inductiveHypothesis in Refl
 
 ||| Mapping two functions is the same as mapping their composition.
 mapFusion : (f : b -> c) -> (g : a -> b) -> (l : List a) ->
@@ -795,7 +862,7 @@
 mapFusion f g []      = Refl
 mapFusion f g (x::xs) =
   let inductiveHypothesis = mapFusion f g xs in
-    ?mapFusionStepCase
+    rewrite inductiveHypothesis in Refl
 
 ||| No list contains an element of the empty list by any predicate.
 hasAnyByNilFalse : (p : a -> a -> Bool) -> (l : List a) ->
@@ -803,12 +870,13 @@
 hasAnyByNilFalse p []      = Refl
 hasAnyByNilFalse p (x::xs) =
   let inductiveHypothesis = hasAnyByNilFalse p xs in
-    ?hasAnyByNilFalseStepCase
+    rewrite inductiveHypothesis in Refl
 
 ||| No list contains an element of the empty list.
 hasAnyNilFalse : Eq a => (l : List a) -> hasAny [] l = False
-hasAnyNilFalse l = ?hasAnyNilFalseBody
+hasAnyNilFalse l = rewrite (hasAnyByNilFalse (==) l) in Refl
 
+||| Implement foldl using foldr, for a later equality proof.
 foldlAsFoldr : (b -> a -> b) -> b -> List a -> b
 foldlAsFoldr f z t = foldr (flip (.) . flip f) id t z
 
@@ -817,81 +885,4 @@
 foldlMatchesFoldr : (f : b -> a -> b) -> (q : b) -> (xs : List a) -> foldl f q xs = foldlAsFoldr f q xs
 foldlMatchesFoldr f q [] = Refl
 foldlMatchesFoldr f q (x :: xs) = foldlMatchesFoldr f (f q x) xs
-
-
---------------------------------------------------------------------------------
--- Proofs
---------------------------------------------------------------------------------
-
-indexTailProof = proof {
-  intros;
-  rewrite sym p;
-  trivial;
-}
-
-lengthAppendStepCase = proof {
-    intros;
-    rewrite inductiveHypothesis;
-    trivial;
-}
-
-hasAnyNilFalseBody = proof {
-    intros;
-    rewrite (hasAnyByNilFalse (==) l);
-    trivial;
-}
-
-hasAnyByNilFalseStepCase = proof {
-    intros;
-    rewrite inductiveHypothesis;
-    trivial;
-}
-
-appendNilRightNeutralStepCase = proof {
-    intros;
-    rewrite inductiveHypothesis;
-    trivial;
-}
-
-appendAssociativeStepCase = proof {
-    intros;
-    rewrite inductiveHypothesis;
-    trivial;
-}
-
-mapFusionStepCase = proof {
-    intros;
-    rewrite inductiveHypothesis;
-    trivial;
-}
-
-mapDistributesOverAppendStepCase = proof {
-    intros;
-    rewrite inductiveHypothesis;
-    trivial;
-}
-
-mapPreservesLengthStepCase = proof {
-    intros;
-    rewrite inductiveHypothesis;
-    trivial;
-}
-
-zipWithTailProof = proof {
-    intros;
-    rewrite (succInjective (length xs) (length ys) p);
-    trivial;
-}
-
-zipWith3TailProof = proof {
-    intros;
-    rewrite (succInjective (length xs) (length ys) p);
-    trivial;
-}
-
-zipWith3TailProof' = proof {
-    intros;
-    rewrite (succInjective (length ys) (length zs) q);
-    trivial;
-}
 
diff --git a/libs/prelude/Prelude/Maybe.idr b/libs/prelude/Prelude/Maybe.idr
--- a/libs/prelude/Prelude/Maybe.idr
+++ b/libs/prelude/Prelude/Maybe.idr
@@ -11,9 +11,13 @@
 %access public
 %default total
 
+||| An optional value. This can be used to represent the possibility of
+||| failure, where a function may return a value, or not.
 data Maybe a
-    = Nothing
-    | Just a
+    = ||| No value stored
+      Nothing
+    | ||| A value of type `a` is stored
+      Just a
 
 --------------------------------------------------------------------------------
 -- Syntactic tests
diff --git a/libs/prelude/Prelude/Monad.idr b/libs/prelude/Prelude/Monad.idr
--- a/libs/prelude/Prelude/Monad.idr
+++ b/libs/prelude/Prelude/Monad.idr
@@ -3,9 +3,10 @@
 -- Monads and Functors
 
 import Builtins
-import Prelude.List
+import Prelude.Functor
 import Prelude.Applicative
 import Prelude.Basics
+import IO
 
 %access public
 
@@ -22,3 +23,20 @@
 ||| define `return` and `pure` differently!
 return : Monad m => a -> m a
 return = pure
+
+-- Annoyingly, these need to be here, so that we can use them in other
+-- Prelude modules other than the top level.
+
+instance Functor (IO' ffi) where
+    map f io = io_bind io (\b => io_return (f b))
+
+instance Applicative (IO' ffi) where
+    pure x = io_return x
+    f <*> a = io_bind f (\f' =>
+                io_bind a (\a' =>
+                  io_return (f' a')))
+
+
+instance Monad (IO' ffi) where
+    b >>= k = io_bind b k
+
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
@@ -12,7 +12,8 @@
 %access public
 %default total
 
-||| Unary natural numbers
+||| Natural numbers: unbounded, unsigned integers which can be pattern
+||| matched.
 %elim data Nat =
   ||| Zero
   Z |
@@ -213,12 +214,12 @@
 instance Cast Integer Nat where
   cast = fromInteger
 
-||| A wrapper for Nat that specifies the semigroup and monad instances that use (+)
+||| A wrapper for Nat that specifies the semigroup and monad instances that use (*)
 record Multiplicative where
   constructor getMultiplicative
   _ : Nat
 
-||| A wrapper for Nat that specifies the semigroup and monad instances that use (*)
+||| A wrapper for Nat that specifies the semigroup and monad instances that use (+)
 record Additive where
   constructor getAdditive  
   _ : Nat
@@ -262,6 +263,9 @@
 instance Cast Nat Int where
   cast = toIntNat
 
+instance Cast Nat Double where
+  cast = cast . toIntegerNat
+
 --------------------------------------------------------------------------------
 -- Auxilliary notions
 --------------------------------------------------------------------------------
@@ -403,28 +407,29 @@
 plusZeroRightNeutral Z     = Refl
 plusZeroRightNeutral (S n) =
   let inductiveHypothesis = plusZeroRightNeutral n in
-    ?plusZeroRightNeutralStepCase
+    rewrite inductiveHypothesis in Refl
 
 total plusSuccRightSucc : (left : Nat) -> (right : Nat) ->
   S (left + right) = left + (S right)
 plusSuccRightSucc Z right        = Refl
 plusSuccRightSucc (S left) right =
   let inductiveHypothesis = plusSuccRightSucc left right in
-    ?plusSuccRightSuccStepCase
+    rewrite inductiveHypothesis in Refl
 
 total plusCommutative : (left : Nat) -> (right : Nat) ->
   left + right = right + left
-plusCommutative Z        right = ?plusCommutativeBaseCase
+plusCommutative Z        right = rewrite plusZeroRightNeutral right in Refl
 plusCommutative (S left) right =
   let inductiveHypothesis = plusCommutative left right in
-    ?plusCommutativeStepCase
+    rewrite inductiveHypothesis in 
+      rewrite plusSuccRightSucc right left in Refl
 
 total plusAssociative : (left : Nat) -> (centre : Nat) -> (right : Nat) ->
   left + (centre + right) = (left + centre) + right
 plusAssociative Z        centre right = Refl
 plusAssociative (S left) centre right =
   let inductiveHypothesis = plusAssociative left centre right in
-    ?plusAssociativeStepCase
+    rewrite inductiveHypothesis in Refl
 
 total plusConstantRight : (left : Nat) -> (right : Nat) -> (c : Nat) ->
   (p : left = right) -> left + c = right + c
@@ -439,24 +444,26 @@
 
 total plusLeftCancel : (left : Nat) -> (right : Nat) -> (right' : Nat) ->
   (p : left + right = left + right') -> right = right'
-plusLeftCancel Z        right right' p = ?plusLeftCancelBaseCase
+plusLeftCancel Z        right right' p = p
 plusLeftCancel (S left) right right' p =
   let inductiveHypothesis = plusLeftCancel left right right' in
-    ?plusLeftCancelStepCase
+    inductiveHypothesis (succInjective _ _ p) 
 
 total plusRightCancel : (left : Nat) -> (left' : Nat) -> (right : Nat) ->
   (p : left + right = left' + right) -> left = left'
-plusRightCancel left left' Z         p = ?plusRightCancelBaseCase
+plusRightCancel left left' Z         p = rewrite sym (plusZeroRightNeutral left) in
+                                         rewrite sym (plusZeroRightNeutral left') in
+                                                 p 
 plusRightCancel left left' (S right) p =
-  let inductiveHypothesis = plusRightCancel left left' right in
-    ?plusRightCancelStepCase
+  plusRightCancel left left' right 
+    (succInjective _ _ (rewrite plusSuccRightSucc left right in 
+                        rewrite plusSuccRightSucc left' right in p))
 
 total plusLeftLeftRightZero : (left : Nat) -> (right : Nat) ->
   (p : left + right = left) -> right = Z
-plusLeftLeftRightZero Z        right p = ?plusLeftLeftRightZeroBaseCase
+plusLeftLeftRightZero Z        right p = p 
 plusLeftLeftRightZero (S left) right p =
-  let inductiveHypothesis = plusLeftLeftRightZero left right in
-    ?plusLeftLeftRightZeroStepCase
+  plusLeftLeftRightZero left right (succInjective _ _ p)
 
 -- Mult
 total multZeroLeftZero : (right : Nat) -> Z * right = Z
@@ -464,16 +471,18 @@
 
 total multZeroRightZero : (left : Nat) -> left * Z = Z
 multZeroRightZero Z        = Refl
-multZeroRightZero (S left) =
-  let inductiveHypothesis = multZeroRightZero left in
-    ?multZeroRightZeroStepCase
+multZeroRightZero (S left) = multZeroRightZero left
 
 total multRightSuccPlus : (left : Nat) -> (right : Nat) ->
   left * (S right) = left + (left * right)
 multRightSuccPlus Z        right = Refl
 multRightSuccPlus (S left) right =
   let inductiveHypothesis = multRightSuccPlus left right in
-    ?multRightSuccPlusStepCase
+    rewrite inductiveHypothesis in 
+    rewrite plusAssociative left right (mult left right) in
+    rewrite plusAssociative right left (mult left right) in
+    rewrite plusCommutative right left in
+            Refl
 
 total multLeftSuccPlus : (left : Nat) -> (right : Nat) ->
   (S left) * right = right + (left * right)
@@ -481,43 +490,57 @@
 
 total multCommutative : (left : Nat) -> (right : Nat) ->
   left * right = right * left
-multCommutative Z right        = ?multCommutativeBaseCase
+multCommutative Z right        = rewrite multZeroRightZero right in Refl 
 multCommutative (S left) right =
   let inductiveHypothesis = multCommutative left right in
-    ?multCommutativeStepCase
+      rewrite inductiveHypothesis in
+      rewrite multRightSuccPlus right left in 
+              Refl
 
 total multDistributesOverPlusRight : (left : Nat) -> (centre : Nat) -> (right : Nat) ->
   left * (centre + right) = (left * centre) + (left * right)
 multDistributesOverPlusRight Z        centre right = Refl
 multDistributesOverPlusRight (S left) centre right =
   let inductiveHypothesis = multDistributesOverPlusRight left centre right in
-    ?multDistributesOverPlusRightStepCase
+    rewrite inductiveHypothesis in 
+    rewrite plusAssociative (plus centre (mult left centre)) right (mult left right) in
+    rewrite sym (plusAssociative centre (mult left centre) right) in
+    rewrite plusCommutative (mult left centre) right in
+    rewrite plusAssociative centre right (mult left centre) in
+    rewrite plusAssociative (plus centre right) (mult left centre) (mult left right) in
+            Refl
 
 total multDistributesOverPlusLeft : (left : Nat) -> (centre : Nat) -> (right : Nat) ->
   (left + centre) * right = (left * right) + (centre * right)
 multDistributesOverPlusLeft Z        centre right = Refl
 multDistributesOverPlusLeft (S left) centre right =
   let inductiveHypothesis = multDistributesOverPlusLeft left centre right in
-    ?multDistributesOverPlusLeftStepCase
+    rewrite inductiveHypothesis in
+    rewrite plusAssociative right (mult left right) (mult centre right) in
+            Refl
 
 total multAssociative : (left : Nat) -> (centre : Nat) -> (right : Nat) ->
   left * (centre * right) = (left * centre) * right
 multAssociative Z        centre right = Refl
 multAssociative (S left) centre right =
   let inductiveHypothesis = multAssociative left centre right in
-    ?multAssociativeStepCase
+    rewrite inductiveHypothesis in 
+    rewrite multDistributesOverPlusLeft centre (mult left centre) right in
+            Refl
 
 total multOneLeftNeutral : (right : Nat) -> 1 * right = right
 multOneLeftNeutral Z         = Refl
 multOneLeftNeutral (S right) =
   let inductiveHypothesis = multOneLeftNeutral right in
-    ?multOneLeftNeutralStepCase
+    rewrite inductiveHypothesis in
+            Refl
 
 total multOneRightNeutral : (left : Nat) -> left * 1 = left
 multOneRightNeutral Z        = Refl
 multOneRightNeutral (S left) =
   let inductiveHypothesis = multOneRightNeutral left in
-    ?multOneRightNeutralStepCase
+    rewrite inductiveHypothesis in
+            Refl
 
 -- Minus
 total minusSuccSucc : (left : Nat) -> (right : Nat) ->
@@ -554,29 +577,37 @@
 minusMinusMinusPlus Z        (S centre) right = Refl
 minusMinusMinusPlus (S left) (S centre) right =
   let inductiveHypothesis = minusMinusMinusPlus left centre right in
-    ?minusMinusMinusPlusStepCase
+    rewrite inductiveHypothesis in
+            Refl
 
 total plusMinusLeftCancel : (left : Nat) -> (right : Nat) -> (right' : Nat) ->
   (left + right) - (left + right') = right - right'
 plusMinusLeftCancel Z right right'        = Refl
 plusMinusLeftCancel (S left) right right' =
   let inductiveHypothesis = plusMinusLeftCancel left right right' in
-    ?plusMinusLeftCancelStepCase
+    rewrite inductiveHypothesis in
+            Refl
 
 total multDistributesOverMinusLeft : (left : Nat) -> (centre : Nat) -> (right : Nat) ->
   (left - centre) * right = (left * right) - (centre * right)
 multDistributesOverMinusLeft Z        Z          right = Refl
 multDistributesOverMinusLeft (S left) Z          right =
-  ?multDistributesOverMinusLeftBaseCase
+    rewrite (minusZeroRight (plus right (mult left right))) in Refl
 multDistributesOverMinusLeft Z        (S centre) right = Refl
 multDistributesOverMinusLeft (S left) (S centre) right =
   let inductiveHypothesis = multDistributesOverMinusLeft left centre right in
-    ?multDistributesOverMinusLeftStepCase
+    rewrite inductiveHypothesis in
+    rewrite plusMinusLeftCancel right (mult left right) (mult centre right) in
+            Refl
 
 total multDistributesOverMinusRight : (left : Nat) -> (centre : Nat) -> (right : Nat) ->
   left * (centre - right) = (left * centre) - (left * right)
 multDistributesOverMinusRight left centre right =
-  ?multDistributesOverMinusRightBody
+    rewrite multCommutative left (minus centre right) in
+    rewrite multDistributesOverMinusLeft centre right left in
+    rewrite multCommutative centre left in
+    rewrite multCommutative right left in
+            Refl
 
 -- Power
 total powerSuccPowerLeft : (base : Nat) -> (exp : Nat) -> power base (S exp) =
@@ -585,10 +616,13 @@
 
 total multPowerPowerPlus : (base : Nat) -> (exp : Nat) -> (exp' : Nat) ->
   (power base exp) * (power base exp') = power base (exp + exp')
-multPowerPowerPlus base Z       exp' = ?multPowerPowerPlusBaseCase
+multPowerPowerPlus base Z       exp' = 
+    rewrite sym (plusZeroRightNeutral (power base exp')) in Refl
 multPowerPowerPlus base (S exp) exp' =
   let inductiveHypothesis = multPowerPowerPlus base exp exp' in
-    ?multPowerPowerPlusStepCase
+    rewrite sym inductiveHypothesis in
+    rewrite sym (multAssociative base (power base exp) (power base exp')) in
+            Refl
 
 total powerZeroOne : (base : Nat) -> power base 0 = S Z
 powerZeroOne base = Refl
@@ -597,26 +631,27 @@
 powerOneNeutral Z        = Refl
 powerOneNeutral (S base) =
   let inductiveHypothesis = powerOneNeutral base in
-    ?powerOneNeutralStepCase
+    rewrite inductiveHypothesis in Refl
 
 total powerOneSuccOne : (exp : Nat) -> power 1 exp = S Z
 powerOneSuccOne Z       = Refl
 powerOneSuccOne (S exp) =
   let inductiveHypothesis = powerOneSuccOne exp in
-    ?powerOneSuccOneStepCase
+    rewrite inductiveHypothesis in Refl
 
 total powerSuccSuccMult : (base : Nat) -> power base 2 = mult base base
 powerSuccSuccMult Z        = Refl
-powerSuccSuccMult (S base) =
-  let inductiveHypothesis = powerSuccSuccMult base in
-    ?powerSuccSuccMultStepCase
+powerSuccSuccMult (S base) = rewrite multOneRightNeutral base in Refl
 
 total powerPowerMultPower : (base : Nat) -> (exp : Nat) -> (exp' : Nat) ->
   power (power base exp) exp' = power base (exp * exp')
-powerPowerMultPower base exp Z        = ?powerPowerMultPowerBaseCase
+powerPowerMultPower base exp Z        = rewrite multZeroRightZero exp in Refl
 powerPowerMultPower base exp (S exp') =
   let inductiveHypothesis = powerPowerMultPower base exp exp' in
-    ?powerPowerMultPowerStepCase
+    rewrite inductiveHypothesis in 
+    rewrite multRightSuccPlus exp exp' in
+    rewrite sym (multPowerPowerPlus base exp (mult exp exp')) in
+            Refl
 
 -- Pred
 total predSucc : (n : Nat) -> pred (S n) = n
@@ -626,11 +661,10 @@
   left - (S right) = pred (left - right)
 minusSuccPred Z        right = Refl
 minusSuccPred (S left) Z =
-  let inductiveHypothesis = minusSuccPred left Z in
-    ?minusSuccPredStepCase
+    rewrite minusZeroRight left in Refl 
 minusSuccPred (S left) (S right) =
   let inductiveHypothesis = minusSuccPred left right in
-    ?minusSuccPredStepCase'
+    rewrite inductiveHypothesis in Refl
 
 -- ifThenElse
 total ifThenElseSuccSucc : (cond : Bool) -> (t : Nat) -> (f : Nat) ->
@@ -713,9 +747,7 @@
 minimumSuccSucc Z        Z         = Refl
 minimumSuccSucc (S left) Z         = Refl
 minimumSuccSucc Z        (S right) = Refl
-minimumSuccSucc (S left) (S right) =
-  let inductiveHypothesis = minimumSuccSucc left right in
-    ?minimumSuccSuccStepCase
+minimumSuccSucc (S left) (S right) = Refl
 
 total maximumZeroNRight : (right : Nat) -> maximum Z right = right
 maximumZeroNRight Z         = Refl
@@ -730,9 +762,7 @@
 maximumSuccSucc Z        Z         = Refl
 maximumSuccSucc (S left) Z         = Refl
 maximumSuccSucc Z        (S right) = Refl
-maximumSuccSucc (S left) (S right) =
-  let inductiveHypothesis = maximumSuccSucc left right in
-    ?maximumSuccSuccStepCase
+maximumSuccSucc (S left) (S right) = Refl
 
 total sucMaxL : (l : Nat) -> maximum (S l) l = (S l)
 sucMaxL Z = Refl
@@ -750,252 +780,3 @@
 sucMinR Z = Refl
 sucMinR (S l) = cong (sucMinR l)
 
---------------------------------------------------------------------------------
--- Proofs
---------------------------------------------------------------------------------
-
-powerPowerMultPowerStepCase = proof {
-    intros;
-    rewrite sym inductiveHypothesis;
-    rewrite sym (multRightSuccPlus exp exp');
-    rewrite (multPowerPowerPlus base exp (mult exp exp'));
-    trivial;
-}
-
-powerPowerMultPowerBaseCase = proof {
-    intros;
-    rewrite sym (multZeroRightZero exp);
-    trivial;
-}
-
-powerSuccSuccMultStepCase = proof {
-    intros;
-    rewrite (multOneRightNeutral base);
-    rewrite sym (multOneRightNeutral base);
-    trivial;
-}
-
-powerOneSuccOneStepCase = proof {
-    intros;
-    rewrite inductiveHypothesis;
-    rewrite sym (plusZeroRightNeutral (power (S Z) exp));
-    trivial;
-}
-
-powerOneNeutralStepCase = proof {
-    intros;
-    rewrite inductiveHypothesis;
-    trivial;
-}
-
-multAssociativeStepCase = proof {
-    intros;
-    rewrite sym (multDistributesOverPlusLeft centre (mult left centre) right);
-    rewrite inductiveHypothesis;
-    trivial;
-}
-
-minusSuccPredStepCase' = proof {
-    intros;
-    rewrite sym inductiveHypothesis;
-    trivial;
-}
-
-minusSuccPredStepCase = proof {
-    intros;
-    rewrite (minusZeroRight left);
-    trivial;
-}
-
-multPowerPowerPlusStepCase = proof {
-    intros;
-    rewrite inductiveHypothesis;
-    rewrite (multAssociative base (power base exp) (power base exp'));
-    trivial;
-}
-
-multPowerPowerPlusBaseCase = proof {
-    intros;
-    rewrite (plusZeroRightNeutral (power base exp'));
-    trivial;
-}
-
-multOneRightNeutralStepCase = proof {
-    intros;
-    rewrite inductiveHypothesis;
-    trivial;
-}
-
-multOneLeftNeutralStepCase = proof {
-    intros;
-    rewrite (plusZeroRightNeutral right);
-    trivial;
-}
-
-multDistributesOverPlusLeftStepCase = proof {
-    intros;
-    rewrite sym inductiveHypothesis;
-    rewrite sym (plusAssociative right (mult left right) (mult centre right));
-    trivial;
-}
-
-multDistributesOverPlusRightStepCase = proof {
-    intros;
-    rewrite sym inductiveHypothesis;
-    rewrite sym (plusAssociative (plus centre (mult left centre)) right (mult left right));
-    rewrite (plusAssociative centre (mult left centre) right);
-    rewrite sym (plusCommutative (mult left centre) right);
-    rewrite sym (plusAssociative centre right (mult left centre));
-    rewrite sym (plusAssociative (plus centre right) (mult left centre) (mult left right));
-    trivial;
-}
-
-multCommutativeStepCase = proof {
-    intros;
-    rewrite sym (multRightSuccPlus right left);
-    rewrite inductiveHypothesis;
-    trivial;
-}
-
-multCommutativeBaseCase = proof {
-    intros;
-    rewrite (multZeroRightZero right);
-    trivial;
-}
-
-multRightSuccPlusStepCase = proof {
-    intros;
-    rewrite inductiveHypothesis;
-    rewrite sym inductiveHypothesis;
-    rewrite sym (plusAssociative right left (mult left right));
-    rewrite sym (plusCommutative right left);
-    rewrite (plusAssociative left right (mult left right));
-    trivial;
-}
-
-multZeroRightZeroStepCase = proof {
-    intros;
-    rewrite inductiveHypothesis;
-    trivial;
-}
-
-plusAssociativeStepCase = proof {
-    intros;
-    rewrite inductiveHypothesis;
-    trivial;
-}
-
-plusCommutativeStepCase = proof {
-    intros;
-    rewrite (plusSuccRightSucc right left);
-    rewrite inductiveHypothesis;
-    trivial;
-}
-
-plusSuccRightSuccStepCase = proof {
-    intros;
-    rewrite inductiveHypothesis;
-    trivial;
-}
-
-plusCommutativeBaseCase = proof {
-    intros;
-    rewrite sym (plusZeroRightNeutral right);
-    trivial;
-}
-
-plusZeroRightNeutralStepCase = proof {
-    intros;
-    rewrite inductiveHypothesis;
-    trivial;
-}
-
-maximumSuccSuccStepCase = proof {
-    intros;
-    rewrite sym (ifThenElseSuccSucc (lte left right) (S right) (S left));
-    trivial;
-}
-
-minimumSuccSuccStepCase = proof {
-    intros;
-    rewrite (ifThenElseSuccSucc (lte left right) (S left) (S right));
-    trivial;
-}
-
-multDistributesOverMinusRightBody = proof {
-    intros;
-    rewrite sym (multCommutative left (minus centre right));
-    rewrite sym (multDistributesOverMinusLeft centre right left);
-    rewrite sym (multCommutative centre left);
-    rewrite sym (multCommutative right left);
-    trivial;
-}
-
-multDistributesOverMinusLeftStepCase = proof {
-    intros;
-    rewrite sym (plusMinusLeftCancel right (mult left right) (mult centre right));
-    trivial;
-}
-
-multDistributesOverMinusLeftBaseCase = proof {
-    intros;
-    rewrite (minusZeroRight (plus right (mult left right)));
-    trivial;
-}
-
-plusMinusLeftCancelStepCase = proof {
-    intros;
-    rewrite inductiveHypothesis;
-    trivial;
-}
-
-minusMinusMinusPlusStepCase = proof {
-    intros;
-    rewrite inductiveHypothesis;
-    trivial;
-}
-
-plusLeftLeftRightZeroBaseCase = proof {
-    intros;
-    rewrite p;
-    trivial;
-}
-
-plusLeftLeftRightZeroStepCase = proof {
-    intros;
-    refine inductiveHypothesis;
-    let p' = succInjective (plus left right) left p;
-    rewrite p';
-    trivial;
-}
-
-plusRightCancelStepCase = proof {
-    intros;
-    refine inductiveHypothesis;
-    refine succInjective _ _ ?;
-    rewrite sym (plusSuccRightSucc left right);
-    rewrite sym (plusSuccRightSucc left' right);
-    rewrite p;
-    trivial;
-}
-
-plusRightCancelBaseCase = proof {
-    intros;
-    rewrite (plusZeroRightNeutral left);
-    rewrite (plusZeroRightNeutral left');
-    rewrite p;
-    trivial;
-}
-
-plusLeftCancelStepCase = proof {
-    intros;
-    let injectiveProof = succInjective (plus left right) (plus left right') p;
-    rewrite (inductiveHypothesis injectiveProof);
-    trivial;
-}
-
-plusLeftCancelBaseCase = proof {
-    intros;
-    rewrite p;
-    trivial;
-}
diff --git a/libs/prelude/Prelude/Show.idr b/libs/prelude/Prelude/Show.idr
new file mode 100644
--- /dev/null
+++ b/libs/prelude/Prelude/Show.idr
@@ -0,0 +1,190 @@
+module Prelude.Show
+
+import Builtins
+
+import Prelude.Basics
+import Prelude.Bits
+import Prelude.Bool
+import Prelude.Cast
+import Prelude.Chars
+import Prelude.Classes
+import Prelude.List
+import Prelude.Maybe
+import Prelude.Nat
+import Prelude.Strings
+
+%default total
+
+||| The precedence of an Idris operator or syntactic context.
+data Prec = Open | Eq | Dollar | Backtick | User Nat | PrefixMinus | App
+
+||| Gives the constructor index of the Prec as a helper for writing instances.
+precCon : Prec -> Integer
+precCon Open        = 0
+precCon Eq          = 1
+precCon Dollar      = 2
+precCon Backtick    = 3
+precCon (User n)    = 4
+precCon PrefixMinus = 5
+precCon App         = 6
+
+instance Eq Prec where
+  (==) (User m) (User n) = m == n
+  (==) x        y        = precCon x == precCon y
+
+instance Ord Prec where
+  compare (User m) (User n) = compare m n
+  compare x        y        = compare (precCon x) (precCon y)
+
+||| Things that have a canonical `String` representation.
+class Show a where
+  ||| Convert a value to its `String` representation.
+  |||
+  ||| @ a the value to convert
+  partial
+  show : (x : a) -> String
+  show = showPrec Open
+
+  ||| Convert a value to its `String` representation in a certain precedence
+  ||| context.
+  |||
+  ||| A value should produce parentheses around itself if and only if the given
+  ||| precedence context is greater than or equal to the precedence of the
+  ||| outermost operation represented in the produced `String`. *This is
+  ||| different from Haskell*, which requires it to be strictly greater. `Open`
+  ||| should thus always produce *no* outermost parens, `App` should always
+  ||| produce outermost parens except on atomic values and those that provide
+  ||| their own bracketing, like `Pair` and `List`.
+  |||
+  ||| @ d the precedence context.
+  ||| @ a the value to convert
+  partial
+  showPrec : (d : Prec) -> (x : a) -> String
+  showPrec _ = show
+
+||| Surround a `String` with parentheses depending on a condition.
+|||
+||| @ b whether to add parentheses
+showParens : (b : Bool) -> String -> String
+showParens False s = s
+showParens True  s = "(" ++ s ++ ")"
+
+||| A helper for the common case of showing a non-infix constructor with at
+||| least one argument, for use with `showArg`.
+|||
+||| Apply `showCon` to the precedence context, the constructor name, and the
+||| args shown with `showArg` and concatenated. Example:
+||| ```
+||| data Ann a = MkAnn String a
+|||
+||| instance Show a => Show (Ann a) where
+|||   showPrec d (MkAnn s x) = showCon d "MkAnn" $ showArg s ++ showArg x
+||| ```
+showCon : (d : Prec) -> (conName : String) -> (shownArgs : String) -> String
+showCon d conName shownArgs = showParens (d >= App) $ conName ++ shownArgs
+
+||| A helper for the common case of showing a non-infix constructor with at
+||| least one argument, for use with `showCon`.
+|||
+||| This adds a space to the front so the results can be directly
+||| concatenated. See `showCon` for details and an example.
+showArg : Show a => (x : a) -> String
+showArg x = " " ++ showPrec App x
+
+firstCharIs : (Char -> Bool) -> String -> Bool
+firstCharIs p s with (strM s)
+  firstCharIs p ""             | StrNil = False
+  firstCharIs p (strCons c cs) | StrCons c cs = p c
+
+primNumShow : (a -> String) -> Prec -> a -> String
+primNumShow f d x = let str = f x in showParens (d >= PrefixMinus && firstCharIs (== '-') str) str
+
+instance Show Int where
+  showPrec = primNumShow prim__toStrInt
+
+instance Show Integer where
+  showPrec = primNumShow prim__toStrBigInt
+
+instance Show Double where
+  showPrec = primNumShow prim__floatToStr
+
+protectEsc : (Char -> Bool) -> String -> String -> String
+protectEsc p f s = f ++ (if firstCharIs p s then "\\&" else "") ++ s
+
+showLitChar : Char -> String -> String
+showLitChar '\a'   = ("\\a" ++)
+showLitChar '\b'   = ("\\b" ++)
+showLitChar '\f'   = ("\\f" ++)
+showLitChar '\n'   = ("\\n" ++)
+showLitChar '\r'   = ("\\r" ++)
+showLitChar '\t'   = ("\\t" ++)
+showLitChar '\v'   = ("\\v" ++)
+showLitChar '\SO'  = protectEsc (== 'H') "\\SO"
+showLitChar '\DEL' = ("\\DEL" ++)
+showLitChar '\\'   = ("\\\\" ++)
+showLitChar c      = case getAt (cast (cast {to=Int} c)) asciiTab of
+                          Just k => strCons '\\' . (k ++)
+                          Nothing => if (c > '\DEL')
+                                        then strCons '\\' . protectEsc isDigit (show (cast {to=Int} c))
+                                        else strCons c
+  where asciiTab : List String
+        asciiTab = ["NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
+                    "BS",  "HT",  "LF",  "VT",  "FF",  "CR",  "SO",  "SI",
+                    "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
+                    "CAN", "EM",  "SUB", "ESC", "FS",  "GS",  "RS",  "US"]
+
+        getAt : Nat -> List String -> Maybe String
+        getAt Z     (x :: xs) = Just x
+        getAt (S k) (x :: xs) = getAt k xs
+        getAt _     []        = Nothing
+
+showLitString : List Char -> String -> String
+showLitString []        = id
+showLitString ('"'::cs) = ("\\\"" ++) . showLitString cs
+showLitString (c  ::cs) = showLitChar c . showLitString cs
+
+instance Show Char where
+  show '\'' = "'\\''"
+  show c    = strCons '\'' (showLitChar c "'")
+
+instance Show String where
+  show cs = strCons '"' (showLitString (cast cs) "\"")
+
+instance Show Nat where
+    show n = show (the Integer (cast n))
+
+instance Show Bool where
+    show True = "True"
+    show False = "False"
+
+instance Show () where
+  show () = "()"
+
+instance Show Bits8 where
+  show b = b8ToString b
+
+instance Show Bits16 where
+  show b = b16ToString b
+
+instance Show Bits32 where
+  show b = b32ToString b
+
+instance Show Bits64 where
+  show b = b64ToString b
+
+instance (Show a, Show b) => Show (a, b) where
+    show (x, y) = "(" ++ show x ++ ", " ++ show y ++ ")"
+
+instance Show a => Show (List a) where
+    show xs = "[" ++ show' "" xs ++ "]" where
+        show' acc []        = acc
+        show' acc [x]       = acc ++ show x
+        show' acc (x :: xs) = show' (acc ++ show x ++ ", ") xs
+
+instance Show a => Show (Maybe a) where
+  showPrec d Nothing  = "Nothing"
+  showPrec d (Just x) = showCon d "Just" $ showArg x
+
+instance (Show a, {y : a} -> Show (p y)) => Show (Sigma a p) where
+    show (y ** prf) = "(" ++ show y ++ " ** " ++ show prf ++ ")"
+
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
@@ -1,6 +1,7 @@
 module Prelude.Strings
 
 import Builtins
+import IO
 
 import Prelude.Algebra
 import Prelude.Basics
@@ -13,8 +14,18 @@
 import Prelude.Functor
 import Prelude.List
 import Prelude.Nat
+import Prelude.Monad
 import Decidable.Equality
 
+partial
+foldr1 : (a -> a -> a) -> List a -> a
+foldr1 _ [x] = x
+foldr1 f (x::xs) = f x (foldr1 f xs)
+
+partial
+foldl1 : (a -> a -> a) -> List a -> a
+foldl1 f (x::xs) = foldl f x xs
+
 ||| Appends two strings together.
 |||
 ||| ```idris example
@@ -247,15 +258,6 @@
 lines : String -> List String
 lines s = map pack $ lines' $ unpack s
 
-partial
-foldr1 : (a -> a -> a) -> List a -> a
-foldr1 _ [x] = x
-foldr1 f (x::xs) = f x (foldr1 f xs)
-
-partial
-foldl1 : (a -> a -> a) -> List a -> a
-foldl1 f (x::xs) = foldl f x xs
-
 ||| Joins the character lists by spaces into a single character list.
 |||
 ||| ```idris example
@@ -263,12 +265,11 @@
 ||| ```
 unwords' : List (List Char) -> List Char
 unwords' [] = []
-unwords' ws = assert_total (foldr1 addSpace ws)
-        where
-            addSpace : List Char -> List Char -> List Char
-            addSpace w s = w ++ (' ' :: s)
+unwords' ws = assert_total (foldr1 addSpace ws) where
+  addSpace : List Char -> List Char -> List Char
+  addSpace w s = w ++ (' ' :: s)
 
-||| Joins the strings by spaces into a single string. 
+||| Joins the strings by spaces into a single string.
 |||
 ||| ```idris example
 ||| unwords ["A", "BC", "D", "E"]
@@ -276,6 +277,25 @@
 unwords : List String -> String
 unwords = pack . unwords' . map unpack
 
+||| Joins the character lists by newlines into a single character list.
+|||
+||| ```idris example
+||| unlines' [['l','i','n','e'], ['l','i','n','e','2'], ['l','n','3'], ['D']]
+||| ```
+unlines' : List (List Char) -> List Char
+unlines' [] = []
+unlines' ls = assert_total (foldr1 addLine ls) where
+  addLine : List Char -> List Char -> List Char
+  addLine l s = l ++ ('\n' :: s)
+
+||| Joins the strings by newlines into a single string.
+|||
+||| ```idris example
+||| unlines ["line", "line2", "ln3", "D"]
+||| ```
+unlines : List String -> String
+unlines = pack . unlines' . map unpack
+
 ||| Returns the length of the string.
 |||
 ||| ```idris example
@@ -287,6 +307,14 @@
 length : String -> Nat
 length = fromInteger . prim__zextInt_BigInt . prim_lenString
 
+||| Returns a substring of a given string
+||| @index The (zero based) index of the string to extract. If this is
+||| beyond the end of the String, the function returns the empty string.
+||| @len The desired length of the substring. Truncated if this exceeds
+||| the length of the input.
+substr : (index : Nat) -> (len : Nat) -> String -> String
+substr i len = pack . List.take len . drop i . unpack
+
 ||| Lowercases all characters in the string.
 |||
 ||| ```idris example
@@ -321,3 +349,16 @@
 
 isInfixOf : String -> String -> Bool
 isInfixOf a b = isInfixOf (unpack a) (unpack b)
+
+||| Check if a foreign pointer is null
+partial
+nullPtr : Ptr -> IO Bool
+nullPtr p = do ok <- foreign FFI_C "isNull" (Ptr -> IO Int) p
+               return (ok /= 0)
+
+||| Check if a supposed string was actually a null pointer
+partial
+nullStr : String -> IO Bool
+nullStr p = do ok <- foreign FFI_C "isNull" (String -> IO Int) p
+               return (ok /= 0)
+
diff --git a/libs/prelude/prelude.ipkg b/libs/prelude/prelude.ipkg
--- a/libs/prelude/prelude.ipkg
+++ b/libs/prelude/prelude.ipkg
@@ -6,9 +6,10 @@
           Prelude.Algebra, Prelude.Basics, Prelude.Bool, Prelude.Cast,
           Prelude.Classes, Prelude.Nat, Prelude.List,
           Prelude.Maybe, Prelude.Monad, Prelude.Applicative, Prelude.Either,
-          Prelude.Strings, Prelude.Chars, Prelude.Functor,
+          Prelude.Strings, Prelude.Chars, Prelude.Show, Prelude.Functor,
           Prelude.Foldable, Prelude.Traversable, Prelude.Bits, Prelude.Stream,
           Prelude.Uninhabited, Prelude.Pairs, Prelude.Providers,
+          Prelude.Interactive, Prelude.File,
 
           Language.Reflection, Language.Reflection.Errors, Language.Reflection.Elab,
 
diff --git a/rts/idris_rts.c b/rts/idris_rts.c
--- a/rts/idris_rts.c
+++ b/rts/idris_rts.c
@@ -26,6 +26,7 @@
 
     VAL* valstack = malloc(stack_size * sizeof(VAL));
 
+    vm->active = 1;
     vm->valstack = valstack;
     vm->valstack_top = valstack;
     vm->valstack_base = valstack;
@@ -104,7 +105,12 @@
     pthread_mutex_destroy(&(vm -> inbox_block));
     pthread_cond_destroy(&(vm -> inbox_waiting));
 #endif
-    free(vm);
+    // free(vm); 
+    // Set the VM as inactive, so that if any message gets sent to it
+    // it will not get there, rather than crash the entire system.
+    // (TODO: We really need to be cleverer than this if we're going to
+    // write programs than create lots of threads...)
+    vm->active = 0;
 
     STATS_LEAVE_EXIT(stats)
     return stats;
@@ -464,7 +470,7 @@
     Closure* cl = allocate(sizeof(Closure) + sizeof(char)*32, 0);
     SETTY(cl, STRING);
     cl -> info.str = (char*)cl + sizeof(Closure);
-    sprintf(cl -> info.str, "%g", GETFLOAT(i));
+    snprintf(cl -> info.str, 32, "%.16g", GETFLOAT(i));
     return cl;
 }
 
@@ -738,7 +744,7 @@
 }
 
 // Add a message to another VM's message queue
-void idris_sendMessage(VM* sender, VM* dest, VAL msg) {
+int idris_sendMessage(VM* sender, VM* dest, VAL msg) {
     // FIXME: If GC kicks in in the middle of the copy, we're in trouble.
     // Probably best check there is enough room in advance. (How?)
 
@@ -749,6 +755,8 @@
     // So: we try to copy, if a collection happens, we do the copy again
     // under the assumption there's enough space this time.
 
+    if (dest->active == 0) { return 0; } // No VM to send to
+
     int gcs = dest->stats.collections;
     pthread_mutex_lock(&dest->alloc_lock);
     VAL dmsg = copyTo(dest, msg);
@@ -784,6 +792,7 @@
 
     pthread_mutex_unlock(&(dest->inbox_lock));
 //    printf("Sending [unlock]...\n");
+    return 1;
 }
 
 VM* idris_checkMessages(VM* vm) {
@@ -800,6 +809,29 @@
     }
     return 0;
 }
+
+VM* idris_checkMessagesTimeout(VM* vm, int delay) {
+    VM* sender = idris_checkMessagesFrom(vm, NULL);
+    if (sender != NULL) {
+        return sender;
+    }
+
+    struct timespec timeout;
+    int status;
+
+    // Wait either for a timeout or until we get a signal that a message
+    // has arrived.
+    pthread_mutex_lock(&vm->inbox_block);
+    timeout.tv_sec = time (NULL) + delay;
+    timeout.tv_nsec = 0;
+    status = pthread_cond_timedwait(&vm->inbox_waiting, &vm->inbox_block,
+                               &timeout);
+    (void)(status); //don't emit 'unused' warning
+    pthread_mutex_unlock(&vm->inbox_block);
+
+    return idris_checkMessagesFrom(vm, NULL);
+}
+
 
 Msg* idris_getMessageFrom(VM* vm, VM* sender) {
     Msg* msg;
diff --git a/rts/idris_rts.h b/rts/idris_rts.h
--- a/rts/idris_rts.h
+++ b/rts/idris_rts.h
@@ -78,6 +78,10 @@
 typedef struct Msg_t Msg;
 
 struct VM_t {
+    int active; // 0 if no longer running; keep for message passing
+                // TODO: If we're going to have lots of concurrent threads,
+                // we really need to be cleverer than this!
+
     VAL* valstack;
     VAL* valstack_top;
     VAL* valstack_base;
@@ -253,12 +257,14 @@
 VAL copyTo(VM* newVM, VAL x);
 
 // Add a message to another VM's message queue
-void idris_sendMessage(VM* sender, VM* dest, VAL msg);
+int idris_sendMessage(VM* sender, VM* dest, VAL msg);
 // Check whether there are any messages in the queue and return PID of
 // sender if so (null if not)
 VM* idris_checkMessages(VM* vm);
 // Check whether there are any messages in the queue
 VM* idris_checkMessagesFrom(VM* vm, VM* sender);
+// Check whether there are any messages in the queue, and wait if not
+VM* idris_checkMessagesTimeout(VM* vm, int timeout);
 // block until there is a message in the queue
 Msg* idris_recvMessage(VM* vm);
 // block until there is a message in the queue
diff --git a/rts/idris_stdfgn.c b/rts/idris_stdfgn.c
--- a/rts/idris_stdfgn.c
+++ b/rts/idris_stdfgn.c
@@ -1,5 +1,6 @@
 #include "idris_stdfgn.h"
 #include "idris_rts.h"
+#include "idris_gmp.h"
 #include "idris_gc.h"
 #include <sys/select.h>
 #include <fcntl.h>
@@ -80,9 +81,9 @@
     return *(environ + i);
 }
 
-int idris_time() {
+VAL idris_time() {
     time_t t = time(NULL);
-    return (int)t;
+    return MKBIGI(t);
 }
 
 void idris_forceGC(void* vm) {
diff --git a/rts/idris_stdfgn.h b/rts/idris_stdfgn.h
--- a/rts/idris_stdfgn.h
+++ b/rts/idris_stdfgn.h
@@ -1,6 +1,8 @@
 #ifndef _IDRISSTDFGN_H
 #define _IDRISSTDFGN_H
 
+#include "idris_rts.h"
+
 // A collection of useful standard functions to be used by the prelude.
 
 void putStr(char* str);
@@ -22,7 +24,7 @@
 
 char* getEnvPair(int i);
 
-int idris_time();
+VAL idris_time();
 
 void idris_forceGC();
 
diff --git a/rts/windows/idris_stdfgn.c b/rts/windows/idris_stdfgn.c
--- a/rts/windows/idris_stdfgn.c
+++ b/rts/windows/idris_stdfgn.c
@@ -72,9 +72,9 @@
     return *(environ + i);
 }
 
-int idris_time() {
+VAL idris_time() {
     time_t t = time(NULL);
-    return (int)t;
+    return MKBIGI(t);
 }
 
 void idris_forceGC(void* vm) {
diff --git a/src/IRTS/CodegenC.hs b/src/IRTS/CodegenC.hs
--- a/src/IRTS/CodegenC.hs
+++ b/src/IRTS/CodegenC.hs
@@ -64,7 +64,7 @@
                      (if (exec == Executable) then mprog else hi)
          case exec of
            MavenProject -> putStrLn ("FAILURE: output type not supported")
-           Raw -> writeFile out cout
+           Raw -> writeSource out cout
            _ -> do
              (tmpn, tmph) <- tempfile
              hPutStr tmph cout
@@ -570,6 +570,10 @@
 doOp v (LExternal se) [] | se == sUN "prim__stderr" = v ++ "MKPTR(vm, stderr)"
 
 doOp v (LExternal nul) [] | nul == sUN "prim__null" = v ++ "MKPTR(vm, NULL)"
+doOp v (LExternal eqp) [x, y] | eqp == sUN "prim__eqPtr" 
+    = v ++ "MKINT((i_int)(GETPTR(" ++ creg x ++ ") == GETPTR(" ++ creg y ++ ")))"
+doOp v (LExternal eqp) [x, y] | eqp == sUN "prim__eqManagedPtr" 
+    = v ++ "MKINT((i_int)(GETMPTR(" ++ creg x ++ ") == GETMPTR(" ++ creg y ++ ")))"
 doOp v (LExternal rp) [p, i] | rp == sUN "prim__registerPtr"
     = v ++ "MKMPTR(vm, GETPTR(" ++ creg p ++ "), GETINT(" ++ creg i ++ "))"
 
diff --git a/src/IRTS/CodegenJavaScript.hs b/src/IRTS/CodegenJavaScript.hs
--- a/src/IRTS/CodegenJavaScript.hs
+++ b/src/IRTS/CodegenJavaScript.hs
@@ -132,12 +132,12 @@
                 ++ idrRuntime
                 ++ tgtRuntime
                 )
-  TIO.writeFile filename (  T.pack runtime
-                         `T.append` T.concat (map compileJS opt)
-                         `T.append` T.concat (map compileJS cons)
-                         `T.append` main
-                         `T.append` invokeMain
-                         )
+  writeSourceText filename (  T.pack runtime
+                           `T.append` T.concat (map compileJS opt)
+                           `T.append` T.concat (map compileJS cons)
+                           `T.append` main
+                           `T.append` invokeMain
+                           )
   setPermissions filename (emptyPermissions { readable   = True
                                             , executable = target == Node
                                             , writable   = True
@@ -250,12 +250,7 @@
               , JSApp (
                   JSIdent (translateName (sMN 0 "runMain"))
                 ) [JSNew "i$POINTER" [JSNum (JSInt 0)]]
-              , JSWhile (JSProj jsCALLSTACK "length") (
-                  JSSeq [ JSAlloc "func" (Just jsPOP)
-                        , JSAlloc "args" (Just jsPOP)
-                        , JSApp (JSProj (JSIdent "func") "apply") [JSThis, JSIdent "args"]
-                        ]
-                )
+              , JSApp (JSIdent "i$RUN") []
               ]
 
       invokeMain :: T.Text
@@ -601,7 +596,7 @@
 jsBASETOP _ n = JSAssign jsSTACKBASE (JSBinOp "+" jsSTACKTOP (JSNum (JSInt n)))
 
 jsNULL :: CompileInfo -> Reg -> JS
-jsNULL _ r = JSAssign (translateReg r) JSNull
+jsNULL _ r = JSDelete (translateReg r)
 
 jsERROR :: CompileInfo -> String -> JS
 jsERROR _ = JSError
@@ -680,9 +675,10 @@
       | LNoOp <- op = translateReg (last args)
 
       | LWriteStr <- op,
-        (_:str:_) <- args = JSAssign (translateReg reg)
-                               (JSApp (JSIdent "i$putStr") [translateReg str])
+        (_:str:_) <- args = JSApp (JSIdent "i$putStr") [translateReg str]
 
+      | LReadStr <- op  = JSApp (JSIdent "i$getLine") []
+
       | (LZExt (ITFixed IT8) ITNative)  <- op = jsUnPackBits $ translateReg (last args)
       | (LZExt (ITFixed IT16) ITNative) <- op = jsUnPackBits $ translateReg (last args)
       | (LZExt (ITFixed IT32) ITNative) <- op = jsUnPackBits $ translateReg (last args)
@@ -699,15 +695,15 @@
       | (LSRem (ATInt ITBig))  <- op
       , (lhs:rhs:_)            <- args = invokeMeth lhs "mod" [rhs]
       | (LEq (ATInt ITBig))    <- op
-      , (lhs:rhs:_)            <- args = invokeMeth lhs "equals" [rhs]
+      , (lhs:rhs:_)            <- args = JSPreOp "+" $ invokeMeth lhs "equals" [rhs]
       | (LSLt (ATInt ITBig))   <- op
-      , (lhs:rhs:_)            <- args = invokeMeth lhs "lesser" [rhs]
+      , (lhs:rhs:_)            <- args = JSPreOp "+" $ invokeMeth lhs "lesser" [rhs]
       | (LSLe (ATInt ITBig))   <- op
-      , (lhs:rhs:_)            <- args = invokeMeth lhs "lesserOrEquals" [rhs]
+      , (lhs:rhs:_)            <- args = JSPreOp "+" $ invokeMeth lhs "lesserOrEquals" [rhs]
       | (LSGt (ATInt ITBig))   <- op
-      , (lhs:rhs:_)            <- args = invokeMeth lhs "greater" [rhs]
+      , (lhs:rhs:_)            <- args = JSPreOp "+" $ invokeMeth lhs "greater" [rhs]
       | (LSGe (ATInt ITBig))   <- op
-      , (lhs:rhs:_)            <- args = invokeMeth lhs "greaterOrEquals" [rhs]
+      , (lhs:rhs:_)            <- args = JSPreOp "+" $ invokeMeth lhs "greaterOrEquals" [rhs]
 
       | (LPlus ATFloat)  <- op
       , (lhs:rhs:_)      <- args = translateBinaryOp "+" lhs rhs
@@ -718,15 +714,15 @@
       | (LSDiv ATFloat)  <- op
       , (lhs:rhs:_)      <- args = translateBinaryOp "/" lhs rhs
       | (LEq ATFloat)    <- op
-      , (lhs:rhs:_)      <- args = translateBinaryOp "==" lhs rhs
+      , (lhs:rhs:_)      <- args = translateCompareOp "==" lhs rhs
       | (LSLt ATFloat)   <- op
-      , (lhs:rhs:_)      <- args = translateBinaryOp "<" lhs rhs
+      , (lhs:rhs:_)      <- args = translateCompareOp "<" lhs rhs
       | (LSLe ATFloat)   <- op
-      , (lhs:rhs:_)      <- args = translateBinaryOp "<=" lhs rhs
+      , (lhs:rhs:_)      <- args = translateCompareOp "<=" lhs rhs
       | (LSGt ATFloat)   <- op
-      , (lhs:rhs:_)      <- args = translateBinaryOp ">" lhs rhs
+      , (lhs:rhs:_)      <- args = translateCompareOp ">" lhs rhs
       | (LSGe ATFloat)   <- op
-      , (lhs:rhs:_)      <- args = translateBinaryOp ">=" lhs rhs
+      , (lhs:rhs:_)      <- args = translateCompareOp ">=" lhs rhs
 
       | (LPlus (ATInt ITChar)) <- op
       , (lhs:rhs:_)            <- args =
@@ -765,44 +761,26 @@
           ]
 
       | (LLSHR (ITFixed IT8)) <- op
-      , (lhs:rhs:_)           <- args =
-          jsPackUBits8 (
-            JSBinOp ">>" (jsUnPackBits $ translateReg lhs) (jsUnPackBits $ translateReg rhs)
-          )
+      , (lhs:rhs:_)           <- args = jsPackUBits8 $ bitsBinaryOp ">>" lhs rhs
 
       | (LLSHR (ITFixed IT16)) <- op
-      , (lhs:rhs:_)            <- args =
-          jsPackUBits16 (
-            JSBinOp ">>" (jsUnPackBits $ translateReg lhs) (jsUnPackBits $ translateReg rhs)
-          )
+      , (lhs:rhs:_)            <- args = jsPackUBits16 $ bitsBinaryOp ">>" lhs rhs
 
       | (LLSHR (ITFixed IT32)) <- op
-      , (lhs:rhs:_)            <- args =
-          jsPackUBits32  (
-            JSBinOp ">>" (jsUnPackBits $ translateReg lhs) (jsUnPackBits $ translateReg rhs)
-          )
+      , (lhs:rhs:_)            <- args = jsPackUBits32 $ bitsBinaryOp ">>" lhs rhs
 
       | (LLSHR (ITFixed IT64)) <- op
       , (lhs:rhs:_)            <- args =
           jsMeth (translateReg lhs) "shiftRight" [translateReg rhs]
 
       | (LSHL (ITFixed IT8)) <- op
-      , (lhs:rhs:_)          <- args =
-          jsPackUBits8 (
-            JSBinOp "<<" (jsUnPackBits $ translateReg lhs) (jsUnPackBits $ translateReg rhs)
-          )
+      , (lhs:rhs:_)          <- args = jsPackUBits8 $ bitsBinaryOp "<<" lhs rhs
 
       | (LSHL (ITFixed IT16)) <- op
-      , (lhs:rhs:_)           <- args =
-          jsPackUBits16 (
-            JSBinOp "<<" (jsUnPackBits $ translateReg lhs) (jsUnPackBits $ translateReg rhs)
-          )
+      , (lhs:rhs:_)           <- args = jsPackUBits16 $ bitsBinaryOp "<<" lhs rhs
 
       | (LSHL (ITFixed IT32)) <- op
-      , (lhs:rhs:_)           <- args =
-          jsPackUBits32  (
-            JSBinOp "<<" (jsUnPackBits $ translateReg lhs) (jsUnPackBits $ translateReg rhs)
-          )
+      , (lhs:rhs:_)           <- args = jsPackUBits32 $ bitsBinaryOp "<<" lhs rhs
 
       | (LSHL (ITFixed IT64)) <- op
       , (lhs:rhs:_)           <- args =
@@ -811,88 +789,52 @@
           ]
 
       | (LAnd (ITFixed IT8)) <- op
-      , (lhs:rhs:_)          <- args =
-          jsPackUBits8 (
-            JSBinOp "&" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)          <- args = jsPackUBits8 $ bitsBinaryOp "&" lhs rhs
 
       | (LAnd (ITFixed IT16)) <- op
-      , (lhs:rhs:_)           <- args =
-          jsPackUBits16 (
-            JSBinOp "&" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)           <- args = jsPackUBits16 $ bitsBinaryOp "&" lhs rhs
 
       | (LAnd (ITFixed IT32)) <- op
-      , (lhs:rhs:_)           <- args =
-          jsPackUBits32 (
-            JSBinOp "&" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)           <- args = jsPackUBits32 $ bitsBinaryOp "&" lhs rhs
 
       | (LAnd (ITFixed IT64)) <- op
       , (lhs:rhs:_)           <- args =
           jsMeth (translateReg lhs) "and" [translateReg rhs]
 
       | (LOr (ITFixed IT8)) <- op
-      , (lhs:rhs:_)         <- args =
-          jsPackUBits8 (
-            JSBinOp "|" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)         <- args = jsPackUBits8 $ bitsBinaryOp "|" lhs rhs
 
       | (LOr (ITFixed IT16)) <- op
-      , (lhs:rhs:_)          <- args =
-          jsPackUBits16 (
-            JSBinOp "|" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)          <- args = jsPackUBits16 $ bitsBinaryOp "|" lhs rhs
 
       | (LOr (ITFixed IT32)) <- op
-      , (lhs:rhs:_)          <- args =
-          jsPackUBits32 (
-            JSBinOp "|" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)          <- args = jsPackUBits32 $ bitsBinaryOp "|" lhs rhs
 
       | (LOr (ITFixed IT64)) <- op
       , (lhs:rhs:_)          <- args =
           jsMeth (translateReg lhs) "or" [translateReg rhs]
 
       | (LXOr (ITFixed IT8)) <- op
-      , (lhs:rhs:_)          <- args =
-          jsPackUBits8 (
-            JSBinOp "^" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)          <- args = jsPackUBits8 $ bitsBinaryOp "^" lhs rhs
 
       | (LXOr (ITFixed IT16)) <- op
-      , (lhs:rhs:_)           <- args =
-          jsPackUBits16 (
-            JSBinOp "^" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)           <- args = jsPackUBits16 $ bitsBinaryOp "^" lhs rhs
 
       | (LXOr (ITFixed IT32)) <- op
-      , (lhs:rhs:_)           <- args =
-          jsPackUBits32 (
-            JSBinOp "^" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)           <- args = jsPackUBits32 $ bitsBinaryOp "^" lhs rhs
 
       | (LXOr (ITFixed IT64)) <- op
       , (lhs:rhs:_)           <- args =
           jsMeth (translateReg lhs) "xor" [translateReg rhs]
 
       | (LPlus (ATInt (ITFixed IT8))) <- op
-      , (lhs:rhs:_)                   <- args =
-          jsPackUBits8 (
-            JSBinOp "+" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)                   <- args = jsPackUBits8 $ bitsBinaryOp "+" lhs rhs
 
       | (LPlus (ATInt (ITFixed IT16))) <- op
-      , (lhs:rhs:_)                    <- args =
-          jsPackUBits16 (
-            JSBinOp "+" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)                    <- args = jsPackUBits16 $ bitsBinaryOp "+" lhs rhs
 
       | (LPlus (ATInt (ITFixed IT32))) <- op
-      , (lhs:rhs:_)                    <- args =
-          jsPackUBits32 (
-            JSBinOp "+" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)                    <- args = jsPackUBits32 $ bitsBinaryOp "+" lhs rhs
 
       | (LPlus (ATInt (ITFixed IT64))) <- op
       , (lhs:rhs:_)                    <- args =
@@ -901,22 +843,13 @@
           ]
 
       | (LMinus (ATInt (ITFixed IT8))) <- op
-      , (lhs:rhs:_)                    <- args =
-          jsPackUBits8 (
-            JSBinOp "-" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)                    <- args = jsPackUBits8 $ bitsBinaryOp "-" lhs rhs
 
       | (LMinus (ATInt (ITFixed IT16))) <- op
-      , (lhs:rhs:_)                     <- args =
-          jsPackUBits16 (
-            JSBinOp "-" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)                     <- args = jsPackUBits16 $ bitsBinaryOp "-" lhs rhs
 
       | (LMinus (ATInt (ITFixed IT32))) <- op
-      , (lhs:rhs:_)                     <- args =
-          jsPackUBits32 (
-            JSBinOp "-" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)                     <- args = jsPackUBits32 $ bitsBinaryOp "-" lhs rhs
 
       | (LMinus (ATInt (ITFixed IT64))) <- op
       , (lhs:rhs:_)                     <- args =
@@ -925,22 +858,13 @@
           ]
 
       | (LTimes (ATInt (ITFixed IT8))) <- op
-      , (lhs:rhs:_)                    <- args =
-          jsPackUBits8 (
-            JSBinOp "*" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)                    <- args = jsPackUBits8 $ bitsBinaryOp "*" lhs rhs
 
       | (LTimes (ATInt (ITFixed IT16))) <- op
-      , (lhs:rhs:_)                     <- args =
-          jsPackUBits16 (
-            JSBinOp "*" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)                     <- args = jsPackUBits16 $ bitsBinaryOp "*" lhs rhs
 
       | (LTimes (ATInt (ITFixed IT32))) <- op
-      , (lhs:rhs:_)                     <- args =
-          jsPackUBits32 (
-            JSBinOp "*" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)                     <- args = jsPackUBits32 $ bitsBinaryOp "*" lhs rhs
 
       | (LTimes (ATInt (ITFixed IT64))) <- op
       , (lhs:rhs:_)                     <- args =
@@ -949,110 +873,62 @@
           ]
 
       | (LEq (ATInt (ITFixed IT8))) <- op
-      , (lhs:rhs:_)                 <- args =
-          jsPackUBits8 (
-            JSBinOp "==" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)                 <- args = bitsCompareOp "==" lhs rhs
 
       | (LEq (ATInt (ITFixed IT16))) <- op
-      , (lhs:rhs:_)                  <- args =
-          jsPackUBits16 (
-            JSBinOp "==" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)                  <- args = bitsCompareOp "==" lhs rhs
 
       | (LEq (ATInt (ITFixed IT32))) <- op
-      , (lhs:rhs:_)                  <- args =
-          jsPackUBits32 (
-            JSBinOp "==" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)                  <- args = bitsCompareOp "==" lhs rhs
 
       | (LEq (ATInt (ITFixed IT64))) <- op
-      , (lhs:rhs:_)                   <- args =
-          jsMeth (jsMeth (translateReg lhs) "equals" [translateReg rhs]) "and" [
-            jsBigInt (JSString $ show 0xFFFFFFFFFFFFFFFF)
-          ]
+      , (lhs:rhs:_)                  <- args = JSPreOp "+" $ invokeMeth lhs "equals" [rhs]
 
       | (LLt (ITFixed IT8)) <- op
-      , (lhs:rhs:_)         <- args =
-          jsPackUBits8 (
-            JSBinOp "<" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)         <- args = bitsCompareOp "<" lhs rhs
 
       | (LLt (ITFixed IT16)) <- op
-      , (lhs:rhs:_)          <- args =
-          jsPackUBits16 (
-            JSBinOp "<" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)          <- args = bitsCompareOp "<" lhs rhs
 
       | (LLt (ITFixed IT32)) <- op
-      , (lhs:rhs:_)          <- args =
-          jsPackUBits32 (
-            JSBinOp "<" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)          <- args = bitsCompareOp "<" lhs rhs
 
       | (LLt (ITFixed IT64)) <- op
-      , (lhs:rhs:_)          <- args = invokeMeth lhs "lesser" [rhs]
+      , (lhs:rhs:_)          <- args = JSPreOp "+" $ invokeMeth lhs "lesser" [rhs]
 
       | (LLe (ITFixed IT8)) <- op
-      , (lhs:rhs:_)         <- args =
-          jsPackUBits8 (
-            JSBinOp "<=" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)         <- args = bitsCompareOp "<=" lhs rhs
 
       | (LLe (ITFixed IT16)) <- op
-      , (lhs:rhs:_)          <- args =
-          jsPackUBits16 (
-            JSBinOp "<=" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)          <- args = bitsCompareOp "<=" lhs rhs
 
       | (LLe (ITFixed IT32)) <- op
-      , (lhs:rhs:_)          <- args =
-          jsPackUBits32 (
-            JSBinOp "<=" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)          <- args = bitsCompareOp "<=" lhs rhs
 
       | (LLe (ITFixed IT64)) <- op
-      , (lhs:rhs:_)          <- args = invokeMeth lhs "lesserOrEquals" [rhs]
+      , (lhs:rhs:_)          <- args = JSPreOp "+" $ invokeMeth lhs "lesserOrEquals" [rhs]
 
       | (LGt (ITFixed IT8)) <- op
-      , (lhs:rhs:_)         <- args =
-          jsPackUBits8 (
-            JSBinOp ">" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)         <- args = bitsCompareOp ">" lhs rhs
 
       | (LGt (ITFixed IT16)) <- op
-      , (lhs:rhs:_)          <- args =
-          jsPackUBits16 (
-            JSBinOp ">" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)          <- args = bitsCompareOp ">" lhs rhs
       | (LGt (ITFixed IT32)) <- op
-      , (lhs:rhs:_)          <- args =
-          jsPackUBits32 (
-            JSBinOp ">" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)          <- args = bitsCompareOp ">" lhs rhs
 
       | (LGt (ITFixed IT64)) <- op
-      , (lhs:rhs:_)          <- args = invokeMeth lhs "greater" [rhs]
+      , (lhs:rhs:_)          <- args = JSPreOp "+" $ invokeMeth lhs "greater" [rhs]
 
       | (LGe (ITFixed IT8)) <- op
-      , (lhs:rhs:_)         <- args =
-          jsPackUBits8 (
-            JSBinOp ">=" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)         <- args = bitsCompareOp ">=" lhs rhs
 
       | (LGe (ITFixed IT16)) <- op
-      , (lhs:rhs:_)          <- args =
-          jsPackUBits16 (
-            JSBinOp ">=" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)          <- args = bitsCompareOp ">=" lhs rhs
       | (LGe (ITFixed IT32)) <- op
-      , (lhs:rhs:_)          <- args =
-          jsPackUBits32 (
-            JSBinOp ">=" (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
-          )
+      , (lhs:rhs:_)          <- args = bitsCompareOp ">=" lhs rhs
 
       | (LGe (ITFixed IT64)) <- op
-      , (lhs:rhs:_)          <- args = invokeMeth lhs "greaterOrEquals" [rhs]
+      , (lhs:rhs:_)          <- args = JSPreOp "+" $ invokeMeth lhs "greaterOrEquals" [rhs]
 
       | (LUDiv (ITFixed IT8)) <- op
       , (lhs:rhs:_)           <- args =
@@ -1154,8 +1030,7 @@
           jsPackSBits32 $ JSPreOp "~" $ jsUnPackBits (translateReg arg)
 
       | (LCompl (ITFixed IT64)) <- op
-      , (arg:_)     <- args =
-          invokeMeth arg "not" []
+      , (arg:_)                 <- args = invokeMeth arg "not" []
 
       | (LPlus _)   <- op
       , (lhs:rhs:_) <- args = translateBinaryOp "+" lhs rhs
@@ -1168,15 +1043,15 @@
       | (LSRem _)   <- op
       , (lhs:rhs:_) <- args = translateBinaryOp "%" lhs rhs
       | (LEq _)     <- op
-      , (lhs:rhs:_) <- args = translateBinaryOp "==" lhs rhs
+      , (lhs:rhs:_) <- args = translateCompareOp "==" lhs rhs
       | (LSLt _)    <- op
-      , (lhs:rhs:_) <- args = translateBinaryOp "<" lhs rhs
+      , (lhs:rhs:_) <- args = translateCompareOp "<" lhs rhs
       | (LSLe _)    <- op
-      , (lhs:rhs:_) <- args = translateBinaryOp "<=" lhs rhs
+      , (lhs:rhs:_) <- args = translateCompareOp "<=" lhs rhs
       | (LSGt _)    <- op
-      , (lhs:rhs:_) <- args = translateBinaryOp ">" lhs rhs
+      , (lhs:rhs:_) <- args = translateCompareOp ">" lhs rhs
       | (LSGe _)    <- op
-      , (lhs:rhs:_) <- args = translateBinaryOp ">=" lhs rhs
+      , (lhs:rhs:_) <- args = translateCompareOp ">=" lhs rhs
       | (LAnd _)    <- op
       , (lhs:rhs:_) <- args = translateBinaryOp "&" lhs rhs
       | (LOr _)     <- op
@@ -1193,9 +1068,9 @@
       | LStrConcat  <- op
       , (lhs:rhs:_) <- args = translateBinaryOp "+" lhs rhs
       | LStrEq      <- op
-      , (lhs:rhs:_) <- args = translateBinaryOp "==" lhs rhs
+      , (lhs:rhs:_) <- args = translateCompareOp "==" lhs rhs
       | LStrLt      <- op
-      , (lhs:rhs:_) <- args = translateBinaryOp "<" lhs rhs
+      , (lhs:rhs:_) <- args = translateCompareOp "<" lhs rhs
       | LStrLen     <- op
       , (arg:_)     <- args = JSProj (translateReg arg) "length"
       | (LStrInt ITNative)      <- op
@@ -1270,13 +1145,28 @@
       , (arg:_) <- args = jsCall "i$systemInfo"  [translateReg arg]
       | LExternal nul <- op
       , nul == sUN "prim__null"
-      , (_)         <- args = JSNull
+      , _ <- args = JSNull
+      | LExternal ex <- op
+      , ex == sUN "prim__eqPtr"
+      , [lhs, rhs] <- args = translateCompareOp "==" lhs rhs
       | otherwise = JSError $ "Not implemented: " ++ show op
         where
           translateBinaryOp :: String -> Reg -> Reg -> JS
           translateBinaryOp op lhs rhs =
             JSBinOp op (translateReg lhs) (translateReg rhs)
 
+          translateCompareOp :: String -> Reg -> Reg -> JS
+          translateCompareOp op lhs rhs =
+            JSPreOp "+" $ translateBinaryOp op lhs rhs
+
+          bitsBinaryOp :: String -> Reg -> Reg -> JS
+          bitsBinaryOp op lhs rhs =
+            JSBinOp op (jsUnPackBits (translateReg lhs)) (jsUnPackBits (translateReg rhs))
+
+          bitsCompareOp :: String -> Reg -> Reg -> JS
+          bitsCompareOp op lhs rhs =
+            JSPreOp "+" $ bitsBinaryOp op lhs rhs
+
           invokeMeth :: Reg -> String -> [Reg] -> JS
           invokeMeth obj meth args =
             JSApp (JSProj (translateReg obj) meth) $ map translateReg args
@@ -1331,6 +1221,7 @@
   | TAILCALL n            <- bc = jsTAILCALL info n
   | FOREIGNCALL r _ (FStr n) args
                           <- bc = jsFOREIGN info r n (map fcall args)
+  | FOREIGNCALL _ _ _ _   <- bc = error "JS FFI call not statically known"
   | TOPBASE n             <- bc = jsTOPBASE info n
   | BASETOP n             <- bc = jsBASETOP info n
   | STOREOLD              <- bc = jsSTOREOLD info
diff --git a/src/IRTS/Compiler.hs b/src/IRTS/Compiler.hs
--- a/src/IRTS/Compiler.hs
+++ b/src/IRTS/Compiler.hs
@@ -60,7 +60,7 @@
         maindef <- case mtm of
                         Nothing -> return []
                         Just tm -> do md <- irMain tm
-                                      iLOG $ "MAIN: " ++ show md
+                                      logLvl 1 $ "MAIN: " ++ show md
                                       return [(sMN 0 "runMain", md)]
         objs <- getObjectFiles codegen
         libs <- getLibs codegen
@@ -83,13 +83,13 @@
         let (nexttag, tagged) = addTags 65536 (liftAll defsUniq)
         let ctxtIn = addAlist tagged emptyContext
 
-        iLOG "Defunctionalising"
+        logLvl 1 "Defunctionalising"
         let defuns_in = defunctionalise nexttag ctxtIn
         logLvl 5 $ show defuns_in
-        iLOG "Inlining"
+        logLvl 1 "Inlining"
         let defuns = inline defuns_in
         logLvl 5 $ show defuns
-        iLOG "Resolving variables for CG"
+        logLvl 1 "Resolving variables for CG"
         -- iputStrLn $ showSep "\n" (map show (toAlist defuns))
         let checked = simplifyDefs defuns (toAlist defuns)
         outty <- outputTy
@@ -103,7 +103,7 @@
             Just f -> runIO $ writeFile f (dumpDefuns defuns)
         triple <- Idris.AbsSyntax.targetTriple
         cpu <- Idris.AbsSyntax.targetCPU
-        iLOG "Building output"
+        logLvl 1 "Building output"
         case checked of
             OK c -> do return $ CodegenInfo f outty triple cpu
                                             hdrs impdirs objs libs flags
@@ -120,7 +120,7 @@
   where checkMVs = do i <- getIState
                       case map fst (idris_metavars i) \\ primDefs of
                             [] -> return ()
-                            ms -> ifail $ "There are undefined metavariables: " ++ show ms
+                            ms -> ifail $ "There are undefined holes: " ++ show ms
         checkTotality = do i <- getIState
                            case idris_totcheckfail i of
                              [] -> return ()
@@ -136,7 +136,7 @@
        Via "c" -> codegenC ir
        -- Any external code generator
        Via cg -> do let cmd = "idris-" ++ cg
-                        args = [mainmod, "-o", outputFile ir]
+                        args = [mainmod, "-o", outputFile ir] ++ compilerFlags ir
                     exit <- rawSystem cmd args
                     when (exit /= ExitSuccess) $
                        putStrLn ("FAILURE: " ++ show cmd ++ " " ++ show args)
diff --git a/src/IRTS/JavaScript/AST.hs b/src/IRTS/JavaScript/AST.hs
--- a/src/IRTS/JavaScript/AST.hs
+++ b/src/IRTS/JavaScript/AST.hs
@@ -76,6 +76,7 @@
         | JSWhile JS JS
         | JSFFI String [JS]
         | JSAnnotation JSAnnotation JS
+        | JSDelete JS
         | JSNoop
         deriving Eq
 
@@ -129,6 +130,9 @@
   `T.append` " */\n"
   `T.append` compileJS' indent js
 
+compileJS' indent (JSDelete js) =
+  "delete " `T.append` compileJS' 0 js
+
 compileJS' indent (JSFFI raw args) =
   ffi raw (map (T.unpack . compileJS' indent) args)
 
@@ -190,7 +194,7 @@
   `T.append` compileJS' indent rhs
 
 compileJS' indent (JSPreOp op val) =
-  T.pack op `T.append` compileJS' indent val
+  T.pack op `T.append` "(" `T.append` compileJS' indent val `T.append` ")"
 
 compileJS' indent (JSProj obj field)
   | JSFunction {} <- obj =
diff --git a/src/Idris/ASTUtils.hs b/src/Idris/ASTUtils.hs
--- a/src/Idris/ASTUtils.hs
+++ b/src/Idris/ASTUtils.hs
@@ -1,4 +1,7 @@
-module Idris.ASTUtils where
+module Idris.ASTUtils(Field(), cg_usedpos, ctxt_lookup, fgetState, fmodifyState,
+                      fputState, idris_fixities, ist_callgraph, ist_optimisation,
+                      known_classes, known_terms, opt_detaggable, opt_inaccessible, 
+                      opts_idrisCmdline, repl_definitions) where
 
 -- This implements just a few basic lens-like concepts to ease state updates.
 -- Similar to fclabels in approach, just without the extra dependency.
diff --git a/src/Idris/AbsSyntax.hs b/src/Idris/AbsSyntax.hs
--- a/src/Idris/AbsSyntax.hs
+++ b/src/Idris/AbsSyntax.hs
@@ -16,6 +16,7 @@
 
 import System.Console.Haskeline
 import System.IO
+import System.Directory (canonicalizePath, doesFileExist)
 
 import Control.Applicative
 import Control.Monad (liftM3)
@@ -344,7 +345,7 @@
 addToCalledG n ns = return () -- TODO
 
 push_estack :: Name -> Bool -> Idris ()
-push_estack n inst 
+push_estack n inst
     = do i <- getIState
          putIState (i { elab_stack = (n, inst) : elab_stack i })
 
@@ -400,10 +401,10 @@
 addAutoHint n hint =
     do ist <- getIState
        case lookupCtxtExact n (idris_autohints ist) of
-            Nothing -> 
+            Nothing ->
                  do let hs = addDef n [hint] (idris_autohints ist)
                     putIState $ ist { idris_autohints = hs }
-            Just nhints -> 
+            Just nhints ->
                  do let hs = addDef n (hint : nhints) (idris_autohints ist)
                     putIState $ ist { idris_autohints = hs }
 
@@ -516,14 +517,26 @@
 addInternalApp :: FilePath -> Int -> PTerm -> Idris ()
 addInternalApp fp l t
     = do i <- getIState
-         putIState (i { idris_lineapps = ((fp, l), t) : idris_lineapps i })
+         -- We canonicalise the path to make "./Test/Module.idr" equal
+         -- to "Test/Module.idr"
+         exists <- runIO $ doesFileExist fp
+         when exists $
+           do fp' <- runIO $ canonicalizePath fp
+              putIState (i { idris_lineapps = ((fp', l), t) : idris_lineapps i })
 
 getInternalApp :: FilePath -> Int -> Idris PTerm
 getInternalApp fp l = do i <- getIState
-                         case lookup (fp, l) (idris_lineapps i) of
-                              Just n' -> return n'
-                              Nothing -> return Placeholder
-                              -- TODO: What if it's not there?
+                         -- We canonicalise the path to make
+                         -- "./Test/Module.idr" equal to
+                         -- "Test/Module.idr"
+                         exists <- runIO $ doesFileExist fp
+                         if exists
+                           then do fp' <- runIO $ canonicalizePath fp
+                                   case lookup (fp', l) (idris_lineapps i) of
+                                     Just n' -> return n'
+                                     Nothing -> return Placeholder
+                                     -- TODO: What if it's not there?
+                           else return Placeholder
 
 -- Pattern definitions are only used for coverage checking, so erase them
 -- when we're done
@@ -576,7 +589,7 @@
          putIState $ i { tt_ctxt = ctxt', idris_constraints = ics }
   where
     insertAll [] c = c
-    insertAll ((c, fc) : cs) ics 
+    insertAll ((c, fc) : cs) ics
        = insertAll cs $ S.insert (ConstraintFC c fc) ics
 
 addDeferred = addDeferred' Ref
@@ -584,7 +597,7 @@
 
 -- | Save information about a name that is not yet defined
 addDeferred' :: NameType
-             -> [(Name, (Int, Maybe Name, Type, Bool))]
+             -> [(Name, (Int, Maybe Name, Type, [Name], Bool))]
                 -- ^ The Name is the name being made into a metavar,
                 -- the Int is the number of vars that are part of a
                 -- putative proof context, the Maybe Name is the
@@ -593,10 +606,10 @@
                 -- allowed
              -> Idris ()
 addDeferred' nt ns
-  = do mapM_ (\(n, (i, _, t, _)) -> updateContext (addTyDecl n nt (tidyNames S.empty t))) ns
+  = do mapM_ (\(n, (i, _, t, _, _)) -> updateContext (addTyDecl n nt (tidyNames S.empty t))) ns
        mapM_ (\(n, _) -> when (not (n `elem` primDefs)) $ addIBC (IBCMetavar n)) ns
        i <- getIState
-       putIState $ i { idris_metavars = map (\(n, (i, top, _, isTopLevel)) -> (n, (top, i, isTopLevel))) ns ++
+       putIState $ i { idris_metavars = map (\(n, (i, top, _, ns, isTopLevel)) -> (n, (top, i, ns, isTopLevel))) ns ++
                                             idris_metavars i }
   where
         -- 'tidyNames' is to generate user accessible names in case they are
@@ -637,7 +650,12 @@
 setWidth w = do ist <- getIState
                 put ist { idris_consolewidth = w }
 
+setDepth :: Maybe Int -> Idris ()
+setDepth d = do ist <- getIState
+                put ist { idris_options = (idris_options ist) { opt_printdepth = d } }
 
+typeDescription :: String
+typeDescription = "The type of types"
 
 
 type1Doc :: Doc OutputAnnotation
@@ -676,6 +694,11 @@
 getCmdLine = do i <- getIState
                 return (opt_cmdline (idris_options i))
 
+getDumpHighlighting :: Idris Bool
+getDumpHighlighting = do ist <- getIState
+                         return (findC (opt_cmdline (idris_options ist)))
+  where findC = elem DumpHighlights
+
 getDumpDefun :: Idris (Maybe FilePath)
 getDumpDefun = do i <- getIState
                   return $ findC (opt_cmdline (idris_options i))
@@ -767,6 +790,12 @@
                  let opts = idris_options i
                  return (opt_nobanner opts)
 
+setEvalTypes :: Bool -> Idris ()
+setEvalTypes n = do i <- getIState
+                    let opts = idris_options i
+                    let opt' = opts { opt_evaltypes = n }
+                    putIState $ i { idris_options = opt' }
+
 setQuiet :: Bool -> Idris ()
 setQuiet q = do i <- getIState
                 let opts = idris_options i
@@ -928,9 +957,6 @@
 cmdOptType x = do i <- getIState
                   return $ x `elem` opt_cmdline (idris_options i)
 
-iLOG :: String -> Idris ()
-iLOG = logLvl 1
-
 noErrors :: Idris Bool
 noErrors = do i <- getIState
               case errSpan i of
@@ -978,15 +1004,15 @@
                      PLet fc n' nfc (en ty) (en v) (en (shadow n n' s))
        | otherwise = PLet fc n nfc (en ty) (en v) (en s)
     -- FIXME: Should only do this in a type signature!
-    en (PDPair f p (PRef f' n) t r)
+    en (PDPair f hls p (PRef f' fcs n) t r)
        | n `elem` (map fst ps ++ ns) && t /= Placeholder
            = let n' = mkShadow n in
-                 PDPair f p (PRef f' n') (en t) (en (shadow n n' r))
+                 PDPair f hls p (PRef f' fcs n') (en t) (en (shadow n n' r))
     en (PRewrite f l r g) = PRewrite f (en l) (en r) (fmap en g)
     en (PTyped l r) = PTyped (en l) (en r)
-    en (PPair f p l r) = PPair f p (en l) (en r)
-    en (PDPair f p l t r) = PDPair f p (en l) (en t) (en r)
-    en (PAlternative a as) = PAlternative a (map en as)
+    en (PPair f hls p l r) = PPair f hls p (en l) (en r)
+    en (PDPair f hls p l t r) = PDPair f hls p (en l) (en t) (en r)
+    en (PAlternative ns a as) = PAlternative ns a (map en as)
     en (PHidden t) = PHidden (en t)
     en (PUnifyLog t) = PUnifyLog (en t)
     en (PDisamb ds t) = PDisamb ds (en t)
@@ -997,32 +1023,33 @@
 
     en (PQuote (Var n))
         | n `nselem` ns = PQuote (Var (dec n))
-    en (PApp fc (PInferRef fc' n) as)
-        | n `nselem` ns = PApp fc (PInferRef fc' (dec n))
-                           (map (pexp . (PRef fc)) (map fst ps) ++ (map (fmap en) as))
-    en (PApp fc (PRef fc' n) as)
-        | n `elem` infs = PApp fc (PInferRef fc' (dec n))
-                           (map (pexp . (PRef fc)) (map fst ps) ++ (map (fmap en) as))
-        | n `nselem` ns = PApp fc (PRef fc' (dec n))
-                           (map (pexp . (PRef fc)) (map fst ps) ++ (map (fmap en) as))
-    en (PAppBind fc (PRef fc' n) as)
-        | n `elem` infs = PAppBind fc (PInferRef fc' (dec n))
-                           (map (pexp . (PRef fc)) (map fst ps) ++ (map (fmap en) as))
-        | n `nselem` ns = PAppBind fc (PRef fc' (dec n))
-                           (map (pexp . (PRef fc)) (map fst ps) ++ (map (fmap en) as))
-    en (PRef fc n)
-        | n `elem` infs = PApp fc (PInferRef fc (dec n))
-                           (map (pexp . (PRef fc)) (map fst ps))
-        | n `nselem` ns = PApp fc (PRef fc (dec n))
-                           (map (pexp . (PRef fc)) (map fst ps))
-    en (PInferRef fc n)
-        | n `nselem` ns = PApp fc (PInferRef fc (dec n))
-                           (map (pexp . (PRef fc)) (map fst ps))
+    en (PApp fc (PInferRef fc' hl n) as)
+        | n `nselem` ns = PApp fc (PInferRef fc' hl (dec n))
+                           (map (pexp . (PRef fc hl)) (map fst ps) ++ (map (fmap en) as))
+    en (PApp fc (PRef fc' hl n) as)
+        | n `elem` infs = PApp fc (PInferRef fc' hl (dec n))
+                           (map (pexp . (PRef fc hl)) (map fst ps) ++ (map (fmap en) as))
+        | n `nselem` ns = PApp fc (PRef fc' hl (dec n))
+                           (map (pexp . (PRef fc hl)) (map fst ps) ++ (map (fmap en) as))
+    en (PAppBind fc (PRef fc' hl n) as)
+        | n `elem` infs = PAppBind fc (PInferRef fc' hl (dec n))
+                           (map (pexp . (PRef fc hl)) (map fst ps) ++ (map (fmap en) as))
+        | n `nselem` ns = PAppBind fc (PRef fc' hl (dec n))
+                           (map (pexp . (PRef fc hl)) (map fst ps) ++ (map (fmap en) as))
+    en (PRef fc hl n)
+        | n `elem` infs = PApp fc (PInferRef fc hl (dec n))
+                           (map (pexp . (PRef fc hl)) (map fst ps))
+        | n `nselem` ns = PApp fc (PRef fc hl (dec n))
+                           (map (pexp . (PRef fc hl)) (map fst ps))
+    en (PInferRef fc hl n)
+        | n `nselem` ns = PApp fc (PInferRef fc hl (dec n))
+                           (map (pexp . (PRef fc hl)) (map fst ps))
     en (PApp fc f as) = PApp fc (en f) (map (fmap en) as)
     en (PAppBind fc f as) = PAppBind fc (en f) (map (fmap en) as)
     en (PCase fc c os) = PCase fc (en c) (map (pmap en) os)
     en (PIfThenElse fc c t f) = PIfThenElse fc (en c) (en t) (en f)
-    en (PRunElab fc tm) = PRunElab fc (en tm)
+    en (PRunElab fc tm ns) = PRunElab fc (en tm) ns
+    en (PConstSugar fc tm) = PConstSugar fc (en tm)
     en t = t
 
     nselem x [] = False
@@ -1043,13 +1070,13 @@
               PTy doc argdocs syn fc o (dec n) nfc (piBindp expl_param ps (expandParams dec ps ns [] ty))
          else --trace (show (n, expandParams dec ps ns ty)) $
               PTy doc argdocs syn fc o n nfc (expandParams dec ps ns [] ty)
-expandParamsD rhsonly ist dec ps ns (PPostulate e doc syn fc o n ty)
+expandParamsD rhsonly ist dec ps ns (PPostulate e doc syn fc nfc o n ty)
     = if n `elem` ns && (not rhsonly)
          then -- trace (show (n, expandParams dec ps ns ty)) $
-              PPostulate e doc syn fc o (dec n) (piBind ps
-                            (expandParams dec ps ns [] ty))
+              PPostulate e doc syn fc nfc o (dec n)
+                         (piBind ps (expandParams dec ps ns [] ty))
          else --trace (show (n, expandParams dec ps ns ty)) $
-              PPostulate e doc syn fc o n (expandParams dec ps ns [] ty)
+              PPostulate e doc syn fc nfc o n (expandParams dec ps ns [] ty)
 expandParamsD rhsonly ist dec ps ns (PClauses fc opts n cs)
     = let n' = if n `elem` ns then dec n else n in
           PClauses fc opts n' (map expandParamsC cs)
@@ -1083,10 +1110,10 @@
 
     removeBound lhs ns = ns \\ nub (bnames lhs)
 
-    bnames (PRef _ n) = [n]
+    bnames (PRef _ _ n) = [n]
     bnames (PApp _ _ args) = concatMap bnames (map getTm args)
-    bnames (PPair _ _ l r) = bnames l ++ bnames r
-    bnames (PDPair _ _ l Placeholder r) = bnames l ++ bnames r
+    bnames (PPair _ _ _ l r) = bnames l ++ bnames r
+    bnames (PDPair _ _ _ l Placeholder r) = bnames l ++ bnames r
     bnames _ = []
 
 -- | Expands parameters defined in parameter and where blocks inside of declarations
@@ -1142,7 +1169,7 @@
 getPriority :: IState -> PTerm -> Int
 getPriority i tm = 1 -- pri tm
   where
-    pri (PRef _ n) =
+    pri (PRef _ _ n) =
         case lookupP n (tt_ctxt i) of
             ((P (DCon _ _ _) _ _):_) -> 1
             ((P (TCon _ _) _ _):_) -> 1
@@ -1155,9 +1182,9 @@
     pri (PAppBind _ f as) = max 1 (max (pri f) (foldr max 0 (map (pri.getTm) as)))
     pri (PCase _ f as) = max 1 (max (pri f) (foldr max 0 (map (pri.snd) as)))
     pri (PTyped l r) = pri l
-    pri (PPair _ _ l r) = max 1 (max (pri l) (pri r))
-    pri (PDPair _ _ l t r) = max 1 (max (pri l) (max (pri t) (pri r)))
-    pri (PAlternative a as) = maximum (map pri as)
+    pri (PPair _ _ _ l r) = max 1 (max (pri l) (pri r))
+    pri (PDPair _ _ _ l t r) = max 1 (max (pri l) (max (pri t) (pri r)))
+    pri (PAlternative _ a as) = maximum (map pri as)
     pri (PConstant _ _) = 0
     pri Placeholder = 1
     pri _ = 3
@@ -1268,20 +1295,20 @@
                          (mkConst c args) (doAdd cs ns t)
              | otherwise = doAdd cs ns t
 
-         mkConst c args = PApp fc (PRef fc c)
-                           (map (\n -> PExp 0 [] (sMN 0 "carg") (PRef fc n)) args)
+         mkConst c args = PApp fc (PRef fc [] c)
+                           (map (\n -> PExp 0 [] (sMN 0 "carg") (PRef fc [] n)) args)
 
          getConstraints (PPi (Constraint _ _) _ _ c sc)
              = getcapp c ++ getConstraints sc
          getConstraints (PPi _ _ _ c sc) = getConstraints sc
          getConstraints _ = []
 
-         getcapp (PApp _ (PRef _ c) args)
+         getcapp (PApp _ (PRef _ _ c) args)
              = do ns <- mapM getName args
                   return (UConstraint c ns)
          getcapp _ = []
 
-         getName (PExp _ _ _ (PRef _ n)) = return n
+         getName (PExp _ _ _ (PRef _ _ n)) = return n
          getName _ = []
 
 -- Add implicit bindings from using block, and bind any missing names
@@ -1318,7 +1345,7 @@
          bindFree (n:ns) tm
              | elem n (map iname uimpls) = bindFree ns tm
              | otherwise
-                    = PPi (Imp [] Dynamic False Nothing) n NoFC Placeholder (bindFree ns tm)
+                    = PPi (Imp [InaccessibleArg] Dynamic False Nothing) n NoFC Placeholder (bindFree ns tm)
 
          getArgnames (PPi _ n _ c sc)
              = n : getArgnames sc
@@ -1358,8 +1385,9 @@
 -- argument position.
 
 -- This has become a right mess already. Better redo it some time...
--- TODO: This is obsoleted by the new way of elaborating types, but there's still
--- a couple of places which use it. Clean them up!
+-- TODO: This is obsoleted by the new way of elaborating types, (which
+-- calls addUsingImpls) but there's still a couple of places which use
+-- it. Clean them up!
 --
 -- Issue 1739 in the issue tracker
 --     https://github.com/idris-lang/Idris-dev/issues/1739
@@ -1437,7 +1465,7 @@
              imps True (n:env) 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]
+                            (PRef _ _ x) -> namesIn uvars ist sc `dropAll` [n]
                             _ -> [])
              (decls, ns) <- get -- ignore decls in HO types
              put (PExp (getPriority ist ty) l n Placeholder : decls,
@@ -1445,7 +1473,7 @@
              imps True (n:env) 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]
+                            (PRef _ _ x) -> namesIn uvars ist sc `dropAll` [n]
                             _ -> [])
              (decls, ns) <- get -- ignore decls in HO types
              put (PConstraint 10 l n Placeholder : decls,
@@ -1453,7 +1481,7 @@
              imps True (n:env) 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]
+                            (PRef _ _ x) -> namesIn uvars ist sc `dropAll` [n]
                             _ -> [])
              (decls, ns) <- get -- ignore decls in HO types
              put (PTacImplicit 10 l n scr Placeholder : decls,
@@ -1465,20 +1493,20 @@
              put (decls, nub (ns ++ (isn `dropAll` (env ++ map fst (getImps decls)))))
     imps top env (PTyped l r)
         = imps top env l
-    imps top env (PPair _ _ l r)
+    imps top env (PPair _ _ _ l r)
         = do (decls, ns) <- get
              let isn = namesIn uvars ist l ++ namesIn uvars ist r
              put (decls, nub (ns ++ (isn `dropAll` (env ++ map fst (getImps decls)))))
-    imps top env (PDPair _ _ (PRef _ n) t r)
+    imps top env (PDPair _ _ _ (PRef _ _ n) t r)
         = do (decls, ns) <- get
              let isn = nub (namesIn uvars ist t ++ namesIn uvars ist r) \\ [n]
              put (decls, nub (ns ++ (isn \\ (env ++ map fst (getImps decls)))))
-    imps top env (PDPair _ _ l t r)
+    imps top env (PDPair _ _ _ l t r)
         = do (decls, ns) <- get
              let isn = namesIn uvars ist l ++ namesIn uvars ist t ++
                        namesIn uvars ist r
              put (decls, nub (ns ++ (isn \\ (env ++ map fst (getImps decls)))))
-    imps top env (PAlternative a as)
+    imps top env (PAlternative ms a as)
         = do (decls, ns) <- get
              let isn = concatMap (namesIn uvars ist) as
              put (decls, nub (ns ++ (isn `dropAll` (env ++ map fst (getImps decls)))))
@@ -1488,15 +1516,17 @@
     imps top env (PHidden tm)    = imps False env tm
     imps top env (PUnifyLog tm)  = imps False env tm
     imps top env (PNoImplicits tm)  = imps False env tm
-    imps top env (PRunElab fc tm) = imps False env tm
+    imps top env (PRunElab fc tm ns) = imps False env tm
+    imps top env (PConstSugar fc tm) = imps top env tm -- ignore PConstSugar - it's for highlighting only!
     imps top env _               = return ()
 
     pibind using []     sc = sc
     pibind using (n:ns) sc
       = case lookup n using of
-            Just ty -> PPi (Imp [] Dynamic False Nothing) n NoFC ty (pibind using ns sc)
-            Nothing -> PPi (Imp [] Dynamic False Nothing) n NoFC Placeholder
-                                   (pibind using ns sc)
+            Just ty -> PPi (Imp [] Dynamic False Nothing)
+                           n NoFC ty (pibind using ns sc)
+            Nothing -> PPi (Imp [InaccessibleArg] Dynamic False Nothing)
+                           n NoFC Placeholder (pibind using ns sc)
 
 -- Add implicit arguments in function calls
 addImplPat :: IState -> PTerm -> PTerm
@@ -1520,13 +1550,13 @@
 
 addImpl' :: Bool -> [Name] -> [Name] -> [Name] -> IState -> PTerm -> PTerm
 addImpl' inpat env infns imp_meths ist ptm
-         = mkUniqueNames env (ai False (zip env (repeat Nothing)) [] ptm)
+         = mkUniqueNames env [] (ai False (zip env (repeat Nothing)) [] ptm)
   where
     ai :: Bool -> [(Name, Maybe PTerm)] -> [[T.Text]] -> PTerm -> PTerm
-    ai qq env ds (PRef fc f)
-        | f `elem` infns = PInferRef fc f
+    ai qq env ds (PRef fc fcs f)
+        | f `elem` infns = PInferRef fc fcs f
         | not (f `elem` map fst env) = handleErr $ aiFn inpat inpat qq imp_meths ist fc f fc ds []
-    ai qq env ds (PHidden (PRef fc f))
+    ai qq env ds (PHidden (PRef fc hl f))
         | not (f `elem` map fst env) = PHidden (handleErr $ aiFn inpat False qq imp_meths ist fc f fc ds [])
     ai qq env ds (PRewrite fc l r g)
        = let l' = ai qq env ds l
@@ -1537,24 +1567,24 @@
       = let l' = ai qq env ds l
             r' = ai qq env ds r in
             PTyped l' r'
-    ai qq env ds (PPair fc p l r)
+    ai qq env ds (PPair fc hls p l r)
       = let l' = ai qq env ds l
             r' = ai qq env ds r in
-            PPair fc p l' r'
-    ai qq env ds (PDPair fc p l t r)
+            PPair fc hls p l' r'
+    ai qq env ds (PDPair fc hls p l t r)
          = let l' = ai qq env ds l
                t' = ai qq env ds t
                r' = ai qq env ds r in
-           PDPair fc p l' t' r'
-    ai qq env ds (PAlternative a as)
+           PDPair fc hls p l' t' r'
+    ai qq env ds (PAlternative ms a as)
            = let as' = map (ai qq env ds) as in
-                 PAlternative a as'
+                 PAlternative ms a as'
     ai qq env _ (PDisamb ds' as) = ai qq env ds' as
-    ai qq env ds (PApp fc (PInferRef ffc f) as)
+    ai qq env ds (PApp fc (PInferRef ffc hl f) as)
         = let as' = map (fmap (ai qq env ds)) as in
-              PApp fc (PInferRef ffc f) as'
-    ai qq env ds (PApp fc ftm@(PRef ffc f) as)
-        | f `elem` infns = ai qq env ds (PApp fc (PInferRef ffc f) as)
+              PApp fc (PInferRef ffc hl f) as'
+    ai qq env ds (PApp fc ftm@(PRef ffc hl f) as)
+        | f `elem` infns = ai qq env ds (PApp fc (PInferRef ffc hl f) as)
         | not (f `elem` map fst env)
                           = let as' = map (fmap (ai qq env ds)) as in
                                 handleErr $ aiFn inpat False qq imp_meths ist fc f ffc ds as'
@@ -1586,15 +1616,16 @@
                        sc' = ai qq ((n, Just ty):env) ds sc in
                        PLam fc n nfc ty' sc'
              _ -> ai qq env ds (PLam fc (sMN 0 "lamp") NoFC ty
-                                     (PCase fc (PRef fc (sMN 0 "lamp") )
-                                        [(PRef fc n, sc)]))
+                                     (PCase fc (PRef fc [] (sMN 0 "lamp") )
+                                        [(PRef fc [] n, sc)]))
     ai qq env ds (PLet fc n nfc ty val sc)
       = case lookupDef n (tt_ctxt ist) of
              [] -> let ty' = ai qq env ds ty
                        val' = ai qq env ds val
                        sc' = ai qq ((n, Just ty):env) ds sc in
                        PLet fc n nfc ty' val' sc'
-             _ -> ai qq env ds (PCase fc val [(PRef fc n, sc)])
+             defs ->
+               ai qq env ds (PCase fc val [(PRef fc [] n, sc)])
     ai qq env ds (PPi p n nfc ty sc)
       = let ty' = ai qq env ds ty
             env' = if n `elem` imp_meths then env
@@ -1613,7 +1644,8 @@
     ai qq env ds (PQuasiquote tm g) = PQuasiquote (ai True env ds tm)
                                                   (fmap (ai True env ds) g)
     ai qq env ds (PUnquote tm) = PUnquote (ai False env ds tm)
-    ai qq env ds (PRunElab fc tm) = PRunElab fc (ai False env ds tm)
+    ai qq env ds (PRunElab fc tm ns) = PRunElab fc (ai False env ds tm) ns
+    ai qq env ds (PConstSugar fc tm) = PConstSugar fc (ai qq env ds tm)
     ai qq env ds tm = tm
 
     handleErr (Left err) = PElabError err
@@ -1652,7 +1684,7 @@
           vname _ = False
 
 aiFn inpat expat qq imp_meths ist fc f ffc ds as
-    | f `elem` primNames = Right $ PApp fc (PRef ffc f) as
+    | f `elem` primNames = Right $ PApp fc (PRef ffc [ffc] f) as
 aiFn inpat expat qq imp_meths ist fc f ffc ds as
           -- This is where namespaces get resolved by adding PAlternative
      = do let ns = lookupCtxtName f (idris_implicits ist)
@@ -1661,13 +1693,13 @@
                          [] -> nh
                          x -> x
           case ns' of
-            [(f',ns)] -> Right $ mkPApp fc (length ns) (PRef ffc (isImpName f f')) (insertImpl ns as)
+            [(f',ns)] -> Right $ mkPApp fc (length ns) (PRef ffc [ffc] (isImpName f f')) (insertImpl ns as)
             [] -> if f `elem` (map fst (idris_metavars ist))
-                    then Right $ PApp fc (PRef ffc f) as
-                    else Right $ mkPApp fc (length as) (PRef ffc f) as
+                    then Right $ PApp fc (PRef ffc [ffc] f) as
+                    else Right $ mkPApp fc (length as) (PRef ffc [ffc] f) as
             alts -> Right $
-                         PAlternative (ExactlyOne True) $
-                           map (\(f', ns) -> mkPApp fc (length ns) (PRef ffc (isImpName f f'))
+                         PAlternative [] (ExactlyOne True) $
+                           map (\(f', ns) -> mkPApp fc (length ns) (PRef ffc [ffc] (isImpName f f'))
                                                   (insertImpl ns as)) alts
   where
     -- if the name is in imp_meths, we should actually refer to the bound
@@ -1694,9 +1726,9 @@
     insertImpl :: [PArg] -- ^ expected argument types (from idris_implicits)
                -> [PArg] -- ^ given arguments
                -> [PArg]
-    insertImpl ps as 
+    insertImpl ps as
         = let (as', badimpls) = partition (impIn ps) as in
-              map addUnknownImp badimpls ++ 
+              map addUnknownImp badimpls ++
               insImpAcc M.empty ps (filter expArg as') (filter (not . expArg) as')
 
     insImpAcc :: M.Map Name PTerm -- accumulated param names & arg terms
@@ -1715,7 +1747,7 @@
         case find n imps [] of
             Just (tm, imps') ->
               PImp p False l n tm : insImpAcc (M.insert n tm pnas) ps given imps'
-            Nothing -> let ph = if f `elem` imp_meths then PRef fc n else Placeholder in
+            Nothing -> let ph = if f `elem` imp_meths then PRef fc [] n else Placeholder in
               PImp p True l n ph :
                 insImpAcc (M.insert n ph pnas) ps given imps
     insImpAcc pnas (PTacImplicit p l n sc' ty : ps) given imps =
@@ -1741,7 +1773,7 @@
     find n (PTacImplicit _ _ n' _ t : gs) acc
          | n == n' = Just (t, reverse acc ++ gs)
     find n (g : gs) acc = find n gs (g : acc)
-    
+
 -- return True if the second argument is an implicit argument which is
 -- expected in the implicits, or if it's not an implicit
 impIn :: [PArg] -> PArg -> Bool
@@ -1758,14 +1790,14 @@
 stripLinear :: IState -> PTerm -> PTerm
 stripLinear i tm = evalState (sl tm) [] where
     sl :: PTerm -> State [Name] PTerm
-    sl (PRef fc f)
+    sl (PRef fc hl f)
          | (_:_) <- lookupTy f (tt_ctxt i)
-              = return $ PRef fc f
+              = return $ PRef fc hl f
          | otherwise = do ns <- get
                           if (f `elem` ns)
-                             then return $ PHidden (PRef fc f) -- Placeholder
+                             then return $ PHidden (PRef fc hl f) -- Placeholder
                              else do put (f : ns)
-                                     return (PRef fc f)
+                                     return (PRef fc hl f)
     sl (PPatvar fc f)
                      = do ns <- get
                           if (f `elem` ns)
@@ -1773,22 +1805,22 @@
                              else do put (f : ns)
                                      return (PPatvar fc f)
     -- Assumption is that variables are all the same in each alternative
-    sl t@(PAlternative b as) = do ns <- get
-                                  as' <- slAlts ns as
-                                  return (PAlternative b as')
+    sl t@(PAlternative ms b as) = do ns <- get
+                                     as' <- slAlts ns as
+                                     return (PAlternative ms b as')
        where slAlts ns (a : as) = do put ns
                                      a' <- sl a
                                      as' <- slAlts ns as
                                      return (a' : as')
              slAlts ns [] = return []
-    sl (PPair fc p l r) = do l' <- sl l; r' <- sl r; return (PPair fc p l' r')
-    sl (PDPair fc p l t r) = do l' <- sl l
-                                t' <- sl t
-                                r' <- sl r
-                                return (PDPair fc p l' t' r')
+    sl (PPair fc hls p l r) = do l' <- sl l; r' <- sl r; return (PPair fc hls p l' r')
+    sl (PDPair fc hls p l t r) = do l' <- sl l
+                                    t' <- sl t
+                                    r' <- sl r
+                                    return (PDPair fc hls p l' t' r')
     sl (PApp fc fn args) = do fn' <- case fn of
                                      -- Just the args, fn isn't matchable as a var
-                                          PRef _ _ -> return fn
+                                          PRef _ _ _ -> return fn
                                           t -> sl t
                               args' <- mapM slA args
                               return $ PApp fc fn' args'
@@ -1810,10 +1842,14 @@
 stripUnmatchable :: IState -> PTerm -> PTerm
 stripUnmatchable i (PApp fc fn args) = PApp fc fn (fmap (fmap su) args) where
     su :: PTerm -> PTerm
-    su (PRef fc f)
+    su tm@(PRef fc hl f)
        | (Bind n (Pi _ t _) sc :_) <- lookupTy f (tt_ctxt i)
           = Placeholder
-    su (PApp fc f@(PRef _ fn) args)
+       | (TType _ : _) <- lookupTy f (tt_ctxt i)
+          = PHidden tm
+       | (UType _ : _) <- lookupTy f (tt_ctxt i)
+          = PHidden tm
+    su (PApp fc f@(PRef _ _ fn) args)
        -- here we use canBeDConName because the impossible pattern
        -- check will not necessarily fully resolve constructor names,
        -- and these bare names will otherwise get in the way of
@@ -1822,14 +1858,15 @@
           = PApp fc f (fmap (fmap su) args)
     su (PApp fc f args)
           = PHidden (PApp fc f args)
-    su (PAlternative b alts)
+    su (PAlternative ms b alts)
        = let alts' = filter (/= Placeholder) (map su alts) in
              if null alts' then Placeholder
-                           else PAlternative b alts'
-    su (PPair fc p l r) = PPair fc p (su l) (su r)
-    su (PDPair fc p l t r) = PDPair fc p (su l) (su t) (su r)
+                           else PAlternative ms b alts'
+    su (PPair fc hls p l r) = PPair fc hls p (su l) (su r)
+    su (PDPair fc hls p l t r) = PDPair fc hls p (su l) (su t) (su r)
     su t@(PLam fc _ _ _ _) = PHidden t
     su t@(PPi _ _ _ _ _) = PHidden t
+    su t@(PConstant _ c) | isTypeConst c = PHidden t
     su t = t
 
     ctxt = tt_ctxt i
@@ -1850,9 +1887,8 @@
 -- FIXME: It's possible that this really has to happen after elaboration
 
 findStatics :: IState -> PTerm -> (PTerm, [Bool])
-findStatics ist tm = trace (show tm) $
-                      let (ns, ss) = fs tm in
-                         runState (pos ns ss tm) []
+findStatics ist tm = let (ns, ss) = fs tm
+                     in runState (pos ns ss tm) []
   where fs (PPi p n fc t sc)
             | Static <- pstatic p
                         = let (ns, ss) = fs sc in
@@ -1903,24 +1939,24 @@
     fullApp x = x
 
     match' x y = match (fullApp x) (fullApp y)
-    match (PApp _ (PRef _ (NS (UN fi) [b])) [_,_,x]) x'
+    match (PApp _ (PRef _ _ (NS (UN fi) [b])) [_,_,x]) x'
         | fi == txt "fromInteger" && b == txt "builtins",
           PConstant _ (I _) <- getTm x = match (getTm x) x'
-    match x' (PApp _ (PRef _ (NS (UN fi) [b])) [_,_,x])
+    match x' (PApp _ (PRef _ _ (NS (UN fi) [b])) [_,_,x])
         | fi == txt "fromInteger" && b == txt "builtins",
           PConstant _ (I _) <- getTm x = match (getTm x) x'
-    match (PApp _ (PRef _ (UN l)) [_,x]) x' | l == txt "lazy" = match (getTm x) x'
-    match x (PApp _ (PRef _ (UN l)) [_,x']) | l == txt "lazy" = match x (getTm x')
+    match (PApp _ (PRef _ _ (UN l)) [_,x]) x' | l == txt "lazy" = match (getTm x) x'
+    match x (PApp _ (PRef _ _ (UN l)) [_,x']) | l == txt "lazy" = match x (getTm x')
     match (PApp _ f args) (PApp _ f' args')
         | length args == length args'
             = do mf <- match' f f'
                  ms <- zipWithM matchArg args args'
                  return (mf ++ concat ms)
-    match (PRef f n) (PApp _ x []) = match (PRef f n) x
-    match (PPatvar f n) xr = match (PRef f n) xr
-    match xr (PPatvar f n) = match xr (PRef f n)
-    match (PApp _ x []) (PRef f n) = match x (PRef f n)
-    match (PRef _ n) tm@(PRef _ n')
+    match (PRef f hl n) (PApp _ x []) = match (PRef f hl n) x
+    match (PPatvar f n) xr = match (PRef f [f] n) xr
+    match xr (PPatvar f n) = match xr (PRef f [f] n)
+    match (PApp _ x []) (PRef f hl n) = match x (PRef f hl n)
+    match (PRef _ _ n) tm@(PRef _ _ n')
         | n == n' && not names &&
           (not (isConName n (tt_ctxt i) || isFnName n (tt_ctxt i))
                 || tm == Placeholder)
@@ -1929,7 +1965,7 @@
         | n == n' || n == dropNS n' || dropNS n == n' = return []
        where dropNS (NS n _) = n
              dropNS n = n
-    match (PRef _ n) tm
+    match (PRef _ _ n) tm
         | not names && (not (isConName n (tt_ctxt i) ||
                              isFnName n (tt_ctxt i)) || tm == Placeholder)
             = return [(n, tm)]
@@ -1942,24 +1978,24 @@
                                            return (ml ++ mr)
     match (PTyped l r) x = match l x
     match x (PTyped l r) = match x l
-    match (PPair _ _ l r) (PPair _ _ l' r') = do ml <- match' l l'
-                                                 mr <- match' r r'
-                                                 return (ml ++ mr)
-    match (PDPair _ _ l t r) (PDPair _ _ l' t' r') = do ml <- match' l l'
-                                                        mt <- match' t t'
-                                                        mr <- match' r r'
-                                                        return (ml ++ mt ++ mr)
-    match (PAlternative a as) (PAlternative a' as')
+    match (PPair _ _ _ l r) (PPair _ _ _ l' r') = do ml <- match' l l'
+                                                     mr <- match' r r'
+                                                     return (ml ++ mr)
+    match (PDPair _ _ _ l t r) (PDPair _ _ _ l' t' r') = do ml <- match' l l'
+                                                            mt <- match' t t'
+                                                            mr <- match' r r'
+                                                            return (ml ++ mt ++ mr)
+    match (PAlternative _ a as) (PAlternative _ a' as')
         = do ms <- zipWithM match' as as'
              return (concat ms)
-    match a@(PAlternative _ as) b
+    match a@(PAlternative _ _ as) b
         = do let ms = zipWith match' as (repeat b)
              case (rights (map toEither ms)) of
                 (x: _) -> return x
                 _ -> LeftErr (a, b)
     match (PCase _ _ _) _ = return [] -- lifted out
     match (PMetavar _ _) _ = return [] -- modified
-    match (PInferRef _ _) _ = return [] -- modified
+    match (PInferRef _ _ _) _ = return [] -- modified
     match (PQuote _) _ = return []
     match (PProof _) _ = return []
     match (PTactics _) _ = return []
@@ -2017,13 +2053,13 @@
 
 substMatchShadow :: Name -> [Name] -> PTerm -> PTerm -> PTerm
 substMatchShadow n shs tm t = sm shs t where
-    sm xs (PRef _ n') | n == n' = tm
+    sm xs (PRef _ _ n') | n == n' = tm
     sm xs (PLam fc x xfc t sc) = PLam fc x xfc (sm xs t) (sm xs sc)
     sm xs (PPi p x fc t sc)
          | x `elem` xs
              = let x' = nextName x in
-                   PPi p x' fc (sm (x':xs) (substMatch x (PRef emptyFC x') t))
-                               (sm (x':xs) (substMatch x (PRef emptyFC x') sc))
+                   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 (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)
@@ -2031,13 +2067,14 @@
     sm xs (PRewrite f x y tm) = PRewrite f (sm xs x) (sm xs y)
                                            (fmap (sm xs) tm)
     sm xs (PTyped x y) = PTyped (sm xs x) (sm xs y)
-    sm xs (PPair f p x y) = PPair f p (sm xs x) (sm xs y)
-    sm xs (PDPair f p x t y) = PDPair f p (sm xs x) (sm xs t) (sm xs y)
-    sm xs (PAlternative a as) = PAlternative a (map (sm xs) as)
+    sm xs (PPair f hls p x y) = PPair f hls p (sm xs x) (sm xs y)
+    sm xs (PDPair f hls p x t y) = PDPair f hls p (sm xs x) (sm xs t) (sm xs y)
+    sm xs (PAlternative ms a as) = PAlternative ms a (map (sm xs) as)
     sm xs (PHidden x) = PHidden (sm xs x)
     sm xs (PUnifyLog x) = PUnifyLog (sm xs x)
     sm xs (PNoImplicits x) = PNoImplicits (sm xs x)
-    sm xs (PRunElab fc script) = PRunElab fc (sm xs script)
+    sm xs (PRunElab fc script ns) = PRunElab fc (sm xs script) ns
+    sm xs (PConstSugar fc tm) = PConstSugar fc (sm xs tm)
     sm xs x = x
 
     fullApp (PApp _ (PApp fc f args) xs) = fullApp (PApp fc f (args ++ xs))
@@ -2045,7 +2082,7 @@
 
 shadow :: Name -> Name -> PTerm -> PTerm
 shadow n n' t = sm t where
-    sm (PRef fc x) | n == x = PRef fc n'
+    sm (PRef fc hl x) | n == x = PRef fc hl n'
     sm (PLam fc x xfc t sc) | n /= x = PLam fc x xfc (sm t) (sm sc)
                             | otherwise = PLam fc x xfc (sm t) sc
     sm (PPi p x fc t sc) | n /= x = PPi p x fc (sm t) (sm sc)
@@ -2058,9 +2095,9 @@
     sm (PIfThenElse fc c t f) = PIfThenElse fc (sm c) (sm t) (sm f)
     sm (PRewrite f x y tm) = PRewrite f (sm x) (sm y) (fmap sm tm)
     sm (PTyped x y) = PTyped (sm x) (sm y)
-    sm (PPair f p x y) = PPair f p (sm x) (sm y)
-    sm (PDPair f p x t y) = PDPair f p (sm x) (sm t) (sm y)
-    sm (PAlternative a as) = PAlternative a (map sm as)
+    sm (PPair f hls p x y) = PPair f hls p (sm x) (sm y)
+    sm (PDPair f hls p x t y) = PDPair f hls p (sm x) (sm t) (sm y)
+    sm (PAlternative ms a as) = PAlternative ms a (map sm as)
     sm (PTactics ts) = PTactics (map (fmap sm) ts)
     sm (PProof ts) = PProof (map (fmap sm) ts)
     sm (PHidden x) = PHidden (sm x)
@@ -2068,16 +2105,19 @@
     sm (PNoImplicits x) = PNoImplicits (sm x)
     sm x = x
 
--- Rename any binders which are repeated (so that we don't have to mess
+-- | Rename any binders which are repeated (so that we don't have to mess
 -- about with shadowing anywhere else).
+mkUniqueNames :: [Name] -> [(Name, Name)] -> PTerm -> PTerm
+mkUniqueNames env shadows tm 
+      = evalState (mkUniq initMap tm) (S.fromList env) where
 
-mkUniqueNames :: [Name] -> PTerm -> PTerm
-mkUniqueNames env tm = evalState (mkUniq tm) (S.fromList env) where
+  initMap = M.fromList shadows
+
   inScope :: S.Set Name
   inScope = S.fromList $ boundNamesIn tm
 
-  mkUniqA arg = do t' <- mkUniq (getTm arg)
-                   return (arg { getTm = t' })
+  mkUniqA nmap arg = do t' <- mkUniq nmap (getTm arg)
+                        return (arg { getTm = t' })
 
   -- Initialise the unique name with the environment length (so we're not
   -- looking for too long...)
@@ -2087,84 +2127,95 @@
 
   -- FIXME: Probably ought to do this for completeness! It's fine as
   -- long as there are no bindings inside tactics though.
-  mkUniqT tac = return tac
+  mkUniqT nmap tac = return tac
 
-  mkUniq :: PTerm -> State (S.Set Name) PTerm
-  mkUniq (PLam fc n nfc ty sc)
+  mkUniq :: M.Map Name Name -> PTerm -> State (S.Set Name) PTerm
+  mkUniq nmap (PLam fc n nfc ty sc)
          = do env <- get
               (n', sc') <-
                     if n `S.member` env
                        then do let n' = uniqueNameSet (initN n (S.size env))
                                                       (S.union env inScope)
-                               return (n', shadow n n' sc)
+                               return (n', sc) -- shadow n n' sc)
                        else return (n, sc)
               put (S.insert n' env)
-              ty' <- mkUniq ty
-              sc'' <- mkUniq sc'
+              let nmap' = M.insert n n' nmap
+              ty' <- mkUniq nmap ty
+              sc'' <- mkUniq nmap' sc'
               return $! PLam fc n' nfc ty' sc''
-  mkUniq (PPi p n fc ty sc)
+  mkUniq nmap (PPi p n fc ty sc)
          = do env <- get
               (n', sc') <-
                     if n `S.member` env
                        then do let n' = uniqueNameSet (initN n (S.size env))
                                                       (S.union env inScope)
-                               return (n', shadow n n' sc)
+                               return (n', sc) -- shadow n n' sc)
                        else return (n, sc)
               put (S.insert n' env)
-              ty' <- mkUniq ty
-              sc'' <- mkUniq sc'
+              let nmap' = M.insert n n' nmap
+              ty' <- mkUniq nmap ty
+              sc'' <- mkUniq nmap' sc'
               return $! PPi p n' fc ty' sc''
-  mkUniq (PLet fc n nfc ty val sc)
+  mkUniq nmap (PLet fc n nfc ty val sc)
          = do env <- get
               (n', sc') <-
                     if n `S.member` env
                        then do let n' = uniqueNameSet (initN n (S.size env))
                                                       (S.union env inScope)
-                               return (n', shadow n n' sc)
+                               return (n', sc) -- shadow n n' sc)
                        else return (n, sc)
               put (S.insert n' env)
-              ty' <- mkUniq ty; val' <- mkUniq val
-              sc'' <- mkUniq sc'
+              let nmap' = M.insert n n' nmap
+              ty' <- mkUniq nmap ty; val' <- mkUniq nmap val
+              sc'' <- mkUniq nmap' sc'
               return $! PLet fc n' nfc ty' val' sc''
-  mkUniq (PApp fc t args)
-         = do t' <- mkUniq t
-              args' <- mapM mkUniqA args
+  mkUniq nmap (PApp fc t args)
+         = do t' <- mkUniq nmap t
+              args' <- mapM (mkUniqA nmap) args
               return $! PApp fc t' args'
-  mkUniq (PAppBind fc t args)
-         = do t' <- mkUniq t
-              args' <- mapM mkUniqA args
+  mkUniq nmap (PAppBind fc t args)
+         = do t' <- mkUniq nmap t
+              args' <- mapM (mkUniqA nmap) args
               return $! PAppBind fc t' args'
-  mkUniq (PCase fc t alts)
-         = do t' <- mkUniq t
-              alts' <- mapM (\(x,y)-> do x' <- mkUniq x; y' <- mkUniq y
+  mkUniq nmap (PCase fc t alts)
+         = do t' <- mkUniq nmap t
+              alts' <- mapM (\(x,y)-> do x' <- mkUniq nmap x; y' <- mkUniq nmap y
                                          return (x', y')) alts
               return $! PCase fc t' alts'
-  mkUniq (PIfThenElse fc c t f)
-         = liftM3 (PIfThenElse fc) (mkUniq c) (mkUniq t) (mkUniq f)
-  mkUniq (PPair fc p l r)
-         = do l' <- mkUniq l; r' <- mkUniq r
-              return $! PPair fc p l' r'
-  mkUniq (PDPair fc p (PRef fc' n) t sc)
+  mkUniq nmap (PIfThenElse fc c t f)
+         = liftM3 (PIfThenElse fc) (mkUniq nmap c) (mkUniq nmap t) (mkUniq nmap f)
+  mkUniq nmap (PPair fc hls p l r)
+         = do l' <- mkUniq nmap l; r' <- mkUniq nmap r
+              return $! PPair fc hls p l' r'
+  mkUniq nmap (PDPair fc hls p (PRef fc' hls' n) t sc)
       | t /= Placeholder
          = do env <- get
               (n', sc') <- if n `S.member` env
                               then do let n' = uniqueNameSet n (S.union env inScope)
-                                      return (n', shadow n n' sc)
+                                      return (n', sc) -- shadow n n' sc)
                               else return (n, sc)
               put (S.insert n' env)
-              t' <- mkUniq t
-              sc'' <- mkUniq sc'
-              return $! PDPair fc p (PRef fc' n') t' sc''
-  mkUniq (PDPair fc p l t r)
-         = do l' <- mkUniq l; t' <- mkUniq t; r' <- mkUniq r
-              return $! PDPair fc p l' t' r'
-  mkUniq (PAlternative b as)
-         = liftM (PAlternative b) (mapM mkUniq as)
-  mkUniq (PHidden t) = liftM PHidden (mkUniq t)
-  mkUniq (PUnifyLog t) = liftM PUnifyLog (mkUniq t)
-  mkUniq (PDisamb n t) = liftM (PDisamb n) (mkUniq t)
-  mkUniq (PNoImplicits t) = liftM PNoImplicits (mkUniq t)
-  mkUniq (PProof ts) = liftM PProof (mapM mkUniqT ts)
-  mkUniq (PTactics ts) = liftM PTactics (mapM mkUniqT ts)
-  mkUniq (PRunElab fc ts) = liftM (PRunElab fc ) (mkUniq ts)
-  mkUniq t = return t
+              let nmap' = M.insert n n' nmap
+              t' <- mkUniq nmap t
+              sc'' <- mkUniq nmap' sc'
+              return $! PDPair fc hls p (PRef fc' hls' n') t' sc''
+  mkUniq nmap (PDPair fc hls p l t r)
+         = do l' <- mkUniq nmap l; t' <- mkUniq nmap t; r' <- mkUniq nmap r
+              return $! PDPair fc hls p l' t' r'
+  mkUniq nmap (PAlternative ns b as)
+         -- store the nmap and defer the rest until we've pruned the set
+         -- during elaboration
+         = return $ PAlternative (M.toList nmap ++ ns) b as
+  mkUniq nmap (PHidden t) = liftM PHidden (mkUniq nmap t)
+  mkUniq nmap (PUnifyLog t) = liftM PUnifyLog (mkUniq nmap t)
+  mkUniq nmap (PDisamb n t) = liftM (PDisamb n) (mkUniq nmap t)
+  mkUniq nmap (PNoImplicits t) = liftM PNoImplicits (mkUniq nmap t)
+  mkUniq nmap (PProof ts) = liftM PProof (mapM (mkUniqT nmap) ts)
+  mkUniq nmap (PTactics ts) = liftM PTactics (mapM (mkUniqT nmap) ts)
+  mkUniq nmap (PRunElab fc ts ns) = liftM (\tm -> PRunElab fc tm ns) (mkUniq nmap ts)
+  mkUniq nmap (PConstSugar fc tm) = liftM (PConstSugar fc) (mkUniq nmap tm)
+  mkUniq nmap t = return (shadowAll (M.toList nmap) t)
+    where
+      shadowAll [] t = t
+      shadowAll ((n, n') : ns) t = shadow n n' (shadowAll ns t)
+
diff --git a/src/Idris/AbsSyntaxTree.hs b/src/Idris/AbsSyntaxTree.hs
--- a/src/Idris/AbsSyntaxTree.hs
+++ b/src/Idris/AbsSyntaxTree.hs
@@ -88,7 +88,9 @@
                          opt_origerr      :: Bool,
                          opt_autoSolve    :: Bool, -- ^ automatically apply "solve" tactic in prover
                          opt_autoImport   :: [FilePath], -- ^ e.g. Builtins+Prelude
-                         opt_optimise     :: [Optimisation]
+                         opt_optimise     :: [Optimisation],
+                         opt_printdepth   :: Maybe Int,
+                         opt_evaltypes    :: Bool -- ^ normalise types in :t
                        }
     deriving (Show, Eq)
 
@@ -113,10 +115,14 @@
                       , opt_autoSolve  = True
                       , opt_autoImport = []
                       , opt_optimise   = defaultOptimise
+                      , opt_printdepth = Just 5000
+                      , opt_evaltypes  = True
                       }
 
 data PPOption = PPOption {
     ppopt_impl :: Bool -- ^^ whether to show implicits
+  , ppopt_pinames :: Bool -- ^^ whether to show names in pi bindings
+  , ppopt_depth :: Maybe Int
 } deriving (Show)
 
 data Optimisation = PETransform -- partial eval and associated transforms
@@ -126,16 +132,22 @@
 
 -- | Pretty printing options with default verbosity.
 defaultPPOption :: PPOption
-defaultPPOption = PPOption { ppopt_impl = False }
+defaultPPOption = PPOption { ppopt_impl = False, 
+                             ppopt_pinames = False,
+                             ppopt_depth = Just 200 }
 
 -- | Pretty printing options with the most verbosity.
 verbosePPOption :: PPOption
-verbosePPOption = PPOption { ppopt_impl = True }
+verbosePPOption = PPOption { ppopt_impl = True,
+                             ppopt_pinames = True,
+                             ppopt_depth = Just 200 }
 
 -- | Get pretty printing options from the big options record.
 ppOption :: IOption -> PPOption
 ppOption opt = PPOption {
-    ppopt_impl = opt_showimp opt
+    ppopt_impl = opt_showimp opt,
+    ppopt_pinames = False,
+    ppopt_depth = opt_printdepth opt
 }
 
 -- | Get pretty printing options from an idris state record.
@@ -189,10 +201,11 @@
     idris_name :: Int,
     idris_lineapps :: [((FilePath, Int), PTerm)],
           -- ^ Full application LHS on source line
-    idris_metavars :: [(Name, (Maybe Name, Int, Bool))],
+    idris_metavars :: [(Name, (Maybe Name, Int, [Name], Bool))],
     -- ^ The currently defined but not proven metavariables. The Int
     -- is the number of vars to display as a context, the Maybe Name
-    -- is its top-level function, and the Bool is whether :p is
+    -- is its top-level function, the [Name] is the list of local variables
+    -- available for proof search and the Bool is whether :p is
     -- allowed
     idris_coercions :: [Name],
     idris_errRev :: [(Term, Term)],
@@ -205,7 +218,7 @@
     idris_cgflags :: [(Codegen, String)],
     idris_hdrs :: [(Codegen, String)],
     idris_imported :: [(FilePath, Bool)], -- ^ Imported ibc file names, whether public
-    proof_list :: [(Name, [String])],
+    proof_list :: [(Name, (Bool, [String]))],
     errSpan :: Maybe FC,
     parserWarnings :: [(FC, Err)],
     lastParse :: Maybe Name,
@@ -237,7 +250,9 @@
     elab_stack :: [(Name, Bool)], -- ^ Stack of names currently being elaborated, Bool set if it's an instance
                                   -- (instances appear twice; also as a funtion name)
     idris_symbols :: M.Map Name Name, -- ^ Symbol table (preserves sharing of names)
-    idris_exports :: [Name] -- ^ Functions with ExportList
+    idris_exports :: [Name], -- ^ Functions with ExportList
+    idris_highlightedRegions :: [(FC, OutputAnnotation)], -- ^ Highlighting information to output
+    idris_parserHighlights :: [(FC, OutputAnnotation)] -- ^ Highlighting information from the parser
    }
 
 -- Required for parsers library, and therefore trifecta
@@ -325,7 +340,7 @@
                    [] [] [] defaultOpts 6 [] [] [] [] emptySyntaxRules [] [] [] [] [] [] []
                    [] [] Nothing [] Nothing [] [] Nothing Nothing [] Hidden False [] Nothing [] []
                    (RawOutput stdout) True defaultTheme [] (0, emptyContext) emptyContext M.empty
-                   AutomaticWidth S.empty S.empty [] Nothing Nothing [] [] M.empty []
+                   AutomaticWidth S.empty S.empty [] Nothing Nothing [] [] M.empty [] [] []
 
 -- | The monad for the main REPL - reading and processing files and updating
 -- global state (hence the IO inner monad).
@@ -373,7 +388,7 @@
              | Execute PTerm
              | ExecVal PTerm
              | Metavars
-             | Prove Name
+             | Prove Bool Name -- ^ If false, use prover, if true, use elab shell
              | AddProof (Maybe Name)
              | RmProof Name
              | ShowProof Name
@@ -381,7 +396,7 @@
              | Universes
              | LogLvl Int
              | Spec PTerm
-             | HNF PTerm
+             | WHNF PTerm
              | TestInline PTerm
              | Defn Name
              | Missing Name
@@ -394,10 +409,13 @@
              | AddProofClauseFrom Bool Int Name
              | AddMissing Bool Int Name
              | MakeWith Bool Int Name
+             | MakeCase Bool Int Name
              | MakeLemma Bool Int Name
-             | DoProofSearch Bool Bool Int Name [Name]
-               -- ^ the first bool is whether to update,
-               -- the second is whether to search recursively (i.e. for the arguments)
+             | DoProofSearch Bool -- update file
+                             Bool -- recursive search
+                             Int -- depth
+                             Name -- top level name
+                             [Name] -- hints
              | SetOpt Opt
              | UnsetOpt Opt
              | NOP
@@ -406,6 +424,7 @@
              | ColourOff
              | ListErrorHandlers
              | SetConsoleWidth ConsoleWidth
+             | SetPrinterDepth (Maybe Int)
              | Apropos [String] String
              | WhoCalls Name
              | CallsWho Name
@@ -444,6 +463,7 @@
          | DefaultPartial
          | WarnPartial
          | WarnReach
+         | EvalTypes
          | NoCoverage
          | ErrContext
          | ShowImpl
@@ -465,6 +485,7 @@
          | DumpDefun String
          | DumpCases String
          | UseCodegen Codegen
+         | CodegenArgs String
          | OutputTy OutputType
          | Extension LanguageExt
          | InterpretScript String
@@ -479,8 +500,14 @@
          | AutoWidth -- ^ Automatically adjust terminal width
          | AutoSolve -- ^ Automatically issue "solve" tactic in interactive prover
          | UseConsoleWidth ConsoleWidth
+         | DumpHighlights
     deriving (Show, Eq)
 
+data ElabShellCmd = EQED | EAbandon | EUndo | EProofState | EProofTerm
+                  | EEval PTerm | ECheck PTerm | ESearch PTerm
+                  | EDocStr (Either Name Const)
+  deriving (Show, Eq)
+
 -- Parsed declarations
 
 data Fixity = Infixl { prec :: Int }
@@ -568,6 +595,7 @@
            | Specialise [(Name, Maybe Int)] -- specialise it, freeze these names
            | Constructor -- Data constructor type
            | AutoHint -- use in auto implicit search
+           | PEGenerated -- generated by partial evaluator
     deriving (Show, Eq)
 {-!
 deriving instance Binary FnOpt
@@ -594,41 +622,41 @@
 -- datatypes and typeclasses.
 data PDecl' t
    = PFix     FC Fixity [String] -- ^ Fixity declaration
-   | PTy      (Docstring (Either Err PTerm)) [(Name, Docstring (Either Err PTerm))] SyntaxInfo FC FnOpts Name FC t   -- ^ Type declaration (last FC is precise name location)
+   | PTy      (Docstring (Either Err t)) [(Name, Docstring (Either Err t))] SyntaxInfo FC FnOpts Name FC t   -- ^ Type declaration (last FC is precise name location)
    | PPostulate Bool -- external def if true
-          (Docstring (Either Err PTerm)) SyntaxInfo FC FnOpts Name t -- ^ Postulate
+          (Docstring (Either Err t)) SyntaxInfo FC FC FnOpts Name t -- ^ Postulate, second FC is precise name location
    | PClauses FC FnOpts Name [PClause' t]   -- ^ Pattern clause
    | PCAF     FC Name t -- ^ Top level constant
-   | PData    (Docstring (Either Err PTerm)) [(Name, Docstring (Either Err PTerm))] SyntaxInfo FC DataOpts (PData' t)  -- ^ Data declaration.
+   | PData    (Docstring (Either Err t)) [(Name, Docstring (Either Err t))] SyntaxInfo FC DataOpts (PData' t)  -- ^ Data declaration.
    | PParams  FC [(Name, t)] [PDecl' t] -- ^ Params block
    | PNamespace String FC [PDecl' t]
      -- ^ New namespace, where FC is accurate location of the
      -- namespace in the file
-   | PRecord  (Docstring (Either Err PTerm)) SyntaxInfo FC DataOpts
+   | PRecord  (Docstring (Either Err t)) SyntaxInfo FC DataOpts
               Name                 -- Record name
               FC                   -- Record name precise location
               [(Name, FC, Plicity, t)] -- Parameters, where FC is precise name span
-              [(Name, Docstring (Either Err PTerm))] -- Param Docs
-              [((Maybe (Name, FC)), Plicity, t, Maybe (Docstring (Either Err PTerm)))] -- Fields
+              [(Name, Docstring (Either Err t))] -- Param Docs
+              [((Maybe (Name, FC)), Plicity, t, Maybe (Docstring (Either Err t)))] -- Fields
               (Maybe (Name, FC)) -- Optional constructor name and location
-              (Docstring (Either Err PTerm)) -- Constructor doc
+              (Docstring (Either Err t)) -- Constructor doc
               SyntaxInfo -- Constructor SyntaxInfo
               -- ^ Record declaration
-   | PClass   (Docstring (Either Err PTerm)) SyntaxInfo FC
+   | PClass   (Docstring (Either Err t)) SyntaxInfo FC
               [(Name, t)] -- constraints
               Name -- class name
               FC -- accurate location of class name
               [(Name, FC, t)] -- parameters and precise locations
-              [(Name, Docstring (Either Err PTerm))] -- parameter docstrings
+              [(Name, Docstring (Either Err t))] -- parameter docstrings
               [(Name, FC)] -- determining parameters and precise locations
               [PDecl' t] -- declarations
               (Maybe (Name, FC)) -- instance constructor name and location
-              (Docstring (Either Err PTerm)) -- instance constructor docs
+              (Docstring (Either Err t)) -- instance constructor docs
               -- ^ Type class: arguments are documentation, syntax info, source location, constraints,
               -- class name, class name location, parameters, method declarations, optional constructor name
    | PInstance
-       (Docstring (Either Err PTerm)) -- Instance docs
-       [(Name, Docstring (Either Err PTerm))] -- Parameter docs
+       (Docstring (Either Err t)) -- Instance docs
+       [(Name, Docstring (Either Err t))] -- Parameter docs
        SyntaxInfo
        FC [(Name, t)] -- constraints
        Name -- class
@@ -644,9 +672,11 @@
    | PSyntax  FC Syntax -- ^ Syntax definition
    | PMutual  FC [PDecl' t] -- ^ Mutual block
    | PDirective Directive -- ^ Compiler directive.
-   | PProvider (Docstring (Either Err PTerm)) SyntaxInfo FC (ProvideWhat' t) Name -- ^ Type provider. The first t is the type, the second is the term
+   | PProvider (Docstring (Either Err t)) SyntaxInfo FC FC (ProvideWhat' t) Name -- ^ Type provider. The first t is the type, the second is the term. The second FC is precise highlighting location.
    | PTransform FC Bool t t -- ^ Source-to-source transformation rule. If
                             -- bool is True, lhs and rhs must be convertible
+   | PRunElabDecl FC t [String] -- ^ FC is decl-level, for errors, and
+                                -- Strings represent the namespace
  deriving Functor
 {-!
 deriving instance Binary PDecl'
@@ -664,8 +694,8 @@
                  DDefault Bool |
                  DLogging Integer |
                  DDynamicLibs [String] |
-                 DNameHint Name [Name] |
-                 DErrorHandlers Name Name [Name] |
+                 DNameHint Name FC [(Name, FC)] |
+                 DErrorHandlers Name FC Name FC [(Name, FC)] |
                  DLanguage LanguageExt |
                  DUsed FC Name Name
 
@@ -722,6 +752,18 @@
                | PLaterdecl { d_name :: Name, d_name_fc :: FC, d_tcon :: t }
                  -- ^ "Placeholder" for data whose constructors are defined later
     deriving Functor
+    
+-- | Transform the FCs in a PData and its associated terms. The first
+-- function transforms the general-purpose FCs, and the second transforms
+-- those that are used for semantic source highlighting, so they can be
+-- treated specially.
+mapPDataFC :: (FC -> FC) -> (FC -> FC) -> PData -> PData
+mapPDataFC f g (PDatadecl n nfc tycon ctors) =
+  PDatadecl n (g nfc) (mapPTermFC f g tycon) (map ctorFC ctors)
+    where ctorFC (doc, argDocs, n, nfc, ty, fc, ns) =
+                 (doc, argDocs, n, g nfc, mapPTermFC f g ty, f fc, ns)
+mapPDataFC f g (PLaterdecl n nfc tycon) =
+  PLaterdecl n (g nfc) (mapPTermFC f g tycon)
 {-!
 deriving instance Binary PData'
 deriving instance NFData PData'
@@ -734,12 +776,80 @@
 type PData   = PData' PTerm
 type PClause = PClause' PTerm
 
--- get all the names declared in a decl
+-- | Transform the FCs in a PTerm. The first function transforms the
+-- general-purpose FCs, and the second transforms those that are used
+-- for semantic source highlighting, so they can be treated specially.
+mapPDeclFC :: (FC -> FC) -> (FC -> FC) -> PDecl -> PDecl
+mapPDeclFC f g (PFix fc fixity ops) =
+    PFix (f fc) fixity ops
+mapPDeclFC f g (PTy doc argdocs syn fc opts n nfc ty) =
+    PTy doc argdocs syn (f fc) opts n (g nfc) (mapPTermFC f g ty)
+mapPDeclFC f g (PPostulate ext doc syn fc nfc opts n ty) =
+    PPostulate ext doc syn (f fc) (g nfc) opts n (mapPTermFC f g ty)
 
+mapPDeclFC f g (PClauses fc opts n clauses) =
+    PClauses (f fc) opts n (map (fmap (mapPTermFC f g)) clauses)
+mapPDeclFC f g (PCAF fc n tm) = PCAF (f fc) n (mapPTermFC f g tm)
+mapPDeclFC f g (PData doc argdocs syn fc opts dat) =
+    PData doc argdocs syn (f fc) opts (mapPDataFC f g dat)
+mapPDeclFC f g (PParams fc params decls) =
+    PParams (f fc)
+            (map (\(n, ty) -> (n, mapPTermFC f g ty)) params)
+            (map (mapPDeclFC f g) decls)
+mapPDeclFC f g (PNamespace ns fc decls) =
+    PNamespace ns (f fc) (map (mapPDeclFC f g) decls)
+mapPDeclFC f g (PRecord doc syn fc opts n nfc params paramdocs fields ctor ctorDoc syn') =
+    PRecord doc syn (f fc) opts n (g nfc)
+            (map (\(pn, pnfc, plic, ty) -> (pn, g pnfc, plic, mapPTermFC f g ty)) params)
+            paramdocs
+            (map (\(fn, plic, ty, fdoc) -> (fmap (\(fn', fnfc) -> (fn', g fnfc)) fn,
+                                            plic, mapPTermFC f g ty, fdoc))
+                 fields)
+            (fmap (\(ctorN, ctorNFC) -> (ctorN, g ctorNFC)) ctor)
+            ctorDoc
+            syn'
+mapPDeclFC f g (PClass doc syn fc constrs n nfc params paramDocs det body ctor ctorDoc) =
+    PClass doc syn (f fc)
+           (map (\(constrn, constr) -> (constrn, mapPTermFC f g constr)) constrs)
+           n (g nfc) (map (\(n, nfc, pty) -> (n, g nfc, mapPTermFC f g pty)) params)
+           paramDocs (map (\(dn, dnfc) -> (dn, g dnfc)) det)
+           (map (mapPDeclFC f g) body)
+           (fmap (\(n, nfc) -> (n, g nfc)) ctor)
+           ctorDoc
+mapPDeclFC f g (PInstance doc paramDocs syn fc constrs cn cnfc params instTy instN body) =
+    PInstance doc paramDocs syn (f fc)
+              (map (\(constrN, constrT) -> (constrN, mapPTermFC f g constrT)) constrs)
+              cn (g cnfc) (map (mapPTermFC f g) params)
+              (mapPTermFC f g instTy)
+              instN
+              (map (mapPDeclFC f g) body)
+mapPDeclFC f g (PDSL n dsl) = PDSL n (fmap (mapPTermFC f g) dsl)
+mapPDeclFC f g (PSyntax fc syn) = PSyntax (f fc) $
+                                    case syn of
+                                      Rule syms tm ctxt -> Rule syms (mapPTermFC f g tm) ctxt
+                                      DeclRule syms decls -> DeclRule syms (map (mapPDeclFC f g) decls)
+mapPDeclFC f g (PMutual fc decls) =
+    PMutual (f fc) (map (mapPDeclFC f g) decls)
+mapPDeclFC f g (PDirective d) =
+    PDirective $
+      case d of
+        DNameHint n nfc ns ->
+            DNameHint n (g nfc) (map (\(hn, hnfc) -> (hn, g hnfc)) ns)
+        DErrorHandlers n nfc n' nfc' ns ->
+            DErrorHandlers n (g nfc) n' (g nfc') $
+                map (\(an, anfc) -> (an, g anfc)) ns
+mapPDeclFC f g (PProvider doc syn fc nfc what n) =
+    PProvider doc syn (f fc) (g nfc) (fmap (mapPTermFC f g) what) n
+mapPDeclFC f g (PTransform fc safe l r) =
+    PTransform (f fc) safe (mapPTermFC f g l) (mapPTermFC f g r)
+mapPDeclFC f g (PRunElabDecl fc script ns) =
+    PRunElabDecl (f fc) (mapPTermFC f g script) ns
+
+-- | Get all the names declared in a declaration
 declared :: PDecl -> [Name]
 declared (PFix _ _ _) = []
 declared (PTy _ _ _ _ _ n fc t) = [n]
-declared (PPostulate _ _ _ _ _ n t) = [n]
+declared (PPostulate _ _ _ _ _ _ n t) = [n]
 declared (PClauses _ _ n _) = [] -- not a declaration
 declared (PCAF _ n _) = [n]
 declared (PData _ _ _ _ _ (PDatadecl n _ _ ts)) = n : map fstt ts
@@ -760,7 +870,7 @@
 tldeclared :: PDecl -> [Name]
 tldeclared (PFix _ _ _) = []
 tldeclared (PTy _ _ _ _ _ n _ t) = [n]
-tldeclared (PPostulate _ _ _ _ _ n t) = [n]
+tldeclared (PPostulate _ _ _ _ _ _ n t) = [n]
 tldeclared (PClauses _ _ n _) = [] -- not a declaration
 tldeclared (PRecord _ _ _ _ n _ _ _ _ cn _ _) = n : map fst (maybeToList cn)
 tldeclared (PData _ _ _ _ _ (PDatadecl n _ _ ts)) = n : map fstt ts
@@ -775,7 +885,7 @@
 defined :: PDecl -> [Name]
 defined (PFix _ _ _) = []
 defined (PTy _ _ _ _ _ n _ t) = []
-defined (PPostulate _ _ _ _ _ n t) = []
+defined (PPostulate _ _ _ _ _ _ n t) = []
 defined (PClauses _ _ n _) = [n] -- not a declaration
 defined (PCAF _ n _) = [n]
 defined (PData _ _ _ _ _ (PDatadecl n _ _ ts)) = n : map fstt ts
@@ -799,7 +909,7 @@
 updateNs :: [(Name, Name)] -> PTerm -> PTerm
 updateNs [] t = t
 updateNs ns t = mapPT updateRef t
-  where updateRef (PRef fc f) = PRef fc (updateN ns f)
+  where updateRef (PRef fc fcs f) = PRef fc fcs (updateN ns f)
         updateRef t = t
 
 -- updateDNs :: [(Name, Name)] -> PDecl -> PDecl
@@ -817,8 +927,8 @@
 
 -- | High level language terms
 data PTerm = PQuote Raw -- ^ Inclusion of a core term into the high-level language
-           | PRef FC Name -- ^ A reference to a variable
-           | PInferRef FC Name -- ^ A name to be defined later
+           | PRef FC [FC] Name -- ^ A reference to a variable. The FC is its precise source location for highlighting. The list of FCs is a collection of additional highlighting locations.
+           | PInferRef FC [FC] Name -- ^ A name to be defined later
            | PPatvar FC Name -- ^ A pattern variable
            | PLam FC Name FC PTerm PTerm -- ^ A lambda abstraction. Second FC is name span.
            | PPi  Plicity Name FC PTerm PTerm -- ^ (n : t1) -> t2, where the FC is for the precise location of the variable
@@ -833,10 +943,10 @@
            | PTrue FC PunInfo -- ^ Unit type..?
            | PResolveTC FC -- ^ Solve this dictionary by type class resolution
            | PRewrite FC PTerm PTerm (Maybe PTerm) -- ^ "rewrite" syntax, with optional result type
-           | PPair FC PunInfo PTerm PTerm -- ^ A pair (a, b) and whether it's a product type or a pair (solved by elaboration)
-           | PDPair FC PunInfo PTerm PTerm PTerm -- ^ A dependent pair (tm : a ** b) and whether it's a sigma type or a pair that inhabits one (solved by elaboration)
+           | PPair FC [FC] PunInfo PTerm PTerm -- ^ A pair (a, b) and whether it's a product type or a pair (solved by elaboration). The list of FCs is its punctuation.
+           | PDPair FC [FC] PunInfo PTerm PTerm PTerm -- ^ A dependent pair (tm : a ** b) and whether it's a sigma type or a pair that inhabits one (solved by elaboration). The [FC] is its punctuation.
            | PAs FC Name PTerm -- ^ @-pattern, valid LHS only
-           | PAlternative PAltType [PTerm] -- ^ True if only one may work. (| A, B, C|)
+           | PAlternative [(Name, Name)] PAltType [PTerm] -- ^ (| A, B, C|). Includes unapplied unique name mappings for mkUniqueNames.
            | PHidden PTerm -- ^ Irrelevant or hidden pattern
            | PType FC -- ^ 'Type' type
            | PUniverse Universe -- ^ Some universe
@@ -857,16 +967,73 @@
            | PNoImplicits PTerm -- ^ never run implicit converions on the term
            | PQuasiquote PTerm (Maybe PTerm) -- ^ `(Term [: Term])
            | PUnquote PTerm -- ^ ~Term
-           | PQuoteName Name -- ^ `{n}
-           | PRunElab FC PTerm -- ^ %runElab tm - New-style proof script
+           | PQuoteName Name FC -- ^ `{n} where the FC is the precise highlighting for the name in particular
+           | PRunElab FC PTerm [String] -- ^ %runElab tm - New-style proof script. Args are location, script, enclosing namespace.
+           | PConstSugar FC PTerm -- ^ A desugared constant. The FC is a precise source location that will be used to highlight it later.
        deriving (Eq, Data, Typeable)
 
 data PAltType = ExactlyOne Bool -- ^ flag sets whether delay is allowed
-              | FirstSuccess 
+              | FirstSuccess
+              | TryImplicit
        deriving (Eq, Data, Typeable)
 
+-- | Transform the FCs in a PTerm. The first function transforms the
+-- general-purpose FCs, and the second transforms those that are used
+-- for semantic source highlighting, so they can be treated specially.
+mapPTermFC :: (FC -> FC) -> (FC -> FC) -> PTerm -> PTerm
+mapPTermFC f g (PQuote q) = PQuote q
+mapPTermFC f g (PRef fc fcs n) = PRef (g fc) (map g fcs) n
+mapPTermFC f g (PInferRef fc fcs n) = PInferRef (g fc) (map g fcs) n
+mapPTermFC f g (PPatvar fc n) = PPatvar (g fc) n
+mapPTermFC f g (PLam fc n fc' t1 t2) = PLam (f fc) n (g fc') (mapPTermFC f g t1) (mapPTermFC f g t2)
+mapPTermFC f g (PPi plic n fc t1 t2) = PPi plic n (g fc) (mapPTermFC f g t1) (mapPTermFC f g t2)
+mapPTermFC f g (PLet fc n fc' t1 t2 t3) = PLet (f fc) n (g fc') (mapPTermFC f g t1) (mapPTermFC f g t2) (mapPTermFC f g t3)
+mapPTermFC f g (PTyped t1 t2) = PTyped (mapPTermFC f g t1) (mapPTermFC f g t2)
+mapPTermFC f g (PApp fc t args) = PApp (f fc) (mapPTermFC f g t) (map (fmap (mapPTermFC f g)) args)
+mapPTermFC f g (PAppImpl t1 impls) = PAppImpl (mapPTermFC f g t1) impls
+mapPTermFC f g (PAppBind fc t args) = PAppBind (f fc) (mapPTermFC f g t) (map (fmap (mapPTermFC f g)) args)
+mapPTermFC f g (PMatchApp fc n) = PMatchApp (f fc) n
+mapPTermFC f g (PIfThenElse fc t1 t2 t3) = PIfThenElse (f fc) (mapPTermFC f g t1) (mapPTermFC f g t2) (mapPTermFC f g t3)
+mapPTermFC f g (PCase fc t cases) = PCase (f fc) (mapPTermFC f g t) (map (\(l,r) -> (mapPTermFC f g l, mapPTermFC f g r)) cases)
+mapPTermFC f g (PTrue fc info) = PTrue (f fc) info
+mapPTermFC f g (PResolveTC fc) =  PResolveTC (f fc)
+mapPTermFC f g (PRewrite fc t1 t2 t3) = PRewrite (f fc) (mapPTermFC f g t1) (mapPTermFC f g t2) (fmap (mapPTermFC f g) t3)
+mapPTermFC f g (PPair fc hls info t1 t2) = PPair (f fc) (map g hls) info (mapPTermFC f g t1) (mapPTermFC f g t2)
+mapPTermFC f g (PDPair fc hls info t1 t2 t3) = PDPair (f fc) (map g hls) info (mapPTermFC f g t1) (mapPTermFC f g t2) (mapPTermFC f g t3)
+mapPTermFC f g (PAs fc n t) = PAs (f fc) n (mapPTermFC f g t)
+mapPTermFC f g (PAlternative ns ty ts) = PAlternative ns ty (map (mapPTermFC f g) ts)
+mapPTermFC f g (PHidden t) = PHidden (mapPTermFC f g t)
+mapPTermFC f g (PType fc) = PType (f fc)
+mapPTermFC f g (PUniverse u) = PUniverse u
+mapPTermFC f g (PGoal fc t1 n t2) = PGoal (f fc) (mapPTermFC f g t1) n (mapPTermFC f g t2)
+mapPTermFC f g (PConstant fc c) = PConstant (f fc) c
+mapPTermFC f g Placeholder = Placeholder
+mapPTermFC f g (PDoBlock dos) = PDoBlock (map mapPDoFC dos)
+  where mapPDoFC (DoExp  fc t) = DoExp (f fc) (mapPTermFC f g t)
+        mapPDoFC (DoBind fc n nfc t) = DoBind (f fc) n (g nfc) (mapPTermFC f g t)
+        mapPDoFC (DoBindP fc t1 t2 alts) =
+          DoBindP (f fc) (mapPTermFC f g t1) (mapPTermFC f g t2) (map (\(l,r)-> (mapPTermFC f g l, mapPTermFC f g r)) alts)
+        mapPDoFC (DoLet fc n nfc t1 t2) = DoLet (f fc) n (g nfc) (mapPTermFC f g t1) (mapPTermFC f g t2)
+        mapPDoFC (DoLetP fc t1 t2) = DoLetP (f fc) (mapPTermFC f g t1) (mapPTermFC f g t2)
+mapPTermFC f g (PIdiom fc t) = PIdiom (f fc) (mapPTermFC f g t)
+mapPTermFC f g (PReturn fc) = PReturn (f fc)
+mapPTermFC f g (PMetavar fc n) = PMetavar (g fc) n
+mapPTermFC f g (PProof tacs) = PProof (map (fmap (mapPTermFC f g)) tacs)
+mapPTermFC f g (PTactics tacs) = PTactics (map (fmap (mapPTermFC f g)) tacs)
+mapPTermFC f g (PElabError err) = PElabError err
+mapPTermFC f g PImpossible = PImpossible
+mapPTermFC f g (PCoerced t) = PCoerced (mapPTermFC f g t)
+mapPTermFC f g (PDisamb msg t) = PDisamb msg (mapPTermFC f g t)
+mapPTermFC f g (PUnifyLog t) = PUnifyLog (mapPTermFC f g t)
+mapPTermFC f g (PNoImplicits t) = PNoImplicits (mapPTermFC f g t)
+mapPTermFC f g (PQuasiquote t1 t2) = PQuasiquote (mapPTermFC f g t1) (fmap (mapPTermFC f g) t2)
+mapPTermFC f g (PUnquote t) = PUnquote (mapPTermFC f g t)
+mapPTermFC f g (PRunElab fc tm ns) = PRunElab (f fc) (mapPTermFC f g tm) ns
+mapPTermFC f g (PConstSugar fc tm) = PConstSugar (g fc) (mapPTermFC f g tm)
+mapPTermFC f g (PQuoteName n fc) = PQuoteName n (g fc)
+
 {-!
-deriving instance Binary PTerm
+dg instance Binary PTerm
 deriving instance NFData PTerm
 !-}
 
@@ -882,9 +1049,9 @@
   mpt (PCase fc c os) = PCase fc (mapPT f c) (map (pmap (mapPT f)) os)
   mpt (PIfThenElse fc c t e) = PIfThenElse fc (mapPT f c) (mapPT f t) (mapPT f e)
   mpt (PTyped l r) = PTyped (mapPT f l) (mapPT f r)
-  mpt (PPair fc p l r) = PPair fc p (mapPT f l) (mapPT f r)
-  mpt (PDPair fc p l t r) = PDPair fc p (mapPT f l) (mapPT f t) (mapPT f r)
-  mpt (PAlternative a as) = PAlternative a (map (mapPT f) as)
+  mpt (PPair fc hls p l r) = PPair fc hls p (mapPT f l) (mapPT f r)
+  mpt (PDPair fc hls p l t r) = PDPair fc hls p (mapPT f l) (mapPT f t) (mapPT f r)
+  mpt (PAlternative ns a as) = PAlternative ns a (map (mapPT f) as)
   mpt (PHidden t) = PHidden (mapPT f t)
   mpt (PDoBlock ds) = PDoBlock (map (fmap (mapPT f)) ds)
   mpt (PProof ts) = PProof (map (fmap (mapPT f)) ts)
@@ -906,7 +1073,9 @@
                 | MatchRefine Name
                 | LetTac Name t | LetTacTy Name t t
                 | Exact t | Compute | Trivial | TCInstance
-                | ProofSearch Bool Bool Int (Maybe Name) [Name]
+                | ProofSearch Bool Bool Int (Maybe Name) 
+                              [Name] -- allowed local names
+                              [Name] -- hints
                   -- ^ the bool is whether to search recursively
                 | Solve
                 | Attack
@@ -957,6 +1126,14 @@
   size Skip = 1
   size (TFail ts) = 1 + size ts
   size SourceFC = 1
+  size DoUnify = 1
+  size (CaseTac x) = 1 + size x
+  size (Equiv t) = 1 + size t
+  size (Claim x y) = 1 + size x + size y
+  size Unfocus = 1
+  size (MatchRefine x) = 1 + size x
+  size (LetTacTy x y z) = 1 + size x + size y + size z
+  size TCInstance = 1
 
 type PTactic = PTactic' PTerm
 
@@ -1028,8 +1205,8 @@
 -- | Get the highest FC in a term, if one exists
 highestFC :: PTerm -> Maybe FC
 highestFC (PQuote _) = Nothing
-highestFC (PRef fc _) = Just fc
-highestFC (PInferRef fc _) = Just fc
+highestFC (PRef fc _ _) = Just fc
+highestFC (PInferRef fc _ _) = Just fc
 highestFC (PPatvar fc _) = Just fc
 highestFC (PLam fc _ _ _ _) = Just fc
 highestFC (PPi _ _ _ _ _) = Nothing
@@ -1043,10 +1220,10 @@
 highestFC (PTrue fc _) = Just fc
 highestFC (PResolveTC fc) = Just fc
 highestFC (PRewrite fc _ _ _) = Just fc
-highestFC (PPair fc _ _ _) = Just fc
-highestFC (PDPair fc _ _ _ _) = Just fc
+highestFC (PPair fc _ _ _ _) = Just fc
+highestFC (PDPair fc _ _ _ _ _) = Just fc
 highestFC (PAs fc _ _) = Just fc
-highestFC (PAlternative _ args) =
+highestFC (PAlternative _ _ args) =
   case mapMaybe highestFC args of
     [] -> Nothing
     (fc:_) -> Just fc
@@ -1080,7 +1257,10 @@
 highestFC (PNoImplicits tm) = highestFC tm
 highestFC (PQuasiquote _ _) = Nothing
 highestFC (PUnquote tm) = highestFC tm
-highestFC (PQuoteName _) = Nothing
+highestFC (PQuoteName _ fc) = Just fc
+highestFC (PRunElab fc _ _) = Just fc
+highestFC (PConstSugar fc _) = Just fc
+highestFC (PAppImpl t _) = highestFC t
 
 -- Type class data
 
@@ -1147,15 +1327,20 @@
 !-}
 
 data Syntax = Rule [SSymbol] PTerm SynContext
+            | DeclRule [SSymbol] [PDecl]
     deriving Show
 
 syntaxNames :: Syntax -> [Name]
 syntaxNames (Rule syms _ _) = mapMaybe ename syms
            where ename (Keyword n) = Just n
                  ename _           = Nothing
+syntaxNames (DeclRule syms _) = mapMaybe ename syms
+           where ename (Keyword n) = Just n
+                 ename _           = Nothing
 
 syntaxSymbols :: Syntax -> [SSymbol]
 syntaxSymbols (Rule ss _ _) = ss
+syntaxSymbols (DeclRule ss _) = ss
 {-!
 deriving instance Binary Syntax
 deriving instance NFData Syntax
@@ -1214,10 +1399,10 @@
     symCompare (SimpleExpr _) (Expr _) = GT
     symCompare (SimpleExpr e1) (SimpleExpr e2) = compare e1 e2
 
-initDSL = DSL (PRef f (sUN ">>="))
-              (PRef f (sUN "return"))
-              (PRef f (sUN "<*>"))
-              (PRef f (sUN "pure"))
+initDSL = DSL (PRef f [] (sUN ">>="))
+              (PRef f [] (sUN "return"))
+              (PRef f [] (sUN "<*>"))
+              (PRef f [] (sUN "pure"))
               Nothing
               Nothing
               Nothing
@@ -1228,7 +1413,7 @@
 
 data Using = UImplicit Name PTerm
            | UConstraint Name [Name]
-    deriving (Show, Eq)
+    deriving (Show, Eq, Data, Typeable)
 {-!
 deriving instance Binary Using
 deriving instance NFData Using
@@ -1272,11 +1457,11 @@
 inferDecl = PDatadecl inferTy NoFC
                       (PType bi)
                       [(emptyDocstring, [], inferCon, NoFC, PPi impl (sMN 0 "iType") NoFC (PType bi) (
-                                                   PPi expl (sMN 0 "ival") NoFC (PRef bi (sMN 0 "iType"))
-                                                   (PRef bi inferTy)), bi, [])]
+                                                   PPi expl (sMN 0 "ival") NoFC (PRef bi [] (sMN 0 "iType"))
+                                                   (PRef bi [] inferTy)), bi, [])]
 inferOpts = []
 
-infTerm t = PApp bi (PRef bi inferCon) [pimp (sMN 0 "iType") Placeholder True, pexp t]
+infTerm t = PApp bi (PRef bi [] inferCon) [pimp (sMN 0 "iType") Placeholder True, pexp t]
 infP = P (TCon 6 0) inferTy (TType (UVal 0))
 
 getInferTerm, getInferType :: Term -> Term
@@ -1327,15 +1512,15 @@
           "You may need to use `(~=~)` to explicitly request heterogeneous equality."
 
 eqDecl = PDatadecl eqTy NoFC (piBindp impl [(n "A", PType bi), (n "B", PType bi)]
-                                      (piBind [(n "x", PRef bi (n "A")), (n "y", PRef bi (n "B"))]
+                                      (piBind [(n "x", PRef bi [] (n "A")), (n "y", PRef bi [] (n "B"))]
                                       (PType bi)))
                 [(reflDoc, reflParamDoc,
                   eqCon, NoFC, PPi impl (n "A") NoFC (PType bi) (
-                                        PPi impl (n "x") NoFC (PRef bi (n "A"))
-                                            (PApp bi (PRef bi eqTy) [pimp (n "A") Placeholder False,
+                                        PPi impl (n "x") NoFC (PRef bi [] (n "A"))
+                                            (PApp bi (PRef bi [] eqTy) [pimp (n "A") Placeholder False,
                                                                      pimp (n "B") Placeholder False,
-                                                                     pexp (PRef bi (n "x")),
-                                                                     pexp (PRef bi (n "x"))])), bi, [])]
+                                                                     pexp (PRef bi [] (n "x")),
+                                                                     pexp (PRef bi [] (n "x"))])), bi, [])]
     where n a = sUN a
           reflDoc = annotCode (const (Left $ Msg "")) . parseDocstring . T.pack $
                       "A proof that `x` in fact equals `x`. To construct this, you must have already " ++
@@ -1391,34 +1576,42 @@
 -- | Colourise annotations according to an Idris state. It ignores the names
 -- in the annotation, as there's no good way to show extended information on a
 -- terminal.
-consoleDecorate :: IState -> OutputAnnotation -> String -> String
-consoleDecorate ist _ | not (idris_colourRepl ist) = id
-consoleDecorate ist (AnnConst c) = let theme = idris_colourTheme ist
-                                   in if constIsType c
-                                        then colouriseType theme
-                                        else colouriseData theme
-consoleDecorate ist (AnnData _ _) = colouriseData (idris_colourTheme ist)
-consoleDecorate ist (AnnType _ _) = colouriseType (idris_colourTheme ist)
-consoleDecorate ist (AnnBoundName _ True) = colouriseImplicit (idris_colourTheme ist)
-consoleDecorate ist (AnnBoundName _ False) = colouriseBound (idris_colourTheme ist)
-consoleDecorate ist AnnKeyword = colouriseKeyword (idris_colourTheme ist)
-consoleDecorate ist (AnnName n _ _ _) = let ctxt  = tt_ctxt ist
-                                            theme = idris_colourTheme ist
-                                        in case () of
-                                             _ | isDConName n ctxt     -> colouriseData theme
-                                             _ | isFnName n ctxt       -> colouriseFun theme
-                                             _ | isTConName n ctxt     -> colouriseType theme
-                                             _ | isPostulateName n ist -> colourisePostulate theme
-                                             _ | otherwise             -> id -- don't colourise unknown names
-consoleDecorate ist (AnnFC _) = id
-consoleDecorate ist (AnnTextFmt fmt) = Idris.Colours.colourise (colour fmt)
+annotationColour :: IState -> OutputAnnotation -> Maybe IdrisColour
+annotationColour ist _ | not (idris_colourRepl ist) = Nothing
+annotationColour ist (AnnConst c) =
+    let theme = idris_colourTheme ist
+    in Just $ if constIsType c
+                then typeColour theme
+                else dataColour theme
+annotationColour ist (AnnData _ _) = Just $ dataColour (idris_colourTheme ist)
+annotationColour ist (AnnType _ _) = Just $ typeColour (idris_colourTheme ist)
+annotationColour ist (AnnBoundName _ True) = Just $ implicitColour (idris_colourTheme ist)
+annotationColour ist (AnnBoundName _ False) = Just $ boundVarColour (idris_colourTheme ist)
+annotationColour ist AnnKeyword = Just $ keywordColour (idris_colourTheme ist)
+annotationColour ist (AnnName n _ _ _) =
+  let ctxt = tt_ctxt ist
+      theme = idris_colourTheme ist
+  in case () of
+       _ | isDConName n ctxt     -> Just $ dataColour theme
+       _ | isFnName n ctxt       -> Just $ functionColour theme
+       _ | isTConName n ctxt     -> Just $ typeColour theme
+       _ | isPostulateName n ist -> Just $ postulateColour theme
+       _ | otherwise             -> Nothing -- don't colourise unknown names
+annotationColour ist (AnnTextFmt fmt) = Just (colour fmt)
   where colour BoldText      = IdrisColour Nothing True False True False
         colour UnderlineText = IdrisColour Nothing True True False False
         colour ItalicText    = IdrisColour Nothing True False False True
-consoleDecorate ist (AnnTerm _ _) = id
-consoleDecorate ist (AnnSearchResult _) = id
-consoleDecorate ist (AnnErr _) = id
+annotationColour ist _ = Nothing
 
+
+-- | Colourise annotations according to an Idris state. It ignores the names
+-- in the annotation, as there's no good way to show extended
+-- information on a terminal. Note that strings produced this way will
+-- not be coloured on Windows, so the use of the colour rendering
+-- functions in Idris.Output is to be preferred.
+consoleDecorate :: IState -> OutputAnnotation -> String -> String
+consoleDecorate ist ann = maybe id colourise (annotationColour ist ann)
+
 isPostulateName :: Name -> IState -> Bool
 isPostulateName n ist = S.member n (idris_postulates ist)
 
@@ -1441,96 +1634,103 @@
             -> [FixDecl] -- ^^ Fixity declarations
             -> PTerm -- ^^ the term to pretty-print
             -> Doc OutputAnnotation
-pprintPTerm ppo bnd docArgs infixes = prettySe startPrec bnd
+pprintPTerm ppo bnd docArgs infixes = prettySe (ppopt_depth ppo) startPrec bnd
   where
     startPrec = 0
     funcAppPrec = 10
 
-    prettySe :: Int -> [(Name, Bool)] -> PTerm -> Doc OutputAnnotation
-    prettySe p bnd (PQuote r) =
+    prettySe :: Maybe Int -> Int -> [(Name, Bool)] -> PTerm -> Doc OutputAnnotation
+    prettySe d p bnd (PQuote r) =
         text "![" <> pretty r <> text "]"
-    prettySe p bnd (PPatvar fc n) = pretty n
-    prettySe p bnd e
-      | Just str <- slist p bnd e = str
-      | Just n <- snat p e = annotate (AnnData "Nat" "") (text (show n))
-    prettySe p bnd (PRef fc n) = prettyName True (ppopt_impl ppo) bnd n
-    prettySe p bnd (PLam fc n nfc ty sc) =
-      bracket p startPrec . group . align . hang 2 $
+    prettySe d p bnd (PPatvar fc n) = pretty n
+    prettySe d p bnd e
+      | Just str <- slist d p bnd e = depth d $ str
+      | Just n <- snat d p e = depth d $ annotate (AnnData "Nat" "") (text (show n))
+    prettySe d p bnd (PRef fc _ n) = prettyName True (ppopt_impl ppo) bnd n
+    prettySe d p bnd (PLam fc n nfc ty sc) =
+      depth d . bracket p startPrec . group . align . hang 2 $
       text "\\" <> prettyBindingOf n False <+> text "=>" <$>
-      prettySe startPrec ((n, False):bnd) sc
-    prettySe p bnd (PLet fc n nfc ty v sc) =
-      bracket p startPrec . group . align $
-      kwd "let" <+> (group . align . hang 2 $ prettyBindingOf n False <+> text "=" <$> prettySe startPrec bnd v) </>
-      kwd "in" <+> (group . align . hang 2 $ prettySe startPrec ((n, False):bnd) sc)
-    prettySe p bnd (PPi (Exp l s _) n _ ty sc)
-      | n `elem` allNamesIn sc || ppopt_impl ppo || n `elem` docArgs =
-          bracket p startPrec . group $
-          enclose lparen rparen (group . align $ prettyBindingOf n False <+> colon <+> prettySe startPrec bnd ty) <+>
-          st <> text "->" <$> prettySe startPrec ((n, False):bnd) sc
+      prettySe (decD d) startPrec ((n, False):bnd) sc
+    prettySe d p bnd (PLet fc n nfc ty v sc) =
+      depth d . bracket p startPrec . group . align $
+      kwd "let" <+> (group . align . hang 2 $ prettyBindingOf n False <+> text "=" <$> prettySe (decD d) startPrec bnd v) </>
+      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)
+      | n `elem` allNamesIn sc || ppopt_impl ppo && uname n || n `elem` docArgs
+          || ppopt_pinames ppo && uname n =
+          depth d . bracket p startPrec . group $
+          enclose lparen rparen (group . align $ prettyBindingOf n False <+> colon <+> prettySe (decD d) startPrec bnd ty) <+>
+          st <> text "->" <$> prettySe (decD d) startPrec ((n, False):bnd) sc
       | otherwise                      =
-          bracket p startPrec . group $
-          group (prettySe (startPrec + 1) bnd ty <+> st) <> text "->" <$> group (prettySe startPrec ((n, False):bnd) sc)
+          depth d . bracket p startPrec . group $
+          group (prettySe (decD d) (startPrec + 1) bnd ty <+> st) <> text "->" <$>
+          group (prettySe (decD d) startPrec ((n, False):bnd) sc)
       where
+        uname (UN n) = case str n of
+                            ('_':_) -> False
+                            _ -> True
+        uname _ = False
+
         st =
           case s of
             Static -> text "[static]" <> space
             _      -> empty
-    prettySe p bnd (PPi (Imp l s _ fa) n _ ty sc)
+    prettySe d p bnd (PPi (Imp l s _ fa) n _ ty sc)
       | ppopt_impl ppo =
-          bracket p startPrec $
-          lbrace <> prettyBindingOf n True <+> colon <+> prettySe startPrec bnd ty <> rbrace <+>
-          st <> text "->" </> prettySe startPrec ((n, True):bnd) sc
-      | otherwise = prettySe startPrec ((n, True):bnd) sc
+          depth d . bracket p startPrec $
+          lbrace <> prettyBindingOf n True <+> 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
         st =
           case s of
             Static -> text "[static]" <> space
             _      -> empty
-    prettySe p bnd (PPi (Constraint _ _) n _ ty sc) =
-      bracket p startPrec $
-      prettySe (startPrec + 1) bnd ty <+> text "=>" </> prettySe startPrec ((n, True):bnd) sc
-    prettySe p bnd (PPi (TacImp _ _ (PTactics [ProofSearch _ _ _ _ _])) n _ ty sc) =
-      lbrace <> kwd "auto" <+> pretty n <+> colon <+> prettySe startPrec bnd ty <>
-      rbrace <+> text "->" </> prettySe startPrec ((n, True):bnd) sc
-    prettySe p bnd (PPi (TacImp _ _ s) n _ ty sc) =
-      bracket p startPrec $
-      lbrace <> kwd "default" <+> prettySe (funcAppPrec + 1) bnd s <+> pretty n <+> colon <+> prettySe startPrec bnd ty <>
-      rbrace <+> text "->" </> prettySe startPrec ((n, True):bnd) sc
+    prettySe d p bnd (PPi (Constraint _ _) 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) =
+      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) =
+      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
     -- This case preserves the behavior of the former constructor PEq.
     -- It should be removed if feasible when the pretty-printing of infix
     -- operators in general is improved.
-    prettySe p bnd (PApp _ (PRef _ n) [lt, rt, l, r])
+    prettySe d p bnd (PApp _ (PRef _ _ n) [lt, rt, l, r])
       | n == eqTy, ppopt_impl ppo =
-          bracket p eqPrec $
+          depth d . bracket p eqPrec $
             enclose lparen rparen eq <+>
-            align (group (vsep (map (prettyArgS bnd)
+            align (group (vsep (map (prettyArgS (decD d) bnd)
                                     [lt, rt, l, r])))
       | n == eqTy =
-          bracket p eqPrec . align . group $
+          depth d . bracket p eqPrec . align . group $
             prettyTerm (getTm l) <+> eq <$> group (prettyTerm (getTm r))
       where eq = annName eqTy (text "=")
             eqPrec = startPrec
-            prettyTerm = prettySe (eqPrec + 1) bnd
-    prettySe p bnd (PApp _ (PRef _ f) args) -- normal names, no explicit args
+            prettyTerm = prettySe (decD d) (eqPrec + 1) bnd
+    prettySe d p bnd (PApp _ (PRef _ _ f) args) -- normal names, no explicit args
       | UN nm <- basename f
       , not (ppopt_impl ppo) && null (getShowArgs args) =
           prettyName True (ppopt_impl ppo) bnd f
-    prettySe p bnd (PAppBind _ (PRef _ f) [])
+    prettySe d p bnd (PAppBind _ (PRef _ _ f) [])
       | not (ppopt_impl ppo) = text "!" <> prettyName True (ppopt_impl ppo) bnd f
-    prettySe p bnd (PApp _ (PRef _ op) args) -- infix operators
+    prettySe d p bnd (PApp _ (PRef _ _ op) args) -- infix operators
       | UN nm <- basename op
       , not (tnull nm) &&
         (not (ppopt_impl ppo)) && (not $ isAlpha (thead nm)) =
           case getShowArgs args of
             [] -> opName True
-            [x] -> group (opName True <$> group (prettySe startPrec bnd (getTm x)))
+            [x] -> group (opName True <$> group (prettySe (decD d) startPrec bnd (getTm x)))
             [l,r] -> let precedence = maybe (startPrec - 1) prec f
-                     in bracket p precedence $ inFix (getTm l) (getTm r)
+                     in depth d . bracket p precedence $ inFix (getTm l) (getTm r)
             (l@(PExp _ _ _ _) : r@(PExp _ _ _ _) : rest) ->
-                   bracket p funcAppPrec $
+                   depth d . bracket p funcAppPrec $
                           enclose lparen rparen (inFix (getTm l) (getTm r)) <+>
-                          align (group (vsep (map (prettyArgS bnd) rest)))
-            as -> opName True <+> align (vsep (map (prettyArgS bnd) as))
+                          align (group (vsep (map (prettyArgS d bnd) rest)))
+            as -> opName True <+> align (vsep (map (prettyArgS d bnd) as))
           where opName isPrefix = prettyName isPrefix (ppopt_impl ppo) bnd op
                 f = getFixity (opStr op)
                 left = case f of
@@ -1542,26 +1742,26 @@
                             Just (Infixr p') -> p'
                             Just f' -> prec f' + 1
                 inFix l r = align . group $
-                  (prettySe left bnd l <+> opName False) <$>
-                    group (prettySe right bnd r)
-    prettySe p bnd (PApp _ hd@(PRef fc f) [tm]) -- symbols, like 'foo
+                  (prettySe (decD d) left bnd l <+> opName False) <$>
+                    group (prettySe (decD d) right bnd r)
+    prettySe d p bnd (PApp _ hd@(PRef fc _ f) [tm]) -- symbols, like 'foo
       | PConstant NoFC (Idris.Core.TT.Str str) <- getTm tm,
         f == sUN "Symbol_" = annotate (AnnType ("'" ++ str) ("The symbol " ++ str)) $
-                               char '\'' <> prettySe startPrec bnd (PRef fc (sUN str))
-    prettySe p bnd (PApp _ f as) = -- Normal prefix applications
+                               char '\'' <> prettySe (decD d) startPrec bnd (PRef fc [] (sUN str))
+    prettySe d p bnd (PApp _ f as) = -- Normal prefix applications
       let args = getShowArgs as
-          fp   = prettySe (startPrec + 1) bnd f
+          fp   = prettySe (decD d) (startPrec + 1) bnd f
           shownArgs = if ppopt_impl ppo then as else args
       in
-        bracket p funcAppPrec . group $
+        depth d . bracket p funcAppPrec . group $
             if null shownArgs
               then fp
-              else fp <+> align (vsep (map (prettyArgS bnd) shownArgs))
-    prettySe p bnd (PCase _ scr cases) =
-      align $ kwd "case" <+> prettySe startPrec bnd scr <+> kwd "of" <$>
-      indent 2 (vsep (map ppcase cases))
+              else fp <+> align (vsep (map (prettyArgS d bnd) shownArgs))
+    prettySe d p bnd (PCase _ scr cases) =
+      align $ kwd "case" <+> prettySe (decD d) startPrec bnd scr <+> kwd "of" <$>
+      depth d (indent 2 (vsep (map ppcase cases)))
       where
-        ppcase (l, r) = let prettyCase = prettySe startPrec
+        ppcase (l, r) = let prettyCase = prettySe (decD d) startPrec
                                          ([(n, False) | n <- vars l] ++ bnd)
                         in nest nestingSize $
                              prettyCase l <+> text "=>" <+> prettyCase r
@@ -1579,70 +1779,97 @@
         noNS (NS _ _) = False
         noNS _ = True
 
-    prettySe p bnd (PIfThenElse _ c t f) =
-      group . align . hang 2 . vsep $
-        [ kwd "if" <+> prettySe startPrec bnd c
-        , kwd "then" <+> prettySe startPrec bnd t
-        , kwd "else" <+> prettySe startPrec bnd f
+    prettySe d p bnd (PIfThenElse _ c t f) =
+      depth d . bracket p funcAppPrec . group . align . hang 2 . vsep $
+        [ kwd "if" <+> prettySe (decD d) startPrec bnd c
+        , kwd "then" <+> prettySe (decD d) startPrec bnd t
+        , kwd "else" <+> prettySe (decD d) startPrec bnd f
         ]
-    prettySe p bnd (PHidden tm) = text "." <> prettySe funcAppPrec bnd tm
-    prettySe p bnd (PResolveTC _) = kwd "%instance"
-    prettySe p bnd (PTrue _ IsType) = annName unitTy $ text "()"
-    prettySe p bnd (PTrue _ IsTerm) = annName unitCon $ text "()"
-    prettySe p bnd (PTrue _ TypeOrTerm) = text "()"
-    prettySe p bnd (PRewrite _ l r _) =
-      bracket p startPrec $
-      text "rewrite" <+> prettySe (startPrec + 1) bnd l <+> text "in" <+> prettySe startPrec bnd r
-    prettySe p bnd (PTyped l r) =
-      lparen <> prettySe startPrec bnd l <+> colon <+> prettySe startPrec bnd r <> rparen
-    prettySe p bnd pair@(PPair _ pun _ _) -- flatten tuples to the right, like parser
-      | Just elts <- pairElts pair = enclose (ann lparen) (ann rparen) .
+    prettySe d p bnd (PHidden tm) = text "." <> prettySe (decD d) funcAppPrec bnd tm
+    prettySe d p bnd (PResolveTC _) = kwd "%instance"
+    prettySe d p bnd (PTrue _ IsType) = annName unitTy $ text "()"
+    prettySe d p bnd (PTrue _ IsTerm) = annName unitCon $ text "()"
+    prettySe d p bnd (PTrue _ TypeOrTerm) = text "()"
+    prettySe d p bnd (PRewrite _ l r _) =
+      depth d . bracket p startPrec $
+      text "rewrite" <+> prettySe (decD d) (startPrec + 1) bnd l <+> text "in" <+> prettySe (decD d) startPrec bnd r
+    prettySe d p bnd (PTyped l r) =
+      lparen <> prettySe (decD d) startPrec bnd l <+> colon <+> prettySe (decD d) startPrec bnd r <> rparen
+    prettySe d p bnd pair@(PPair _ _ pun _ _) -- flatten tuples to the right, like parser
+      | Just elts <- pairElts pair = depth d . enclose (ann lparen) (ann rparen) .
                                      align . group . vsep . punctuate (ann comma) $
-                                     map (prettySe startPrec bnd) elts
+                                     map (prettySe (decD d) startPrec bnd) elts
         where ann = case pun of
                       TypeOrTerm -> id
                       IsType -> annName pairTy
                       IsTerm -> annName pairCon
-    prettySe p bnd (PDPair _ pun l t r) =
+    prettySe d p bnd (PDPair _ _ pun l t r) =
+      depth d $
       annotated lparen <>
       left <+>
       annotated (text "**") <+>
-      prettySe startPrec (addBinding bnd) r <>
+      prettySe (decD d) startPrec (addBinding bnd) r <>
       annotated rparen
       where annotated = case pun of
               IsType -> annName sigmaTy
               IsTerm -> annName sigmaCon
               TypeOrTerm -> id
             (left, addBinding) = case (l, pun) of
-              (PRef _ n, IsType) -> (bindingOf n False <+> text ":" <+> prettySe startPrec bnd t,        ((n, False) :))
-              _ ->                  (prettySe startPrec bnd l, id            )
-    prettySe p bnd (PAlternative a as) =
+              (PRef _ _ n, IsType) -> (bindingOf n False <+> text ":" <+> prettySe (decD d) startPrec bnd t, ((n, False) :))
+              _ ->                    (prettySe (decD d) startPrec bnd l, id)
+    prettySe d p bnd (PAlternative ns a as) =
       lparen <> text "|" <> prettyAs <> text "|" <> rparen
         where
           prettyAs =
-            foldr (\l -> \r -> l <+> text "," <+> r) empty $ map (prettySe startPrec bnd) as
-    prettySe p bnd (PType _) = annotate (AnnType "Type" "The type of types") $ text "Type"
-    prettySe p bnd (PUniverse u) = annotate (AnnType (show u) "The type of unique types") $ text (show u)
-    prettySe p bnd (PConstant _ c) = annotate (AnnConst c) (text (show c))
+            foldr (\l -> \r -> l <+> text "," <+> r) empty $ map (depth d . prettySe (decD d) startPrec bnd) as
+    prettySe d p bnd (PType _) = annotate (AnnType "Type" "The type of types") $ text "Type"
+    prettySe d p bnd (PUniverse u) = annotate (AnnType (show u) "The type of unique types") $ text (show u)
+    prettySe d p bnd (PConstant _ c) = annotate (AnnConst c) (text (show c))
     -- XXX: add pretty for tactics
-    prettySe p bnd (PProof ts) =
-      kwd "proof" <+> lbrace <> text "..." <> rbrace
-    prettySe p bnd (PTactics ts) =
-      kwd "tactics" <+> lbrace <> text "..." <> rbrace
-    prettySe p bnd (PMetavar _ n) = annotate (AnnName n (Just MetavarOutput) Nothing Nothing) $  text "?" <> pretty n
-    prettySe p bnd (PReturn f) = kwd "return"
-    prettySe p bnd PImpossible = kwd "impossible"
-    prettySe p bnd Placeholder = text "_"
-    prettySe p bnd (PDoBlock _) = text "do block pretty not implemented"
-    prettySe p bnd (PCoerced t) = prettySe p bnd t
-    prettySe p bnd (PElabError s) = pretty s
+    prettySe d p bnd (PProof ts) =
+      kwd "proof" <+> lbrace <> ellipsis <> rbrace
+    prettySe d p bnd (PTactics ts) =
+      kwd "tactics" <+> lbrace <> ellipsis <> rbrace
+    prettySe d p bnd (PMetavar _ n) = annotate (AnnName n (Just MetavarOutput) Nothing Nothing) $  text "?" <> pretty n
+    prettySe d p bnd (PReturn f) = kwd "return"
+    prettySe d p bnd PImpossible = kwd "impossible"
+    prettySe d p bnd Placeholder = text "_"
+    prettySe d p bnd (PDoBlock dos) =
+      bracket p startPrec $
+      kwd "do" <+> align (vsep (map (group . align . hang 2) (ppdo bnd dos)))
+       where ppdo bnd (DoExp _ tm:dos) = prettySe (decD d) startPrec bnd tm : ppdo bnd dos
+             ppdo bnd (DoBind _ bn _ tm : dos) =
+               (prettyBindingOf bn False <+> text "<-" <+>
+                group (align (hang 2 (prettySe (decD d) startPrec bnd tm)))) :
+               ppdo ((bn, False):bnd) dos
+             ppdo bnd (DoBindP _ _ _ _ : dos) = -- ok because never made by delab
+               text "no pretty printer for pattern-matching do binding" :
+               ppdo bnd dos
+             ppdo bnd (DoLet _ ln _ ty v : dos) =
+               (kwd "let" <+> prettyBindingOf ln False <+>
+                (if ty /= Placeholder
+                   then colon <+> prettySe (decD d) startPrec bnd ty <+> text "="
+                   else text "=") <+>
+                group (align (hang 2 (prettySe (decD d) startPrec bnd v)))) :
+               ppdo ((ln, False):bnd) dos
+             ppdo bnd (DoLetP _ _ _ : dos) = -- ok because never made by delab
+               text "no pretty printer for pattern-matching do binding" :
+               ppdo bnd dos
+             ppdo _ [] = []
+    prettySe d p bnd (PCoerced t) = prettySe d p bnd t
+    prettySe d p bnd (PElabError s) = pretty s
     -- Quasiquote pprinting ignores bound vars
-    prettySe p bnd (PQuasiquote t Nothing) = text "`(" <> prettySe p [] t <> text ")"
-    prettySe p bnd (PQuasiquote t (Just g)) = text "`(" <> prettySe p [] t <+> colon <+> prettySe p [] g <> text ")"
-    prettySe p bnd (PUnquote t) = text "~" <> prettySe p bnd t
-    prettySe p bnd (PQuoteName n) = text "`{" <> prettyName True (ppopt_impl ppo) bnd n <> text "}"
+    prettySe d p bnd (PQuasiquote t Nothing) = text "`(" <> prettySe (decD d) p [] t <> text ")"
+    prettySe d p bnd (PQuasiquote t (Just g)) = text "`(" <> prettySe (decD d) p [] t <+> colon <+> prettySe (decD d) p [] g <> text ")"
+    prettySe d p bnd (PUnquote t) = text "~" <> prettySe (decD d) p bnd t
+    prettySe d p bnd (PQuoteName n _) = text "`{" <> prettyName True (ppopt_impl ppo) bnd n <> text "}"
+    prettySe d p bnd (PRunElab _ tm _) =
+      bracket p funcAppPrec . group . align . hang 2 $
+      text "%runElab" <$>
+      prettySe (decD d) funcAppPrec bnd tm
+    prettySe d p bnd (PConstSugar fc tm) = prettySe d p bnd tm -- should never occur, but harmless 
 
-    prettySe p bnd _ = text "missing pretty-printer for term"
+    prettySe d p bnd _ = text "missing pretty-printer for term"
 
     prettyBindingOf :: Name -> Bool -> Doc OutputAnnotation
     prettyBindingOf n imp = annotate (AnnBoundName n imp) (text (display n))
@@ -1652,15 +1879,15 @@
             display (NS n ns) = (concat . intersperse "." . map T.unpack . reverse) ns ++ "." ++ display n
             display n         = show n
 
-    prettyArgS bnd (PImp _ _ _ n tm) = prettyArgSi bnd (n, tm)
-    prettyArgS bnd (PExp _ _ _ tm)   = prettyArgSe bnd tm
-    prettyArgS bnd (PConstraint _ _ _ tm) = prettyArgSc bnd tm
-    prettyArgS bnd (PTacImplicit _ _ n _ tm) = prettyArgSti bnd (n, tm)
+    prettyArgS d bnd (PImp _ _ _ n tm) = prettyArgSi d bnd (n, tm)
+    prettyArgS d bnd (PExp _ _ _ tm)   = prettyArgSe d bnd tm
+    prettyArgS d bnd (PConstraint _ _ _ tm) = prettyArgSc d bnd tm
+    prettyArgS d bnd (PTacImplicit _ _ n _ tm) = prettyArgSti d bnd (n, tm)
 
-    prettyArgSe bnd arg = prettySe (funcAppPrec + 1) bnd arg
-    prettyArgSi bnd (n, val) = lbrace <> pretty n <+> text "=" <+> prettySe startPrec bnd val <> rbrace
-    prettyArgSc bnd val = lbrace <> lbrace <> prettySe startPrec bnd val <> rbrace <> rbrace
-    prettyArgSti bnd (n, val) = lbrace <> kwd "auto" <+> pretty n <+> text "=" <+> prettySe startPrec bnd val <> rbrace
+    prettyArgSe d bnd arg = prettySe d (funcAppPrec + 1) bnd arg
+    prettyArgSi d bnd (n, val) = lbrace <> pretty n <+> text "=" <+> prettySe (decD d) startPrec bnd val <> rbrace
+    prettyArgSc d bnd val = lbrace <> lbrace <> prettySe (decD d) startPrec bnd val <> rbrace <> rbrace
+    prettyArgSti d bnd (n, val) = lbrace <> kwd "auto" <+> pretty n <+> text "=" <+> prettySe (decD d) startPrec bnd val <> rbrace
 
     annName :: Name -> Doc OutputAnnotation -> Doc OutputAnnotation
     annName n = annotate (AnnName n Nothing Nothing Nothing)
@@ -1669,55 +1896,65 @@
     opStr (NS n _) = opStr n
     opStr (UN n) = T.unpack n
 
-    slist' _ _ e
+    slist' :: Maybe Int -> Int -> [(Name, Bool)] -> PTerm -> Maybe [Doc OutputAnnotation]
+    slist' (Just d) _ _ _ | d <= 0 = Nothing
+    slist' d _ _ e
       | containsHole e = Nothing
-    slist' p bnd (PApp _ (PRef _ nil) _)
+    slist' d p bnd (PApp _ (PRef _ _ nil) _)
       | not (ppopt_impl ppo) && nsroot nil == sUN "Nil" = Just []
-    slist' p bnd (PRef _ nil)
+    slist' d p bnd (PRef _ _ nil)
       | not (ppopt_impl ppo) && nsroot nil == sUN "Nil" = Just []
-    slist' p bnd (PApp _ (PRef _ cons) args)
+    slist' d p bnd (PApp _ (PRef _ _ cons) args)
       | nsroot cons == sUN "::",
         (PExp {getTm=tl}):(PExp {getTm=hd}):imps <- reverse args,
         all isImp imps,
-        Just tl' <- slist' p bnd tl
-      = Just (hd:tl')
+        Just tl' <- slist' (decD d) p bnd tl
+      = Just (prettySe d startPrec bnd hd : tl')
       where
         isImp (PImp {}) = True
         isImp _ = False
-    slist' _ _ tm = Nothing
+    slist' _ _ _ tm = Nothing
 
-    slist p bnd e | Just es <- slist' p bnd e = Just $
-      case es of [] -> annotate (AnnData "" "") $ text "[]"
-                 [x] -> enclose left right . group $
-                        prettySe p bnd x
-                 xs -> (enclose left right .
-                        align . group . vsep .
-                        punctuate comma .
-                        map (prettySe p bnd)) xs
+    slist d p bnd e | Just es <- slist' d p bnd e = Just $
+      case es of
+        [] -> annotate (AnnData "" "") $ text "[]"
+        [x] -> enclose left right . group $ x
+        xs -> enclose left right .
+              align . group . vsep .
+              punctuate comma $ xs
       where left  = (annotate (AnnData "" "") (text "["))
             right = (annotate (AnnData "" "") (text "]"))
             comma = (annotate (AnnData "" "") (text ","))
-    slist _ _ _ = Nothing
+    slist _ _ _ _ = Nothing
 
     pairElts :: PTerm -> Maybe [PTerm]
-    pairElts (PPair _ _ x y) | Just elts <- pairElts y = Just (x:elts)
-                             | otherwise = Just [x, y]
+    pairElts (PPair _ _ _ x y) | Just elts <- pairElts y = Just (x:elts)
+                               | otherwise = Just [x, y]
     pairElts _ = Nothing
 
     natns = "Prelude.Nat."
 
-    snat p (PRef _ z)
+    snat :: Maybe Int -> Int -> PTerm -> Maybe Integer
+    snat (Just x) _ _ | x <= 0 = Nothing
+    snat d p (PRef _ _ z)
       | show z == (natns++"Z") || show z == "Z" = Just 0
-    snat p (PApp _ s [PExp {getTm=n}])
+    snat d p (PApp _ s [PExp {getTm=n}])
       | show s == (natns++"S") || show s == "S",
-        Just n' <- snat p n
+        Just n' <- snat (decD d) p n
       = Just $ 1 + n'
-    snat _ _ = Nothing
+    snat _ _ _ = Nothing
 
     bracket outer inner doc
       | outer > inner = lparen <> doc <> rparen
       | otherwise     = doc
 
+    ellipsis = text "..."
+
+    depth Nothing = id
+    depth (Just d) = if d <= 0 then const (ellipsis) else id
+
+    decD = fmap (\x -> x - 1)
+
     kwd = annotate AnnKeyword . text
 
     fixities :: M.Map String Fixity
@@ -1739,7 +1976,7 @@
 
 -- | Check whether a PTerm has been delaborated from a Term containing a Hole or Guess
 containsHole :: PTerm -> Bool
-containsHole pterm = or [isHoleName n | PRef _ n <- take 1000 $ universe pterm]
+containsHole pterm = or [isHoleName n | PRef _ _ n <- take 1000 $ universe pterm]
 
 -- | Pretty-printer helper for names that attaches the correct annotations
 prettyName
@@ -1872,11 +2109,14 @@
 showTmImpls :: PTerm -> String
 showTmImpls = flip (displayS . renderCompact . prettyImp verbosePPOption) ""
 
+-- | Show a term with specific options 
+showTmOpts :: PPOption -> PTerm -> String
+showTmOpts opt = flip (displayS . renderPretty 1.0 10000000 . prettyImp opt) ""
 
 
 instance Sized PTerm where
   size (PQuote rawTerm) = size rawTerm
-  size (PRef fc name) = size name
+  size (PRef fc _ name) = size name
   size (PLam fc name _ ty bdy) = 1 + size ty + size bdy
   size (PPi plicity name fc ty bdy) = 1 + size ty + size fc + size bdy
   size (PLet fc name nfc ty def bdy) = 1 + size ty + size def + size bdy
@@ -1888,9 +2128,9 @@
   size (PTrue fc _) = 1
   size (PResolveTC fc) = 1
   size (PRewrite fc left right _) = 1 + size left + size right
-  size (PPair fc _ left right) = 1 + size left + size right
-  size (PDPair fs _ left ty right) = 1 + size left + size ty + size right
-  size (PAlternative a alts) = 1 + size alts
+  size (PPair fc _ _ left right) = 1 + size left + size right
+  size (PDPair fs _ _ left ty right) = 1 + size left + size ty + size right
+  size (PAlternative _ a alts) = 1 + size alts
   size (PHidden hidden) = size hidden
   size (PUnifyLog tm) = size tm
   size (PDisamb _ tm) = size tm
@@ -1917,7 +2157,7 @@
 allNamesIn :: PTerm -> [Name]
 allNamesIn tm = nub $ ni [] tm
   where -- TODO THINK added niTacImp, but is it right?
-    ni env (PRef _ n)
+    ni env (PRef _ _ n)
         | not (n `elem` env) = [n]
     ni env (PPatvar _ n) = [n]
     ni env (PApp _ f as)   = ni env f ++ concatMap (ni env) (map getTm as)
@@ -1926,13 +2166,15 @@
     ni env (PIfThenElse _ c t f) = ni env c ++ ni env t ++ ni env f
     ni env (PLam fc n _ ty sc)  = ni env ty ++ ni (n:env) sc
     ni env (PPi p n _ ty sc) = niTacImp env p ++ ni env ty ++ ni (n:env) sc
+    ni env (PLet _ n _ ty val sc) = ni env ty ++ ni env val ++ ni (n:env) sc
     ni env (PHidden tm)    = ni env tm
     ni env (PRewrite _ l r _) = ni env l ++ ni env r
     ni env (PTyped l r)    = ni env l ++ ni env r
-    ni env (PPair _ _ l r)   = ni env l ++ ni env r
-    ni env (PDPair _ _ (PRef _ n) t r)  = ni env t ++ ni (n:env) r
-    ni env (PDPair _ _ l t r)  = ni env l ++ ni env t ++ ni env r
-    ni env (PAlternative a ls) = concatMap (ni env) ls
+    ni env (PPair _ _ _ l r)   = ni env l ++ ni env r
+    ni env (PDPair _ _ _ (PRef _ _ n) Placeholder r)  = n : ni env r
+    ni env (PDPair _ _ _ (PRef _ _ n) t r)  = ni env t ++ ni (n:env) r
+    ni env (PDPair _ _ _ l t r)  = ni env l ++ ni env t ++ ni env r
+    ni env (PAlternative ns a ls) = concatMap (ni env) ls
     ni env (PUnifyLog tm)    = ni env tm
     ni env (PDisamb _ tm)    = ni env tm
     ni env (PNoImplicits tm)    = ni env tm
@@ -1955,10 +2197,10 @@
     ni set (PPi p n _ ty sc) = niTacImp (S.insert n $ ni (ni set ty) sc) p
     ni set (PRewrite _ l r _) = ni (ni set l) r
     ni set (PTyped l r) = ni (ni set l) r
-    ni set (PPair _ _ l r) = ni (ni set l) r
-    ni set (PDPair _ _ (PRef _ n) t r) = ni (ni set t) r
-    ni set (PDPair _ _ l t r) = ni (ni (ni set l) t) r
-    ni set (PAlternative a as) = niTms set as
+    ni set (PPair _ _ _ l r) = ni (ni set l) r
+    ni set (PDPair _ _ _ (PRef _ _ n) t r) = ni (ni set t) r
+    ni set (PDPair _ _ _ l t r) = ni (ni (ni set l) t) r
+    ni set (PAlternative ns a as) = niTms set as
     ni set (PHidden tm) = ni set tm
     ni set (PUnifyLog tm) = ni set tm
     ni set (PDisamb _ tm) = ni set tm
@@ -1975,12 +2217,12 @@
 implicitNamesIn :: [Name] -> IState -> PTerm -> [Name]
 implicitNamesIn uvars ist tm = nub $ ni [] tm
   where
-    ni env (PRef _ n)
+    ni env (PRef _ _ n)
         | not (n `elem` env)
             = case lookupTy n (tt_ctxt ist) of
                 [] -> [n]
                 _ -> if n `elem` uvars then [n] else []
-    ni env (PApp _ f@(PRef _ n) as)
+    ni env (PApp _ f@(PRef _ _ n) as)
         | n `elem` uvars = ni env f ++ concatMap (ni env) (map getTm as)
         | otherwise = concatMap (ni env) (map getTm as)
     ni env (PApp _ f as) = ni env f ++ concatMap (ni env) (map getTm as)
@@ -1994,10 +2236,10 @@
     ni env (PPi p n _ ty sc) = ni env ty ++ ni (n:env) sc
     ni env (PRewrite _ l r _) = ni env l ++ ni env r
     ni env (PTyped l r)    = ni env l ++ ni env r
-    ni env (PPair _ _ l r)   = ni env l ++ ni env r
-    ni env (PDPair _ _ (PRef _ n) t r) = ni env t ++ ni (n:env) r
-    ni env (PDPair _ _ l t r) = ni env l ++ ni env t ++ ni env r
-    ni env (PAlternative a as) = concatMap (ni env) as
+    ni env (PPair _ _ _ l r)   = ni env l ++ ni env r
+    ni env (PDPair _ _ _ (PRef _ _ n) t r) = ni env t ++ ni (n:env) r
+    ni env (PDPair _ _ _ l t r) = ni env l ++ ni env t ++ ni env r
+    ni env (PAlternative ns a as) = concatMap (ni env) as
     ni env (PHidden tm)    = ni env tm
     ni env (PUnifyLog tm)    = ni env tm
     ni env (PDisamb _ tm)    = ni env tm
@@ -2008,7 +2250,7 @@
 namesIn :: [(Name, PTerm)] -> IState -> PTerm -> [Name]
 namesIn uvars ist tm = nub $ ni [] tm
   where
-    ni env (PRef _ n)
+    ni env (PRef _ _ n)
         | not (n `elem` env)
             = case lookupTy n (tt_ctxt ist) of
                 [] -> [n]
@@ -2024,10 +2266,10 @@
     ni env (PPi p n _ ty sc) = niTacImp env p ++ ni env ty ++ ni (n:env) sc
     ni env (PRewrite _ l r _) = ni env l ++ ni env r
     ni env (PTyped l r)    = ni env l ++ ni env r
-    ni env (PPair _ _ l r)   = ni env l ++ ni env r
-    ni env (PDPair _ _ (PRef _ n) t r) = ni env t ++ ni (n:env) r
-    ni env (PDPair _ _ l t r) = ni env l ++ ni env t ++ ni env r
-    ni env (PAlternative a as) = concatMap (ni env) as
+    ni env (PPair _ _ _ l r)   = ni env l ++ ni env r
+    ni env (PDPair _ _ _ (PRef _ _ n) t r) = ni env t ++ ni (n:env) r
+    ni env (PDPair _ _ _ l t r) = ni env l ++ ni env t ++ ni env r
+    ni env (PAlternative ns a as) = concatMap (ni env) as
     ni env (PHidden tm)    = ni env tm
     ni env (PUnifyLog tm)    = ni env tm
     ni env (PDisamb _ tm)    = ni env tm
@@ -2042,7 +2284,7 @@
 usedNamesIn :: [Name] -> IState -> PTerm -> [Name]
 usedNamesIn vars ist tm = nub $ ni [] tm
   where -- TODO THINK added niTacImp, but is it right?
-    ni env (PRef _ n)
+    ni env (PRef _ _ n)
         | n `elem` vars && not (n `elem` env)
             = case lookupDefExact n (tt_ctxt ist) of
                 Nothing -> [n]
@@ -2055,10 +2297,10 @@
     ni env (PPi p n _ ty sc) = niTacImp env p ++ ni env ty ++ ni (n:env) sc
     ni env (PRewrite _ l r _) = ni env l ++ ni env r
     ni env (PTyped l r)    = ni env l ++ ni env r
-    ni env (PPair _ _ l r)   = ni env l ++ ni env r
-    ni env (PDPair _ _ (PRef _ n) t r) = ni env t ++ ni (n:env) r
-    ni env (PDPair _ _ l t r) = ni env l ++ ni env t ++ ni env r
-    ni env (PAlternative a as) = concatMap (ni env) as
+    ni env (PPair _ _ _ l r)   = ni env l ++ ni env r
+    ni env (PDPair _ _ _ (PRef _ _ n) t r) = ni env t ++ ni (n:env) r
+    ni env (PDPair _ _ _ l t r) = ni env l ++ ni env t ++ ni env r
+    ni env (PAlternative ns a as) = concatMap (ni env) as
     ni env (PHidden tm)    = ni env tm
     ni env (PUnifyLog tm)    = ni env tm
     ni env (PDisamb _ tm)    = ni env tm
diff --git a/src/Idris/CaseSplit.hs b/src/Idris/CaseSplit.hs
--- a/src/Idris/CaseSplit.hs
+++ b/src/Idris/CaseSplit.hs
@@ -32,7 +32,6 @@
 import Text.Parser.Char(anyChar)
 import Text.Trifecta(Result(..), parseString)
 import Text.Trifecta.Delta
-import qualified Data.ByteString.UTF8 as UTF8
 
 import Debug.Trace
 
@@ -72,7 +71,7 @@
              Nothing -> ifail $ show n ++ " is not a pattern variable"
              Just ty ->
                 do let splits = findPats ist ty
-                   iLOG ("New patterns " ++ showSep ", "  
+                   logLvl 1 ("New patterns " ++ showSep ", "  
                          (map showTmImpls splits))
                    let newPats_in = zipWith (replaceVar ctxt n) splits (repeat t)
                    logLvl 4 ("Working from " ++ show t)
@@ -84,7 +83,7 @@
                               (showSep "\n" (map show (mapMaybe id newPats))))
                    logLvl 3 "----"
                    let newPats' = mergeAllPats ist n t (mapMaybe id newPats)
-                   iLOG ("Name updates " ++ showSep "\n"
+                   logLvl 1 ("Name updates " ++ showSep "\n"
                          (map (\ (p, u) -> show u ++ " " ++ show p) newPats'))
                    return (map snd newPats')
 
@@ -128,7 +127,7 @@
 
 stripNS :: Idris.AbsSyntaxTree.PTerm -> Idris.AbsSyntaxTree.PTerm
 stripNS tm = mapPT dens tm where
-    dens (PRef fc n) = PRef fc (nsroot n)
+    dens (PRef fc hls n) = PRef fc hls (nsroot n)
     dens t = t
 
 mergeAllPats :: IState -> Name -> PTerm -> [PTerm] -> [(PTerm, [(Name, PTerm)])]
@@ -138,7 +137,7 @@
                                       (MS [] [] (filter (/=cv) (patvars t)) [])
           ps' = mergeAllPats ist cv t ps in
           ((p', u) : ps')
-  where patvars (PRef _ n) = [n]
+  where patvars (PRef _ _ n) = [n]
         patvars (PApp _ _ as) = concatMap (patvars . getTm) as
         patvars (PPatvar _ n) = [n]
         patvars _ = []
@@ -147,19 +146,19 @@
 -- If any names are unified, make sure they stay unified. Always prefer
 -- user provided name (first pattern)
 mergePat ist (PPatvar fc n) new t
-  = mergePat ist (PRef fc n) new t
+  = mergePat ist (PRef fc [] n) new t
 mergePat ist old (PPatvar fc n) t
-  = mergePat ist old (PRef fc n) t
-mergePat ist orig@(PRef fc n) new@(PRef _ n') t
+  = mergePat ist old (PRef fc [] n) t
+mergePat ist orig@(PRef fc _ n) new@(PRef _ _ n') t
   | isDConName n' (tt_ctxt ist) = do addUpdate n new
                                      return new
   | otherwise
     = do ms <- get
          case lookup n' (namemap ms) of
-              Just x -> do addUpdate n (PRef fc x)
-                           return (PRef fc x)
+              Just x -> do addUpdate n (PRef fc [] x)
+                           return (PRef fc [] x)
               Nothing -> do put (ms { namemap = ((n', n) : namemap ms) })
-                            return (PRef fc n)
+                            return (PRef fc [] n)
 mergePat ist (PApp _ _ args) (PApp fc f args') t
       = do newArgs <- zipWithM mergeArg args (zip args' (argTys ist f))
            return (PApp fc f newArgs)
@@ -170,16 +169,16 @@
                              return (y { machine_inf = machine_inf x,
                                          getTm = tm' })
                         _ -> return (y { getTm = tm' })
-mergePat ist (PRef fc n) tm ty = do tm <- tidy ist tm ty
-                                    addUpdate n tm
-                                    return tm
+mergePat ist (PRef fc _ n) tm ty = do tm <- tidy ist tm ty
+                                      addUpdate n tm
+                                      return tm
 mergePat ist x y t = return y
 
 mergeUserImpl :: PTerm -> PTerm -> PTerm
 mergeUserImpl x y = x
 
 argTys :: IState -> PTerm -> [Maybe Name]
-argTys ist (PRef fc n) 
+argTys ist (PRef fc hls n) 
     = case lookupTy n (tt_ctxt ist) of
            [ty] -> map (tyName . snd) (getArgTys ty) ++ repeat Nothing
            _ -> repeat Nothing
@@ -189,14 +188,14 @@
 argTys _ _ = repeat Nothing
 
 tidy :: IState -> PTerm -> Maybe Name -> State MergeState PTerm
-tidy ist orig@(PRef fc n) ty
+tidy ist orig@(PRef fc hls n) ty
      = do ms <- get
           case lookup n (namemap ms) of
-               Just x -> return (PRef fc x)
+               Just x -> return (PRef fc [] x)
                Nothing -> case n of
                                (UN _) -> return orig
                                _ -> do n' <- inventName ist ty n
-                                       return (PRef fc n')
+                                       return (PRef fc [] n')
 tidy ist (PApp fc f args) ty
      = do args' <- zipWithM tidyArg args (argTys ist f)
           return (PApp fc f args')
@@ -223,7 +222,7 @@
            [ti] -> map genPat (con_names ti)
            _ -> [Placeholder]
     where genPat n = case lookupCtxt n (idris_implicits ist) of
-                        [args] -> PApp emptyFC (PRef emptyFC n)
+                        [args] -> PApp emptyFC (PRef emptyFC [] n)
                                          (map toPlaceholder args)
                         _ -> error $ "Can't happen (genPat) " ++ show n
           toPlaceholder tm = tm { getTm = Placeholder }
@@ -234,10 +233,10 @@
   where subst :: PTerm -> PTerm
         subst orig@(PPatvar _ v) | v == n = t
                                  | otherwise = Placeholder
-        subst orig@(PRef _ v) | v == n = t
-                              | isDConName v ctxt = orig
-        subst (PRef _ _) = Placeholder
-        subst (PApp fc (PRef _ t) pats) 
+        subst orig@(PRef _ _ v) | v == n = t
+                                | isDConName v ctxt = orig
+        subst (PRef _ _ _) = Placeholder
+        subst (PApp fc (PRef _ _ t) pats) 
             | isTConName t ctxt = Placeholder -- infer types
         subst (PApp fc f pats) = PApp fc f (map substArg pats)
         subst x = x
@@ -266,24 +265,29 @@
     rep str ((n, tm) : ups) = rep (updatePat False (show n) (nshow tm) str) ups
 
     updateRHSs i [] = return []
-    updateRHSs i (x : xs) = do (x', i') <- updateRHS i x
+    updateRHSs i (x : xs) = do (x', i') <- updateRHS (null xs) i x
                                xs' <- updateRHSs i' xs
                                return (x' : xs')
 
-    updateRHS i ('?':'=':xs) = do (xs', i') <- updateRHS i xs
-                                  return ("?=" ++ xs', i')
-    updateRHS i ('?':xs) = do let (nm, rest) = span (not . isSpace) xs
-                              (nm', i') <- getUniq nm i
-                              return ('?':nm' ++ rest, i')
-    updateRHS i (x : xs) = do (xs', i') <- updateRHS i xs
-                              return (x : xs', i')
-    updateRHS i [] = return ("", i)
+    updateRHS last i ('?':'=':xs) = do (xs', i') <- updateRHS last i xs
+                                       return ("?=" ++ xs', i')
+    updateRHS last i ('?':xs) 
+        = do let (nm, rest_in) = span (not . (\x -> isSpace x || x == ')'
+                                                              || x == '(')) xs
+             let rest = if last then rest_in else
+                           case span (not . (=='\n')) rest_in of
+                                (_, restnl) -> restnl
+             (nm', i') <- getUniq nm i
+             return ('?':nm' ++ rest, i')
+    updateRHS last i (x : xs) = do (xs', i') <- updateRHS last i xs
+                                   return (x : xs', i')
+    updateRHS last i [] = return ("", i)
 
 
     -- TMP HACK: If there are Nats, we don't want to show as numerals since
     -- this isn't supported in a pattern, so special case here
-    nshow (PRef _ (UN z)) | z == txt "Z" = "Z"
-    nshow (PApp _ (PRef _ (UN s)) [x]) | s == txt "S" =
+    nshow (PRef _ _ (UN z)) | z == txt "Z" = "Z"
+    nshow (PApp _ (PRef _ _ (UN s)) [x]) | s == txt "S" =
                "(S " ++ addBrackets (nshow (getTm x)) ++ ")"
     nshow t = show t
 
@@ -360,11 +364,13 @@
          getNameFrom i used (PPi _ _ _ _ _)
               = uniqueNameFrom (mkSupply [sUN "f", sUN "g"]) used
          getNameFrom i used (PApp fc f as) = getNameFrom i used f
-         getNameFrom i used (PRef fc f) 
+         getNameFrom i used (PRef fc _ f)
             = case getNameHints i f of
-                   [] -> uniqueName (sUN "x") used
+                   [] -> uniqueNameFrom (mkSupply [sUN "x", sUN "y",
+                                                   sUN "z"]) used
                    ns -> uniqueNameFrom (mkSupply ns) used
-         getNameFrom i used _ = uniqueName (sUN "x") used 
+         getNameFrom i used _ = uniqueNameFrom (mkSupply [sUN "x", sUN "y",
+                                                          sUN "z"]) used 
 
          -- write method declarations, indent with 4 spaces
          mkClassBodies :: IState -> [(Name, (FnOpts, PTerm))] -> String
@@ -416,7 +422,7 @@
                                                 newPats
                     return (map fst newPats')
   where
-    base (PApp fc f args) = PApp fc f (map (fmap (const (PRef fc (sUN "_")))) args)
+    base (PApp fc f args) = PApp fc f (map (fmap (const (PRef fc [] (sUN "_")))) args)
     base t = t
 
     nm ptm = do mptm <- elabNewPat ptm
diff --git a/src/Idris/Chaser.hs b/src/Idris/Chaser.hs
--- a/src/Idris/Chaser.hs
+++ b/src/Idris/Chaser.hs
@@ -90,11 +90,11 @@
   btree done f =
     do i <- getIState
        let file = extractFileName f
-       iLOG $ "CHASING " ++ show file
+       logLvl 1 $ "CHASING " ++ show file
        ibcsd <- valIBCSubDir i
        ids <- allImportDirs
        fp <- findImport ids ibcsd file
-       iLOG $ "Found " ++ show fp
+       logLvl 1 $ "Found " ++ show fp
        mt <- runIO $ getIModTime fp
        if (file `elem` built)
           then return [MTree fp False mt []]
@@ -116,29 +116,29 @@
                              else return []
                    mt <- idrisCatch (runIO $ getModificationTime fn)
                                     (\c -> runIO $ getIModTime src)
-                   ok <- checkIBCUpToDate fn src
-                   return [MTree (IBC fn src) ok mt ms]
+                   -- FIXME: It's also not up to date if anything it imports has
+                   -- been modified since its own ibc has.
+                   --
+                   -- Issue #1592 on the issue tracker.
+                   --
+                   -- https://github.com/idris-lang/Idris-dev/issues/1592
+                   ibcOutdated <- fn `younger` (getSrcFile src)
+                   -- FIXME (EB): The below 'hasValidIBCVersion' that's
+                   -- commented out appears to be breaking reloading in vim
+                   -- mode. Until we know why, I've commented it out.
+                   ibcValid <- return True -- hasValidIBCVersion fn
+                   return [MTree (IBC fn src) (ibcOutdated || not ibcValid) mt ms]
 
           getSrcFile (IBC _ src) = getSrcFile src
           getSrcFile (LIDR src) = src
           getSrcFile (IDR src) = src
 
-          -- FIXME: It's also not up to date if anything it imports has
-          -- been modified since its own ibc has.
-          --
-          -- Issue #1592 on the issue tracker.
-          --
-          -- https://github.com/idris-lang/Idris-dev/issues/1592
-
-          checkIBCUpToDate fn (LIDR src) = older fn src
-          checkIBCUpToDate fn (IDR src) = older fn src
-
-          older ibc src = do exist <- runIO $ doesFileExist src
-                             if exist then do
-                                 ibct <- runIO $ getModificationTime ibc
-                                 srct <- runIO $ getModificationTime src
-                                 return (srct >= ibct)
-                               else return False
+          younger ibc src = do exist <- runIO $ doesFileExist src
+                               if exist then do
+                                   ibct <- runIO $ getModificationTime ibc
+                                   srct <- runIO $ getModificationTime src
+                                   return (srct > ibct)
+                                 else return False
 
   children :: Bool -> FilePath -> [FilePath] -> Idris [ModuleTree]
   children lit f done = -- idrisCatch
diff --git a/src/Idris/CmdOptions.hs b/src/Idris/CmdOptions.hs
--- a/src/Idris/CmdOptions.hs
+++ b/src/Idris/CmdOptions.hs
@@ -78,12 +78,15 @@
 parseFlags = many $
   flag' NoBanner (long "nobanner" <> help "Suppress the banner")
   <|> flag' Quiet (short 'q' <> long "quiet" <> help "Quiet verbosity")
+  -- IDE Mode Specific Flags
   <|> 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")
   <|> flag' Idemode (long "ideslave" <> help "Deprecated version of --ide-mode") -- TODO: Remove in v0.9.18
   <|> flag' IdemodeSocket (long "ideslave-socket" <> help "Deprecated version of --ide-mode-socket") -- TODO: Remove in v0.9.18
   <|> (Client <$> strOption (long "client"))
+  -- Logging Flags
   <|> (OLogging <$> option auto (long "log" <> metavar "LEVEL" <> help "Debugging log level"))
+  -- Turn off Certain libraries.
   <|> flag' NoBasePkgs (long "nobasepkgs" <> help "Do not use the given base package")
   <|> flag' NoPrelude (long "noprelude" <> help "Do not use the given prelude")
   <|> flag' NoBuiltins (long "nobuiltins" <> help "Do not use the builtin functions")
@@ -91,7 +94,7 @@
   <|> (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")
-  <|> flag' TypeInType (long "typeintype")
+  <|> flag' TypeInType (long "typeintype" <> help "Turn off Universe checking")
   <|> flag' DefaultTotal (long "total" <> help "Require functions to be total by default")
   <|> flag' DefaultPartial (long "partial")
   <|> flag' WarnPartial (long "warnpartial" <> help "Warn about undeclared partial functions")
@@ -123,11 +126,13 @@
   <|> flag' (OutputTy MavenProject) (long "mvn" <> help "Create a maven project (for Java codegen)")
   <|> (DumpDefun <$> strOption (long "dumpdefuns"))
   <|> (DumpCases <$> strOption (long "dumpcases"))
-  <|> ((\s -> UseCodegen $ parseCodegen s) <$> strOption (long "codegen" <> metavar "TARGET" <> help "Select code generator: C, Java, bytecode"))
+  <|> ((\s -> UseCodegen $ parseCodegen s) <$> strOption (long "codegen" <> metavar "TARGET" <> help "Select code generator: C, Javascript, Node and bytecode are bundled with Idris"))
+  <|> (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"))
   <|> flag' (InterpretScript "Main.main") (long "execute" <> help "Execute as idris")
   <|> (InterpretScript <$> strOption (long "exec" <> metavar "EXPR" <> help "Execute as idris"))
   <|> ((\s -> Extension $ getExt s) <$> strOption (long "extension" <> short 'X' <> metavar "EXT" <> help "Turn on language extension (TypeProviders or ErrorReflection)"))
+  -- Optimisation Levels
   <|> flag' (OptLevel 3) (long "O3")
   <|> flag' (OptLevel 2) (long "O2")
   <|> flag' (OptLevel 1) (long "O1")
@@ -137,11 +142,12 @@
   <|> (OptLevel <$> option auto (short 'O' <> long "level"))
   <|> (TargetTriple <$> strOption (long "target" <> metavar "TRIPLE" <> help "Select target triple (for llvm codegen)"))
   <|> (TargetCPU <$> strOption (long "cpu" <> metavar "CPU" <> help "Select target CPU e.g. corei7 or cortex-m3 (for LLVM codegen)"))
+  -- Colour Options
   <|> flag' (ColourREPL True) (long "colour" <> long "color" <> help "Force coloured output")
   <|> flag' (ColourREPL False) (long "nocolour" <> long "nocolor" <> help "Disable coloured output")
 
   <|> (UseConsoleWidth <$> option (str >>= parseConsoleWidth) (long "consolewidth" <> metavar "WIDTH" <> help "Select console width: auto, infinite, nat"))
-
+  <|> flag' DumpHighlights (long "highlight" <> help "Emit source code highlighting")
 
   where
     getExt s = case maybeRead s of
@@ -178,6 +184,5 @@
 
 integerReader :: ReadP Int
 integerReader = do
-    digits <- many1 $ satisfy isDigit 
+    digits <- many1 $ satisfy isDigit
     return $ read digits
-
diff --git a/src/Idris/Colours.hs b/src/Idris/Colours.hs
--- a/src/Idris/Colours.hs
+++ b/src/Idris/Colours.hs
@@ -4,9 +4,10 @@
   defaultTheme,
   colouriseKwd, colouriseBound, colouriseImplicit, colourisePostulate,
   colouriseType, colouriseFun, colouriseData, colouriseKeyword,
-  colourisePrompt, colourise, ColourType(..)) where
+  colourisePrompt, colourise, ColourType(..), hStartColourise, hEndColourise) where
 
 import System.Console.ANSI
+import System.IO (Handle)
 
 data IdrisColour = IdrisColour { colour    :: Maybe Color
                                , vivid     :: Bool
@@ -42,15 +43,28 @@
                            , postulateColour = IdrisColour (Just Green) True False True False
                            }
 
+-- | Compute the ANSI colours corresponding to an Idris colour
+mkSGR :: IdrisColour -> [SGR]
+mkSGR (IdrisColour c v u b i) =
+    fg c ++
+    (if u then [SetUnderlining SingleUnderline] else []) ++
+    (if b then [SetConsoleIntensity BoldIntensity] else []) ++
+    (if i then [SetItalicized True] else [])
+  where
+    fg Nothing = []
+    fg (Just c) = [SetColor Foreground (if v then Vivid else Dull) c]
+
 -- | Set the colour of a string using POSIX escape codes
 colourise :: IdrisColour -> String -> String
-colourise (IdrisColour c v u b i) str = setSGRCode sgr ++ str ++ setSGRCode [Reset]
-    where sgr = fg c ++
-                (if u then [SetUnderlining SingleUnderline] else []) ++
-                (if b then [SetConsoleIntensity BoldIntensity] else []) ++
-                (if i then [SetItalicized True] else [])
-          fg Nothing = []
-          fg (Just c) = [SetColor Foreground (if v then Vivid else Dull) c]
+colourise c str = setSGRCode (mkSGR c) ++ str ++ setSGRCode [Reset]
+
+-- | Start a colour on a handle, to support colour output on Windows
+hStartColourise :: Handle -> IdrisColour -> IO ()
+hStartColourise h c = hSetSGR h (mkSGR c)
+
+-- | End a colour region on a handle
+hEndColourise :: Handle -> IdrisColour -> IO ()
+hEndColourise h _ = hSetSGR h [Reset]
 
 -- | Set the colour of a string using POSIX escape codes, with trailing '\STX' denoting the end
 -- (required by Haskeline in the prompt string)
diff --git a/src/Idris/Completion.hs b/src/Idris/Completion.hs
--- a/src/Idris/Completion.hs
+++ b/src/Idris/Completion.hs
@@ -52,7 +52,7 @@
 
 metavars :: Idris [String]
 metavars = do i <- get
-              return . map (show . nsroot) $ map fst (filter (\(_, (_,_,t)) -> not t) (idris_metavars i)) \\ primDefs
+              return . map (show . nsroot) $ map fst (filter (\(_, (_,_,_,t)) -> not t) (idris_metavars i)) \\ primDefs
 
 
 modules :: Idris [String]
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
@@ -18,6 +18,7 @@
   put (NamePart n) = do putWord8 1 ; put n
   put (TermPart t) = do putWord8 2 ; put t
   put (SubReport ps) = do putWord8 3 ; put ps
+  put (RawPart r) = do putWord8 4 ; put r
 
   get = do i <- getWord8
            case i of
@@ -25,6 +26,7 @@
              1 -> fmap NamePart get
              2 -> fmap TermPart get
              3 -> fmap SubReport get
+             4 -> fmap RawPart get
              _ -> error "Corrupted binary data for ErrorReportPart"
 
 instance Binary Provenance where
@@ -182,6 +184,10 @@
   put (UnknownImplicit n f) = do putWord8 40
                                  put n
                                  put f
+  put (NoValidAlts ns) = do putWord8 41
+                            put ns
+  put (RunningElabScript e) = do putWord8 42
+                                 put e
 
   get = do i <- getWord8
            case i of
@@ -251,6 +257,8 @@
                       return (ElabScriptStuck x1)
              40 -> do x <- get ; y <- get
                       return $ UnknownImplicit x y
+             41 -> fmap NoValidAlts get
+             42 -> fmap RunningElabScript get
              _ -> error "Corrupted binary data for Err'"
 ----- Generated by 'derive'
 
@@ -494,9 +502,10 @@
                                  put x2
                 Hole x1 -> do putWord8 4
                               put x1
-                GHole x1 x2 -> do putWord8 5
-                                  put x1
-                                  put x2
+                GHole x1 x2 x3 -> do putWord8 5
+                                     put x1
+                                     put x2
+                                     put x3
                 Guess x1 x2 -> do putWord8 6
                                   put x1
                                   put x2
@@ -523,7 +532,8 @@
                            return (Hole x1)
                    5 -> do x1 <- get
                            x2 <- get
-                           return (GHole x1 x2)
+                           x3 <- get
+                           return (GHole x1 x2 x3)
                    6 -> do x1 <- get
                            x2 <- get
                            return (Guess x1 x2)
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
@@ -269,6 +269,8 @@
           fstT (x, _, _) = x
           lstT (_, _, x) = x
 
+          -- Check that all pattern variables are reachable by a case split
+          -- Otherwise, they won't make sense on the RHS.
           chkAccessible (avs, l, c)
                | phase == RunTime || reflect = return (l, c)
                | otherwise = do mapM_ (acc l) avs
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
@@ -76,7 +76,7 @@
           = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` rnf x4 `seq` ()
         rnf (CantInferType x1) = rnf x1 `seq` ()
         rnf (CantMatch x1) = rnf x1 `seq` ()
-        rnf (ReflectionError x1 x2) = x1 `seq` rnf x2 `seq` ()
+        rnf (ReflectionError x1 x2) = rnf x1 `seq` rnf x2 `seq` ()
         rnf (ReflectionFailed x1 x2) = rnf x1 `seq` rnf x2 `seq` ()
         rnf (CantSolveGoal x1 x2) = rnf x1 `seq` rnf x2 `seq` ()
         rnf (UniqueError x1 x2) = rnf x1 `seq` rnf x2 `seq` ()
@@ -93,6 +93,7 @@
         rnf (CantResolve x1 x2) = rnf x1 `seq` rnf x2 `seq` ()
         rnf (InvalidTCArg x1 x2) = rnf x1 `seq` rnf x2 `seq` ()
         rnf (CantResolveAlts x1) = rnf x1 `seq` ()
+        rnf (NoValidAlts x1) = rnf x1 `seq` ()
         rnf (IncompleteTerm x1) = rnf x1 `seq` ()
         rnf (NoEliminator x1 x2) = rnf x1 `seq` rnf x2 `seq` ()
         rnf (UniverseError x1 x2 x3 x4 x5) = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` rnf x4 `seq` rnf x5 `seq` ()
@@ -110,7 +111,15 @@
         rnf (LoadingFailed x1 x2) = rnf x1 `seq` rnf x2 `seq` ()
         rnf (ElabScriptDebug x1 x2 x3) = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` ()
         rnf (ElabScriptStuck x1) = rnf x1 `seq` ()
+        rnf (RunningElabScript x1) = rnf x1 `seq` ()
 
+instance NFData ErrorReportPart where
+  rnf (TextPart x1) = rnf x1 `seq` ()
+  rnf (TermPart x1) = rnf x1 `seq` ()
+  rnf (RawPart x1) = rnf x1 `seq` ()
+  rnf (NamePart x1) = rnf x1 `seq` ()
+  rnf (SubReport x1) = rnf x1 `seq` ()
+
 instance NFData ImplicitInfo where
         rnf (Impl x1) = rnf x1 `seq` ()
 
@@ -120,7 +129,7 @@
         rnf (Let x1 x2) = rnf x1 `seq` rnf x2 `seq` ()
         rnf (NLet x1 x2) = rnf x1 `seq` rnf x2 `seq` ()
         rnf (Hole x1) = rnf x1 `seq` ()
-        rnf (GHole x1 x2) = rnf x1 `seq` rnf x2 `seq` ()
+        rnf (GHole x1 x2 x3) = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` ()
         rnf (Guess x1 x2) = rnf x1 `seq` rnf x2 `seq` ()
         rnf (PVar x1) = rnf x1 `seq` ()
         rnf (PVTy x1) = rnf x1 `seq` ()
@@ -191,6 +200,7 @@
         rnf Productive = ()
         rnf (Partial x1) = rnf x1 `seq` ()
         rnf Unchecked = ()
+        rnf Generated = ()
         
 instance NFData PReason where
         rnf (Other x1) = rnf x1 `seq` ()
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
@@ -51,6 +51,20 @@
                 let p' = p { dontunify = n : dontunify p }
                 put (ES (p', a) s m)
 
+-- Add a name that's okay to use in proof search (typically either because 
+-- it was given explicitly on the lhs, or intrduced as an explicit lambda
+-- or let binding)
+addPSname :: Name -> Elab' aux ()
+addPSname n@(UN _)
+     = do ES (p, a) s m <- get
+          let p' = p { psnames = n : psnames p }
+          put (ES (p', a) s m)
+addPSname _ = return () -- can only use user given names
+
+getPSnames :: Elab' aux [Name]
+getPSnames = do ES (p, a) s m <- get
+                return (psnames p)
+
 saveState :: Elab' aux ()
 saveState = do e@(ES p s _) <- get
                put (ES p s (Just e))
@@ -90,15 +104,25 @@
     maxName m (_ : xs) = maxName m xs
     maxName m [] = m + 1
 
+
+-- | Transform the error returned by an elaboration script, preserving
+-- location information and proof search failure messages.
+transformErr :: (Err -> Err) -> Elab' aux a -> Elab' aux a
+transformErr f elab = do s <- get
+                         case runStateT elab s of
+                           OK (a, s') -> do put s'
+                                            return $! a
+                           Error e -> lift $ Error (rewriteErr e)
+
+    where
+      rewriteErr (At f e) = At f (rewriteErr e)
+      rewriteErr (ProofSearchFail e) = ProofSearchFail (rewriteErr e)
+      rewriteErr e = f e
+
 errAt :: String -> Name -> Elab' aux a -> Elab' aux a
-errAt thing n elab = do s <- get
-                        case runStateT elab s of
-                             OK (a, s') -> do put s'
-                                              return $! a
-                             Error (At f e) ->
-                                 lift $ Error (At f (Elaborating thing n e))
-                             Error e -> lift $ Error (Elaborating thing n e)
+errAt thing n = transformErr (Elaborating thing n)
 
+
 erun :: FC -> Elab' aux a -> Elab' aux a
 erun f elab = do s <- get
                  case runStateT elab s of
@@ -210,6 +234,13 @@
 get_holes = do ES p _ _ <- get
                return $! (holes (fst p))
 
+get_usedns :: Elab' aux [Name]
+get_usedns = do ES p _ _ <- get
+                let bs = bound_in (pterm (fst p)) ++
+                         bound_in_term (ptype (fst p))
+                let nouse = holes (fst p) ++ bs ++ dontunify (fst p) ++ usedns (fst p)
+                return $! nouse
+
 get_probs :: Elab' aux Fails
 get_probs = do ES p _ _ <- get
                return $! (problems (fst p))
@@ -398,9 +429,10 @@
 equiv :: Raw -> Elab' aux ()
 equiv tm = processTactic' (Equiv tm)
 
--- | Turn the current hole into a pattern variable with the provided name, made unique if MN
+-- | Turn the current hole into a pattern variable with the provided
+-- name, made unique if MN
 patvar :: Name -> Elab' aux ()
-patvar n@(SN _) = do apply (Var n) []; solve 
+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
@@ -411,6 +443,15 @@
                                     x -> return $! n
                         processTactic' (PatVar n')
 
+-- | Turn the current hole into a pattern variable with the provided
+-- name, but don't make MNs unique.
+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 processTactic' (PatVar n)
+
 patbind :: Name -> Elab' aux ()
 patbind n = processTactic' (PatBind n)
 
@@ -553,7 +594,12 @@
     rebind hs (App s f a) = App s (rebind hs f) (rebind hs a)
     rebind hs t = t
 
-apply, match_apply :: Raw -> [(Bool, Int)] -> Elab' aux [(Name, Name)]
+-- | Apply an operator, solving some arguments by unification or matching.
+apply, match_apply :: Raw -- ^ The operator to apply
+                   -> [(Bool, Int)] -- ^ For each argument, whether to
+                                    -- attempt to solve it and the
+                                    -- priority in which to do so
+                   -> Elab' aux [(Name, Name)]
 apply = apply' fill
 match_apply = apply' match_fill
 
@@ -564,7 +610,7 @@
        -- (remove from unified list before calling end_unify)
        hs <- get_holes
        ES (p, a) s prev <- get
-       let dont = if null imps 
+       let dont = if null imps
                      then head hs : dontunify p
                      else getNonUnify (head hs : dontunify p) imps args
        let (n, hunis) = -- trace ("AVOID UNIFY: " ++ show (fn, dont)) $
@@ -684,7 +730,7 @@
        s <- getNameFrom (sMN 0 "s")
        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 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
@@ -758,9 +804,7 @@
                     Error e1 -> if p e1 then
                                    do case runStateT t2 s of
                                          OK (v, s') -> do put s'; return $! v
-                                         Error e2 -> if score e1 >= score e2
-                                                        then lift (tfail e1)
-                                                        else lift (tfail e2)
+                                         Error e2 -> lift (tfail e2)
                                    else lift (tfail e1)
 
 try' :: Elab' aux a -> Elab' aux a -> Bool -> Elab' aux a
@@ -776,15 +820,13 @@
                          if recoverableErr e1 then
                             do case runStateT t2 s of
                                  OK (v, s') -> do put s'; return $! v
-                                 Error e2 -> if score e1 >= score e2
-                                                then lift (tfail e1)
-                                                else lift (tfail e2)
+                                 Error e2 -> lift (tfail e2)
                            else lift (tfail e1)
   where recoverableErr err@(CantUnify r x y _ _ _)
              = -- traceWhen r (show err) $
                r || proofSearch
         recoverableErr (CantSolveGoal _ _) = False
-        recoverableErr (CantResolveAlts _) = False
+        recoverableErr (CantResolveAlts _) = proofSearch
         recoverableErr (ProofSearchFail (Msg _)) = True
         recoverableErr (ProofSearchFail _) = False
         recoverableErr (ElaboratingArg _ _ _ e) = recoverableErr e
@@ -797,16 +839,15 @@
   = do s <- get
        ps <- get_probs
        ulog <- getUnifyLog
-       case prunStateT 999999 False ps t1 s of
-            OK ((v, _, _), s') -> do put s'
-                                     return $! v
+--        case prunStateT 999999 False ps t1 s of
+       case runStateT t1 s of
+            OK (v, s') -> do put s'
+                             return $! v
             Error e1 -> traceWhen ulog ("tryCatch failed " ++ show e1) $
                           case runStateT (t2 e1) s of
                                OK (v, s') -> do put s'
                                                 return $! v
-                               Error e2 -> if score e1 >= score e2
-                                              then lift (tfail e1)
-                                              else lift (tfail e2)
+                               Error e2 -> lift (tfail e2)
 
 tryWhen :: Bool -> Elab' aux a -> Elab' aux a -> Elab' aux a
 tryWhen True a b = try a b
@@ -816,20 +857,22 @@
 -- to False, then the whole tactic fails if there are any new problems
 tryAll :: [(Elab' aux a, Name)] -> Elab' aux a
 tryAll [(x, _)] = x
-tryAll xs = tryAll' [] 999999 (cantResolve, 0) xs
+tryAll xs = tryAll' [] 999999 xs
   where
     cantResolve :: Elab' aux a
     cantResolve = lift $ tfail $ CantResolveAlts (map snd xs)
 
+    noneValid :: Elab' aux a
+    noneValid = lift $ tfail $ NoValidAlts (map snd xs)
+
     tryAll' :: [Elab' aux a] -> -- successes
                Int -> -- most problems
-               (Elab' aux a, Int) -> -- smallest failure
                [(Elab' aux a, Name)] -> -- still to try
                Elab' aux a
-    tryAll' [res] pmax _   [] = res
-    tryAll' (_:_) pmax _   [] = cantResolve
-    tryAll' [] pmax (f, _) [] = f
-    tryAll' cs pmax f ((x, msg):xs)
+    tryAll' [res] pmax [] = res
+    tryAll' (_:_) pmax [] = cantResolve
+    tryAll' [] pmax    [] = noneValid
+    tryAll' cs pmax    ((x, msg):xs)
        = do s <- get
             ps <- get_probs
             case prunStateT pmax True ps x s of
@@ -837,17 +880,11 @@
                       do let cs' = if (newps < pmax)
                                       then [do put s'; return $! v]
                                       else (do put s'; return $! v) : cs
-                         tryAll' cs' newps f xs
+                         tryAll' cs' newps xs
                 Error err -> do put s
---                                 if (score err) < 100
-                                tryAll' cs pmax (better err f) xs
---                                     else tryAll' [] pmax (better err f) xs -- give up
-
-
-    better err (f, i) = let s = score err in
-                            if (s >= i) then (lift (tfail err), s)
-                                        else (f, i)
+                                tryAll' cs pmax xs
 
+-- Run an elaborator, and fail if any problems are introduced
 prunStateT
   :: Int
      -> Bool
@@ -867,7 +904,7 @@
                     else OK ((v, newpmax, problems p), s')
              Error e -> Error e
 
-debugElaborator :: Maybe String -> Elab' aux a
+debugElaborator :: [ErrorReportPart] -> Elab' aux a
 debugElaborator msg = do ps <- fmap proof get
                          saveState -- so we don't need to remember the hole order
                          hs <- get_holes
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
@@ -1,7 +1,8 @@
 {-# LANGUAGE MultiParamTypeClasses, FlexibleInstances,
              PatternGuards #-}
+{-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
 
-module Idris.Core.Evaluate(normalise, normaliseTrace, normaliseC, normaliseAll,
+module Idris.Core.Evaluate(normalise, normaliseTrace, normaliseC, normaliseAll, toValue, quoteTerm,
                 rt_simplify, simplify, specialise, hnf, convEq, convEq',
                 Def(..), CaseInfo(..), CaseDefs(..),
                 Accessibility(..), Totality(..), PReason(..), MetaInformation(..),
@@ -91,6 +92,13 @@
    = evalState (do val <- eval tr ctxt [] (map finalEntry env) (finalise t) []
                    quote 0 val) initEval
 
+toValue :: Context -> Env -> TT Name -> Value
+toValue ctxt env t 
+  = evalState (eval False ctxt [] (map finalEntry env) t []) initEval
+
+quoteTerm :: Value -> TT Name
+quoteTerm val = evalState (quote 0 val) initEval
+
 -- Return a specialised name, and an updated list of reductions available,
 -- so that the caller can tell how much specialisation was achieved.
 specialise :: Context -> Env -> [(Name, Int)] -> TT Name ->
@@ -157,6 +165,7 @@
 unbindEnv :: EnvTT n -> TT n -> TT n
 unbindEnv [] tm = tm
 unbindEnv (_:bs) (Bind n b sc) = unbindEnv bs sc
+unbindEnv env tm = error $ "Impossible case occurred: couldn't unbind env."
 
 usable :: Bool -- specialising
           -> Name -> [(Name, Int)] -> Eval (Bool, [(Name, Int)])
@@ -738,6 +747,7 @@
               | Productive -- ^ productive
               | Partial PReason
               | Unchecked
+              | Generated
     deriving Eq
 {-!
 deriving instance NFData Totality
@@ -764,6 +774,8 @@
     show (Partial (Other ns)) = "possibly not total due to: " ++ showSep ", " (map show ns)
     show (Partial (Mutual ns)) = "possibly not total due to recursive path " ++
                                  showSep " --> " (map show ns)
+    show (Partial (UseUndef n)) = "possibly not total because it uses the undefined name " ++ show n
+    show Generated = "auto-generated"
 
 {-!
 deriving instance Binary Accessibility
@@ -866,22 +878,23 @@
               [([Name], Term, Term)] -> -- compile time
               [([Name], Term, Term)] -> -- inlined
               [([Name], Term, Term)] -> -- run time
-              Type -> Context -> Context
+              Type -> Context -> TC Context
 addCasedef n ei ci@(CaseInfo inline alwaysInline tcdict)
            tcase covering reflect asserted argtys inacc
            ps_in ps_tot ps_inl ps_ct ps_rt ty uctxt
-    = let ctxt = definitions uctxt
-          access = case lookupDefAcc n False uctxt of
-                        [(_, acc)] -> acc
-                        _ -> Public
-          ctxt' = case (simpleCase tcase covering reflect CompileTime emptyFC inacc argtys ps_tot ei,
-                        simpleCase tcase covering reflect CompileTime emptyFC inacc argtys ps_ct ei,
-                        simpleCase tcase covering reflect CompileTime emptyFC inacc argtys ps_inl ei,
-                        simpleCase tcase covering reflect RunTime emptyFC inacc argtys ps_rt ei) of
-                    (OK (CaseDef args_tot sc_tot _),
-                     OK (CaseDef args_ct sc_ct _),
-                     OK (CaseDef args_inl sc_inl _),
-                     OK (CaseDef args_rt sc_rt _)) ->
+    = do let ctxt = definitions uctxt
+             access = case lookupDefAcc n False uctxt of
+                           [(_, acc)] -> acc
+                           _ -> Public
+         totalityTime <- simpleCase tcase covering reflect CompileTime emptyFC inacc argtys ps_tot ei
+         compileTime <- simpleCase tcase covering reflect CompileTime emptyFC inacc argtys ps_ct ei
+         inlined <- simpleCase tcase covering reflect CompileTime emptyFC inacc argtys ps_inl ei
+         runtime <- simpleCase tcase covering reflect RunTime emptyFC inacc argtys ps_rt ei
+         ctxt' <- case (totalityTime, compileTime, inlined, runtime) of
+                    (CaseDef args_tot sc_tot _,
+                     CaseDef args_ct sc_ct _,
+                     CaseDef args_inl sc_inl _,
+                     CaseDef args_rt sc_rt _) ->
                        let inl = alwaysInline -- tcdict
                            inlc = (inl || small n args_ct sc_ct) && (not asserted)
                            inlr = inl || small n args_rt sc_rt
@@ -892,28 +905,27 @@
                            op = (CaseOp (ci { case_inlinable = inlc })
                                                 ty argtys ps_in ps_tot cdef,
                                  access, Unchecked, EmptyMI)
-                       in addDef n op ctxt
-                    other -> error ("Error adding case def: " ++ show other)
-      in uctxt { definitions = ctxt' }
+                       in return $ addDef n op ctxt
+--                    other -> tfail (Msg $ "Error adding case def: " ++ show other)
+         return uctxt { definitions = ctxt' }
 
 -- simplify a definition for totality checking
-simplifyCasedef :: Name -> ErasureInfo -> Context -> Context
+simplifyCasedef :: Name -> ErasureInfo -> Context -> TC Context
 simplifyCasedef n ei uctxt
-   = let ctxt = definitions uctxt
-         ctxt' = case lookupCtxt n ctxt of
-              [(CaseOp ci ty atys [] ps _, acc, tot, metainf)] ->
-                 ctxt -- nothing to simplify (or already done...)
-              [(CaseOp ci ty atys ps_in ps cd, acc, tot, metainf)] ->
-                 let ps_in' = map simpl ps_in
-                     pdef = map debind ps_in' in
-                     case simpleCase False (STerm Erased) False CompileTime emptyFC [] atys pdef ei of
-                       OK (CaseDef args sc _) ->
-                          addDef n (CaseOp ci
-                                           ty atys ps_in' ps (cd { cases_totcheck = (args, sc) }),
-                                    acc, tot, metainf) ctxt
-                       Error err -> error (show err)
-              _ -> ctxt in
-         uctxt { definitions = ctxt' }
+   = do let ctxt = definitions uctxt
+        ctxt' <- case lookupCtxt n ctxt of
+                   [(CaseOp ci ty atys [] ps _, acc, tot, metainf)] ->
+                      return ctxt -- nothing to simplify (or already done...)
+                   [(CaseOp ci ty atys ps_in ps cd, 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_totcheck = (args, sc) }),
+                                              acc, tot, metainf) ctxt
+
+                   _ -> return ctxt
+        return uctxt { definitions = ctxt' }
   where
     depat acc (Bind n (PVar t) sc)
         = depat (n : acc) (instantiate (P Bound n t) sc)
@@ -1068,6 +1080,7 @@
         case tfst def of
           (Function _ htm) -> return (veval ctxt [] htm)
           (TyDecl nt ty) -> return (VP nt n (veval ctxt [] ty))
+          _ -> []
 
 lookupTyEnv :: Name -> Env -> Maybe (Int, Type)
 lookupTyEnv n env = li n 0 env where
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
@@ -93,7 +93,7 @@
           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 t)   = GHole i <$> 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 (PVTy t)      = PVTy    <$> toTT t
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
@@ -39,6 +39,7 @@
                        deferred :: [Name], -- ^ names we'll need to define
                        instances :: [Name], -- ^ instance arguments (for type classes)
                        autos    :: [(Name, [Name])], -- ^ unsolved 'auto' implicits with their holes
+                       psnames  :: [Name], -- ^ Local names okay to use in proof search
                        previous :: Maybe ProofState, -- ^ for undo
                        context  :: Context,
                        datatypes :: Ctxt TypeInfo,
@@ -244,7 +245,8 @@
            let (notu', probs_notu) = mergeNotunified env (holes ps) (notu ++ notunified ps)
            traceWhen (unifylog ps)
             ("Now solved: " ++ show ns' ++
-             "\nNow problems: " ++ qshow (probs' ++ probs_notu)) $
+             "\nNow problems: " ++ qshow (probs' ++ probs_notu) ++
+             "\nNow injective: " ++ show (updateInj u (injective ps))) $
              put (ps { problems = probs' ++ probs_notu,
                        unified = (h, ns'),
                        injective = updateInj u (injective ps),
@@ -300,7 +302,7 @@
   in PS n [h] [] 1 (mkProofTerm (Bind h (Hole ty')
         (P Bound h ty'))) ty [] (h, []) [] []
         Nothing [] []
-        [] [] []
+        [] [] [] []
         Nothing ctxt datatypes "" False False [] []
 
 type TState = ProofState -- [TacticAction])
@@ -428,7 +430,8 @@
     do let env' = filter (\(n, t) -> n `notElem` dropped) env
        action (\ps -> let hs = holes ps in
                           ps { holes = hs \\ [x] })
-       return (Bind n (GHole (length env') (mkTy (reverse env') t))
+       ps <- get
+       return (Bind n (GHole (length env') (psnames ps) (mkTy (reverse env') t))
                       (mkApp (P Ref n ty) (map getP (reverse env'))))
   where
     mkTy []           t = t
@@ -444,7 +447,7 @@
                           ds = deferred ps in
                           ps { holes = hs \\ [x],
                                deferred = n : ds })
-       return (Bind n (GHole 0 fty)
+       return (Bind n (GHole 0 [] fty)
                       (mkApp (P Ref n ty) (map getP args)))
   where
     getP n = case lookup n env of
@@ -624,8 +627,11 @@
                     x@(Bind y (Pi _ s _) _) -> x
                     _ -> hnf ctxt env t
        case t' of
-           Bind y (Pi _ s _) t -> -- trace ("in type " ++ show t') $
-               let t' = updsubst y (P Bound n s) t in
+           Bind y (Pi _ s _) t ->
+               -- It's important that this be subst and not updsubst,
+               -- because we want to substitute even in portions of
+               -- terms that we know do not contain holes.
+               let t' = subst y (P Bound n s) t in
                    return $ Bind n (Lam s) (Bind x (Hole t') (P Bound x t'))
            _ -> lift $ tfail $ CantIntroduce t'
 intro n ctxt env _ = fail "Can't introduce here."
@@ -759,7 +765,7 @@
           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
-induction tm induction ctxt env _ = do fail "Can't do induction here"
+casetac tm induction ctxt env _ = fail $ "Can't do " ++ (if induction then "induction" else "case analysis") ++ " here"
 
 
 equiv :: Raw -> RunTactic
@@ -1025,7 +1031,10 @@
                        holes = holes ps \\ (map fst ns'') }, plog ps)
 processTactic t ps
     = case holes ps of
-        [] -> fail "Nothing to fill in."
+        [] -> case t of
+                   Focus _ -> return (ps, "") -- harmless to refocus when done, since
+                                              -- 'focus' doesn't fail
+                   _ -> fail $ "Nothing to fill in."
         (h:_)  -> do ps' <- execStateT (process t h) ps
                      let (ns_in, probs')
                                 = case solved ps' of
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
@@ -1,4 +1,5 @@
-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, DeriveFunctor, DeriveDataTypeable #-}
+{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, DeriveFunctor, 
+             DeriveDataTypeable, PatternGuards #-}
 {-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
 {-| TT is the core language of Idris. The language has:
 
@@ -18,8 +19,36 @@
      programs with implicit syntax into fully explicit terms.
 -}
 
-module Idris.Core.TT where
+module Idris.Core.TT(AppStatus(..), ArithTy(..), Binder(..), Const(..), Ctxt(..),
+                     ConstraintFC(..), DataOpt(..), DataOpts(..), Datatype(..),
+                     Env(..), EnvTT(..), Err(..), Err'(..), ErrorReportPart(..),
+                     FC(..), FC'(..), ImplicitInfo(..), IntTy(..), Name(..),
+                     NameOutput(..), NameType(..), NativeTy(..), OutputAnnotation(..),
+                     Provenance(..), Raw(..), SpecialName(..), TC(..), Term(..),
+                     TermSize(..), TextFormatting(..), TT(..),Type(..), TypeInfo(..),
+                     UConstraint(..), UCs(..), UExp(..), Universe(..),
+                     addAlist, addBinder, addDef, allTTNames, arity, bindAll,
+                     bindingOf, bindTyArgs, constDocs, constIsType, deleteDefExact,
+                     discard, emptyContext, emptyFC, explicitNames, fc_end, fc_fname,
+                     fc_start, fcIn, fileFC, finalise, fmapMB, forget, forgetEnv,
+                     freeNames, getArgTys, getRetTy, implicitable, instantiate,
+                     intTyName, isInjective, isTypeConst, liftPats, lookupCtxt,
+                     lookupCtxtExact, lookupCtxtName, mapCtxt, mkApp, nativeTyWidth,
+                     nextName, noOccurrence, nsroot, occurrences, orderPats,
+                     pEraseType, pmap, pprintRaw, pprintTT, prettyEnv, psubst, pToV,
+                     pToVs, pureTerm, raw_apply, raw_unapply, refsIn, safeForget,
+                     safeForgetEnv, showCG, showEnv, showEnvDbg, showSep,
+                     sInstanceN, sMN, sNS, spanFC, str, subst, substNames, substTerm,
+                     substV, sUN, tcname, termSmallerThan, tfail, thead, tnull,
+                     toAlist, traceWhen, txt, unApply, uniqueBinders, uniqueName,
+                     uniqueNameFrom, uniqueNameSet, unList, updateDef, vToP, weakenTm) where
 
+-- Work around AMP without CPP
+import Prelude (Eq(..), Show(..), Ord(..), Functor(..), Monad(..), String, Int,
+                Integer, Ordering(..), Maybe(..), Num(..), Bool(..), Enum(..),
+                Read(..), FilePath, Double, (&&), (||), ($), (.), div, error, fst,
+                snd, not, mod, read, otherwise)
+
 import Control.Applicative (Applicative (..), Alternative)
 import qualified Control.Applicative as A (Alternative (..))
 import Control.Monad.State.Strict
@@ -102,6 +131,16 @@
 spanFC NoFC fc = fc
 spanFC fc NoFC = fc
 
+-- | Determine whether the first argument is completely contained in the second
+fcIn :: FC -> FC -> Bool
+fcIn NoFC   _ = False
+fcIn (FileFC _) _ = False
+fcIn (FC {}) NoFC = False
+fcIn (FC {}) (FileFC _) = False
+fcIn (FC fn1 (sl1, sc1) (el1, ec1)) (FC fn2 (sl2, sc2) (el2, ec2)) =
+  fn1 == fn2 &&
+  (sl1 == sl2 && sc1 > sc2 || sl1 > sl2) &&
+  (el1 == el2 && ec1 < ec2 || el1 < el2)
 
 -- | Ignore source location equality (so deriving classes do not compare FCs)
 instance Eq FC where
@@ -144,10 +183,10 @@
     show (FileFC f) = f
 
 -- | Output annotation for pretty-printed name - decides colour
-data NameOutput = TypeOutput | FunOutput | DataOutput | MetavarOutput | PostulateOutput deriving Show
+data NameOutput = TypeOutput | FunOutput | DataOutput | MetavarOutput | PostulateOutput deriving (Show, Eq)
 
 -- | Text formatting output
-data TextFormatting = BoldText | ItalicText | UnderlineText deriving Show
+data TextFormatting = BoldText | ItalicText | UnderlineText deriving (Show, Eq)
 
 -- | Output annotations for pretty-printing
 data OutputAnnotation = AnnName Name (Maybe NameOutput) (Maybe String) (Maybe String)
@@ -160,6 +199,7 @@
                       | AnnKeyword
                       | AnnFC FC
                       | AnnTextFmt TextFormatting
+                      | AnnLink String -- ^ A link to this URL
                       | AnnTerm [(Name, Bool)] (TT Name) -- ^ pprint bound vars, original term
                       | AnnSearchResult Ordering -- ^ more general, isomorphic, or more specific
                       | AnnErr Err
@@ -170,12 +210,15 @@
                         -- resolved. If a file path is present, then
                         -- the namespace represents a module imported
                         -- from that file.
-  deriving Show
+                      | AnnQuasiquote
+                      | AnnAntiquote
+  deriving (Show, Eq)
 
 -- | Used for error reflection
 data ErrorReportPart = TextPart String
                      | NamePart Name
                      | TermPart Term
+                     | RawPart Raw
                      | SubReport [ErrorReportPart]
                        deriving (Show, Eq, Data, Typeable)
 
@@ -223,6 +266,7 @@
                         t
           | InvalidTCArg Name t
           | CantResolveAlts [Name]
+          | NoValidAlts [Name]
           | IncompleteTerm t
           | NoEliminator String t
           | UniverseError FC UExp (Int, Int) (Int, Int) [ConstraintFC]
@@ -244,9 +288,10 @@
           | LoadingFailed String (Err' t)
           | ReflectionError [[ErrorReportPart]] (Err' t)
           | ReflectionFailed String (Err' t)
-          | ElabScriptDebug (Maybe String) t [(Name, t, [(Name, Binder t)])]
+          | ElabScriptDebug [ErrorReportPart] t [(Name, t, [(Name, Binder t)])]
             -- ^ User-specified message, proof term, goals with context (first goal is focused)
           | ElabScriptStuck t
+          | RunningElabScript (Err' t) -- ^ The error occurred during a top-level elaboration script
   deriving (Eq, Functor, Data, Typeable)
 
 type Err = Err' Term
@@ -288,6 +333,7 @@
 instance Sized ErrorReportPart where
   size (TextPart msg) = 1 + length msg
   size (TermPart t) = 1 + size t
+  size (RawPart r) = 1 + size r
   size (NamePart n) = 1 + size n
   size (SubReport rs) = 1 + size rs
 
@@ -313,18 +359,6 @@
   size (LoadingFailed fn e) = 1 + length fn + size e
   size _ = 1
 
-score :: Err -> Int
-score (CantUnify _ _ _ m _ s) = s + score m
-score (CantResolve _ _) = 20
-score (NoSuchVariable _) = 1000
-score (ProofSearchFail e) = score e
-score (CantSolveGoal _ _) = 100000
-score (InternalMsg _) = -1
-score (At _ e) = score e
-score (ElaboratingArg _ _ _ e) = score e
-score (Elaborating _ _ e) = score e
-score _ = 0
-
 instance Show Err where
     show (Msg s) = s
     show (InternalMsg s) = "Internal error: " ++ show s
@@ -776,6 +810,7 @@
                         binderVal :: b }
               | Hole  { binderTy  :: !b}
               | GHole { envlen :: Int,
+                        localnames :: [Name],
                         binderTy  :: !b}
               | Guess { binderTy  :: !b,
                         binderVal :: b }
@@ -794,7 +829,7 @@
   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 (GHole _ _ ty) = 1 + size ty
   size (Guess ty val) = 1 + size ty + size val
   size (PVar ty) = 1 + size ty
   size (PVTy ty) = 1 + size ty
@@ -806,7 +841,7 @@
 fmapMB f (Lam t)     = liftM Lam (f t)
 fmapMB f (Pi i t k)  = liftM2 (Pi i) (f t) (f k)
 fmapMB f (Hole t)    = liftM Hole (f t)
-fmapMB f (GHole i t) = liftM (GHole i) (f t)
+fmapMB f (GHole i ns t) = liftM (GHole i ns) (f t)
 fmapMB f (PVar t)    = liftM PVar (f t)
 fmapMB f (PVTy t)    = liftM PVTy (f t)
 
@@ -1247,6 +1282,22 @@
                      return $ x:rest
               (f, args) -> Nothing
 
+-- | Hard-code a heuristic maximum term size, to prevent attempts to
+-- serialize or force infinite or just gigantic terms
+termSmallerThan :: Int -> Term -> Bool
+termSmallerThan x tm | x <= 0 =  False
+termSmallerThan x (P _ _ ty) = termSmallerThan (x-1) ty
+termSmallerThan x (Bind _ _ tm) = termSmallerThan (x-1) tm
+termSmallerThan x (App _ f a) = termSmallerThan (x-1) f && termSmallerThan (x-1) a
+termSmallerThan x (Proj tm _) = termSmallerThan (x-1) tm
+termSmallerThan x (V i) = True
+termSmallerThan x (Constant c) = True
+termSmallerThan x Erased = True
+termSmallerThan x Impossible = True
+termSmallerThan x (TType u) = True
+termSmallerThan x (UType u) = True
+
+
 -- | Cast a 'TT' term to a 'Raw' value, discarding universe information and
 -- the types of named references and replacing all de Bruijn indices
 -- with the corresponding name. It is an error if there are free de
@@ -1325,7 +1376,7 @@
 
 uniqueNameSet :: Name -> Set Name -> Name
 uniqueNameSet n hs | n `member` hs = uniqueNameSet (nextName n) hs
-                | otherwise   = n
+                   | otherwise   = n
 
 uniqueBinders :: [Name] -> TT Name -> TT Name
 uniqueBinders ns = ubSet (fromList ns) where
@@ -1445,7 +1496,7 @@
     -- Render a `Binder` and its name
     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 (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 (PVTy t) = prettyB env "pty" "." n t
@@ -1490,7 +1541,7 @@
 
     sb env n (Lam t)  = showb env "\\ " " => " n t
     sb env n (Hole t) = showb env "? " ". " n t
-    sb env n (GHole i t) = showb env "?defer " ". " 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
@@ -1690,7 +1741,7 @@
     ppb p bound n (Hole ty) sc =
       bracket p startPrec . group . align . hang 2 $
       text "?" <+> bindingOf n False <+> text "." <> line <> sc
-    ppb p bound n (GHole _ ty) sc =
+    ppb p bound n (GHole _ _ ty) sc =
       bracket p startPrec . group . align . hang 2 $
       text "¿" <+> bindingOf n False <+> text "." <> line <> sc
     ppb p bound n (Guess ty val) sc =
@@ -1715,6 +1766,53 @@
       | outer > inner = lparen <> doc <> rparen
       | otherwise     = doc
 
+-- | Pretty-print a raw term.
+pprintRaw :: [Name] -- ^ Bound names, for highlighting
+          -> Raw -- ^ The term to pretty-print
+          -> Doc OutputAnnotation
+pprintRaw bound (Var n) =
+  enclose lparen rparen . group . align . hang 2 $
+    (text "Var") <$> annotate (if n `elem` bound
+                                  then AnnBoundName n False
+                                  else AnnName n Nothing Nothing Nothing)
+                              (text $ show n)
+pprintRaw bound (RBind n b body) =
+  enclose lparen rparen . group . align . hang 2 $
+  vsep [ text "RBind"
+       , annotate (AnnBoundName n False) (text $ show n)
+       , 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 (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 $
+                      vsep [text "NLet", pprintRaw bound ty, pprintRaw bound v]
+    ppb (Hole ty) = enclose lparen rparen . group . align . hang 2 $
+                    text "Hole" <$> pprintRaw bound ty
+    ppb (GHole _ _ ty) = enclose lparen rparen . group . align . hang 2 $
+                         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 (PVTy ty) = enclose lparen rparen . group . align . hang 2 $
+                    text "PVTy" <$> pprintRaw bound ty
+pprintRaw bound (RApp f x) =
+  enclose lparen rparen . group . align . hang 2 . vsep $
+  [text "RApp", pprintRaw bound f, pprintRaw bound x]
+pprintRaw bound RType = text "RType"
+pprintRaw bound (RUType u) = enclose lparen rparen . group . align . hang 2 $
+                             text "RUType" <$> text (show u)
+pprintRaw bound (RForce r) =
+  enclose lparen rparen . group . align . hang 2 $
+  vsep [text "RForce", pprintRaw bound r]
+pprintRaw bound (RConstant c) =
+  enclose lparen rparen . group . align . hang 2 $
+  vsep [text "RConstant", annotate (AnnConst c) (text (show c))]
 
 -- | Pretty-printer helper for the binding site of a name
 bindingOf :: Name -- ^^ the bound name
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
@@ -232,12 +232,12 @@
                         let tt' = normalise ctxt env tt
                         lift $ isType ctxt env tt'
                         return (Hole tv, tt')
-          checkBinder (GHole i t)
+          checkBinder (GHole i ns t)
             = do (tv, tt) <- chk u env t
                  let tv' = normalise ctxt env tv
                  let tt' = normalise ctxt env tt
                  lift $ isType ctxt env tt'
-                 return (GHole i tv, tt')
+                 return (GHole i ns tv, tt')
           checkBinder (Guess t v)
             | not holes = lift $ tfail (IncompleteTerm undefined)
             | otherwise
@@ -273,8 +273,8 @@
             = 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 t) bt scv sct
-            = return (Bind n (GHole i 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
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
@@ -688,14 +688,26 @@
     | (P _ (UN l) _, _) <- unApply t, l == txt "Lazy'" = False
 recoverable (P (DCon _ _ _) x _) (P (DCon _ _ _) y _) = x == y
 recoverable (P (TCon _ _) x _) (P (TCon _ _) y _) = x == y
+recoverable (TType _) (P (DCon _ _ _) y _) = False
+recoverable (UType _) (P (DCon _ _ _) y _) = False
 recoverable (Constant _) (P (DCon _ _ _) y _) = False
 recoverable (Constant x) (Constant y) = x == y
+recoverable (P (DCon _ _ _) x _) (TType _) = False
+recoverable (P (DCon _ _ _) x _) (UType _) = False
 recoverable (P (DCon _ _ _) x _) (Constant _) = False
+recoverable (TType _) (P (TCon _ _) y _) = False
+recoverable (UType _) (P (TCon _ _) y _) = False
 recoverable (Constant _) (P (TCon _ _) y _) = False
+recoverable (P (TCon _ _) x _) (TType _) = False
+recoverable (P (TCon _ _) x _) (UType _) = False
 recoverable (P (TCon _ _) x _) (Constant _) = False
 recoverable (P (DCon _ _ _) x _) (P (TCon _ _) y _) = False
 recoverable (P (TCon _ _) x _) (P (DCon _ _ _) y _) = False
+recoverable p@(TType _) (App _ f a) = recoverable p f
+recoverable p@(UType _) (App _ f a) = recoverable p f
 recoverable p@(Constant _) (App _ f a) = recoverable p f
+recoverable (App _ f a) p@(TType _) = recoverable f p
+recoverable (App _ f a) p@(UType _) = recoverable f p
 recoverable (App _ f a) p@(Constant _) = recoverable f p
 recoverable p@(P _ n _) (App _ f a) = recoverable p f
 recoverable (App _ f a) p@(P _ _ _) = recoverable f p
diff --git a/src/Idris/Core/WHNF.hs b/src/Idris/Core/WHNF.hs
new file mode 100644
--- /dev/null
+++ b/src/Idris/Core/WHNF.hs
@@ -0,0 +1,208 @@
+{-# LANGUAGE PatternGuards #-}
+{-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
+
+-- Reduction to Weak Head Normal Form
+module Idris.Core.WHNF(whnf, WEnv) where
+
+import Idris.Core.TT
+import Idris.Core.CaseTree
+import Idris.Core.Evaluate hiding (quote)
+import qualified Idris.Core.Evaluate as Evaluate 
+
+import Debug.Trace
+
+-- A stack entry consists of a term and the environment it is to be
+-- evaluated in (i.e. it's a thunk)
+type StackEntry = (Term, WEnv)
+data WEnv = WEnv Int -- number of free variables
+                 [(Term, WEnv)] 
+  deriving Show
+
+type Stack = [StackEntry]
+
+-- A WHNF is a top level term evaluated in the empty environment. It is
+-- always headed by either an irreducible expression, i.e. a constructor,
+-- a lambda, a constant, or a postulate
+
+-- Every 'Term' or 'Type' in this structure is associated with the
+-- environment it was encountered in, so that when we quote back to a term
+-- we get the substitutions right.
+
+data WHNF = WDCon Int Int Bool Name (Type, WEnv) -- data constructor
+          | WTCon Int Int Name (Type, WEnv) -- type constructor
+          | WPRef Name (Type, WEnv) -- irreducible global (e.g. a postulate)
+          | WBind Name (Binder Term) (Term, WEnv)
+          | WApp WHNF (Term, WEnv)
+          | WConstant Const
+          | WProj WHNF Int
+          | WType UExp
+          | WUType Universe
+          | WErased
+          | WImpossible
+
+-- Reduce a *closed* term to weak head normal form.
+whnf :: Context -> Term -> Term
+whnf ctxt tm = quote (do_whnf ctxt (WEnv 0 []) tm)
+
+do_whnf :: Context -> WEnv -> Term -> WHNF
+do_whnf ctxt env tm = eval env [] tm
+  where
+    eval :: WEnv -> Stack -> Term -> WHNF
+    eval wenv@(WEnv d env) stk (V i) 
+         | i < length env = let (tm, env') = env !! i in
+                                eval env' stk tm
+         | otherwise = error "Can't happen: WHNF scope error"
+    eval wenv@(WEnv d env) stk (Bind n (Let t v) sc) 
+         = eval (WEnv d ((v, wenv) : env)) stk sc
+    eval (WEnv d env) [] (Bind n b sc) = WBind n b (sc, WEnv (d + 1) env)
+    eval (WEnv d env) ((tm, tenv) : stk) (Bind n b sc) 
+         = eval (WEnv d ((tm, tenv) : env)) stk sc
+
+    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
+
+    -- Should never happen in compile time code (for now...)
+    eval env stk (Proj tm i) = unload (WProj (eval env [] tm) i) stk
+
+    eval env stk Erased = unload WErased stk
+    eval env stk Impossible = unload WImpossible stk
+    eval env stk (TType u) = unload (WType u) stk
+    eval env stk (UType u) = unload (WUType u) stk
+
+    apply :: WEnv -> NameType -> Name -> Type -> Stack -> WHNF
+    apply env nt n ty stk 
+          = 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)
+                          _ -> WPRef n (ty, env)
+                        in
+            case lookupDefExact n ctxt of
+                 Just (CaseOp ci _ _ _ _ cd) -> 
+                      let (ns, tree) = cases_compiletime cd in
+                          case evalCase env ns tree stk of
+                               Just w -> w
+                               Nothing -> unload wp stk
+                 Just (Operator _ i op) -> 
+                          if i <= length stk
+                             then case runOp env op (take i stk) (drop i stk) of
+                                  Just v -> v
+                                  Nothing -> unload wp stk
+                             else unload wp stk
+                 _ -> unload wp stk
+
+    unload :: WHNF -> Stack -> WHNF
+    unload f [] = f
+    unload f (a : as) = unload (WApp f a) as
+
+    runOp :: WEnv -> ([Value] -> Maybe Value) -> Stack -> Stack -> Maybe WHNF
+    runOp env op stk rest 
+        = do vals <- mapM tmtoValue stk
+             case op vals of
+                  Just (VConstant c) -> Just $ unload (WConstant c) rest
+                  -- Operators run on values, so we have to convert back
+                  -- and forth. This is pretty ugly, but operators that
+                  -- aren't run on constants are themselves pretty ugly
+                  -- (it's prim__believe_me and prim__syntacticEq, for
+                  -- example) so let's not worry too much...
+                  Just val -> Just $ eval env rest (quoteTerm val)
+                  _ -> Nothing
+
+    tmtoValue :: (Term, WEnv) -> Maybe Value
+    tmtoValue (tm, tenv) 
+        = case eval tenv [] tm of
+               WConstant c -> Just (VConstant c)
+               _ -> let tm' = quoteEnv tenv tm in
+                        Just (toValue ctxt [] tm')
+
+    evalCase :: WEnv -> [Name] -> SC -> Stack -> Maybe WHNF
+    evalCase wenv@(WEnv d env) ns tree args 
+        | length ns > length args = Nothing
+        | otherwise = let args' = take (length ns) args
+                          rest = drop (length ns) args in
+                          do (tm, amap) <- evalTree wenv (zip ns args') tree
+                             let wtm = pToVs (map fst amap) tm
+                             Just $ eval (WEnv d (map snd amap)) rest wtm
+
+    evalTree :: WEnv -> [(Name, (Term, WEnv))] -> SC -> 
+                Maybe (Term, [(Name, (Term, WEnv))])
+    evalTree env amap (STerm tm) = Just (tm, amap)
+    evalTree env amap (Case _ n alts)
+        = case lookup n amap of
+            Just (tm, tenv) -> findAlt env amap 
+                                   (deconstruct (eval tenv [] tm) []) alts
+            _ -> Nothing
+    evalTree _ _ _ = Nothing
+
+    deconstruct :: WHNF -> Stack -> (WHNF, Stack)
+    deconstruct (WApp f arg) stk = deconstruct f (arg : stk)
+    deconstruct t stk = (t, stk) 
+
+    findAlt :: WEnv -> [(Name, (Term, WEnv))] -> (WHNF, Stack) -> 
+               [CaseAlt] ->
+               Maybe (Term, [(Name, (Term, WEnv))])
+    findAlt env amap (WDCon tag _ _ _ _, args) alts 
+        | Just (ns, sc) <- findTag tag alts 
+              = let amap' = updateAmap (zip ns args) amap in
+                    evalTree env amap' sc
+        | Just sc <- findDefault alts
+              = evalTree env amap sc
+    findAlt env amap (WConstant c, []) alts
+        | Just sc <- findConst c alts
+              = evalTree env amap sc
+        | Just sc <- findDefault alts
+              = evalTree env amap sc
+    findAlt _ _ _ _ = Nothing
+
+    findTag :: Int -> [CaseAlt] -> Maybe ([Name], SC)
+    findTag i [] = Nothing
+    findTag i (ConCase n j ns sc : xs) | i == j = Just (ns, sc)
+    findTag i (_ : xs) = findTag i xs
+   
+    findDefault :: [CaseAlt] -> Maybe SC
+    findDefault [] = Nothing
+    findDefault (DefaultCase sc : xs) = Just sc
+    findDefault (_ : xs) = findDefault xs
+
+    findConst c [] = Nothing
+    findConst c (ConstCase c' v : xs) | c == c' = Just v
+    findConst (AType (ATInt ITNative)) (ConCase n 1 [] v : xs) = Just v
+    findConst (AType ATFloat) (ConCase n 2 [] v : xs) = Just v
+    findConst (AType (ATInt ITChar))  (ConCase n 3 [] v : xs) = Just v
+    findConst StrType (ConCase n 4 [] v : xs) = Just v
+    findConst (AType (ATInt ITBig)) (ConCase n 6 [] v : xs) = Just v
+    findConst (AType (ATInt (ITFixed ity))) (ConCase n tag [] v : xs)
+        | tag == 7 + fromEnum ity = Just v
+    findConst c (_ : xs) = findConst c xs
+
+    updateAmap newm amap
+       = newm ++ filter (\ (x, _) -> not (elem x (map fst newm))) amap
+
+quote :: WHNF -> Term
+quote (WDCon t a u n (ty, env)) = P (DCon t a u) n (quoteEnv env ty)
+quote (WTCon t a n (ty, env)) = P (TCon t a) n (quoteEnv env ty)
+quote (WPRef n (ty, env)) = P Ref n (quoteEnv env ty) 
+quote (WBind n ty (sc, env)) = Bind n ty (quoteEnv env sc)
+quote (WApp f (a, env)) = App Complete (quote f) (quoteEnv env a)
+quote (WConstant c) = Constant c
+quote (WProj t i) = Proj (quote t) i
+quote (WType u) = TType u
+quote (WUType u) = UType u
+quote WErased = Erased
+quote WImpossible = Impossible
+
+quoteEnv :: WEnv -> Term -> Term
+quoteEnv (WEnv d ws) tm = qe' d ws tm
+  where
+    qe' d ts (V i) 
+        | i < d = V i
+        | otherwise = let (tm, env) = ts !! (i - d) in
+                          quoteEnv env tm
+    qe' d ts (Bind n b sc)
+        = Bind n (fmap (qe' d ts) b) (qe' (d + 1) ts sc)
+    qe' d ts (App c f a)
+        = App c (qe' d ts f) (qe' d ts a)
+    qe' d ts (P nt n ty) = P nt n (qe' d ts ty)
+    qe' d ts (Proj tm i) = Proj (qe' d ts tm) i
+    qe' d ts tm = tm
+
diff --git a/src/Idris/Coverage.hs b/src/Idris/Coverage.hs
--- a/src/Idris/Coverage.hs
+++ b/src/Idris/Coverage.hs
@@ -28,21 +28,21 @@
                let timp = addImpl' True [] [] [] i t
                evalStateT (toTT (mapPT deNS timp)) 0
   where
-    toTT (PRef _ n) = do i <- lift getIState
-                         case lookupNameDef n (tt_ctxt i) of
-                              [(n', TyDecl nt _)] -> return $ P nt n' Erased
-                              _ -> return $ P Ref n Erased
+    toTT (PRef _ _ n) = do i <- lift getIState
+                           case lookupNameDef n (tt_ctxt i) of
+                                [(n', TyDecl nt _)] -> return $ P nt n' Erased
+                                _ -> return $ P Ref n Erased
     toTT (PApp _ t args) = do t' <- toTT t
                               args' <- mapM (toTT . getTm) args
                               return $ mkApp t' args'
     -- For alternatives, pick the first and drop the namespaces. It doesn't
     -- really matter which is taken since matching will ignore the namespace.
-    toTT (PAlternative _ (a : as)) = toTT a
+    toTT (PAlternative _ _ (a : as)) = toTT a
     toTT _ = do v <- get
                 put (v + 1)
                 return (P Bound (sMN v "imp") Erased)
 
-    deNS (PRef f (NS n _)) = PRef f n
+    deNS (PRef f hl (NS n _)) = PRef f hl n
     deNS t = t
 
 -- | Given a list of LHSs, generate a extra clauses which cover the remaining
@@ -112,7 +112,7 @@
             | all (== [Placeholder]) args = []
         mkClauses parg args
             = do args' <- mkArg args
-                 let tm = PApp fc (PRef fc n) (zipWith upd args' parg)
+                 let tm = PApp fc (PRef fc [] n) (zipWith upd args' parg)
                  return tm
           where
             mkArg :: [[PTerm]] -> [[PTerm]]
@@ -214,15 +214,15 @@
     nubMap f acc (x : xs) = nubMap f (fnub' acc (f x)) xs
 
     otherPats :: PTerm -> [PTerm]
-    otherPats o@(PRef fc n) = ops fc n [] o
-    otherPats o@(PApp _ (PRef fc n) xs) = ops fc n xs o
-    otherPats o@(PPair fc _ l r)
+    otherPats o@(PRef fc hl n) = ops fc n [] o
+    otherPats o@(PApp _ (PRef fc hl n) xs) = ops fc n xs o
+    otherPats o@(PPair fc hls _ l r)
         = ops fc pairCon
                 ([pimp (sUN "A") Placeholder True,
                   pimp (sUN "B") Placeholder True] ++
                  [pexp l, pexp r]) o
-    otherPats o@(PDPair fc p t _ v)
-        = ops fc (sUN "Ex_intro")
+    otherPats o@(PDPair fc hls p t _ v)
+        = ops fc sigmaCon
                 ([pimp (sUN "a") Placeholder True,
                   pimp (sUN "P") Placeholder True] ++
                  [pexp t,pexp v]) o
@@ -232,7 +232,7 @@
     ops fc n xs o
         | (TyDecl c@(DCon _ arity _) ty : _) <- lookupDef n (tt_ctxt i)
             = do xs' <- mapM otherPats (map getExpTm xs)
-                 let p = resugar (PApp fc (PRef fc n) (zipWith upd xs' xs))
+                 let p = resugar (PApp fc (PRef fc [] n) (zipWith upd xs' xs))
                  let tyn = getTy n (tt_ctxt i)
                  case lookupCtxt tyn (idris_datatypes i) of
                          (TI ns _ _ _ _ : _) -> p : map (mkPat fc) (ns \\ [n])
@@ -243,12 +243,12 @@
     getExpTm t = getTm t
 
     -- put it back to its original form
-    resugar (PApp _ (PRef fc (UN ei)) [_,_,t,v])
-      | ei == txt "Ex_intro"
-        = PDPair fc TypeOrTerm (getTm t) Placeholder (getTm v)
-    resugar (PApp _ (PRef fc n) [_,_,l,r])
+    resugar (PApp _ (PRef fc hl n) [_,_,t,v])
+      | n == sigmaCon 
+        = PDPair fc [] TypeOrTerm (getTm t) Placeholder (getTm v)
+    resugar (PApp _ (PRef fc hl n) [_,_,l,r])
       | n == pairCon
-        = PPair fc IsTerm (getTm l) (getTm r)
+        = PPair fc [] IsTerm (getTm l) (getTm r)
     resugar t = t
 
     dropForce force (x : xs) i | i `elem` force
@@ -265,7 +265,7 @@
 
     mkPat fc x = case lookupCtxt x (idris_implicits i) of
                       (pargs : _)
-                         -> PApp fc (PRef fc x) (map (upd Placeholder) pargs)
+                         -> PApp fc (PRef fc [] x) (map (upd Placeholder) pargs)
                       _ -> error "Can't happen - genAll"
 
     fnub :: [PTerm] -> [PTerm]
@@ -279,7 +279,7 @@
     -- quick check for constructor equality
     quickEq :: PTerm -> PTerm -> Bool
     quickEq (PConstant _ n) (PConstant _ n') = n == n'
-    quickEq (PRef _ n) (PRef _ n') = n == n'
+    quickEq (PRef _ _ n) (PRef _ _ n') = n == n'
     quickEq (PApp _ t as) (PApp _ t' as')
         | length as == length as'
            = quickEq t t' && and (zipWith quickEq (map getTm as) (map getTm as'))
@@ -423,7 +423,9 @@
     | otherwise = do
         t <- getTotality n
         i <- getIState
-        updateContext (simplifyCasedef n $ getErasureInfo i)
+        ctxt' <- do ctxt <- getContext
+                    tclift $ simplifyCasedef n (getErasureInfo i) ctxt
+        setContext ctxt'
         ctxt <- getContext
         i <- getIState
         let opts = case lookupCtxt n (idris_flags i) of
diff --git a/src/Idris/DSL.hs b/src/Idris/DSL.hs
--- a/src/Idris/DSL.hs
+++ b/src/Idris/DSL.hs
@@ -18,7 +18,7 @@
 dslify :: SyntaxInfo -> IState -> PTerm -> PTerm
 dslify syn i = transform dslifyApp 
   where
-    dslifyApp (PApp fc (PRef _ f) [a])
+    dslifyApp (PApp fc (PRef _ _ f) [a])
         | [d] <- lookupCtxt f (idris_dsls i)
             = desugar (syn { dsl_info = d }) i (getTm a)
     dslifyApp t = t
@@ -29,20 +29,20 @@
 
 mkTTName :: FC -> Name -> PTerm
 mkTTName fc n =
-    let mkList fc []     = PRef fc (sNS (sUN "Nil") ["List", "Prelude"])
-        mkList fc (x:xs) = PApp fc (PRef fc (sNS (sUN "::") ["List", "Prelude"]))
+    let mkList fc []     = PRef fc [] (sNS (sUN "Nil") ["List", "Prelude"])
+        mkList fc (x:xs) = PApp fc (PRef fc [] (sNS (sUN "::") ["List", "Prelude"]))
                                    [ pexp (stringC x)
                                    , pexp (mkList fc xs)]
         stringC = PConstant fc . Str . str
         intC = PConstant fc . I
         reflm n = sNS (sUN n) ["Reflection", "Language"]
     in case n of
-         UN nm     -> PApp fc (PRef fc (reflm "UN")) [ pexp (stringC nm)]
-         NS nm ns  -> PApp fc (PRef fc (reflm "NS")) [ pexp (mkTTName fc nm)
-                                                     , pexp (mkList fc ns)]
-         MN i nm   -> PApp fc (PRef fc (reflm "MN")) [ pexp (intC i)
-                                                     , pexp (stringC nm)]
-         otherwise -> PRef fc $ reflm "NErased"
+         UN nm     -> PApp fc (PRef fc [] (reflm "UN")) [ pexp (stringC nm)]
+         NS nm ns  -> PApp fc (PRef fc [] (reflm "NS")) [ pexp (mkTTName fc nm)
+                                                        , pexp (mkList fc ns)]
+         MN i nm   -> PApp fc (PRef fc [] (reflm "MN")) [ pexp (intC i)
+                                                        , pexp (stringC nm)]
+         otherwise -> PRef fc [] $ reflm "NErased"
 
 expandSugar :: DSL -> PTerm -> PTerm
 expandSugar dsl (PLam fc n nfc ty tm)
@@ -72,15 +72,15 @@
 expandSugar dsl (PCase fc s opts) = PCase fc (expandSugar dsl s)
                                         (map (pmap (expandSugar dsl)) opts)
 expandSugar dsl (PIfThenElse fc c t f) =
-  PApp fc (PRef NoFC (sUN "ifThenElse"))
+  PApp fc (PRef NoFC [] (sUN "ifThenElse"))
        [ PExp 0 [] (sMN 0 "condition") $ expandSugar dsl c
        , PExp 0 [] (sMN 0 "whenTrue") $ expandSugar dsl t
        , PExp 0 [] (sMN 0 "whenFalse") $ expandSugar dsl f
        ]
-expandSugar dsl (PPair fc p l r) = PPair fc p (expandSugar dsl l) (expandSugar dsl r)
-expandSugar dsl (PDPair fc p l t r) = PDPair fc p (expandSugar dsl l) (expandSugar dsl t)
-                                               (expandSugar dsl r)
-expandSugar dsl (PAlternative a as) = PAlternative a (map (expandSugar dsl) as)
+expandSugar dsl (PPair fc hls p l r) = PPair fc hls p (expandSugar dsl l) (expandSugar dsl r)
+expandSugar dsl (PDPair fc hls p l t r) = PDPair fc hls p (expandSugar dsl l) (expandSugar dsl t)
+                                                          (expandSugar dsl r)
+expandSugar dsl (PAlternative ms a as) = PAlternative ms a (map (expandSugar dsl) as)
 expandSugar dsl (PHidden t) = PHidden (expandSugar dsl t)
 expandSugar dsl (PNoImplicits t) = PNoImplicits (expandSugar dsl t)
 expandSugar dsl (PUnifyLog t) = PUnifyLog (expandSugar dsl t)
@@ -99,7 +99,7 @@
         = PApp fc b [pexp tm, pexp (PLam fc n nfc Placeholder (block b rest))]
     block b (DoBindP fc p tm alts : rest)
         = PApp fc b [pexp tm, pexp (PLam fc (sMN 0 "bpat") NoFC Placeholder
-                                   (PCase fc (PRef fc (sMN 0 "bpat"))
+                                   (PCase fc (PRef fc [] (sMN 0 "bpat"))
                                              ((p, block b rest) : alts)))]
     block b (DoLet fc n nfc ty tm : rest)
         = PLet fc n nfc ty tm (block b rest)
@@ -112,13 +112,14 @@
     block b _ = PElabError (Msg "Invalid statement in do block")
 
 expandSugar dsl (PIdiom fc e) = expandSugar dsl $ unIdiom (dsl_apply dsl) (dsl_pure dsl) fc e
-expandSugar dsl (PRunElab fc tm) = PRunElab fc $ expandSugar dsl tm
+expandSugar dsl (PRunElab fc tm ns) = PRunElab fc (expandSugar dsl tm) ns
+expandSugar dsl (PConstSugar fc tm) = PConstSugar fc (expandSugar dsl tm)
 expandSugar dsl t = t
 
 -- | Replace DSL-bound variable in a term
 var :: DSL -> Name -> PTerm -> Int -> PTerm
 var dsl n t i = v' i t where
-    v' i (PRef fc x) | x == n =
+    v' i (PRef fc hl x) | x == n =
         case dsl_var dsl of
             Nothing -> PElabError (Msg "No 'variable' defined in dsl")
             Just v -> PApp fc v [pexp (mkVar fc i)]
@@ -137,9 +138,9 @@
     v' i (PTyped l r)    = PTyped (v' i l) (v' i r)
     v' i (PApp f x as)   = PApp f (v' i x) (fmap (fmap (v' i)) as)
     v' i (PCase f t as)  = PCase f (v' i t) (fmap (pmap (v' i)) as)
-    v' i (PPair f p l r) = PPair f p (v' i l) (v' i r)
-    v' i (PDPair f p l t r) = PDPair f p (v' i l) (v' i t) (v' i r)
-    v' i (PAlternative a as) = PAlternative a $ map (v' i) as
+    v' i (PPair f hls p l r) = PPair f hls p (v' i l) (v' i r)
+    v' i (PDPair f hls p l t r) = PDPair f hls p (v' i l) (v' i t) (v' i r)
+    v' i (PAlternative ms a as) = PAlternative ms a $ map (v' i) as
     v' i (PHidden t)     = PHidden (v' i t)
     v' i (PIdiom f t)    = PIdiom f (v' i t)
     v' i (PDoBlock ds)   = PDoBlock (map (fmap (v' i)) ds)
@@ -153,7 +154,7 @@
                    Nothing -> PElabError (Msg "No index_next defined")
                    Just f -> PApp fc f [pexp (mkVar fc (n-1))]
 
-    setFC fc (PRef _ n) = PRef fc n
+    setFC fc (PRef _ _ n) = PRef fc [] n
     setFC fc (PApp _ f xs) = PApp fc (setFC fc f) (map (fmap (setFC fc)) xs)
     setFC fc t = t
 
@@ -182,7 +183,7 @@
              (bs, n) <- get
              let nm = sUN ("_bindApp" ++ show n)
              put ((nm, fc, PApp fc t args') : bs, n+1)
-             return (PRef fc nm)
+             return (PRef fc [] nm)
     db' (PApp fc t args)
          = do t' <- db' t
               args' <- mapM dbArg args
@@ -192,13 +193,14 @@
                                      return (PLet fc n nfc ty v' (debind b sc))
     db' (PCase fc s opts) = do s' <- db' s
                                return (PCase fc s' (map (pmap (debind b)) opts))
-    db' (PPair fc p l r) = do l' <- db' l
-                              r' <- db' r
-                              return (PPair fc p l' r')
-    db' (PDPair fc p l t r) = do l' <- db' l
-                                 r' <- db' r
-                                 return (PDPair fc p l' t r')
-    db' (PRunElab fc t) = fmap (PRunElab fc) (db' t)
+    db' (PPair fc hls p l r) = do l' <- db' l
+                                  r' <- db' r
+                                  return (PPair fc hls p l' r')
+    db' (PDPair fc hls p l t r) = do l' <- db' l
+                                     r' <- db' r
+                                     return (PDPair fc hls p l' t r')
+    db' (PRunElab fc t ns) = fmap (\tm -> PRunElab fc tm ns) (db' t)
+    db' (PConstSugar fc tm) = liftM (PConstSugar fc) (db' tm)
     db' t = return t
 
     dbArg a = do t' <- db' (getTm a)
diff --git a/src/Idris/DataOpts.hs b/src/Idris/DataOpts.hs
--- a/src/Idris/DataOpts.hs
+++ b/src/Idris/DataOpts.hs
@@ -1,6 +1,6 @@
 {-# LANGUAGE PatternGuards #-}
 
-module Idris.DataOpts where
+module Idris.DataOpts(applyOpts) where
 
 -- Forcing, detagging and collapsing
 
diff --git a/src/Idris/DeepSeq.hs b/src/Idris/DeepSeq.hs
--- a/src/Idris/DeepSeq.hs
+++ b/src/Idris/DeepSeq.hs
@@ -120,6 +120,7 @@
         rnf (Specialise x1) = rnf x1 `seq` ()
         rnf Constructor = ()
         rnf AutoHint = ()
+        rnf PEGenerated = ()
 
 instance NFData DataOpt where
         rnf Codata = ()
@@ -135,9 +136,12 @@
                 rnf x3 `seq`
                   rnf x4 `seq`
                     rnf x5 `seq` rnf x6 `seq` rnf x7 `seq` rnf x8 `seq` ()
-        rnf (PPostulate x1 x2 x3 x4 x5 x6 x7)
+        rnf (PPostulate x1 x2 x3 x4 x5 x6 x7 x8)
           = rnf x1 `seq`
-              rnf x2 `seq` rnf x3 `seq` rnf x4 `seq` rnf x5 `seq` rnf x6 `seq` rnf x7 `seq` ()
+              rnf x2 `seq`
+                rnf x3 `seq`
+                  rnf x4 `seq`
+                    rnf x5 `seq` rnf x6 `seq` rnf x7 `seq` rnf x8 `seq` ()
         rnf (PClauses x1 x2 x3 x4)
           = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` rnf x4 `seq` ()
         rnf (PCAF x1 x2 x3) = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` ()
@@ -184,10 +188,16 @@
         rnf (PSyntax x1 x2) = rnf x1 `seq` rnf x2 `seq` ()
         rnf (PMutual x1 x2) = rnf x1 `seq` rnf x2 `seq` ()
         rnf (PDirective x1) = ()
-        rnf (PProvider x1 x2 x3 x4 x5)
-          = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` rnf x4 `seq` rnf x5 `seq` ()
+        rnf (PProvider x1 x2 x3 x4 x5 x6)
+          = rnf x1 `seq`
+              rnf x2 `seq`
+                rnf x3 `seq`
+                  rnf x4 `seq`
+                    rnf x5 `seq` rnf x6 `seq` ()
         rnf (PTransform x1 x2 x3 x4)
           = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` rnf x4 `seq` ()
+        rnf (PRunElabDecl x1 x2 x3)
+          = rnf x1 `seq` rnf x2 `seq` x3 `seq` ()
 
 instance NFData t => NFData (ProvideWhat' t)  where
         rnf (ProvTerm ty tm)   = rnf ty `seq` rnf tm `seq` ()
@@ -215,8 +225,8 @@
 
 instance NFData PTerm where
         rnf (PQuote x1) = rnf x1 `seq` ()
-        rnf (PRef x1 x2) = rnf x1 `seq` rnf x2 `seq` ()
-        rnf (PInferRef x1 x2) = rnf x1 `seq` rnf x2 `seq` ()
+        rnf (PRef x1 x2 x3) = rnf x1 `seq` rnf x2 `seq` x3 `seq` ()
+        rnf (PInferRef x1 x2 x3) = rnf x1 `seq` rnf x2 `seq` x3 `seq` ()
         rnf (PPatvar x1 x2) = rnf x1 `seq` rnf x2 `seq` ()
         rnf (PLam _ x1 x2 x3 x4) = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` rnf x4 `seq` ()
         rnf (PPi x1 x2 x3 x4 x5)
@@ -234,11 +244,11 @@
         rnf (PResolveTC x1) = rnf x1 `seq` ()
         rnf (PRewrite x1 x2 x3 x4)
           = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` rnf x4 `seq` ()
-        rnf (PPair x1 x2 x3 x4) = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` rnf x4 `seq` ()
-        rnf (PDPair x1 x2 x3 x4 x5)
-          = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` rnf x4 `seq` rnf x5 `seq` ()
+        rnf (PPair x1 x2 x3 x4 x5) = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` rnf x4 `seq` x5 `seq` ()
+        rnf (PDPair x1 x2 x3 x4 x5 x6)
+          = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` rnf x4 `seq` rnf x5 `seq` x6 `seq` ()
         rnf (PAs x1 x2 x3) = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` ()
-        rnf (PAlternative x1 x2) = rnf x1 `seq` rnf x2 `seq` ()
+        rnf (PAlternative x1 x2 x3) = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` ()
         rnf (PHidden x1) = rnf x1 `seq` ()
         rnf (PType fc) = rnf fc `seq` ()
         rnf (PUniverse _) = ()
@@ -260,12 +270,14 @@
         rnf (PNoImplicits x1) = rnf x1 `seq` ()
         rnf (PQuasiquote x1 x2) = rnf x1 `seq` rnf x2 `seq` ()
         rnf (PUnquote x1) = rnf x1 `seq` ()
-        rnf (PQuoteName x1) = rnf x1 `seq` ()
-        rnf (PRunElab x1 x2) = rnf x1 `seq` rnf x2 `seq` ()
+        rnf (PQuoteName x1 x2) = rnf x1 `seq` rnf x2 `seq` ()
+        rnf (PRunElab x1 x2 x3) = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` ()
+        rnf (PConstSugar x1 x2) = rnf x1 `seq` rnf x2 `seq` ()
 
 instance NFData PAltType where
         rnf (ExactlyOne x1) = rnf x1 `seq` ()
         rnf FirstSuccess = ()
+        rnf TryImplicit = () 
 
 instance (NFData t) => NFData (PTactic' t) where
         rnf (Intro x1) = rnf x1 `seq` ()
@@ -285,8 +297,8 @@
         rnf Compute = ()
         rnf Trivial = ()
         rnf TCInstance = ()
-        rnf (ProofSearch r r1 r2 x1 x2)
-          = rnf x1 `seq` rnf x2 `seq` ()
+        rnf (ProofSearch r r1 r2 x1 x2 x3)
+          = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` ()
         rnf Solve = ()
         rnf Attack = ()
         rnf ProofState = ()
@@ -310,12 +322,6 @@
         rnf SourceFC = ()
         rnf Unfocus = ()
 
-instance NFData ErrorReportPart where
-        rnf (TermPart x1) = rnf x1 `seq` ()
-        rnf (TextPart x1) = rnf x1 `seq` ()
-        rnf (NamePart x1) = rnf x1 `seq` ()
-        rnf (SubReport x1) = rnf x1 `seq` ()
-
 instance (NFData t) => NFData (PDo' t) where
         rnf (DoExp x1 x2) = rnf x1 `seq` rnf x2 `seq` ()
         rnf (DoBind x1 x2 x3 x4) = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` rnf x4 `seq` ()
@@ -363,6 +369,7 @@
 
 instance NFData Syntax where
         rnf (Rule x1 x2 x3) = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` ()
+        rnf (DeclRule x1 x2) = rnf x1 `seq` rnf x2 `seq` ()
 
 instance NFData SSymbol where
         rnf (Keyword x1) = rnf x1 `seq` ()
diff --git a/src/Idris/Delaborate.hs b/src/Idris/Delaborate.hs
--- a/src/Idris/Delaborate.hs
+++ b/src/Idris/Delaborate.hs
@@ -1,6 +1,6 @@
 {-# LANGUAGE PatternGuards #-}
 {-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
-module Idris.Delaborate (annName, bugaddr, delab, delab', delabMV, delabTy, delabTy', fancifyAnnots, pprintDelab, pprintDelabTy, pprintErr) where
+module Idris.Delaborate (annName, bugaddr, delab, delab', delabMV, delabSugared, delabTy, delabTy', fancifyAnnots, pprintDelab, pprintDelabTy, pprintErr, resugar) where
 
 -- Convert core TT back into high level syntax, primarily for display
 -- purposes.
@@ -15,15 +15,63 @@
 
 import Prelude hiding ((<$>))
 
+import Data.Generics.Uniplate.Data (transform)
 import Data.Maybe (mapMaybe)
 import Data.List (intersperse, nub)
 import qualified Data.Text as T
+import Control.Applicative (Alternative((<|>)))
 import Control.Monad.State
 
 import Debug.Trace
 
 bugaddr = "https://github.com/idris-lang/Idris-dev/issues"
 
+-- | Re-add syntactic sugar in a term
+resugar :: IState -> PTerm -> PTerm
+resugar ist = transform flattenDoLet . transform resugarApp
+  where
+    resugarApp (PApp fc (PRef _ _ n) args)
+      | [c, t, f] <- mapMaybe explicitTerm args
+      , basename n == sUN "ifThenElse"
+      = PIfThenElse fc c (dedelay t) (dedelay f)
+    resugarApp (PApp fc (PRef _ _ n) args)
+      | [v, PLam _ bn _ _ next] <- mapMaybe explicitTerm args
+      , basename n == sUN ">>="
+      = let step = if bn `elem` namesIn [] ist next
+                      then DoBind fc bn NoFC v
+                      else DoExp NoFC v
+        in case resugarApp next of
+             PDoBlock dos -> PDoBlock (step : dos)
+             expr -> PDoBlock [step, DoExp NoFC expr]
+    resugarApp (PApp fc (PRef _ _ n) args)
+      | [PConstant fc (BI i)] <- mapMaybe explicitTerm args
+      , basename n == sUN "fromInteger"
+      = PConstant fc (BI i)
+    resugarApp tm = tm
+
+    flattenDoLet (PLet _ ln _ ty v bdy)
+      | PDoBlock dos <- flattenDoLet bdy
+      = PDoBlock (DoLet NoFC ln NoFC ty v : dos)
+    flattenDoLet (PDoBlock dos) =
+      PDoBlock $ concatMap fixExp dos
+        where fixExp (DoExp _ (PLet _ ln _ ty v bdy)) =
+                DoLet NoFC ln NoFC ty v : fixExp (DoExp NoFC bdy)
+              fixExp d = [d]
+    flattenDoLet tm = tm
+
+    dedelay (PApp _ (PRef _ _ delay) [_, _, obj])
+      | delay == sUN "Delay" = getTm obj
+    dedelay x = x
+
+    explicitTerm (PExp {getTm = tm}) = Just tm
+    explicitTerm _ = Nothing
+
+
+-- | Delaborate and resugar a term
+delabSugared :: IState -> Term -> PTerm
+delabSugared ist tm = resugar ist $ delab ist tm
+
+-- | Delaborate a term without resugaring
 delab :: IState -> Term -> PTerm
 delab i tm = delab' i tm False False
 
@@ -50,16 +98,16 @@
   where
     un = fileFC "(val)"
 
-    de env _ (App _ f a) = resugarApp env $ deFn env f [a]
-    de env _ (V i)     | i < length env = PRef un (snd (env!!i))
-                       | otherwise = PRef un (sUN ("v" ++ show i ++ ""))
+    de env _ (App _ f a) = deFn env f [a]
+    de env _ (V i)     | i < length env = PRef un [] (snd (env!!i))
+                       | otherwise = PRef un [] (sUN ("v" ++ show i ++ ""))
     de env _ (P _ n _) | n == unitTy = PTrue un IsType
                        | n == unitCon = PTrue un IsTerm
-                       | Just n' <- lookup n env = PRef un n'
+                       | Just n' <- lookup n env = PRef un [] n'
                        | otherwise
                             = case lookup n (idris_metavars ist) of
-                                  Just (Just _, mi, _) -> mkMVApp n []
-                                  _ -> PRef un n
+                                  Just (Just _, mi, _, _) -> mkMVApp n []
+                                  _ -> PRef un [] n
     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)
@@ -106,22 +154,22 @@
 
     deFn env (App _ f a) args = deFn env f (a:args)
     deFn env (P _ n _) [l,r]
-         | n == pairTy    = PPair un IsType (de env [] l) (de env [] 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]
          | n == sigmaTy
-               = PDPair un IsType (PRef un x) (de env [] ty)
+               = PDPair un [] IsType (PRef un [] x) (de env [] ty)
                            (de ((x,x):env) [] (instantiate (P Bound x ty) r))
     deFn env (P _ n _) [lt,rt,l,r]
-         | n == pairCon = PPair un IsTerm (de env [] l) (de env [] r)
-         | n == sigmaCon = PDPair un IsTerm (de env [] l) Placeholder
-                                             (de env [] r)
+         | n == pairCon = PPair un [] IsTerm (de env [] l) (de env [] r)
+         | n == sigmaCon = PDPair un [] IsTerm (de env [] l) Placeholder
+                                                (de env [] r)
     deFn env f@(P _ n _) args
          | n `elem` map snd env
               = PApp un (de env [] f) (map pexp (map (de env []) args))
     deFn env (P _ n _) args
          | not mvs = case lookup n (idris_metavars ist) of
-                        Just (Just _, mi, _) ->
+                        Just (Just _, mi, _, _) ->
                             mkMVApp n (drop mi (map (de env []) args))
                         _ -> mkPApp n (map (de env []) args)
          | otherwise = mkPApp n (map (de env []) args)
@@ -133,8 +181,8 @@
             = PApp un (PMetavar NoFC n) (map pexp args)
     mkPApp n args
         | Just imps <- lookupCtxtExact n (idris_implicits ist)
-            = PApp un (PRef un n) (zipWith imp (imps ++ repeat (pexp undefined)) args)
-        | otherwise = PApp un (PRef un n) (map pexp args)
+            = PApp un (PRef un [] n) (zipWith imp (imps ++ repeat (pexp undefined)) args)
+        | otherwise = PApp un (PRef un [] n) (map pexp args)
 
     imp (PImp p m l n _) arg = PImp p m l n arg
     imp (PExp p l n _)   arg = PExp p l n arg
@@ -147,17 +195,6 @@
             isCN (SN (CaseN _)) = True
             isCN _ = False
 
-    resugarApp env (PApp _ (PRef _ n) args)
-                 | [c, t, f] <- mapMaybe explicitTerm args
-                 , basename n == sUN "ifThenElse"
-                 = PIfThenElse un c (dedelay t) (dedelay f)
-      where dedelay (PApp _ (PRef _ delay) [_, _, obj])
-              | delay == sUN "Delay" = getTm obj
-            dedelay x = x
-            explicitTerm (PExp {getTm = tm}) = Just tm
-            explicitTerm _ = Nothing
-    resugarApp env tm = tm
-
     delabCase :: [(Name, Name)] -> [PArg] -> Name -> Term -> Name -> [Term] -> Maybe PTerm
     delabCase env imps scvar scrutinee caseName caseArgs =
       do cases <- case lookupCtxt caseName (idris_patdefs ist) of
@@ -187,7 +224,7 @@
 -- | Pretty-print a core term using delaboration
 pprintDelab :: IState -> Term -> Doc OutputAnnotation
 pprintDelab ist tm = annotate (AnnTerm [] tm)
-                              (prettyIst ist (delab ist tm))
+                              (prettyIst ist (delabSugared ist tm))
 
 -- | Pretty-print the type of some name
 pprintDelabTy :: IState -> Name -> Doc OutputAnnotation
@@ -195,8 +232,8 @@
     = case lookupTy n (tt_ctxt i) of
            (ty:_) -> annotate (AnnTerm [] ty) . prettyIst i $
                      case lookupCtxt n (idris_implicits i) of
-                         (imps:_) -> delabTy' i imps ty False False
-                         _ -> delabTy' i [] ty False False
+                         (imps:_) -> resugar i $ delabTy' i imps ty False False
+                         _ -> resugar i $ delabTy' i [] ty False False
            [] -> error "pprintDelabTy got a name that doesn't exist"
 
 pprintTerm :: IState -> PTerm -> Doc OutputAnnotation
@@ -212,11 +249,11 @@
 pprintProv i e (SourceTerm tm) 
   = text "Type of " <> 
     annotate (AnnTerm (zip (map fst e) (repeat False)) tm)
-             (pprintTerm' i (zip (map fst e) (repeat False)) (delab i tm))
+             (pprintTerm' i (zip (map fst e) (repeat False)) (delabSugared i tm))
 pprintProv i e (TooManyArgs tm) 
   = text "Is " <> 
       annotate (AnnTerm (zip (map fst e) (repeat False)) tm)
-               (pprintTerm' i (zip (map fst e) (repeat False)) (delab i tm))
+               (pprintTerm' i (zip (map fst e) (repeat False)) (delabSugared i tm))
        <> text " applied to too many arguments?"
 
 pprintErr :: IState -> Err -> Doc OutputAnnotation
@@ -230,15 +267,15 @@
        ]
 pprintErr' i (CantUnify _ (x_in, xprov) (y_in, yprov) e sc s) =
   let (x_ns, y_ns, nms) = renameMNs x_in y_in
-      (x, y) = addImplicitDiffs (delab i x_ns) (delab i y_ns) in
-    text "Can't unify" <> indented (annTm x_ns
+      (x, y) = addImplicitDiffs (delabSugared i x_ns) (delabSugared i y_ns) in
+    text "Type mismatch between" <> indented (annTm x_ns
                       (pprintTerm' i (map (\ (n, b) -> (n, False)) sc
                                         ++ zip nms (repeat False)) x)) 
         <> case xprov of
                 Nothing -> empty
                 Just t -> text " (" <> pprintProv i sc t <> text ")"
         <$>
-    text "with" <> indented (annTm y_ns
+    text "and" <> indented (annTm y_ns
                       (pprintTerm' i (map (\ (n, b) -> (n, False)) sc
                                         ++ zip nms (repeat False)) y)) 
         <> case yprov of
@@ -252,18 +289,20 @@
       CantUnify _ (x_in', _) (y_in',_) _ _ _ | x_in == x_in' && y_in == y_in' -> empty
       _ -> line <> line <> text "Specifically:" <>
            indented (pprintErr' i e) <>
-           if (opt_errContext (idris_options i)) then showSc i sc else empty
+           if (opt_errContext (idris_options i))
+             then text "Unification failure" <$> showSc i sc
+             else empty
 pprintErr' i (CantConvert x_in y_in env) =
  let (x_ns, y_ns, nms) = renameMNs x_in y_in
-     (x, y) = addImplicitDiffs (delab i (flagUnique x_ns)) 
-                               (delab i (flagUnique y_ns)) in
-  text "Can't convert" <>
+     (x, y) = addImplicitDiffs (delabSugared i (flagUnique x_ns)) 
+                               (delabSugared i (flagUnique y_ns)) in
+  text "Type mismatch between" <>
   indented (annTm x_ns (pprintTerm' i (map (\ (n, b) -> (n, False)) env)
                x)) <$>
-  text "with" <>
+  text "and" <>
   indented (annTm y_ns (pprintTerm' i (map (\ (n, b) -> (n, False)) env)
                y)) <>
-  if (opt_errContext (idris_options i)) then line <> showSc i env else empty
+  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)
               = App Complete (P Ref (sUN (show u)) Erased)
                     (Bind n (Pi i (flagUnique t) k) (flagUnique sc))
@@ -272,51 +311,96 @@
           flagUnique t = t
 pprintErr' i (CantSolveGoal x env) =
   text "Can't solve goal " <>
-  indented (annTm x (pprintTerm' i (map (\ (n, b) -> (n, False)) env) (delab i x))) <>
+  indented (annTm x (pprintTerm' i (map (\ (n, b) -> (n, False)) env) (delabSugared i x))) <>
   if (opt_errContext (idris_options i)) then line <> showSc i env else empty
 pprintErr' i (UnifyScope n out tm env) =
   text "Can't unify" <> indented (annName n) <+>
-  text "with" <> indented (annTm tm (pprintTerm' i (map (\ (n, b) -> (n, False)) env) (delab i tm))) <+>
+  text "with" <> indented (annTm tm (pprintTerm' i (map (\ (n, b) -> (n, False)) env) (delabSugared i tm))) <+>
  text "as" <> indented (annName out) <> text "is not in scope" <>
   if (opt_errContext (idris_options i)) then line <> showSc i env else empty
 pprintErr' i (CantInferType t) = text "Can't infer type for" <+> text t
 pprintErr' i (NonFunctionType f ty) =
-  annTm f (pprintTerm i (delab i f)) <+>
+  annTm f (pprintTerm i (delabSugared i f)) <+>
   text "does not have a function type" <+>
-  parens (pprintTerm i (delab i ty))
+  parens (pprintTerm i (delabSugared i ty))
 pprintErr' i (NotEquality tm ty) =
-  annTm tm (pprintTerm i (delab i tm)) <+>
+  annTm tm (pprintTerm i (delabSugared i tm)) <+>
   text "does not have an equality type" <+>
-  annTm ty (parens (pprintTerm i (delab i ty)))
+  annTm ty (parens (pprintTerm i (delabSugared i ty)))
 pprintErr' i (TooManyArguments f) = text "Too many arguments for" <+> annName f
 pprintErr' i (CantIntroduce ty) =
-  text "Can't use lambda here: type is" <+> annTm ty (pprintTerm i (delab i ty))
+  text "Can't use lambda here: type is" <+> annTm ty (pprintTerm i (delabSugared i ty))
 pprintErr' i (InfiniteUnify x tm env) =
   text "Unifying" <+> annName' x (showbasic x) <+> text "and" <+>
-  annTm tm (pprintTerm' i (map (\ (n, b) -> (n, False)) env) (delab i tm)) <+>
+  annTm tm (pprintTerm' i (map (\ (n, b) -> (n, False)) env) (delabSugared i tm)) <+>
   text "would lead to infinite value" <>
   if (opt_errContext (idris_options i)) then line <> showSc i env else empty
 pprintErr' i (NotInjective p x y) =
-  text "Can't verify injectivity of" <+> annTm p (pprintTerm i (delab i p)) <+>
-  text " when unifying" <+> annTm x (pprintTerm i (delab i x)) <+> text "and" <+>
-  annTm y (pprintTerm i (delab i y))
-pprintErr' i (CantResolve _ c) = text "Can't resolve type class" <+> pprintTerm i (delab i c)
+  text "Can't verify injectivity of" <+> annTm p (pprintTerm i (delabSugared i p)) <+>
+  text " when unifying" <+> annTm x (pprintTerm i (delabSugared i x)) <+> text "and" <+>
+  annTm y (pprintTerm i (delabSugared i y))
+pprintErr' i (CantResolve _ c) = text "Can't resolve type class" <+> pprintTerm i (delabSugared i c)
 pprintErr' i (InvalidTCArg n t) 
-   = annTm t (pprintTerm i (delab i t)) <+> text " cannot be a parameter of "
+   = annTm t (pprintTerm i (delabSugared i t)) <+> text " cannot be a parameter of "
         <> annName n <$>
         text "(Type class arguments must be injective)"
 pprintErr' i (CantResolveAlts as) = text "Can't disambiguate name:" <+>
                                     align (cat (punctuate (comma <> space) (map (fmap (fancifyAnnots i True) . annName) as)))
+pprintErr' i (NoValidAlts as) = text "Can't disambiguate since no name has a suitable type:" <+>
+                                    indented (align (cat (punctuate (comma <> space) (map (fmap (fancifyAnnots i True) . annName) as))))
 pprintErr' i (NoTypeDecl n) = text "No type declaration for" <+> annName n
 pprintErr' i (NoSuchVariable n) = text "No such variable" <+> annName n
 pprintErr' i (WithFnType ty) =
-  text "Can't match on a function: type is" <+> annTm ty (pprintTerm i (delab i ty))
+  text "Can't match on a function: type is" <+> annTm ty (pprintTerm i (delabSugared i ty))
 pprintErr' i (CantMatch t) =
-  text "Can't match on" <+> annTm t (pprintTerm i (delab i t))
-pprintErr' i (IncompleteTerm t) = text "Incomplete term" <+> annTm t (pprintTerm i (delab i t))
+  text "Can't match on" <+> annTm t (pprintTerm i (delabSugared i t))
+pprintErr' i (IncompleteTerm t) 
+    = align (cat (punctuate (comma <> space) 
+            (map pprintIncomplete (nub $ getMissing [] [] t))))
+ where 
+   pprintIncomplete (tm, arg)
+    | expname arg
+      = text "Can't infer explicit argument to" <+>
+                   annTm tm (pprintTerm i (delabSugared i tm))
+    | otherwise
+      = text "Can't infer argument" <+> annName arg <+> text "to" <+>
+                   annTm tm (pprintTerm i (delabSugared i tm))
+
+   expname (UN n) = case str n of
+                         ('_':_) -> True
+                         _ -> False
+   expname (MN _ n) = case str n of
+                         ('_':_) -> True
+                         _ -> False
+   expname _ = False
+
+   getMissing :: [Name] -> [Name] -> Term -> [(Term, Name)]
+   getMissing hs env (Bind n (Hole ty) sc)
+       = getMissing (n : hs) (n : env) sc
+   getMissing hs env (Bind n (Guess _ _) sc)
+       = getMissing (n : hs) (n : env) sc
+   getMissing hs env (Bind n (Let t v) sc)
+       = getMissing hs env t ++ 
+         getMissing hs env v ++
+         getMissing hs (n : env) sc
+   getMissing hs env (Bind n b sc)
+       = getMissing hs env (binderTy b) ++
+         getMissing hs (n : env) sc
+   getMissing hs env ap@(App _ _ _)
+       | (fn@(P _ n _), args) <- unApply ap = getMissingArgs fn args
+     where
+       getMissingArgs n [] = []
+       getMissingArgs n (V i : as)
+          | env!!i `elem` hs = (n, env!!i) : getMissingArgs n as
+       getMissingArgs n (P _ a _ : as) 
+          | a `elem` hs = (n, a) : getMissingArgs n as
+       getMissingArgs n (a : as) = getMissing hs env a ++ getMissingArgs n as
+   getMissing hs env (App _ f a)
+       = getMissing hs env f ++ getMissing hs env a
+   getMissing hs env _ = []
 pprintErr' i (NoEliminator s t)
   = text "No " <> text s <> text " for type " <+>
-       annTm t (pprintTerm i (delab i t)) <$>
+       annTm t (pprintTerm i (delabSugared i t)) <$>
     text "Please note that 'induction' is experimental." <$>
     text "Only types declared with '%elim' can be used." <$>
     text "Consider writing a pattern matching definition instead."
@@ -344,21 +428,21 @@
 pprintErr' i (AlreadyDefined n) = annName n<+>
                                   text "is already defined"
 pprintErr' i (ProofSearchFail e) = pprintErr' i e
-pprintErr' i (NoRewriting tm) = text "rewrite did not change type" <+> annTm tm (pprintTerm i (delab i tm))
+pprintErr' i (NoRewriting tm) = text "rewrite did not change type" <+> annTm tm (pprintTerm i (delabSugared i tm))
 pprintErr' i (At f e) = annotate (AnnFC f) (text (show f)) <> colon <> pprintErr' i e
-pprintErr' i (Elaborating s n e) = text "When elaborating" <+> text s <>
+pprintErr' i (Elaborating s n e) = text "When checking" <+> text s <>
                                    annName' n (showqual i n) <> colon <$>
                                    pprintErr' i e
 pprintErr' i (ElaboratingArg f x _ e)
   | isInternal f = pprintErr' i e
   | isUN x =
-     text "When elaborating argument" <+>
+     text "When checking argument" <+>
      annotate (AnnBoundName x False) (text (showbasic x)) <+> -- TODO check plicity
      -- Issue #1591 on the issue tracker: https://github.com/idris-lang/Idris-dev/issues/1591
      text "to" <+> whatIsName <> annName f <> colon <>
      indented (pprintErr' i e)
   | otherwise =
-     text "When elaborating an application of" <+> whatIsName <>
+     text "When checking an application of" <+> whatIsName <>
      annName f <> colon <> indented (pprintErr' i e)
   where whatIsName = let ctxt = tt_ctxt i
                      in if isTConName f ctxt
@@ -376,23 +460,18 @@
 pprintErr' i (ProviderError msg) = text ("Type provider error: " ++ msg)
 pprintErr' i (LoadingFailed fn e) = text "Loading" <+> text fn <+> text "failed:" <+>  pprintErr' i e
 pprintErr' i (ReflectionError parts orig) =
-  let parts' = map (fillSep . map showPart) parts in
+  let parts' = map (fillSep . map (showPart i)) parts in
   align (fillSep parts') <>
   if (opt_origerr (idris_options i))
     then line <> line <> text "Original error:" <$> indented (pprintErr' i orig)
     else empty
-  where showPart :: ErrorReportPart -> Doc OutputAnnotation
-        showPart (TextPart str) = fillSep . map text . words $ str
-        showPart (NamePart n)   = annName n
-        showPart (TermPart tm)  = pprintTerm i (delab i tm)
-        showPart (SubReport rs) = indented . hsep . map showPart $ rs
 pprintErr' i (ReflectionFailed msg err) =
   text "When attempting to perform error reflection, the following internal error occurred:" <>
   indented (pprintErr' i err) <>
   text ("This is probably a bug. Please consider reporting it at " ++ bugaddr)
 pprintErr' i (ElabScriptDebug msg tm holes) =
   text "Elaboration halted." <>
-  maybe empty (indented . text) msg <>
+  indented (align . hsep $ map (showPart i) msg) <>
   line <> line <>
   text "Holes:" <>
   indented (vsep (map ppHole holes)) <> line <> line <>
@@ -415,7 +494,16 @@
 pprintErr' i (ElabScriptStuck tm) =
   text "Can't run" <+> pprintTT [] tm <+> text "as an elaborator script." <$>
   text "Is it a stuck term?"
+pprintErr' i (RunningElabScript e) =
+  text "While running an elaboration script, the following error occurred" <> colon <$> pprintErr' i e
 
+showPart :: IState -> ErrorReportPart -> Doc OutputAnnotation
+showPart ist (TextPart str) = fillSep . map text . words $ str
+showPart ist (NamePart n)   = annName n
+showPart ist (TermPart tm)  = pprintTerm ist (delabSugared ist tm)
+showPart ist (RawPart tm)   = pprintRaw [] tm
+showPart ist (SubReport rs) = indented . hsep . map (showPart ist) $ rs
+
 -- | Make sure the machine invented names are shown helpfully to the user, so
 -- that any names which differ internally also differ visibly
 renameMNs :: Term -> Term -> (Term, Term, [Name])
@@ -483,19 +571,19 @@
          = let (a', c') = addI a c
                (b', d') = addI b d in
                (PPi p n fc a' b', PPi p' n' fc' c' d')
-    addI (PPair fc pi a b) (PPair fc' pi' c d)
+    addI (PPair fc hls pi a b) (PPair fc' hls' pi' c d)
          = let (a', c') = addI a c
                (b', d') = addI b d in
-               (PPair fc pi a' b', PPair fc' pi' c' d')
-    addI (PDPair fc pi a t b) (PDPair fc' pi' c u d)
+               (PPair fc hls pi a' b', PPair fc' hls' pi' c' d')
+    addI (PDPair fc hls pi a t b) (PDPair fc' hls' pi' c u d)
          = let (a', c') = addI a c
                (t', u') = addI t u
                (b', d') = addI b d in
-               (PDPair fc pi a' t' b', PDPair fc' pi' c' u' d')
+               (PDPair fc hls pi a' t' b', PDPair fc' hls' pi' c' u' d')
     addI x y = (x, y)
 
     -- Just the ones which appear desugared in errors
-    expLike (PRef _ n) (PRef _ n') = n == n'
+    expLike (PRef _ _ n) (PRef _ _ n') = n == n'
     expLike (PApp _ f as) (PApp _ f' as')
         = expLike f f' && length as == length as' &&
           and (zipWith expLike (getExps as) (getExps as'))
@@ -503,8 +591,8 @@
         = n == n' && expLike s s' && expLike t t'
     expLike (PLam _ n _ s t) (PLam _ n' _ s' t')
         = n == n' && expLike s s' && expLike t t'
-    expLike (PPair _ _ x y) (PPair _ _ x' y') = expLike x x' && expLike y y'
-    expLike (PDPair _ _ x _ y) (PDPair _ _ x' _ y') = expLike x x' && expLike y y'
+    expLike (PPair _ _ _ x y) (PPair _ _ _ x' y') = expLike x x' && expLike y y'
+    expLike (PDPair _ _ _ x _ y) (PDPair _ _ _ x' _ y') = expLike x x' && expLike y y'
     expLike x y = x == y
 
 -- Issue #1589 on the issue tracker
@@ -528,18 +616,18 @@
 
 -- | Add extra metadata to an output annotation, optionally marking metavariables.
 fancifyAnnots :: IState -> Bool -> OutputAnnotation -> OutputAnnotation
-fancifyAnnots ist meta annot@(AnnName n _ _ _) =
+fancifyAnnots ist meta annot@(AnnName n nt _ _) =
   do let ctxt = tt_ctxt ist
          docs = docOverview ist n
          ty   = Just (getTy ist n)
      case () of
-       _ | isDConName      n ctxt -> AnnName n (Just DataOutput) docs ty
-       _ | isFnName        n ctxt -> AnnName n (Just FunOutput) docs ty
-       _ | isTConName      n ctxt -> AnnName n (Just TypeOutput) docs ty
+       _ | isDConName      n ctxt -> AnnName n (nt <|> Just DataOutput) docs ty
+       _ | isFnName        n ctxt -> AnnName n (nt <|>  Just FunOutput) docs ty
+       _ | isTConName      n ctxt -> AnnName n (nt <|>  Just TypeOutput) docs ty
        _ | isMetavarName   n ist  -> if meta
-                                       then AnnName n (Just MetavarOutput) docs ty
-                                       else AnnName n (Just FunOutput) docs ty
-       _ | isPostulateName n ist  -> AnnName n (Just PostulateOutput) docs ty
+                                       then AnnName n (nt <|>  Just MetavarOutput) docs ty
+                                       else AnnName n (nt <|>  Just FunOutput) docs ty
+       _ | isPostulateName n ist  -> AnnName n (nt <|>  Just PostulateOutput) docs ty
        _ | otherwise              -> annot
   where docOverview :: IState -> Name -> Maybe String -- pretty-print first paragraph of docs
         docOverview ist n = do docs <- lookupCtxtExact n (idris_docstrings ist)
@@ -554,7 +642,7 @@
                                return (out "")
         getTy :: IState -> Name -> String -- fails if name not already extant!
         getTy ist n = let theTy = pprintPTerm (ppOptionIst ist) [] [] (idris_infixes ist) $
-                                  delabTy ist n
+                                  resugar ist $ delabTy ist n
                       in (displayS . renderPretty 1.0 50 $ theTy) ""
 fancifyAnnots _ _ annot = annot
 
@@ -564,7 +652,7 @@
             indented (vsep (reverse (showSc' [] xs)))
      where showSc' bnd [] = []
            showSc' bnd ((n, ty):ctxt) =
-             let this = bindingOf n False <+> colon <+> pprintTerm' i bnd (delab i ty)
+             let this = bindingOf n False <+> colon <+> pprintTerm' i bnd (delabSugared i ty)
              in this : showSc' ((n,False):bnd) ctxt
 
 
diff --git a/src/Idris/Directives.hs b/src/Idris/Directives.hs
--- a/src/Idris/Directives.hs
+++ b/src/Idris/Directives.hs
@@ -1,9 +1,10 @@
 
-module Idris.Directives where
+module Idris.Directives(directiveAction) where
 
 import Idris.AbsSyntax
 import Idris.ASTUtils
 import Idris.Imports
+import Idris.Output (sendHighlighting)
 
 import Idris.Core.Evaluate
 import Idris.Core.TT
@@ -43,15 +44,24 @@
                                              Left lib -> addIBC (IBCDyLib (lib_name lib))
                                              Right msg -> fail $ msg
 
-directiveAction (DNameHint ty ns) = do ty' <- disambiguate ty
-                                       mapM_ (addNameHint ty') ns
-                                       mapM_ (\n -> addIBC (IBCNameHint (ty', n))) ns
+directiveAction (DNameHint ty tyFC ns) = do ty' <- disambiguate ty
+                                            mapM_ (addNameHint ty' . fst) ns
+                                            mapM_ (\n -> addIBC (IBCNameHint (ty', fst n))) ns
+                                            sendHighlighting $
+                                              [(tyFC, AnnName ty' Nothing Nothing Nothing)] ++
+                                              map (\(n, fc) -> (fc, AnnBoundName n False)) ns
 
-directiveAction (DErrorHandlers fn arg ns) = do fn' <- disambiguate fn
-                                                ns' <- mapM disambiguate ns
-                                                addFunctionErrorHandlers fn' arg ns'
-                                                mapM_ (addIBC .
-                                                    IBCFunctionErrorHandler fn' arg) ns'
+directiveAction (DErrorHandlers fn nfc arg afc ns) =
+  do fn' <- disambiguate fn
+     ns' <- mapM (\(n, fc) -> do n' <- disambiguate n
+                                 return (n', fc)) ns
+     addFunctionErrorHandlers fn' arg (map fst ns')
+     mapM_ (addIBC .
+         IBCFunctionErrorHandler fn' arg . fst) ns'
+     sendHighlighting $
+       [(nfc, AnnName fn' Nothing Nothing Nothing),
+        (afc, AnnBoundName arg False)] ++
+       map (\(n, fc) -> (fc, AnnName n Nothing Nothing Nothing)) ns'
 
 directiveAction (DLanguage ext) = addLangExt ext
 
diff --git a/src/Idris/Docs.hs b/src/Idris/Docs.hs
--- a/src/Idris/Docs.hs
+++ b/src/Idris/Docs.hs
@@ -1,6 +1,6 @@
 {-# LANGUAGE DeriveFunctor, PatternGuards, MultiWayIf #-}
 {-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
-module Idris.Docs (pprintDocs, getDocs, pprintConstDocs, FunDoc, FunDoc'(..), Docs, Docs'(..)) where
+module Idris.Docs (pprintDocs, getDocs, pprintConstDocs, pprintTypeDoc, FunDoc, FunDoc'(..), Docs, Docs'(..)) where
 
 import Idris.AbsSyntax
 import Idris.AbsSyntaxTree
@@ -53,17 +53,26 @@
   | otherwise = text "  -- " <>
                 renderDocstring (renderDocTerm (pprintDelab ist) (normaliseAll (tt_ctxt ist) [])) d
 
-pprintFD :: IState -> FunDoc -> Doc OutputAnnotation
-pprintFD ist (FD n doc args ty f)
-    = nest 4 (prettyName True (ppopt_impl ppo) [] n <+> colon <+>
+pprintFD :: IState -> Bool -> Bool -> FunDoc -> Doc OutputAnnotation
+pprintFD ist totalityFlag nsFlag (FD n doc args ty f)
+    = nest 4 (prettyName True nsFlag [] n <+> colon <+>
               pprintPTerm ppo [] [ n | (n@(UN n'),_,_,_) <- args
                                      , not (T.isPrefixOf (T.pack "__") n') ] infixes ty <$>
+              -- show doc
               renderDocstring (renderDocTerm (pprintDelab ist) (normaliseAll (tt_ctxt ist) [])) doc <$>
+              -- show fixity
               maybe empty (\f -> text (show f) <> line) f <>
+              -- show arguments doc
               let argshow = showArgs args [] in
-              if not (null argshow)
+              (if not (null argshow)
                 then nest 4 $ text "Arguments:" <$> vsep argshow
-                else empty)
+                else empty) <>
+              -- show totality status
+              let totality = getTotality in
+              (if totalityFlag && not (null totality) then
+                line <> (vsep . map (\t -> text "The function is" <+> t) $ totality)
+               else
+                empty))
 
     where ppo = ppOptionIst ist
           infixes = idris_infixes ist
@@ -87,15 +96,21 @@
                showArgs args ((n, True):bnd)
           showArgs ((n, _, _, _):args) bnd = showArgs args ((n, True):bnd)
           showArgs []                  _ = []
+          getTotality = map (text . show) $ lookupTotal n (tt_ctxt ist)
 
+pprintFDWithTotality :: IState -> Bool -> FunDoc -> Doc OutputAnnotation
+pprintFDWithTotality ist = pprintFD ist True
 
+pprintFDWithoutTotality :: IState -> Bool -> FunDoc -> Doc OutputAnnotation
+pprintFDWithoutTotality ist = pprintFD ist False
+
 pprintDocs :: IState -> Docs -> Doc OutputAnnotation
-pprintDocs ist (FunDoc d) = pprintFD ist d
+pprintDocs ist (FunDoc d) = pprintFDWithTotality ist True d
 pprintDocs ist (DataDoc t args)
-           = text "Data type" <+> pprintFD ist t <$>
+           = text "Data type" <+> pprintFDWithoutTotality ist True t <$>
              if null args then text "No constructors."
              else nest 4 (text "Constructors:" <> line <>
-                          vsep (map (pprintFD ist) args))
+                          vsep (map (pprintFDWithoutTotality ist False) args))
 pprintDocs ist (ClassDoc n doc meths params instances subclasses superclasses ctor)
            = nest 4 (text "Type class" <+> prettyName True (ppopt_impl ppo) [] n <>
                      if nullDocstring doc
@@ -105,12 +120,12 @@
              nest 4 (text "Parameters:" <$> prettyParameters)
              <> line <$>
              nest 4 (text "Methods:" <$>
-                      vsep (map (pprintFD ist) meths))
+                      vsep (map (pprintFDWithTotality ist False) meths))
              <$>
              maybe empty
                    ((<> line) . nest 4 .
                     (text "Instance constructor:" <$>) .
-                    pprintFD ist)
+                    pprintFDWithoutTotality ist False)
                    ctor
              <>
              nest 4 (text "Instances:" <$>
@@ -182,12 +197,12 @@
     updateArgs ps     (a:as)                      = a : updateArgs ps as
     updateArgs _      _                           = []
 
-    updateRef nm (PRef fc _) = PRef fc nm
+    updateRef nm (PRef fc _ _) = PRef fc [] nm
     updateRef _  pt          = pt
 
-    isSubclass (PPi (Constraint _ _) _ _ (PApp _ _ args) (PApp _ (PRef _ nm) args')) = nm == n && map getTm args == map getTm args'
-    isSubclass (PPi _   _            _ _ pt)                                       = isSubclass pt
-    isSubclass _                                                                   = False
+    isSubclass (PPi (Constraint _ _) _ _ (PApp _ _ args) (PApp _ (PRef _ _ nm) args')) = nm == n && map getTm args == map getTm args'
+    isSubclass (PPi _   _            _ _ pt)                                           = isSubclass pt
+    isSubclass _                                                                       = False
 
     prettyParameters =
       if any (isJust . snd) params
@@ -195,7 +210,7 @@
          else hsep (punctuate comma (map (prettyName True False params' . fst) params))
 
 pprintDocs ist (NamedInstanceDoc _cls doc)
-   = nest 4 (text "Named instance:" <$> pprintFD ist doc)
+   = nest 4 (text "Named instance:" <$> pprintFDWithoutTotality ist True doc)
 
 pprintDocs ist (ModDoc mod docs)
    = nest 4 $ text "Module" <+> text (concat (intersperse "." mod)) <> colon <$>
@@ -274,7 +289,7 @@
     getDInst (PInstance _ _ _ _ _ _ _ _ t _ _) = Just t
     getDInst _                                 = Nothing
 
-    isSubclass (PPi (Constraint _ _) _ _ (PApp _ _ args) (PApp _ (PRef _ nm) args'))
+    isSubclass (PPi (Constraint _ _) _ _ (PApp _ _ args) (PApp _ (PRef _ _ nm) args'))
       = nm == n && map getTm args == map getTm args'
     isSubclass (PPi _ _ _ _ pt)
       = isSubclass pt
@@ -317,3 +332,8 @@
         t (Str _) = PConstant NoFC StrType
         t (Ch c)  = PConstant NoFC $ AType (ATInt ITChar)
         t _       = PType NoFC
+
+
+pprintTypeDoc :: IState -> Doc OutputAnnotation
+pprintTypeDoc ist = prettyIst ist (PType emptyFC) <+> colon <+> type1Doc <+>
+                     nest 4 (line <> text typeDescription) 
diff --git a/src/Idris/Docstrings.hs b/src/Idris/Docstrings.hs
--- a/src/Idris/Docstrings.hs
+++ b/src/Idris/Docstrings.hs
@@ -190,8 +190,7 @@
 renderInline pp (Emph txt) = annotate (AnnTextFmt ItalicText) $ renderInlines pp txt
 renderInline pp (Strong txt) = annotate (AnnTextFmt BoldText) $ renderInlines pp txt
 renderInline pp (Code txt tm) = pp tm $ T.unpack txt
-renderInline pp (Link body url title) = annotate (AnnTextFmt UnderlineText) (renderInlines pp body) <+>
-                                        parens (text $ T.unpack url)
+renderInline pp (Link body url title) = annotate (AnnLink (T.unpack url)) (renderInlines pp body)
 renderInline pp (Image body url title) = text "<image>" -- TODO
 renderInline pp (Entity a) = text $ "<entity " ++ T.unpack a ++ ">" -- TODO
 renderInline pp (RawHtml txt) = text "<html content>" --TODO
diff --git a/src/Idris/Elab/AsPat.hs b/src/Idris/Elab/AsPat.hs
--- a/src/Idris/Elab/AsPat.hs
+++ b/src/Idris/Elab/AsPat.hs
@@ -44,5 +44,5 @@
 
 
     replaceUnderscore' :: PTerm -> State Int PTerm
-    replaceUnderscore' Placeholder = PRef emptyFC <$> fresh
+    replaceUnderscore' Placeholder = PRef emptyFC [] <$> fresh
     replaceUnderscore' tm          = return tm
diff --git a/src/Idris/Elab/Class.hs b/src/Idris/Elab/Class.hs
--- a/src/Idris/Elab/Class.hs
+++ b/src/Idris/Elab/Class.hs
@@ -65,8 +65,8 @@
 elabClass info syn_in doc fc constraints tn tnfc ps pDocs fds ds mcn cd
     = do let cn = fromMaybe (SN (InstanceCtorN tn)) (fst <$> mcn)
          let tty = pibind (map (\(n, _, ty) -> (n, ty)) ps) (PType fc)
-         let constraint = PApp fc (PRef fc tn)
-                                  (map (pexp . PRef fc) (map (\(n, _, _) -> n) ps))
+         let constraint = PApp fc (PRef fc [] tn)
+                                  (map (pexp . PRef fc []) (map (\(n, _, _) -> n) ps))
 
          let syn =
               syn_in { using = addToUsing (using syn_in)
@@ -142,7 +142,7 @@
         = do when (not $ null cs) . tclift
                 $ tfail (At fc (Msg $ "Default superclass instances can't have constraints."))
              i <- getIState
-             let t = PApp fc (PRef fc n) (map pexp ps)
+             let t = PApp fc (PRef fc [] n) (map pexp ps)
              let isConstrained = any (== t) (map snd constraints)
              when (not isConstrained) . tclift
                 $ tfail (At fc (Msg $ "Default instances must be for a superclass constraint on the containing class."))
@@ -174,7 +174,7 @@
                  let ds = map (decorateid defaultdec)
                               [PTy emptyDocstring [] syn fc [] n nfc ty',
                                PClauses fc (o ++ opts) n cs]
-                 iLOG (show ds)
+                 logLvl 1 (show ds)
                  return (n, ((defaultdec n, ds!!1), ds))
             _ -> ifail $ show n ++ " is not a method"
     defdecl _ _ _ = ifail "Can't happen (defdecl)"
@@ -195,16 +195,16 @@
         = do let cfn = sUN ('@':'@':show cn ++ "#" ++ show con)
                        -- SN (ParentN cn (show con))
              let mnames = take (length all) $ map (\x -> sMN x "meth") [0..]
-             let capp = PApp fc (PRef fc cn) (map (pexp . PRef fc) mnames)
-             let lhs = PApp fc (PRef fc cfn) [pconst capp]
+             let capp = PApp fc (PRef fc [] cn) (map (pexp . PRef fc []) mnames)
+             let lhs = PApp fc (PRef fc [] cfn) [pconst capp]
              let rhs = PResolveTC (fileFC "HACK")
              let ty = PPi constraint cnm NoFC c con
              logLvl 2 ("Dictionary constraint: " ++ showTmImpls ty)
              logLvl 2 (showTmImpls lhs ++ " = " ++ showTmImpls rhs)
              i <- getIState
              let conn = case con of
-                            PRef _ n -> n
-                            PApp _ (PRef _ n) _ -> n
+                            PRef _ _ n -> n
+                            PApp _ (PRef _ _ n) _ -> n
              let conn' = case lookupCtxtName conn (idris_classes i) of
                                 [(n, _)] -> n
                                 _ -> conn
@@ -225,13 +225,13 @@
     tfun cn c syn all (m, (mfc, doc, o, ty))
         = do let ty' = expandMethNS syn (insertConstraint c all ty)
              let mnames = take (length all) $ map (\x -> sMN x "meth") [0..]
-             let capp = PApp fc (PRef fc cn) (map (pexp . PRef fc) mnames)
+             let capp = PApp fc (PRef fc [] cn) (map (pexp . PRef fc []) mnames)
              let margs = getMArgs ty
              let anames = map (\x -> sMN x "arg") [0..]
-             let lhs = PApp fc (PRef fc m) (pconst capp : lhsArgs margs anames)
+             let lhs = PApp fc (PRef fc [] m) (pconst capp : lhsArgs margs anames)
              let rhs = PApp fc (getMeth mnames all m) (rhsArgs margs anames)
              logLvl 2 ("Top level type: " ++ showTmImpls ty')
-             iLOG (show (m, ty', capp, margs))
+             logLvl 1 (show (m, ty', capp, margs))
              logLvl 2 ("Definition: " ++ showTmImpls lhs ++ " = " ++ showTmImpls rhs)
              return [PTy doc [] syn fc o m mfc ty',
                      PClauses fc [Inlinable] m [PClause fc m lhs [] rhs []]]
@@ -242,16 +242,16 @@
     getMArgs _ = []
 
     getMeth :: [Name] -> [Name] -> Name -> PTerm
-    getMeth (m:ms) (a:as) x | x == a = PRef fc m
+    getMeth (m:ms) (a:as) x | x == a = PRef fc [] m
                             | otherwise = getMeth ms as x
 
     lhsArgs (EA _ : xs) (n : ns) = [] -- pexp (PRef fc n) : lhsArgs xs ns
-    lhsArgs (IA n : xs) ns = pimp n (PRef fc n) False : lhsArgs xs ns
+    lhsArgs (IA n : xs) ns = pimp n (PRef fc [] n) False : lhsArgs xs ns
     lhsArgs (CA : xs) ns = lhsArgs xs ns
     lhsArgs [] _ = []
 
     rhsArgs (EA _ : xs) (n : ns) = [] -- pexp (PRef fc n) : rhsArgs xs ns
-    rhsArgs (IA n : xs) ns = pexp (PRef fc n) : rhsArgs xs ns
+    rhsArgs (IA n : xs) ns = pexp (PRef fc [] n) : rhsArgs xs ns
     rhsArgs (CA : xs) ns = pconst (PResolveTC fc) : rhsArgs xs ns
     rhsArgs [] _ = []
 
@@ -269,8 +269,8 @@
         -- to the other methods in the class
        constrainMeths :: [Name] -> Name -> PTerm -> PTerm
        constrainMeths allM dictN tm = transform (addC allM dictN) tm
-       addC allM dictN m@(PRef fc n)
-         | n `elem` allM = PApp NoFC m [pconst (PRef NoFC dictN)]
+       addC allM dictN m@(PRef fc hls n)
+         | n `elem` allM = PApp NoFC m [pconst (PRef NoFC hls dictN)]
          | otherwise = m
        addC _ _ tm = tm
 
@@ -290,7 +290,7 @@
 -- | Get the docstring corresponding to a member, if one exists
 memberDocs :: PDecl -> Maybe (Name, Docstring (Either Err PTerm))
 memberDocs (PTy d _ _ _ _ n _ _) = Just (basename n, d)
-memberDocs (PPostulate _ d _ _ _ n _) = Just (basename n, d)
+memberDocs (PPostulate _ d _ _ _ _ n _) = Just (basename n, d)
 memberDocs (PData d _ _ _ _ pdata) = Just (basename $ d_name pdata, d)
 memberDocs (PRecord d _ _ _ n _ _ _ _ _ _ _ ) = Just (basename n, d)
 memberDocs (PClass d _ _ _ n _ _ _ _ _ _ _) = Just (basename n, d)
@@ -303,7 +303,7 @@
                 -> PTerm -> PTerm
 expandMethNS syn = mapPT expand
   where
-    expand (PRef fc n) | n `elem` imp_methods syn = PRef fc $ expandNS syn n
+    expand (PRef fc hls n) | n `elem` imp_methods syn = PRef fc hls $ expandNS syn n
     expand t = t
 
 -- | Find the determining parameter locations
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
@@ -189,9 +189,9 @@
 
            ist <- getIState
   --          let wf = wellFounded ist n sc
-           let tot = if pcover || AssertTotal `elem` opts
-                      then Unchecked -- finish checking later
-                      else Partial NotCovering -- already know it's not total
+           let tot | pcover || AssertTotal `elem` opts = Unchecked -- finish later
+                   | PEGenerated `elem` opts = Generated 
+                   | otherwise = Partial NotCovering -- already know it's not total
 
   --          case lookupCtxt (namespace info) n (idris_flags ist) of
   --             [fs] -> if TotalFn `elem` fs
@@ -224,20 +224,25 @@
                                                 (idris_patdefs ist) })
            let caseInfo = CaseInfo (inlinable opts) (inlinable opts) (dictionary opts)
            case lookupTy n ctxt of
-               [ty] -> do updateContext (addCasedef n erInfo caseInfo
+               [ty] -> do ctxt' <- do ctxt <- getContext
+                                      tclift $
+                                        addCasedef n erInfo caseInfo
                                                        tcase defaultcase
                                                        reflect
                                                        (AssertTotal `elem` opts)
                                                        atys
                                                        inacc
                                                        pats_pe
-                                                       pdef 
-                                                       pdef -- compile time 
+                                                       pdef
+                                                       pdef -- compile time
                                                        pdef_inl -- inlined
-                                                       pdef' ty)
+                                                       pdef' ty
+                                                       ctxt
+                          setContext ctxt'
                           addIBC (IBCDef n)
                           setTotality n tot
-                          when (not reflect) $ do totcheck (fc, n)
+                          when (not reflect && PEGenerated `notElem` opts) $ 
+                                               do totcheck (fc, n)
                                                   defer_totcheck (fc, n)
                           when (tot /= Unchecked) $ addIBC (IBCTotal n tot)
                           i <- getIState
@@ -263,9 +268,14 @@
            -- 'Partial NotCovering'
            when (CoveringFn `elem` opts) $ checkAllCovering fc [] n n
   where
-    noMatch i cs tm = all (\x -> case matchClause i (delab' i x True True) tm of
+    noMatch i cs tm = all (\x -> case trim_matchClause i (delab' i x True True) tm of
                                       Right _ -> False
                                       Left miss -> True) cs
+      where
+        trim_matchClause i (PApp fcl fl ls) (PApp fcr fr rs)
+            = let args = min (length ls) (length rs) in
+                  matchClause i (PApp fcl fl (take args ls))
+                                (PApp fcr fr (take args rs))
 
     checkUndefined n ctxt = case lookupDef n ctxt of
                                  [] -> return ()
@@ -368,18 +378,19 @@
                 logLvl 3 $ "PE definition " ++ show newnm ++ ":\n" ++
                              showSep "\n"
                                 (map (\ (lhs, rhs) ->
-                                  (show lhs ++ " = " ++
+                                  (showTmImpls lhs ++ " = " ++
                                    showTmImpls rhs)) (pe_clauses specdecl))
 
                 logLvl 2 $ show n ++ " transformation rule: " ++
-                           show rhs ++ " ==> " ++ show lhs
+                           showTmImpls rhs ++ " ==> " ++ showTmImpls lhs
 
                 elabType info defaultSyntax emptyDocstring [] fc opts newnm NoFC specTy
                 let def = map (\(lhs, rhs) ->
-                                  PClause fc newnm lhs [] rhs []) 
+                                 let lhs' = mapPT hiddenToPH $ stripUnmatchable ist lhs in
+                                  PClause fc newnm lhs' [] rhs []) 
                               (pe_clauses specdecl)    
                 trans <- elabTransform info fc False rhs lhs
-                elabClauses info fc opts newnm def
+                elabClauses info fc (PEGenerated:opts) newnm def
                 return [trans]
              else return [])
           -- if it doesn't work, just don't specialise. Could happen for lots
@@ -388,6 +399,9 @@
           (\e -> do logLvl 3 $ "Couldn't specialise: " ++ (pshow ist e)
                     return [])
 
+    hiddenToPH (PHidden _) = Placeholder
+    hiddenToPH x = x
+
     specName simpl (ImplicitS, tm)
         | (P Ref n _, _) <- unApply tm = Just (n, Just (if simpl then 1 else 0))
     specName simpl (ExplicitS, tm)
@@ -468,20 +482,20 @@
 
 
 propagateParams :: IState -> [Name] -> Type -> PTerm -> PTerm
-propagateParams i ps t tm@(PApp _ (PRef fc n) args)
-     = PApp fc (PRef fc n) (addP t args)
+propagateParams i ps t tm@(PApp _ (PRef fc hls n) args)
+     = PApp fc (PRef fc hls n) (addP t args)
    where addP (Bind n _ sc) (t : ts)
               | Placeholder <- getTm t,
                 n `elem` ps,
                 not (n `elem` allNamesIn tm)
-                    = t { getTm = PRef fc n } : addP sc ts
+                    = t { getTm = PRef NoFC [] n } : addP sc ts
          addP (Bind n _ sc) (t : ts) = t : addP sc ts
          addP _ ts = ts
-propagateParams i ps t (PRef fc n)
+propagateParams i ps t (PRef fc hls n)
      = case lookupCtxt n (idris_implicits i) of
             [is] -> let ps' = filter (isImplicit is) ps in
-                        PApp fc (PRef fc n) (map (\x -> pimp x (PRef fc x) True) ps')
-            _ -> PRef fc n
+                        PApp fc (PRef fc hls n) (map (\x -> pimp x (PRef fc [] x) True) ps')
+            _ -> PRef fc hls n
     where isImplicit [] n = False
           isImplicit (PImp _ _ _ x _ : is) n | x == n = True
           isImplicit (_ : is) n = isImplicit is n
@@ -529,7 +543,7 @@
         let fn_is = case lookupCtxt fname (idris_implicits i) of
                          [t] -> t
                          _ -> []
-        let params = getParamsInType i [] fn_is fn_ty
+        let params = getParamsInType i [] fn_is (normalise ctxt [] fn_ty)
         let lhs = mkLHSapp $ stripLinear i $ stripUnmatchable i $
                     propagateParams i params fn_ty (addImplPat i lhs_in)
 --         let lhs = mkLHSapp $ 
@@ -580,7 +594,7 @@
         rep <- useREPL
         when rep $ do
           addInternalApp (fc_fname fc) (fst . fc_start $ fc) (delabMV i clhs) -- TODO: Should use span instead of line and filename?
-          addIBC (IBCLineApp (fc_fname fc) (fst . fc_start $ fc) (delabMV i clhs))
+        addIBC (IBCLineApp (fc_fname fc) (fst . fc_start $ fc) (delabMV i clhs))
 
         logLvl 5 ("Checked " ++ show clhs ++ "\n" ++ show clhsty)
         -- Elaborate where block
@@ -618,6 +632,8 @@
         ((rhs', defer, is, probs, ctxt', newDecls, highlights), _) <-
            tclift $ elaborate ctxt (idris_datatypes i) (sMN 0 "patRHS") clhsty initEState
                     (do pbinds ist lhs_tm
+                        -- proof search can use explicitly written names
+                        mapM_ addPSname (allNamesIn lhs_in)
                         mapM_ setinj (nub (params ++ inj))
                         setNextName
                         (ElabResult _ _ is ctxt' newDecls highlights) <-
@@ -641,10 +657,10 @@
 
         logLvl 5 "DONE CHECK"
         logLvl 4 $ "---> " ++ show rhs'
-        when (not (null defer)) $ iLOG $ "DEFERRED " ++
-                    show (map (\ (n, (_,_,t)) -> (n, t)) defer)
+        when (not (null defer)) $ logLvl 1 $ "DEFERRED " ++
+                    show (map (\ (n, (_,_,t,_)) -> (n, t)) defer)
         def' <- checkDef fc (Elaborating "deferred type of ") defer
-        let def'' = map (\(n, (i, top, t)) -> (n, (i, top, t, False))) def'
+        let def'' = map (\(n, (i, top, t, ns)) -> (n, (i, top, t, ns, False))) def'
         addDeferred def''
         mapM_ (\(n, _) -> addIBC (IBCDef n)) def''
 
@@ -720,7 +736,7 @@
              borrowedB b = borrowedNames env (binderTy b)
     borrowedNames _ _ = []
 
-    mkLHSapp t@(PRef _ _) = PApp fc t []
+    mkLHSapp t@(PRef _ _ _) = PApp fc t []
     mkLHSapp t = t
 
     decorate (NS x ns)
@@ -758,7 +774,7 @@
       where
         isArg' (PClause _ _ (PApp _ _ args) _ _ _)
            = any (\x -> case x of
-                          PRef _ n' -> n == n'
+                          PRef _ _ n' -> n == n'
                           _ -> False) (map getTm args)
         isArg' _ = False
     isArg _ _ = False
@@ -776,7 +792,7 @@
         let fn_is = case lookupCtxt fname (idris_implicits i) of
                          [t] -> t
                          _ -> []
-        let params = getParamsInType i [] fn_is fn_ty
+        let params = getParamsInType i [] fn_is (normalise ctxt [] fn_ty)
         let lhs = stripLinear i $ stripUnmatchable i $ propagateParams i params fn_ty (addImplPat i lhs_in)
         logLvl 2 ("LHS: " ++ show lhs)
         (ElabResult lhs' dlhs [] ctxt' newDecls highlights, _) <-
@@ -802,6 +818,8 @@
             tclift $ elaborate ctxt (idris_datatypes i) (sMN 0 "withRHS")
                         (bindTyArgs PVTy bargs infP) initEState
                         (do pbinds i lhs_tm
+                            -- proof search can use explicitly written names
+                            mapM_ addPSname (allNamesIn lhs_in)
                             setNextName
                             -- TODO: may want where here - see winfo abpve
                             (ElabResult _ d is ctxt' newDecls highlights) <- errAt "with value in " fname
@@ -814,7 +832,7 @@
         sendHighlighting highlights
 
         def' <- checkDef fc iderr defer
-        let def'' = map (\(n, (i, top, t)) -> (n, (i, top, t, False))) def'
+        let def'' = map (\(n, (i, top, t, ns)) -> (n, (i, top, t, ns, False))) def'
         addDeferred def''
         mapM_ (elabCaseBlock info opts) is
         logLvl 5 ("Checked wval " ++ show wval')
@@ -876,8 +894,8 @@
         addIBC (IBCImp wname)
         addIBC (IBCStatic wname)
 
-        def' <- checkDef fc iderr [(wname, (-1, Nothing, wtype))]
-        let def'' = map (\(n, (i, top, t)) -> (n, (i, top, t, False))) def'
+        def' <- checkDef fc iderr [(wname, (-1, Nothing, wtype, []))]
+        let def'' = map (\(n, (i, top, t, ns)) -> (n, (i, top, t, ns, False))) def'
         addDeferred def''
 
         -- in the subdecls, lhs becomes:
@@ -891,13 +909,13 @@
         mapM_ (rec_elabDecl info EAll info) wb
 
         -- rhs becomes: fname' ps_pre wval ps_post Refl
-        let rhs = PApp fc (PRef fc wname)
-                    (map (pexp . (PRef fc) . fst) bargs_pre ++
+        let rhs = PApp fc (PRef fc [] wname)
+                    (map (pexp . (PRef fc []) . fst) bargs_pre ++
                         pexp wval :
-                    (map (pexp . (PRef fc) . fst) bargs_post) ++
+                    (map (pexp . (PRef fc []) . fst) bargs_post) ++
                     case mpn of
                          Nothing -> []
-                         Just _ -> [pexp (PApp NoFC (PRef NoFC eqCon)
+                         Just _ -> [pexp (PApp NoFC (PRef NoFC [] eqCon)
                                                [ pimp (sUN "A") Placeholder False
                                                , pimp (sUN "x") Placeholder False
                                                ])])
@@ -918,7 +936,7 @@
         sendHighlighting highlights
 
         def' <- checkDef fc iderr defer
-        let def'' = map (\(n, (i, top, t)) -> (n, (i, top, t, False))) def'
+        let def'' = map (\(n, (i, top, t, ns)) -> (n, (i, top, t, ns, False))) def'
         addDeferred def''
         mapM_ (elabCaseBlock info opts) is
         logLvl 5 ("Checked RHS " ++ show rhs')
@@ -960,21 +978,21 @@
         = ifail $ show fc ++ ":badly formed with clause"
 
     addArg (PApp fc f args) w = PApp fc f (args ++ [pexp w])
-    addArg (PRef fc f) w = PApp fc (PRef fc f) [pexp w]
+    addArg (PRef fc hls f) w = PApp fc (PRef fc hls f) [pexp w]
 
-    updateLHS n pn wname mvars ns_in ns_in' (PApp fc (PRef fc' n') args) w
+    updateLHS n pn wname mvars ns_in ns_in' (PApp fc (PRef fc' hls' n') args) w
         = let ns = map (keepMvar (map fst mvars) fc') ns_in
               ns' = map (keepMvar (map fst mvars) fc') ns_in' in
               return $ substMatches mvars $
-                  PApp fc (PRef fc' wname)
+                  PApp fc (PRef fc' [] wname)
                       (map pexp ns ++ pexp w : (map pexp ns') ++ 
                         case pn of
                              Nothing -> []
-                             Just pnm -> [pexp (PRef fc pnm)])
+                             Just pnm -> [pexp (PRef fc [] pnm)])
     updateLHS n pn wname mvars ns_in ns_in' tm w
         = updateLHS n pn wname mvars ns_in ns_in' (PApp fc tm []) w
 
-    keepMvar mvs fc v | v `elem` mvs = PRef fc v
+    keepMvar mvs fc v | v `elem` mvs = PRef fc [] v
                       | otherwise = Placeholder
 
     fullApp (PApp _ (PApp fc f args) xs) = fullApp (PApp fc f (args ++ xs))
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
@@ -53,7 +53,7 @@
 elabData :: ElabInfo -> SyntaxInfo -> Docstring (Either Err PTerm)-> [(Name, Docstring (Either Err PTerm))] -> FC -> DataOpts -> PData -> Idris ()
 elabData info syn doc argDocs fc opts (PLaterdecl n nfc t_in)
     = do let codata = Codata `elem` opts
-         iLOG (show (fc, doc))
+         logLvl 1 (show (fc, doc))
          checkUndefined fc n
          (cty, _, t, inacc) <- buildType info syn fc [] n t_in
 
@@ -63,7 +63,7 @@
 
 elabData info syn doc argDocs fc opts (PDatadecl n nfc t_in dcons)
     = do let codata = Codata `elem` opts
-         iLOG (show fc)
+         logLvl 1 (show fc)
          undef <- isUndefined fc n
          (cty, ckind, t, inacc) <- buildType info syn fc [] n t_in
          -- if n is defined already, make sure it is just a type declaration
@@ -259,15 +259,15 @@
 
     mkLazy (PPi pl n nfc ty sc)
         = let ty' = if getTyName ty
-                       then PApp fc (PRef fc (sUN "Lazy'"))
-                            [pexp (PRef fc (sUN "LazyCodata")),
+                       then PApp fc (PRef fc [] (sUN "Lazy'"))
+                            [pexp (PRef fc [] (sUN "LazyCodata")),
                              pexp ty]
                        else ty in
               PPi pl n nfc ty' (mkLazy sc)
     mkLazy t = t
 
-    getTyName (PApp _ (PRef _ n) _) = n == nsroot tn
-    getTyName (PRef _ n) = n == nsroot tn
+    getTyName (PApp _ (PRef _ _ n) _) = n == nsroot tn
+    getTyName (PRef _ _ n) = n == nsroot tn
     getTyName _ = False
 
 
@@ -326,11 +326,11 @@
   scrutineeIdxs <- namePis False idxs
   let motiveConstr = [(motiveName, expl, motive)]
   let scrutinee = (scrutineeName, expl, applyCons n (interlievePos paramPos generalParams scrutineeIdxs 0))
-  let eliminatorTy = piConstr (generalParams ++ motiveConstr ++ consTerms ++ scrutineeIdxs ++ [scrutinee]) (applyMotive (map (\(n,_,_) -> PRef elimFC n) scrutineeIdxs) (PRef elimFC scrutineeName))
+  let eliminatorTy = piConstr (generalParams ++ motiveConstr ++ consTerms ++ scrutineeIdxs ++ [scrutinee]) (applyMotive (map (\(n,_,_) -> PRef elimFC [] n) scrutineeIdxs) (PRef elimFC [] scrutineeName))
   let eliminatorTyDecl = PTy (fmap (const (Left $ Msg "")) . parseDocstring . T.pack $ show n) [] defaultSyntax elimFC [TotalFn] elimDeclName NoFC eliminatorTy
   let clauseConsElimArgs = map getPiName consTerms
   let clauseGeneralArgs' = map getPiName generalParams ++ [motiveName] ++ clauseConsElimArgs
-  let clauseGeneralArgs  = map (\arg -> pexp (PRef elimFC arg)) clauseGeneralArgs'
+  let clauseGeneralArgs  = map (\arg -> pexp (PRef elimFC [] arg)) clauseGeneralArgs'
   let elimSig = "-- case function signature: " ++ showTmImpls eliminatorTy
   elimLog elimSig
   eliminatorClauses <- mapM (\(cns, cnsElim) -> generateEliminatorClauses cns cnsElim clauseGeneralArgs generalParams) (zip cons clauseConsElimArgs)
@@ -381,7 +381,7 @@
         mkPiName _ (oldName, pl, piarg) =  do name <- freshName $ keyOf piarg
                                               return (oldName, (name, pl, piarg))
           where keyOf :: PTerm -> String
-                keyOf (PRef _ name) | isLetter (nameStart name) = (toLower $ nameStart name):"__"
+                keyOf (PRef _ _ name) | isLetter (nameStart name) = (toLower $ nameStart name):"__"
                 keyOf (PApp _ tyf _) = keyOf tyf
                 keyOf (PType _) = "ty__"
                 keyOf _     = "carg__"
@@ -446,10 +446,10 @@
           case findIndex (== n) oldParams of
             Nothing -> (PPi pl n fc (removeParamPis oldParams params tyb) (removeParamPis oldParams params tyr))
             Just i  -> (removeParamPis oldParams params tyr)
-        removeParamPis oldParams params (PRef _ n) =
+        removeParamPis oldParams params (PRef _ _ n) =
           case findIndex (== n) oldParams of
-               Nothing -> (PRef elimFC n)
-               Just i  -> let (newname,_,_) = params !! i in (PRef elimFC (newname))
+               Nothing -> (PRef elimFC [] n)
+               Just i  -> let (newname,_,_) = params !! i in (PRef elimFC [] (newname))
         removeParamPis oldParams params (PApp _ cns args) =
           PApp elimFC (removeParamPis oldParams params cns) $ replaceParamArgs args
             where replaceParamArgs :: [PArg] -> [PArg]
@@ -460,7 +460,7 @@
                       [n]  ->
                         case findIndex (== n) oldParams of
                           Nothing -> arg:replaceParamArgs args
-                          Just i  -> let (newname,_,_) = params !! i in arg {getTm = PRef elimFC newname}:replaceParamArgs args
+                          Just i  -> let (newname,_,_) = params !! i in arg {getTm = PRef elimFC [] newname}:replaceParamArgs args
         removeParamPis oldParams params t = t
 
         paramNamesOf :: Int -> [Int] -> [PArg] -> [Name]
@@ -468,8 +468,8 @@
         paramNamesOf i paramPos (arg:args)  = (if i `elem` paramPos then extractName (getTm arg) else []) ++ paramNamesOf (i+1) paramPos args
 
         extractName :: PTerm -> [Name]
-        extractName (PRef _ n) = [n]
-        extractName _          = []
+        extractName (PRef _ _ n) = [n]
+        extractName _            = []
 
         splitArgPms :: PTerm -> ([PTerm], [PTerm])
         splitArgPms (PApp _ f args) = splitArgPms' args
@@ -505,23 +505,23 @@
           let (_, consIdxs) = splitArgPms resTy
           return $ piConstr (implidxs ++ consArgs ++ recMotives) (applyMotive consIdxs (applyCons cnm consArgs))
             where applyRecMotive :: (Name, Plicity, PTerm) -> (Name, Plicity, PTerm)
-                  applyRecMotive (n,_,ty)  = (sUN $ "ih" ++ simpleName n, expl, applyMotive idxs (PRef elimFC n))
+                  applyRecMotive (n,_,ty)  = (sUN $ "ih" ++ simpleName n, expl, applyMotive idxs (PRef elimFC [] n))
                       where (_, idxs) = splitArgPms ty
 
         findRecArgs :: [(Name, Plicity, PTerm)] -> [(Name, Plicity, PTerm)]
         findRecArgs []                            = []
-        findRecArgs (ty@(_,_,PRef _ tn):rs)            | simpleName tn == simpleName n = ty:findRecArgs rs
-        findRecArgs (ty@(_,_,PApp _ (PRef _ tn) _):rs) | simpleName tn == simpleName n = ty:findRecArgs rs
-        findRecArgs (ty:rs)                                                            = findRecArgs rs
+        findRecArgs (ty@(_,_,PRef _ _ tn):rs)            | simpleName tn == simpleName n = ty:findRecArgs rs
+        findRecArgs (ty@(_,_,PApp _ (PRef _ _ tn) _):rs) | simpleName tn == simpleName n = ty:findRecArgs rs
+        findRecArgs (ty:rs)                                                              = findRecArgs rs
 
         applyCons :: Name -> [(Name, Plicity, PTerm)] -> PTerm
-        applyCons tn targs = PApp elimFC (PRef elimFC tn) (map convertArg targs)
+        applyCons tn targs = PApp elimFC (PRef elimFC [] tn) (map convertArg targs)
 
         convertArg :: (Name, Plicity, PTerm) -> PArg
-        convertArg (n, _, _)      = pexp (PRef elimFC n)
+        convertArg (n, _, _)      = pexp (PRef elimFC [] n)
 
         applyMotive :: [PTerm] -> PTerm -> PTerm
-        applyMotive idxs t = PApp elimFC (PRef elimFC motiveName) (map pexp idxs ++ [pexp t])
+        applyMotive idxs t = PApp elimFC (PRef elimFC [] motiveName) (map pexp idxs ++ [pexp t])
 
         getPiName :: (Name, Plicity, PTerm) -> Name
         getPiName (name,_,_) = name
@@ -539,11 +539,11 @@
           let (_, generalIdxs') = splitArgPms resTy
           let generalIdxs = map pexp generalIdxs'
           consArgs <- namePis False args
-          let lhsPattern = PApp elimFC (PRef elimFC elimDeclName) (generalArgs ++ generalIdxs ++ [pexp $ applyCons cnm consArgs])
+          let lhsPattern = PApp elimFC (PRef elimFC [] elimDeclName) (generalArgs ++ generalIdxs ++ [pexp $ applyCons cnm consArgs])
           let recArgs = findRecArgs consArgs
           let recElims = if ind then map applyRecElim recArgs else []
-          let rhsExpr    = PApp elimFC (PRef elimFC cnsElim) (map convertArg implidxs ++ map convertArg consArgs ++ recElims)
+          let rhsExpr    = PApp elimFC (PRef elimFC [] cnsElim) (map convertArg implidxs ++ map convertArg consArgs ++ recElims)
           return $ PClause elimFC elimDeclName lhsPattern [] rhsExpr []
             where applyRecElim :: (Name, Plicity, PTerm) -> PArg
-                  applyRecElim (constr@(recCnm,_,recTy)) = pexp $ PApp elimFC (PRef elimFC elimDeclName) (generalArgs ++ map pexp idxs ++ [pexp $ PRef elimFC recCnm])
+                  applyRecElim (constr@(recCnm,_,recTy)) = pexp $ PApp elimFC (PRef elimFC [] elimDeclName) (generalArgs ++ map pexp idxs ++ [pexp $ PRef elimFC [] recCnm])
                     where (_, idxs) = splitArgPms recTy
diff --git a/src/Idris/Elab/Instance.hs b/src/Idris/Elab/Instance.hs
--- a/src/Idris/Elab/Instance.hs
+++ b/src/Idris/Elab/Instance.hs
@@ -68,10 +68,10 @@
                   [] -> ifail $ show fc ++ ":" ++ show n ++ " is not a type class"
                   cs -> tclift $ tfail $ At fc
                            (CantResolveAlts (map fst cs))
-    let constraint = PApp fc (PRef fc n) (map pexp ps)
+    let constraint = PApp fc (PRef fc [] n) (map pexp ps)
     let iname = mkiname n (namespace info) ps expn
     let emptyclass = null (class_methods ci)
-    when (what /= EDefns || (null ds && not emptyclass)) $ do
+    when (what /= EDefns) $ do 
          nty <- elabType' True info syn doc argDocs fc [] iname NoFC t
          -- if the instance type matches any of the instances we have already,
          -- and it's not a named instance, then it's overlapping, so report an error
@@ -89,7 +89,7 @@
          -- where block
          wparams <- mapM (\p -> case p of
                                   PApp _ _ args -> getWParams (map getTm args)
-                                  a@(PRef fc f) -> getWParams [a]
+                                  a@(PRef fc _ f) -> getWParams [a]
                                   _ -> return []) ps
          ist <- getIState
          let pnames = nub $ map pname (concat (nub wparams)) ++
@@ -100,7 +100,7 @@
          let all_meths = map (nsroot . fst) (class_methods ci)
          let mtys = map (\ (n, (op, t)) ->
                    let t_in = substMatchesShadow ips pnames t
-                       mnamemap = map (\n -> (n, PRef fc (decorate ns iname n)))
+                       mnamemap = map (\n -> (n, PRef fc [] (decorate ns iname n)))
                                       all_meths
                        t' = substMatchesShadow mnamemap pnames t_in in
                        (decorate ns iname n,
@@ -111,7 +111,7 @@
          let ds_defs = insertDefaults i iname (class_defaults ci) ns ds
          logLvl 3 ("After defaults: " ++ show ds_defs ++ "\n")
          let ds' = reorderDefs (map fst (class_methods ci)) $ ds_defs
-         iLOG ("Reordered: " ++ show ds' ++ "\n")
+         logLvl 1 ("Reordered: " ++ show ds' ++ "\n")
          mapM_ (warnMissing ds' ns iname) (map fst (class_methods ci))
          mapM_ (checkInClass (map fst (class_methods ci))) (concatMap defined ds')
          let wbTys = map mkTyDecl mtys
@@ -123,15 +123,15 @@
 
          -- Bring variables in instance head into scope
          let headVars = nub $ mapMaybe (\p -> case p of
-                                               PRef _ n ->
+                                               PRef _ _ n ->
                                                   case lookupTy n (tt_ctxt ist) of
                                                       [] -> Just n
                                                       _ -> Nothing
                                                _ -> Nothing) ps
 --          let lhs = PRef fc iname
-         let lhs = PApp fc (PRef fc iname)
-                           (map (\n -> pimp n (PRef fc n) True) headVars)
-         let rhs = PApp fc (PRef fc (instanceCtorName ci))
+         let lhs = PApp fc (PRef fc [] iname)
+                           (map (\n -> pimp n (PRef fc [] n) True) headVars)
+         let rhs = PApp fc (PRef fc [] (instanceCtorName ci))
                            (map (pexp . mkMethApp) mtys)
 
          logLvl 5 $ "Instance LHS " ++ show lhs ++ " " ++ show headVars
@@ -139,7 +139,7 @@
 
          let idecls = [PClauses fc [Dictionary] iname
                                  [PClause fc iname lhs [] rhs wb]]
-         iLOG (show idecls)
+         logLvl 1 (show idecls)
          push_estack iname True
          mapM_ (rec_elabDecl info EAll info) idecls
          pop_estack
@@ -218,16 +218,16 @@
     keepDets dets t = t
 
     mkMethApp (n, _, _, ty)
-          = lamBind 0 ty (papp fc (PRef fc n) (methArgs 0 ty))
+          = lamBind 0 ty (papp fc (PRef fc [] n) (methArgs 0 ty))
     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)
-        = PImp 0 True [] n (PRef fc (sMN i "meth")) : methArgs (i+1) sc
+        = PImp 0 True [] n (PRef fc [] (sMN i "meth")) : methArgs (i+1) sc
     methArgs i (PPi (Exp _ _ _) n _ ty sc)
-        = PExp 0 [] (sMN 0 "marg") (PRef fc (sMN i "meth")) : methArgs (i+1) sc
+        = PExp 0 [] (sMN 0 "marg") (PRef fc [] (sMN i "meth")) : methArgs (i+1) sc
     methArgs i (PPi (Constraint _ _) n _ ty sc)
         = PConstraint 0 [] (sMN 0 "marg") (PResolveTC fc) : methArgs (i+1) sc
     methArgs i _ = []
@@ -237,11 +237,11 @@
 
     getWParams [] = return []
     getWParams (p : ps)
-      | PRef _ n <- p
+      | PRef _ _ n <- p
         = do ps' <- getWParams ps
              ctxt <- getContext
              case lookupP n ctxt of
-                [] -> return (pimp n (PRef fc n) True : ps')
+                [] -> return (pimp n (PRef fc [] n) True : ps')
                 _ -> return ps'
     getWParams (_ : ps) = getWParams ps
 
@@ -250,7 +250,7 @@
 
     mkTyDecl (n, op, t, _)
         = PTy emptyDocstring [] syn fc op n NoFC
-               (mkUniqueNames [] t)
+               (mkUniqueNames [] [] t)
 
     conbind :: [(Name, PTerm)] -> PTerm -> PTerm
     conbind ((c,ty) : ns) x = PPi constraint c NoFC ty (conbind ns x)
diff --git a/src/Idris/Elab/Provider.hs b/src/Idris/Elab/Provider.hs
--- a/src/Idris/Elab/Provider.hs
+++ b/src/Idris/Elab/Provider.hs
@@ -52,8 +52,8 @@
 import Util.Pretty(pretty, text)
 
 -- | Elaborate a type provider
-elabProvider :: Docstring (Either Err PTerm) -> ElabInfo -> SyntaxInfo -> FC -> ProvideWhat -> Name -> Idris ()
-elabProvider doc info syn fc what n
+elabProvider :: Docstring (Either Err PTerm) -> ElabInfo -> SyntaxInfo -> FC -> FC -> ProvideWhat -> Name -> Idris ()
+elabProvider doc info syn fc nfc what n
     = do i <- getIState
          -- Ensure that the experimental extension is enabled
          unless (TypeProviders `elem` idris_language_extensions i) $
@@ -94,11 +94,11 @@
              | ProvTerm ty _ <- what ->
                do -- Finally add a top-level definition of the provided term
                   elabType info syn doc [] fc [] n NoFC ty
-                  elabClauses info fc [] n [PClause fc n (PApp fc (PRef fc n) []) [] (delab i tm) []]
+                  elabClauses info fc [] n [PClause fc n (PApp fc (PRef fc [] n) []) [] (delab i tm) []]
                   logLvl 3 $ "Elaborated provider " ++ show n ++ " as: " ++ show tm
              | ProvPostulate _ <- what ->
                do -- Add the postulate
-                  elabPostulate info syn doc fc [] n (delab i tm)
+                  elabPostulate info syn doc fc nfc [] n (delab i tm)
                   logLvl 3 $ "Elaborated provided postulate " ++ show n
              | otherwise ->
                ierror . Msg $ "Attempted to provide a postulate where a term was expected."
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
@@ -34,6 +34,7 @@
 
 -- | Elaborate a record declaration
 elabRecord :: ElabInfo
+           -> ElabWhat
            -> (Docstring (Either Err PTerm)) -- ^ The documentation for the whole declaration
            -> SyntaxInfo -> FC -> DataOpts
            -> Name  -- ^ The name of the type being defined
@@ -45,7 +46,7 @@
            -> (Docstring (Either Err PTerm)) -- ^ Constructor Doc
            -> SyntaxInfo -- ^ Constructor SyntaxInfo
            -> Idris ()
-elabRecord info doc rsyn fc opts tyn nfc params paramDocs fields cname cdoc csyn
+elabRecord info what doc rsyn fc opts tyn nfc params paramDocs fields cname cdoc csyn
   = do logLvl 1 $ "Building data declaration for " ++ show tyn
        -- Type constructor
        let tycon = generateTyConType params
@@ -57,18 +58,21 @@
        logLvl 1 $ "Data constructor: " ++ showTmImpls dconTy
 
        -- Build data declaration for elaboration
-       iLOG $ foldr (++) "" $ intersperse "\n" (map show dconsArgDocs)
-       let datadecl = PDatadecl tyn NoFC tycon [(cdoc, dconsArgDocs, dconName, NoFC, dconTy, fc, [])]
+       logLvl 1 $ foldr (++) "" $ intersperse "\n" (map show dconsArgDocs)
+       let datadecl = case what of
+                           ETypes -> PLaterdecl tyn NoFC tycon
+                           _ -> PDatadecl tyn NoFC tycon [(cdoc, dconsArgDocs, dconName, NoFC, dconTy, fc, [])]
        elabData info rsyn doc paramDocs fc opts datadecl
 
-       iLOG $ "fieldsWithName " ++ show fieldsWithName
-       iLOG $ "fieldsWIthNameAndDoc " ++ show fieldsWithNameAndDoc
-       elabRecordFunctions info rsyn fc tyn paramsAndDoc fieldsWithNameAndDoc dconName target
+       when (what /= ETypes) $ do
+           logLvl 1 $ "fieldsWithName " ++ show fieldsWithName
+           logLvl 1 $ "fieldsWIthNameAndDoc " ++ show fieldsWithNameAndDoc
+           elabRecordFunctions info rsyn fc tyn paramsAndDoc fieldsWithNameAndDoc dconName target
 
-       sendHighlighting $
-         [(nfc, AnnName tyn Nothing Nothing Nothing)] ++
-         maybe [] (\(_, cnfc) -> [(cnfc, AnnName dconName Nothing Nothing Nothing)]) cname ++
-         [(ffc, AnnBoundName fn False) | (fn, ffc, _, _, _) <- fieldsWithName]
+           sendHighlighting $
+             [(nfc, AnnName tyn Nothing Nothing Nothing)] ++
+             maybe [] (\(_, cnfc) -> [(cnfc, AnnName dconName Nothing Nothing Nothing)]) cname ++
+             [(ffc, AnnBoundName fn False) | (fn, ffc, _, _, _) <- fieldsWithName]
 
   where
     -- | Generates a type constructor.
@@ -95,7 +99,7 @@
 
     -- | The target for the constructor and projection functions. Also the source of the update functions.
     target :: PTerm
-    target = PApp fc (PRef fc tyn) $ map (uncurry asPRefArg) [(p, n) | (n, _, p, _) <- params]
+    target = PApp fc (PRef fc [] tyn) $ map (uncurry asPRefArg) [(p, n) | (n, _, p, _) <- params]
 
     paramsAndDoc :: [(Name, FC, Plicity, PTerm, Docstring (Either Err PTerm))]
     paramsAndDoc = pad params paramDocs
@@ -154,8 +158,8 @@
 elabRecordFunctions info rsyn fc tyn params fields dconName target
   = do logLvl 1 $ "Elaborating helper functions for record " ++ show tyn
 
-       iLOG $ "Fields: " ++ show fieldNames
-       iLOG $ "Params: " ++ show paramNames
+       logLvl 1 $ "Fields: " ++ show fieldNames
+       logLvl 1 $ "Params: " ++ show paramNames
        -- The elaborated constructor type for the data declaration
        i <- getIState
        ttConsTy <-
@@ -165,8 +169,8 @@
 
        -- The arguments to the constructor
        let constructorArgs = getArgTys ttConsTy
-       iLOG $ "Cons args: " ++ show constructorArgs
-       iLOG $ "Free fields: " ++ show (filter (not . isFieldOrParam') constructorArgs)
+       logLvl 1 $ "Cons args: " ++ show constructorArgs
+       logLvl 1 $ "Free fields: " ++ show (filter (not . isFieldOrParam') constructorArgs)
        -- If elaborating the constructor has resulted in some new implicit fields we make projection functions for them.
        let freeFieldsForElab = map (freeField i) (filter (not . isFieldOrParam') constructorArgs)
            
@@ -327,10 +331,10 @@
     -- | The left hand side of the projection function.
     generateLhs :: PTerm
     generateLhs = let args = lhsArgs index phArgs
-                  in PApp fc (PRef fc pname) [pexp (PApp fc (PRef fc cn) args)]
+                  in PApp fc (PRef fc [] pname) [pexp (PApp fc (PRef fc [] cn) args)]
       where
         lhsArgs :: Int -> [PArg] -> [PArg]
-        lhsArgs 0 (_ : rest) = (asArg plicity (nsroot cname) (PRef fc pname_in)) : rest
+        lhsArgs 0 (_ : rest) = (asArg plicity (nsroot cname) (PRef fc [] pname_in)) : rest
         lhsArgs i (x : rest) = x : (lhsArgs (i-1) rest)
         lhsArgs _ [] = []
 
@@ -343,7 +347,7 @@
 
     -- | The right hand side of the projection function.
     generateRhs :: PTerm
-    generateRhs = PRef fc pname_in
+    generateRhs = PRef fc [] pname_in
 
 -- | Creates and elaborates an update function.
 -- If 'optional' is true, we will not fail if we can't elaborate the update function.
@@ -387,7 +391,7 @@
     generateTy = PTy pdoc [] psyn fc [] set_pname NoFC $
                    PPi expl (nsroot pname) NoFC pty $
                      PPi expl recName NoFC sty (substInput sty)
-      where substInput = substMatches [(cname, PRef fc (nsroot pname))]
+      where substInput = substMatches [(cname, PRef fc [] (nsroot pname))]
 
     -- | The "_set" name.
     set_pname :: Name
@@ -401,10 +405,10 @@
 
     -- | The left-hand side of the update function.
     generateLhs :: PTerm
-    generateLhs = PApp fc (PRef fc set_pname) [pexp $ PRef fc pname_in, pexp constructorPattern]
+    generateLhs = PApp fc (PRef fc [] set_pname) [pexp $ PRef fc [] pname_in, pexp constructorPattern]
       where
         constructorPattern :: PTerm
-        constructorPattern = PApp fc (PRef fc cn) args
+        constructorPattern = PApp fc (PRef fc [] cn) args
 
     -- | The "_in" name.
     pname_in :: Name
@@ -415,10 +419,10 @@
 
     -- | The right-hand side of the update function.
     generateRhs :: PTerm
-    generateRhs = PApp fc (PRef fc cn) (newArgs i args)
+    generateRhs = PApp fc (PRef fc [] cn) (newArgs i args)
       where
         newArgs :: Int -> [PArg] -> [PArg]
-        newArgs 0 (_ : rest) = (asArg plicity (nsroot cname) (PRef fc pname_in)) : rest
+        newArgs 0 (_ : rest) = (asArg plicity (nsroot cname) (PRef fc [] pname_in)) : rest
         newArgs i (x : rest) = x : (newArgs (i-1) rest)
         newArgs _ [] = []
 
@@ -440,17 +444,17 @@
 recName :: Name
 recName = sMN 0 "rec"
 
-recRef = PRef emptyFC recName
+recRef = PRef emptyFC [] recName
 
 projectInType :: [(Name, Name)] -> PTerm -> PTerm
 projectInType xs = mapPT st
   where
     st :: PTerm -> PTerm
-    st (PRef fc n)
-      | Just pn <- lookup n xs = PApp fc (PRef fc pn) [pexp recRef]
+    st (PRef fc hls n)
+      | Just pn <- lookup n xs = PApp fc (PRef fc hls pn) [pexp recRef]
     st t = t
 
 -- | Creates an PArg from a plicity and a name where the term is a PRef.
 asPRefArg :: Plicity -> Name -> PArg
-asPRefArg p n = asArg p (nsroot n) $ PRef emptyFC (nsroot n)
+asPRefArg p n = asArg p (nsroot n) $ PRef emptyFC [] (nsroot n)
 
diff --git a/src/Idris/Elab/RunElab.hs b/src/Idris/Elab/RunElab.hs
new file mode 100644
--- /dev/null
+++ b/src/Idris/Elab/RunElab.hs
@@ -0,0 +1,49 @@
+module Idris.Elab.RunElab (elabRunElab) where
+
+import Idris.Elab.Term
+import Idris.Elab.Value (elabVal)
+
+import Idris.AbsSyntax
+import Idris.Error
+
+import Idris.Core.Elaborate hiding (Tactic (..))
+import Idris.Core.Evaluate
+import Idris.Core.Execute
+import Idris.Core.TT
+import Idris.Core.Typecheck
+
+import Idris.Output (iputStrLn, pshow, iWarn, sendHighlighting)
+
+elabScriptTy :: Type
+elabScriptTy = App Complete (P Ref (sNS (sUN "Elab") ["Elab", "Reflection", "Language"]) Erased)
+                   (P Ref unitTy Erased)
+
+mustBeElabScript :: Type -> Idris ()
+mustBeElabScript ty =
+    do ctxt <- getContext
+       case converts ctxt [] ty elabScriptTy of
+            OK _    -> return ()
+            Error e -> ierror e
+
+elabRunElab :: ElabInfo -> FC -> PTerm -> [String] -> Idris ()
+elabRunElab info fc script' ns =
+  do -- First elaborate the script itself
+     (script, scriptTy) <- elabVal info ERHS script'
+     mustBeElabScript scriptTy
+     ist <- getIState
+     ctxt <- getContext
+     (ElabResult tyT' defer is ctxt' newDecls highlights, log) <-
+        tclift $ elaborate ctxt (idris_datatypes ist) (sMN 0 "toplLevelElab") elabScriptTy initEState
+                 (transformErr RunningElabScript
+                   (erun fc (do tm <- runElabAction ist fc [] script ns
+                                EState is _ impls highlights <- getAux
+                                ctxt <- get_context
+                                let ds = [] -- todo
+                                log <- getLog
+                                return (ElabResult tm ds (map snd is) ctxt impls highlights))))
+
+
+
+     setContext ctxt'
+     processTacticDecls info newDecls
+     sendHighlighting highlights
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
@@ -16,7 +16,8 @@
 import Idris.Core.Evaluate
 import Idris.Core.Unify
 import Idris.Core.ProofTerm (getProofTerm)
-import Idris.Core.Typecheck (check, recheck, isType)
+import Idris.Core.Typecheck (check, recheck, converts, isType)
+import Idris.Core.WHNF (whnf)
 import Idris.Coverage (buildSCG, checkDeclTotality, genClauses, recoverableCoverage, validCoverageCase)
 import Idris.ErrReverse (errReverse)
 import Idris.ElabQuasiquote (extractUnquotes)
@@ -35,13 +36,13 @@
 
 import Debug.Trace
 
-data ElabMode = ETyDecl | ELHS | ERHS
+data ElabMode = ETyDecl | ETransLHS | ELHS | ERHS
   deriving Eq
 
 
 data ElabResult =
   ElabResult { resultTerm :: Term -- ^ The term resulting from elaboration
-             , resultMetavars :: [(Name, (Int, Maybe Name, Type))]
+             , resultMetavars :: [(Name, (Int, Maybe Name, Type, [Name]))]
                -- ^ Information about new metavariables
              , resultCaseDecls :: [PDecl]
                -- ^ Deferred declarations as the meaning of case blocks
@@ -70,8 +71,6 @@
                         [TIPartial] -> True
                         _ -> False
 
-         when (not pattern) $ solveAutos ist fn True
-
          hs <- get_holes
          ivs <- get_instances
          ptm <- get_term
@@ -81,7 +80,7 @@
               mapM_ (\n -> when (n `elem` hs) $
                              do focus n
                                 g <- goal
-                                try (resolveTC True False 10 g fn ist)
+                                try (resolveTC' True False 10 g fn ist)
                                     (movelast n)) ivs
          ivs <- get_instances
          hs <- get_holes
@@ -90,7 +89,10 @@
                              do focus n
                                 g <- goal
                                 ptm <- get_term
-                                resolveTC True True 10 g fn ist) ivs
+                                resolveTC' True True 10 g fn ist) ivs
+         
+         when (not pattern) $ solveAutos ist fn True
+
          tm <- get_term
          ctxt <- get_context
          probs <- get_probs
@@ -220,7 +222,7 @@
          sequence_ (get_delayed_elab est)
          end_unify
          ptm <- get_term
-         when pattern -- convert remaining holes to pattern vars
+         when (pattern || intransform) -- convert remaining holes to pattern vars
               (do update_term orderPats
                   unify_all
                   matchProblems False -- only the ones we matched earlier
@@ -228,7 +230,8 @@
                   mkPat)
   where
     pattern = emode == ELHS
-    bindfree = emode == ETyDecl || emode == ELHS
+    intransform = emode == ETransLHS
+    bindfree = emode == ETyDecl || emode == ELHS || emode == ETransLHS
 
     get_delayed_elab est =
         let ds = delayed_elab est in
@@ -288,7 +291,7 @@
         env <- get_env
         handleError (forceErr t' env)
             (elab' ina fc' t')
-            (elab' ina fc' (PApp fc (PRef fc (sUN "Force"))
+            (elab' ina fc' (PApp fc (PRef fc [] (sUN "Force"))
                              [pimp (sUN "t") Placeholder True,
                               pimp (sUN "a") Placeholder True,
                               pexp ct]))
@@ -307,7 +310,7 @@
     forceErr orig env (At _ t) = forceErr orig env t
     forceErr orig env t = False
 
-    notDelay t@(PApp _ (PRef _ (UN l)) _) | l == txt "Delay" = False
+    notDelay t@(PApp _ (PRef _ _ (UN l)) _) | l == txt "Delay" = False
     notDelay _ = True
 
     local f = do e <- get_env
@@ -349,24 +352,24 @@
        do hnf_compute
           g <- goal
           case g of
-            TType _ -> elab' ina (Just fc) (PRef fc unitTy)
-            UType _ -> elab' ina (Just fc) (PRef fc unitTy)
-            _ -> elab' ina (Just fc) (PRef fc unitCon)
+            TType _ -> elab' ina (Just fc) (PRef fc [] unitTy)
+            UType _ -> elab' ina (Just fc) (PRef fc [] unitTy)
+            _ -> elab' ina (Just fc) (PRef fc [] unitCon)
     elab' ina fc (PResolveTC (FC "HACK" _ _)) -- for chasing parent classes
-       = do g <- goal; resolveTC False False 5 g fn ist
+       = do g <- goal; resolveTC' False False 5 g fn ist
     elab' ina fc (PResolveTC fc')
         = do c <- getNameFrom (sMN 0 "class")
              instanceArg c
     -- Elaborate the equality type first homogeneously, then
     -- heterogeneously as a fallback
-    elab' ina _ (PApp fc (PRef _ n) args)
+    elab' ina _ (PApp fc (PRef _ _ n) args)
        | n == eqTy, [Placeholder, Placeholder, l, r] <- map getTm args
        = try (do tyn <- getNameFrom (sMN 0 "aqty")
                  claim tyn RType
                  movelast tyn
-                 elab' ina (Just fc) (PApp fc (PRef fc eqTy)
-                              [pimp (sUN "A") (PRef NoFC tyn) True,
-                               pimp (sUN "B") (PRef NoFC tyn) False,
+                 elab' ina (Just fc) (PApp fc (PRef fc [] eqTy)
+                              [pimp (sUN "A") (PRef NoFC [] tyn) True,
+                               pimp (sUN "B") (PRef NoFC [] tyn) False,
                                pexp l, pexp r]))
              (do atyn <- getNameFrom (sMN 0 "aqty")
                  btyn <- getNameFrom (sMN 0 "bqty")
@@ -374,27 +377,27 @@
                  movelast atyn
                  claim btyn RType
                  movelast btyn
-                 elab' ina (Just fc) (PApp fc (PRef fc eqTy)
-                   [pimp (sUN "A") (PRef NoFC atyn) True,
-                    pimp (sUN "B") (PRef NoFC btyn) False,
+                 elab' ina (Just fc) (PApp fc (PRef fc [] eqTy)
+                   [pimp (sUN "A") (PRef NoFC [] atyn) True,
+                    pimp (sUN "B") (PRef NoFC [] btyn) False,
                     pexp l, pexp r]))
 
-    elab' ina _ (PPair fc _ l r)
+    elab' ina _ (PPair fc hls _ l r)
         = do hnf_compute
              g <- goal
              let (tc, _) = unApply g
              case g of
-                TType _ -> elab' ina (Just fc) (PApp fc (PRef fc pairTy)
+                TType _ -> elab' ina (Just fc) (PApp fc (PRef fc hls pairTy)
                                                       [pexp l,pexp r])
-                UType _ -> elab' ina (Just fc) (PApp fc (PRef fc upairTy)
+                UType _ -> elab' ina (Just fc) (PApp fc (PRef fc hls upairTy)
                                                       [pexp l,pexp r])
                 _ -> case tc of
                         P _ n _ | n == upairTy 
-                          -> elab' ina (Just fc) (PApp fc (PRef fc upairCon)
+                          -> elab' ina (Just fc) (PApp fc (PRef fc hls upairCon)
                                                 [pimp (sUN "A") Placeholder False,
                                                  pimp (sUN "B") Placeholder False,
                                                  pexp l, pexp r])
-                        _ -> elab' ina (Just fc) (PApp fc (PRef fc pairCon)
+                        _ -> elab' ina (Just fc) (PApp fc (PRef fc hls pairCon)
                                                 [pimp (sUN "A") Placeholder False,
                                                  pimp (sUN "B") Placeholder False,
                                                  pexp l, pexp r])
@@ -408,7 +411,7 @@
 --                                                  pexp l, pexp r]))
 --                                   True
 
-    elab' ina _ (PDPair fc p l@(PRef _ n) t r)
+    elab' ina _ (PDPair fc hls p l@(PRef nfc hl n) t r)
             = case t of
                 Placeholder ->
                    do hnf_compute
@@ -417,32 +420,27 @@
                          TType _ -> asType
                          _ -> asValue
                 _ -> asType
-         where asType = elab' ina (Just fc) (PApp fc (PRef fc sigmaTy)
+         where asType = elab' ina (Just fc) (PApp fc (PRef NoFC hls sigmaTy)
                                         [pexp t,
-
-                                         -- TODO: save the FC from the dependent pair
-                                         -- syntax and put it on this lambda for interactive
-                                         -- semantic highlighting support. NoFC for now.
-                                         pexp (PLam fc n NoFC Placeholder r)])
-               asValue = elab' ina (Just fc) (PApp fc (PRef fc sigmaCon)
+                                         pexp (PLam fc n nfc Placeholder r)])
+               asValue = elab' ina (Just fc) (PApp fc (PRef fc hls sigmaCon)
                                          [pimp (sMN 0 "a") t False,
                                           pimp (sMN 0 "P") Placeholder True,
                                           pexp l, pexp r])
-    elab' ina _ (PDPair fc p l t r) = elab' ina (Just fc) (PApp fc (PRef fc sigmaCon)
-                                              [pimp (sMN 0 "a") t False,
-                                               pimp (sMN 0 "P") Placeholder True,
-                                               pexp l, pexp r])
-    elab' ina fc (PAlternative (ExactlyOne delayok) as)
-        = do hnf_compute
-             ty <- goal
-             ctxt <- get_context
-             let (tc, _) = unApply ty
-             env <- get_env
-             let as' = pruneByType (map fst env) tc ctxt as
---              trace (-- show tc ++ " " ++ show as ++ "\n ==> " ++ 
---                     show (length as') ++ "\n" ++
---                     showSep ", " (map showTmImpls as') ++ "\nEND") $
+
+    elab' ina _ (PDPair fc hls p l t r) = elab' ina (Just fc) (PApp fc (PRef fc hls sigmaCon)
+                                                  [pimp (sMN 0 "a") t False,
+                                                   pimp (sMN 0 "P") Placeholder True,
+                                                   pexp l, pexp r])
+    elab' ina fc (PAlternative ms (ExactlyOne delayok) as)
+        = do as_pruned <- doPrune as
+             -- Finish the mkUniqueNames job with the pruned set, rather than
+             -- the full set.
+             uns <- get_usedns
+             let as' = map (mkUniqueNames (uns ++ map snd ms) ms) as_pruned
              (h : hs) <- get_holes
+--              trace (show (map showHd as')) $ 
+             ty <- goal
              case as' of
                   [x] -> elab' ina fc x
                   -- If there's options, try now, and if that fails, postpone
@@ -452,22 +450,38 @@
                                         (map showHd as')))
                         (do movelast h
                             delayElab 5 $ do
-                              focus h
-                              tryAll (zip (map (elab' ina fc) as') 
-                                          (map showHd as')))
-        where showHd (PApp _ (PRef _ n) _) = n
-              showHd (PRef _ n) = n
+                              hs <- get_holes
+                              when (not (null hs)) $ do
+                                  focus h
+                                  as'' <- doPrune as'
+                                  case as'' of
+                                       [x] -> elab' ina fc x
+                                       _ -> tryAll (zip (map (elab' ina fc) as'') 
+                                                        (map showHd as'')))
+        where showHd (PApp _ (PRef _ _ n) _) = n
+              showHd (PRef _ _ n) = n
               showHd (PApp _ h _) = showHd h
               showHd x = NErased -- We probably should do something better than this here
 
+              doPrune as = 
+                  do hnf_compute
+                     ty <- goal
+                     let (tc, _) = unApply ty
+                     env <- get_env
+                     return $ pruneByType env tc ist as
+
+
               isAmbiguous (CantResolveAlts _) = delayok
               isAmbiguous (Elaborating _ _ e) = isAmbiguous e
               isAmbiguous (ElaboratingArg _ _ _ e) = isAmbiguous e
               isAmbiguous (At _ e) = isAmbiguous e
               isAmbiguous _ = False
 
-    elab' ina fc (PAlternative FirstSuccess as)
-        = trySeq as
+    elab' ina fc (PAlternative ms FirstSuccess as_in)
+        = do -- finish the mkUniqueNames job
+             uns <- get_usedns
+             let as = map (mkUniqueNames (uns ++ map snd ms) ms) as_in
+             trySeq as
         where -- if none work, take the error from the first
               trySeq (x : xs) = let e1 = elab' ina fc x in
                                     try' e1 (trySeq' e1 xs) True
@@ -476,6 +490,70 @@
               trySeq' deferr (x : xs)
                   = try' (do elab' ina fc x
                              solveAutos ist fn False) (trySeq' deferr xs) True
+    elab' ina fc (PAlternative ms TryImplicit (orig : alts)) = do
+        env <- get_env
+        ty <- goal
+        let doelab = elab' ina fc orig
+        tryCatch doelab
+            (\err -> 
+                if recoverableErr err
+                   then -- trace ("NEED IMPLICIT! " ++ show orig ++ "\n" ++
+                        --       show alts ++ "\n" ++
+                        --       showQuick err) $
+                    -- Prune the coercions so that only the ones
+                    -- with the right type to fix the error will be tried!
+                    case pruneAlts err alts env of
+                         [] -> lift $ tfail err
+                         alts' -> 
+                             try' (elab' ina fc (PAlternative [] (ExactlyOne False) alts'))
+                                  (lift $ tfail err) -- take error from original if all fail
+                                  True
+                   else lift $ tfail err)
+      where
+        recoverableErr (CantUnify _ _ _ _ _ _) = True
+        recoverableErr (TooManyArguments _) = False
+        recoverableErr (CantSolveGoal _ _) = False
+        recoverableErr (CantResolveAlts _) = False
+        recoverableErr (NoValidAlts _) = True
+        recoverableErr (ProofSearchFail (Msg _)) = True
+        recoverableErr (ProofSearchFail _) = False
+        recoverableErr (ElaboratingArg _ _ _ e) = recoverableErr e
+        recoverableErr (At _ e) = recoverableErr e
+        recoverableErr (ElabScriptDebug _ _ _) = False
+        recoverableErr _ = True
+
+        pruneAlts (CantUnify _ (inc, _) (outc, _) _ _ _) alts env
+            = 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'
+        pruneAlts (ElaboratingArg _ _ _ e) alts env = pruneAlts e alts env
+        pruneAlts (At _ e) alts env = pruneAlts e alts env
+        pruneAlts (NoValidAlts _) alts env = alts
+        pruneAlts _ alts _ = filter isLend alts
+
+        hasArg n env ap | isLend ap = True -- special case hack for 'Borrowed'
+        hasArg n env (PApp _ (PRef _ _ a) _) 
+             = case lookupTyExact a (tt_ctxt ist) of
+                    Just ty -> let args = map snd (getArgTys (normalise (tt_ctxt ist) env ty)) in
+                                   any (fnIs n) args
+                    Nothing -> False
+        hasArg n _ _ = False
+
+        isLend (PApp _ (PRef _ _ l) _) = l == sNS (sUN "lend") ["Ownership"]
+        isLend _ = False
+
+        fnIs n ty = case unApply ty of
+                         (P _ n' _, _) -> n == n'
+                         _ -> False
+
+        showQuick (CantUnify _ (l, _) (r, _) _ _ _)
+            = show (l, r)
+        showQuick (ElaboratingArg _ _ _ e) = showQuick e
+        showQuick (At _ e) = showQuick e
+        showQuick (ProofSearchFail (Msg _)) = "search fail"
+        showQuick _ = "No chance"
+
     elab' ina _ (PPatvar fc n) | bindfree
         = do patvar n
              update_term liftPats
@@ -483,13 +561,13 @@
 --    elab' (_, _, inty) (PRef fc f)
 --       | isTConName f (tt_ctxt ist) && pattern && not reflection && not inty
 --          = lift $ tfail (Msg "Typecase is not allowed")
-    elab' ec _ tm@(PRef fc n)
+    elab' ec _ tm@(PRef fc hl n)
       | pattern && not reflection && not (e_qq ec) && not (e_intype ec)
             && isTConName n (tt_ctxt ist)
               = lift $ tfail $ Msg ("No explicit types on left hand side: " ++ show tm)
       | pattern && not reflection && not (e_qq ec) && e_nomatching ec
               = lift $ tfail $ Msg ("Attempting concrete match on polymorphic argument: " ++ show tm)
-      | (pattern || (bindfree && bindable n)) && not (inparamBlock n) && not (e_qq ec)
+      | (pattern || intransform || (bindfree && bindable n)) && not (inparamBlock n) && not (e_qq ec)
         = do let ina = e_inarg ec
                  guarded = e_guarded ec
                  inty = e_intype ec
@@ -500,7 +578,7 @@
                                _ -> True
            -- this is to stop us resolve type classes recursively
              -- trace (show (n, guarded)) $
-             if (tcname n && ina)
+             if (tcname n && ina && not intransform)
                then erun fc $
                       do patvar n
                          update_term liftPats
@@ -523,8 +601,8 @@
             bindable (NS _ _) = False
             bindable (UN xs) = True
             bindable n = implicitable n
-    elab' ina _ f@(PInferRef fc n) = elab' ina (Just fc) (PApp NoFC f [])
-    elab' ina fc' tm@(PRef fc n) 
+    elab' ina _ f@(PInferRef fc hls n) = elab' ina (Just fc) (PApp NoFC f [])
+    elab' ina fc' tm@(PRef fc hls n)
           | pattern && not reflection && not (e_qq ina) && not (e_intype ina)
             && isTConName n (tt_ctxt ist)
               = lift $ tfail $ Msg ("No explicit types on left hand side: " ++ show tm)
@@ -538,9 +616,10 @@
                   if null a'
                      then erun fc $
                             do apply (Var n) []
-                               hl <- findHighlight n
+                               hilite <- findHighlight n
                                solve
-                               highlightSource fc hl
+                               mapM_ (uncurry highlightSource) $
+                                 (fc, hilite) : map (\f -> (f, hilite)) hls
                      else elab' ina fc' (PApp fc tm [])
     elab' ina _ (PLam _ _ _ _ PImpossible) = lift . tfail . Msg $ "Only pattern-matching lambdas can be impossible"
     elab' ina _ (PLam fc n nfc Placeholder sc)
@@ -550,6 +629,7 @@
                     lift $ tfail (Msg $ "Can't use type constructor " ++ show n ++ " here")
                checkPiGoal n
                attack; intro (Just n);
+               addPSname n -- okay for proof search
                -- trace ("------ intro " ++ show n ++ " ---- \n" ++ show ptm)
                elabE (ina { e_inarg = True } ) (Just fc) sc; solve
                highlightSource nfc (AnnBoundName n False)
@@ -566,6 +646,7 @@
                ptm <- get_term
                hs <- get_holes
                introTy (Var tyn) (Just n)
+               addPSname n -- okay for proof search
                focus tyn
                
                elabE (ec { e_inarg = True, e_intype = True }) (Just fc) ty
@@ -574,6 +655,7 @@
                highlightSource nfc (AnnBoundName n False)
     elab' ina fc (PPi p n nfc Placeholder sc)
           = do attack; arg n (is_scoped p) (sMN 0 "ty")
+               addPSname n -- okay for proof search
                elabE (ina { e_inarg = True, e_intype = True }) fc sc
                solve
                highlightSource nfc (AnnBoundName n False)
@@ -584,13 +666,14 @@
                         MN _ _ -> unique_hole n
                         _ -> return n
                forall n' (is_scoped p) (Var tyn)
+               addPSname n' -- okay for proof search
                focus tyn
                let ec' = ina { e_inarg = True, e_intype = True }
                elabE ec' fc ty
                elabE ec' fc sc
                solve
                highlightSource nfc (AnnBoundName n False)
-    elab' ina _ (PLet fc n nfc ty val sc)
+    elab' ina _ tm@(PLet fc n nfc ty val sc)
           = do attack
                ivs <- get_instances
                tyn <- getNameFrom (sMN 0 "letty")
@@ -599,6 +682,7 @@
                claim valn (Var tyn)
                explicit valn
                letbind n (Var tyn) (Var valn)
+               addPSname n
                case ty of
                    Placeholder -> return ()
                    _ -> do focus tyn
@@ -611,12 +695,12 @@
                ivs' <- get_instances
                env <- get_env
                elabE (ina { e_inarg = True }) (Just fc) sc
-               when (not pattern) $
+               when (not (pattern || intransform)) $
                    mapM_ (\n -> do focus n
                                    g <- goal
                                    hs <- get_holes
                                    if all (\n -> n == tyn || not (n `elem` hs)) (freeNames g)
-                                    then try (resolveTC True False 10 g fn ist)
+                                    then try (resolveTC' True False 10 g fn ist)
                                              (movelast n)
                                     else movelast n)
                          (ivs' \\ ivs)
@@ -643,7 +727,7 @@
          solve
 --          elab' ina fc (PLet n Placeholder
 --              (PApp fc r [pexp (delab ist rty)]) sc)
-    elab' ina _ tm@(PApp fc (PInferRef _ f) args) = do
+    elab' ina _ tm@(PApp fc (PInferRef _ _ f) args) = do
          rty <- goal
          ds <- get_deferred
          ctxt <- get_context
@@ -674,7 +758,7 @@
              fnTy [] ret  = forget ret
              fnTy ((x, (_, xt)) : xs) ret = RBind x (Pi Nothing xt RType) (fnTy xs ret)
 
-             localVar env (PRef _ x)
+             localVar env (PRef _ _ x)
                            = case lookup x env of
                                   Just _ -> Just x
                                   _ -> Nothing
@@ -698,7 +782,7 @@
             solve
     -- if f is local, just do a simple_app
     -- FIXME: Anyone feel like refactoring this mess? - EB
-    elab' ina topfc tm@(PApp fc (PRef ffc f) args_in)
+    elab' ina topfc tm@(PApp fc (PRef ffc hls f) args_in)
       | pattern && not reflection && not (e_qq ina) && e_nomatching ina
               = lift $ tfail $ Msg ("Attempting concrete match on polymorphic argument: " ++ show tm)
       | otherwise = implicitApp $
@@ -720,11 +804,12 @@
             if (f `elem` map fst 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 f))
+                                  (elabE (ina { e_isfn = True }) (Just fc) (PRef ffc hls f))
                                   (elabE (ina { e_inarg = True }) (Just fc) (getTm (head args)))
                                   (show tm)
                        solve
-                       highlightSource ffc annot
+                       mapM (uncurry highlightSource) $
+                         (ffc, annot) : map (\f -> (f, annot)) hls
                        return []
                else
                  do ivs <- get_instances
@@ -744,13 +829,14 @@
                     ns <- apply (Var f) (map isph args)
 --                    trace ("ns is " ++ show ns) $ return ()
                     -- mark any type class arguments as injective
-                    mapM_ checkIfInjective (map snd ns)
+                    when (not pattern) $ mapM_ checkIfInjective (map snd ns)
                     unifyProblems -- try again with the new information,
                                   -- to help with disambiguation
                     ulog <- getUnifyLog
 
                     annot <- findHighlight f
-                    highlightSource ffc annot
+                    mapM (uncurry highlightSource) $
+                      (ffc, annot) : map (\f -> (f, annot)) hls
 
                     elabArgs ist (ina { e_inarg = e_inarg ina || not isinf }) 
                            [] fc False f
@@ -786,7 +872,7 @@
                                                     env <- get_env
                                                     hs <- get_holes
                                                     if all (\n -> not (n `elem` hs)) (freeNames g)
-                                                     then try (resolveTC False False 10 g fn ist)
+                                                     then try (resolveTC' False False 10 g fn ist)
                                                               (movelast n)
                                                      else movelast n)
                                           (ivs' \\ ivs)
@@ -799,7 +885,7 @@
             -- to be needed.
             implicitApp :: ElabD [ImplicitInfo] -> ElabD ()
             implicitApp elab 
-              | pattern = do elab; return ()
+              | pattern || intransform = do elab; return ()
               | otherwise
                 = do s <- get
                      imps <- elab
@@ -822,7 +908,7 @@
                 case lookup n env of
                      Nothing -> return ()
                      Just b ->
-                       case unApply (binderTy b) of
+                       case unApply (normalise (tt_ctxt ist) env (binderTy b)) of
                             (P _ c _, args) ->
                                 case lookupCtxtExact c (idris_classes ist) of
                                    Nothing -> return ()
@@ -848,8 +934,8 @@
             tacTm (PProof _) = True
             tacTm _ = False
 
-            setInjective (PRef _ n) = setinj n
-            setInjective (PApp _ (PRef _ n) _) = setinj n
+            setInjective (PRef _ _ n) = setinj n
+            setInjective (PApp _ (PRef _ _ n) _) = setinj n
             setInjective _ = return ()
 
     elab' ina _ tm@(PApp fc f [arg]) =
@@ -859,9 +945,9 @@
                            (elabE (ina { e_inarg = True }) (Just fc) (getTm arg))
                                 (show tm)
                 solve
-        where headRef (PRef _ _) = True
+        where headRef (PRef _ _ _) = True
               headRef (PApp _ f _) = headRef f
-              headRef (PAlternative _ as) = all headRef as
+              headRef (PAlternative _ _ as) = all headRef as
               headRef _ = False
 
     elab' ina fc (PAppImpl f es) = do appImpl (reverse es) -- not that we look... 
@@ -880,15 +966,12 @@
              -- names which have been used elsewhere in the term, since we
              -- won't be able to use them in the resulting application.
              let unique_used = getUniqueUsed (tt_ctxt ist) ptm
-             let n' = mkN n
+             let n' = metavarName (namespace info) n
              attack
+             psns <- getPSnames
              defer unique_used n'
              solve
              highlightSource nfc (AnnName n' (Just MetavarOutput) Nothing Nothing)
-        where mkN n@(NS _ _) = n
-              mkN n = case namespace info of
-                        Just xs@(_:_) -> sNS n xs
-                        _ -> n
     elab' ina fc (PProof ts) = do compute; mapM_ (runTac True ist (elabFC info) fn) ts
     elab' ina fc (PTactics ts)
         | not pattern = do mapM_ (runTac False ist fc fn) ts
@@ -925,7 +1008,7 @@
                    elab' ina (Just fc) t
                    focus valn
                    elab' ina (Just fc) sc
-                   elab' ina (Just fc) (PRef fc letn)
+                   elab' ina (Just fc) (PRef fc [] letn)
                    solve
     elab' ina _ c@(PCase fc scr opts)
         = do attack
@@ -970,7 +1053,7 @@
              -- if the scrutinee is one of the 'args' in env, we should
              -- inspect it directly, rather than adding it as a new argument
              let newdef = PClauses fc [] cname'
-                             (caseBlock fc cname'
+                             (caseBlock fc cname' scr
                                 (map (isScr scr) (reverse args')) opts)
              -- elaborate case
              updateAux (\e -> e { case_decls = (cname', newdef) : case_decls e } )
@@ -1109,15 +1192,18 @@
 
 
     elab' ina fc (PUnquote t) = fail "Found unquote outside of quasiquote"
-    elab' ina fc (PQuoteName n) =
+    elab' ina fc (PQuoteName n nfc) =
       do ctxt <- get_context
          env <- get_env
          case lookup n env of
-           Just _ -> do fill $ reflectName n ; solve
+           Just _ -> do fill $ reflectName n
+                        solve
+                        highlightSource nfc (AnnBoundName n False)
            Nothing ->
              case lookupNameDef n ctxt of
                [(n', _)] -> do fill $ reflectName n'
                                solve
+                               highlightSource nfc (AnnName n' Nothing Nothing Nothing)
                [] -> lift . tfail . NoSuchVariable $ n
                more -> lift . tfail . CantResolveAlts $ map fst more
     elab' ina fc (PAs _ n t) = lift . tfail . Msg $ "@-pattern not allowed here"
@@ -1135,7 +1221,7 @@
              delayElab 10 $ do focus h
                                dotterm
                                elab' ina fc t
-    elab' ina fc (PRunElab fc' tm) =
+    elab' ina fc (PRunElab fc' tm ns) =
       do attack
          n <- getNameFrom (sMN 0 "tacticScript")
          n' <- getNameFrom (sMN 0 "tacticExpr")
@@ -1148,8 +1234,44 @@
          focus n
          elab' ina (Just fc') tm
          env <- get_env
-         runTactical ist (maybe fc' id fc) env (P Bound n' Erased)
+         runElabAction ist (maybe fc' id fc) env (P Bound n' Erased) ns
          solve
+    elab' ina fc (PConstSugar constFC tm) =
+      -- Here we elaborate the contained term, then calculate
+      -- highlighting for constFC.  The highlighting is the
+      -- highlighting for the outermost constructor of the result of
+      -- evaluating the elaborated term, if one exists (it always
+      -- should, but better to fail gracefully for something silly
+      -- like highlighting info). This is how implicit applications of
+      -- fromInteger get highlighted.
+      do saveState -- so we don't pollute the elaborated term
+         n <- getNameFrom (sMN 0 "cstI")
+         n' <- getNameFrom (sMN 0 "cstIhole")
+         g <- forget <$> goal
+         claim n' g
+         movelast n'
+         -- In order to intercept the elaborated value, we need to
+         -- let-bind it.
+         attack
+         letbind n g (Var n')
+         focus n'
+         elab' ina fc tm
+         env <- get_env
+         ctxt <- get_context
+         let v = fmap (normaliseAll ctxt env . finalise . binderVal)
+                      (lookup n env)
+         loadState -- we have the highlighting - re-elaborate the value
+         elab' ina fc tm
+         case v of
+           Just val -> highlightConst constFC val
+           Nothing -> return ()
+       where highlightConst fc (P _ n _) =
+               highlightSource fc (AnnName n Nothing Nothing Nothing)
+             highlightConst fc (App _ f _) =
+               highlightConst fc f
+             highlightConst fc (Constant c) =
+               highlightSource fc (AnnConst c)
+             highlightConst _ _ = return ()
     elab' ina fc x = fail $ "Unelaboratable syntactic form " ++ showTmImpls x
 
     -- delay elaboration of 't', with priority 'pri' until after everything
@@ -1161,12 +1283,13 @@
        = 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 (PRef _ _ n) (n', b) = (n', (n == n', b))
     isScr _ (n', b) = (n', (False, b))
 
-    caseBlock :: FC -> Name ->
-                 [(Name, (Bool, Binder Term))] -> [(PTerm, PTerm)] -> [PClause]
-    caseBlock fc n env opts
+    caseBlock :: FC -> Name
+                 -> PTerm -- original scrutinee
+                 -> [(Name, (Bool, Binder Term))] -> [(PTerm, PTerm)] -> [PClause]
+    caseBlock fc n scr env opts
         = let args' = findScr env
               args = map mkarg (map getNmScr args') in
               map (mkClause args) opts
@@ -1189,29 +1312,44 @@
 
              getNmScr (n, (s, _)) = (n, s)
 
-             mkarg (n, s) = (PRef fc n, s)
+             mkarg (n, s) = (PRef fc [] n, s)
              -- may be shadowed names in the new pattern - so replace the
              -- old ones with an _
+             -- Also, names which don't appear on the rhs should not be
+             -- fixed on the lhs, or this restricts the kind of matching
+             -- we can do to non-dependent types.
              mkClause args (l, r)
                    = let args' = map (shadowed (allNamesIn l)) args
-                         lhs = PApp (getFC fc l) (PRef (getFC fc l) n)
-                                 (map (mkLHSarg l) args') in
+                         args'' = map (implicitable (allNamesIn r ++
+                                                     keepscrName scr)) args'
+                         lhs = PApp (getFC fc l) (PRef NoFC [] n)
+                                 (map (mkLHSarg l) args'') in
                             PClause (getFC fc l) n lhs [] r []
 
+             -- Keep scrutinee available if it's just a name (this makes
+             -- the names in scope look better when looking at a hole on
+             -- the rhs of a case)
+             keepscrName (PRef _ _ n) = [n]
+             keepscrName _ = []
+
              mkLHSarg l (tm, True) = pexp l
              mkLHSarg l (tm, False) = pexp tm
 
-             shadowed new (PRef _ n, s) | n `elem` new = (Placeholder, s)
+             shadowed new (PRef _ _ n, s) | n `elem` new = (Placeholder, s)
              shadowed new t = t
 
+             implicitable rhs (PRef _ _ n, s) | n `notElem` rhs = (Placeholder, s)
+             implicitable rhs t = t
+
+
     getFC d (PApp fc _ _) = fc
-    getFC d (PRef fc _) = fc
-    getFC d (PAlternative _ (x:_)) = getFC d x
+    getFC d (PRef fc _ _) = fc
+    getFC d (PAlternative _ _ (x:_)) = getFC d x
     getFC d x = d
 
     insertLazy :: PTerm -> ElabD PTerm
-    insertLazy t@(PApp _ (PRef _ (UN l)) _) | l == txt "Delay" = return t
-    insertLazy t@(PApp _ (PRef _ (UN l)) _) | l == txt "Force" = return t
+    insertLazy t@(PApp _ (PRef _ _ (UN l)) _) | l == txt "Delay" = return t
+    insertLazy t@(PApp _ (PRef _ _ (UN l)) _) | l == txt "Force" = return t
     insertLazy (PCoerced t) = return t
     insertLazy t =
         do ty <- goal
@@ -1220,13 +1358,13 @@
            let tries = if pattern then [t, mkDelay env t] else [mkDelay env t, t]
            case tyh of
                 P _ (UN l) _ | l == txt "Lazy'"
-                    -> return (PAlternative FirstSuccess tries)
+                    -> return (PAlternative [] FirstSuccess tries)
                 _ -> return t
       where
-        mkDelay env (PAlternative b xs) = PAlternative b (map (mkDelay env) xs)
+        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"))
+                  addImplBound ist (map fst env) (PApp fc (PRef fc [] (sUN "Delay"))
                                                  [pexp t])
 
 
@@ -1235,10 +1373,10 @@
     -- blowup especially where there are errors deep in large expressions.
     notImplicitable (PApp _ f _) = notImplicitable f
     -- TMP HACK no coercing on bind (make this configurable)
-    notImplicitable (PRef _ n)
+    notImplicitable (PRef _ _ n)
         | [opts] <- lookupCtxt n (idris_flags ist)
             = NoImplicit `elem` opts
-    notImplicitable (PAlternative (ExactlyOne _) as) = any notImplicitable as
+    notImplicitable (PAlternative _ (ExactlyOne _) as) = any notImplicitable as
     -- case is tricky enough without implicit coercions! If they are needed,
     -- they can go in the branches separately.
     notImplicitable (PCase _ _ _) = True
@@ -1281,14 +1419,13 @@
            let t' = case (t, cs) of
                          (PCoerced tm, _) -> tm
                          (_, []) -> t
-                         (_, cs) -> PAlternative FirstSuccess [t ,
-                                       PAlternative (ExactlyOne False) 
-                                            (map (mkCoerce env t) cs)]
+                         (_, cs) -> PAlternative [] TryImplicit 
+                                        (t : map (mkCoerce env t) cs)
            return t'
        where
          mkCoerce env t n = let fc = maybe (fileFC "Coercion") id (highestFC t) in
                                 addImplBound ist (map fst env)
-                                  (PApp fc (PRef fc n) [pexp (PCoerced t)])
+                                  (PApp fc (PRef fc [] n) [pexp (PCoerced t)])
 
     -- | Elaborate the arguments to a function
     elabArgs :: IState -- ^ The current Idris state
@@ -1351,28 +1488,28 @@
 pruneAlt :: [PTerm] -> [PTerm]
 pruneAlt xs = map prune xs
   where
-    prune (PApp fc1 (PRef fc2 f) as)
-        = PApp fc1 (PRef fc2 f) (fmap (fmap (choose f)) as)
+    prune (PApp fc1 (PRef fc2 hls f) as)
+        = PApp fc1 (PRef fc2 hls f) (fmap (fmap (choose f)) as)
     prune t = t
 
-    choose f (PAlternative a as)
+    choose f (PAlternative ms a as)
         = let as' = fmap (choose f) as
               fs = filter (headIs f) as' in
               case fs of
                  [a] -> a
-                 _ -> PAlternative a as'
+                 _ -> PAlternative ms a as'
 
     choose f (PApp fc f' as) = PApp fc (choose f f') (fmap (fmap (choose f)) as)
     choose f t = t
 
-    headIs f (PApp _ (PRef _ f') _) = f == f'
+    headIs f (PApp _ (PRef _ _ f') _) = f == f'
     headIs f (PApp _ f' _) = headIs f f'
     headIs f _ = True -- keep if it's not an application
 
 -- Rule out alternatives that don't return the same type as the head of the goal
 -- (If there are none left as a result, do nothing)
-pruneByType :: [Name] -> Term -> -- head of the goal
-               Context -> [PTerm] -> [PTerm]
+pruneByType :: Env -> Term -> -- head of the goal
+               IState -> [PTerm] -> [PTerm]
 -- if an alternative has a locally bound name at the head, take it
 pruneByType env t c as
    | Just a <- locallyBound as = [a]
@@ -1380,15 +1517,16 @@
     locallyBound [] = Nothing
     locallyBound (t:ts)
        | Just n <- getName t,
-         n `elem` env = Just t
+         n `elem` map fst env = Just t
        | otherwise = locallyBound ts
-    getName (PRef _ n) = Just n
+    getName (PRef _ _ n) = Just n
     getName (PApp _ f _) = getName f
     getName (PHidden t) = getName t
     getName _ = Nothing
 
-pruneByType env (P _ n _) ctxt as
--- if the goal type is polymorphic, keep e
+-- 'n' is the name at the head of the goal type
+pruneByType env (P _ n _) ist as
+-- if the goal type is polymorphic, keep everything
    | Nothing <- lookupTyExact n ctxt = as
    | otherwise
        = let asV = filter (headIs True n) as
@@ -1399,8 +1537,10 @@
                         _ -> asV
                _ -> as'
   where
-    headIs var f (PRef _ f') = typeHead var f f'
-    headIs var f (PApp _ (PRef _ f') _) = typeHead var f f'
+    ctxt = tt_ctxt ist 
+
+    headIs var f (PRef _ _ f') = typeHead var f f'
+    headIs var f (PApp _ (PRef _ _ f') _) = typeHead var f f'
     headIs var f (PApp _ f' _) = headIs var f f'
     headIs var f (PPi _ _ _ _ sc) = headIs var f sc
     headIs var f (PHidden t) = headIs var f t
@@ -1414,12 +1554,45 @@
                             _ -> let ty' = normalise ctxt [] ty in
                                      case unApply (getRetTy ty') of
                                           (P _ ftyn _, _) -> ftyn == f
-                                          (V _, _) -> var -- keep, variable
+                                          (V _, _) -> 
+                                            -- keep, variable
+--                                             trace ("Keeping " ++ show (f', ty')
+--                                                      ++ " for " ++ show n) $
+                                              isPlausible ist var env n ty
                                           _ -> False
                _ -> False
 
 pruneByType _ t _ as = as
 
+-- Could the name feasibly be the return type?
+-- If there is a type class constraint on the return type, and no instance
+-- in the environment or globally for that name, then no
+-- Otherwise, yes
+-- (FIXME: This isn't complete, but I'm leaving it here and coming back
+-- to it later - just returns 'var' for now. EB)
+isPlausible :: IState -> Bool -> Env -> Name -> Type -> Bool
+isPlausible ist var env n ty 
+    = let (hvar, classes) = collectConstraints [] [] ty in
+          case hvar of
+               Nothing -> True
+               Just rth -> var -- trace (show (rth, classes)) var
+   where
+     collectConstraints :: [Name] -> [(Term, [Name])] -> Type -> 
+                                     (Maybe Name, [(Term, [Name])])
+     collectConstraints env tcs (Bind n (Pi _ ty _) sc)
+         = let tcs' = case unApply ty of
+                           (P _ c _, _) -> 
+                               case lookupCtxtExact c (idris_classes ist) of
+                                    Just tc -> ((ty, map fst (class_instances tc)) 
+                                                     : tcs) 
+                                    Nothing -> tcs
+                           _ -> tcs 
+                      in
+               collectConstraints (n : env) tcs' sc
+     collectConstraints env tcs t
+         | (V i, _) <- unApply t = (Just (env !! i), tcs)
+         | otherwise = (Nothing, tcs)
+
 -- | Use the local elab context to work out the highlighting for a name
 findHighlight :: Name -> ElabD OutputAnnotation
 findHighlight n = do ctxt <- get_context
@@ -1431,20 +1604,6 @@
                                     Nothing -> lift . tfail . InternalMsg $
                                                  "Can't find name" ++ show n
 
--- | Find the names of instances that have been designeated for
--- searching (i.e. non-named instances or instances from Elab scripts)
-findInstances :: IState -> Term -> [Name]
-findInstances ist t
-    | (P _ n _, _) <- unApply (getRetTy t)
-        = case lookupCtxt n (idris_classes ist) of
-            [CI _ _ _ _ _ ins _] ->
-              [n | (n, True) <- ins, accessible n]
-            _ -> []
-    | otherwise = []
-  where accessible n = case lookupDefAccExact n False (tt_ctxt ist) of
-                            Just (_, Hidden) -> False
-                            _ -> True
-
 -- Try again to solve auto implicits
 solveAuto :: IState -> Name -> Bool -> Name -> ElabD ()
 solveAuto ist fn ambigok n
@@ -1455,7 +1614,7 @@
                   g <- goal
                   isg <- is_guess -- if it's a guess, we're working on it recursively, so stop
                   when (not isg) $
-                    proofSearch' ist True ambigok 100 True Nothing fn []
+                    proofSearch' ist True ambigok 100 True Nothing fn [] []
 
 solveAutos :: IState -> Name -> Bool -> ElabD ()
 solveAutos ist fn ambigok
@@ -1464,181 +1623,21 @@
 
 trivial' ist
     = trivial (elab ist toplevel ERHS [] (sMN 0 "tac")) ist
-trivialHoles' h ist
-    = trivialHoles h (elab ist toplevel ERHS [] (sMN 0 "tac")) ist
-proofSearch' ist rec ambigok depth prv top n hints
+trivialHoles' psn h ist
+    = trivialHoles psn h (elab ist toplevel ERHS [] (sMN 0 "tac")) ist
+proofSearch' ist rec ambigok depth prv top n psns hints
     = do unifyProblems
          proofSearch rec prv ambigok (not prv) depth
-                     (elab ist toplevel ERHS [] (sMN 0 "tac")) top n hints ist
-
--- | Resolve type classes. This will only pick up 'normal' instances, never
--- named instances (which is enforced by 'findInstances').
-resolveTC :: Bool -- ^ using default Int
-          -> Bool -- ^ allow metavariables in the goal
-          -> Int -- ^ depth
-          -> Term -- ^ top level goal, for error messages
-          -> Name -- ^ top level function name, to prevent loops
-          -> IState -> ElabD ()
-resolveTC def mvok depth top fn ist
-   = do hs <- get_holes
-        resTC' [] def hs depth top fn ist
-
-resTC' tcs def topholes 0 topg fn ist = fail $ "Can't resolve type class"
-resTC' tcs def topholes 1 topg fn ist = try' (trivial' ist) (resolveTC def False 0 topg fn ist) True
-resTC' tcs defaultOn topholes depth topg fn ist
-  = do compute
-       g <- goal
-       -- Resolution can proceed only if there is something concrete in the
-       -- determining argument positions. Keep track of the holes in the
-       -- non-determining position, because it's okay for 'trivial' to solve
-       -- those holes and no others.
-       let (argsok, okholePos) = case tcArgsOK g topholes of
-                                    Nothing -> (False, [])
-                                    Just hs -> (True, hs)
-       if not argsok -- && not mvok)
-         then lift $ tfail $ CantResolve True topg
-         else do
-           ptm <- get_term
-           ulog <- getUnifyLog
-           hs <- get_holes
-           env <- get_env
-           t <- goal
-           let (tc, ttypes) = unApply (getRetTy t)
-           let okholes = case tc of
-                              P _ n _ -> zip (repeat n) okholePos
-                              _ -> []
-
-           traceWhen ulog ("Resolving class " ++ show g ++ "\nin" ++ show env ++ "\n" ++ show okholes) $
-            try' (trivialHoles' okholes ist)
-                (do addDefault t tc ttypes
-                    let stk = map fst (filter snd $ elab_stack ist)
-                    let insts = findInstances ist t
-                    blunderbuss t depth stk (stk ++ insts)) True
-  where
-    -- returns Just hs if okay, where hs are holes which are okay in the
-    -- goal, or Nothing if not okay to proceed
-    tcArgsOK ty hs | (P _ nc _, as) <- unApply (getRetTy ty), nc == numclass && defaultOn
-       = Just []
-    tcArgsOK ty hs -- if any determining arguments are metavariables, postpone
-       = let (f, as) = unApply (getRetTy ty) in
-             case f of
-                  P _ cn _ -> case lookupCtxtExact cn (idris_classes ist) of
-                                   Just ci -> tcDetArgsOK 0 (class_determiners ci) hs as
-                                   Nothing -> if any (isMeta hs) as
-                                                 then Nothing
-                                                 else Just []
-                  _ -> if any (isMeta hs) as
-                          then Nothing
-                          else Just []
-
-    -- return the list of argument positions which can safely be a hole
-    -- or Nothing if one of the determining arguments is a hole
-    tcDetArgsOK i ds hs (x : xs)
-        | i `elem` ds = if isMeta hs x
-                           then Nothing
-                           else tcDetArgsOK (i + 1) ds hs xs
-        | otherwise = do rs <- tcDetArgsOK (i + 1) ds hs xs
-                         case x of
-                              P _ n _ -> Just (i : rs)
-                              _ -> Just rs
-    tcDetArgsOK _ _ _ [] = Just []
-
-    isMeta :: [Name] -> Term -> Bool
-    isMeta ns (P _ n _) = n `elem` ns 
-    isMeta _ _ = False
-
-    notHole hs (P _ n _, c)
-       | (P _ cn _, _) <- unApply (getRetTy c),
-         n `elem` hs && isConName cn (tt_ctxt ist) = False
-       | Constant _ <- c = not (n `elem` hs)
-    notHole _ _ = True
-
-    -- HACK! Rather than giving a special name, better to have some kind
-    -- of flag in ClassInfo structure
-    chaser (UN nm)
-        | ('@':'@':_) <- str nm = True -- old way
-    chaser (SN (ParentN _ _)) = True
-    chaser (NS n _) = chaser n
-    chaser _ = False
-
-    numclass = sNS (sUN "Num") ["Classes","Prelude"]
-
-    addDefault t num@(P _ nc _) [P Bound a _] | nc == numclass && defaultOn
-        = do focus a
-             fill (RConstant (AType (ATInt ITBig))) -- default Integer
-             solve
-    addDefault t f as
-          | all boundVar as = return () -- True -- fail $ "Can't resolve " ++ show t
-    addDefault t f a = return () -- trace (show t) $ return ()
-
-    boundVar (P Bound _ _) = True
-    boundVar _ = False
-
-    blunderbuss t d stk [] = do -- c <- get_env
-                            -- ps <- get_probs
-                            lift $ tfail $ CantResolve False topg
-    blunderbuss t d stk (n:ns)
-        | n /= fn -- && (n `elem` stk)
-              = tryCatch (resolve n d)
-                    (\e -> case e of
-                             CantResolve True _ -> lift $ tfail e
-                             _ -> blunderbuss t d stk ns)
-        | otherwise = blunderbuss t d stk ns
-
-    introImps = do g <- goal
-                   case g of
-                        (Bind _ (Pi _ _ _) sc) -> do attack; intro Nothing
-                                                     num <- introImps
-                                                     return (num + 1)
-                        _ -> return 0
-
-    solven 0 = return ()
-    solven n = do solve; solven (n - 1)
-
-    resolve n depth
-       | depth == 0 = fail $ "Can't resolve type class"
-       | otherwise
-           = do lams <- introImps
-                t <- goal
-                let (tc, ttypes) = trace (show t) $ unApply (getRetTy t)
---                 if (all boundVar ttypes) then resolveTC (depth - 1) fn insts ist
---                   else do
-                   -- if there's a hole in the goal, don't even try
-                let imps = case lookupCtxtName n (idris_implicits ist) of
-                                [] -> []
-                                [args] -> map isImp (snd args) -- won't be overloaded!
-                                xs -> error "The impossible happened - overloading is not expected here!"
-                ps <- get_probs
-                tm <- get_term
-                args <- map snd <$> try' (apply (Var n) imps)
-                                         (match_apply (Var n) imps) True
-                solven lams -- close any implicit lambdas we introduced
-                ps' <- get_probs
-                when (length ps < length ps' || unrecoverable ps') $
-                     fail "Can't apply type class"
---                 traceWhen (all boundVar ttypes) ("Progress: " ++ show t ++ " with " ++ show n) $
-                mapM_ (\ (_,n) -> do focus n
-                                     t' <- goal
-                                     let (tc', ttype) = unApply (getRetTy t')
-                                     let got = fst (unApply (getRetTy t))
-                                     let depth' = if tc' `elem` tcs
-                                                     then depth - 1 else depth
-                                     resTC' (got : tcs) defaultOn topholes depth' topg fn ist)
-                      (filter (\ (x, y) -> not x) (zip (map fst imps) args))
-                -- if there's any arguments left, we've failed to resolve
-                hs <- get_holes
-                ulog <- getUnifyLog
-                solve
-                traceWhen ulog ("Got " ++ show n) $ return ()
-       where isImp (PImp p _ _ _ _) = (True, p)
-             isImp arg = (False, priority arg)
+                     (elab ist toplevel ERHS [] (sMN 0 "tac")) top n psns hints ist
+resolveTC' di mv depth tm n ist
+    = resolveTC di mv depth tm n (elab ist toplevel ERHS [] (sMN 0 "tac")) ist
 
 collectDeferred :: Maybe Name -> [Name] -> Context ->
-                   Term -> State [(Name, (Int, Maybe Name, Type))] Term
-collectDeferred top casenames ctxt (Bind n (GHole i t) app) =
+                   Term -> State [(Name, (Int, Maybe Name, Type, [Name]))] Term
+collectDeferred top casenames ctxt (Bind n (GHole i psns t) app) =
     do ds <- get
        t' <- collectDeferred top casenames ctxt t
-       when (not (n `elem` map fst ds)) $ put (ds ++ [(n, (i, top, tidyArg [] t'))])
+       when (not (n `elem` map fst ds)) $ put (ds ++ [(n, (i, top, tidyArg [] t', psns))])
        collectDeferred top casenames ctxt app
   where
     -- Evaluate the top level functions in arguments, if possible, and if it's
@@ -1648,18 +1647,9 @@
     tidyArg env (Bind n b@(Pi im t k) sc) 
         = Bind n (Pi im (tidy ctxt env t) k)
                  (tidyArg ((n, b) : env) sc)
-    tidyArg env t = t
+    tidyArg env t = tidy ctxt env t
 
-    tidy ctxt env t | (f, args) <- unApply t,
-                      P _ specn _ <- getFn f,
-                      n `notElem` casenames
-        = fst $ specialise ctxt env [(specn, 99999)] t 
-    tidy ctxt env t@(Bind n (Let _ _) sct)
-                    | (f, args) <- unApply sct,
-                      P _ specn _ <- getFn f,
-                      n `notElem` casenames
-        = fst $ specialise ctxt env [(specn, 99999)] t 
-    tidy ctxt env t = t
+    tidy ctxt env t = normalise ctxt env t
 
     getFn (Bind n (Lam _) t) = getFn t
     getFn t | (f, a) <- unApply t = f
@@ -1695,11 +1685,16 @@
          else casetac (forget val)
   when autoSolve solveAll
 
+-- | Compute the appropriate name for a top-level metavariable
+metavarName :: Maybe [String] -> Name -> Name
+metavarName _                 n@(NS _ _) = n
+metavarName (Just (ns@(_:_))) n          = sNS n ns
+metavarName _                 n          = n
 
-runTactical :: IState -> FC -> Env -> Term -> ElabD ()
-runTactical ist fc env tm = do tm' <- eval tm
-                               runTacTm tm'
-                               return ()
+runElabAction :: IState -> FC -> Env -> Term -> [String] -> ElabD Term
+runElabAction ist fc env tm ns = do tm' <- eval tm
+                                    runTacTm tm'
+
   where
     eval tm = do ctxt <- get_context
                  return $ normaliseAll ctxt env (finalise tm)
@@ -1720,8 +1715,9 @@
          let info = CaseInfo True True False -- TODO document and figure out
          clauses' <- forM clauses (\case
                                       RMkFunClause lhs rhs ->
-                                        do lhs' <- fmap fst . lift $ check ctxt [] lhs
-                                           rhs' <- fmap fst . lift $ check ctxt [] rhs
+                                        do (lhs', lty) <- lift $ check ctxt [] lhs
+                                           (rhs', rty) <- lift $ check ctxt [] rhs
+                                           lift $ converts ctxt [] lty rty
                                            return $ Right (lhs', rhs')
                                       RMkImpossibleClause lhs ->
                                         do lhs' <- fmap fst . lift $ check ctxt [] lhs
@@ -1730,21 +1726,27 @@
                                     Left lhs -> let (ns, lhs') = patvars [] lhs'
                                                 in (ns, lhs', Impossible))
                             clauses'
-         set_context $
-           addCasedef n (const [])
-                      info False (STerm Erased)
-                      True False -- TODO what are these?
-                      (map snd $ getArgTys ty) [] -- TODO inaccessible types
-                      clauses'
-                      clauses''
-                      clauses''
-                      clauses''
-                      clauses''
-                      ty
-                      ctxt
+         ctxt'<- lift $
+                  addCasedef n (const [])
+                             info False (STerm Erased)
+                             True False -- TODO what are these?
+                             (map snd $ getArgTys ty) [] -- TODO inaccessible types
+                             clauses'
+                             clauses''
+                             clauses''
+                             clauses''
+                             clauses''
+                             ty
+                             ctxt
+         set_context ctxt'
          updateAux $ \e -> e { new_tyDecls = RClausesInstrs n clauses'' : new_tyDecls e}
          return ()
 
+    checkClosed :: Raw -> Elab' aux (Term, Type)
+    checkClosed tm = do ctxt <- get_context
+                        (val, ty) <- lift $ check ctxt [] tm
+                        return $! (finalise val, finalise ty)
+
     -- | Do a step in the reflected elaborator monad. The input is the
     -- step, the output is the (reflected) term returned.
     runTacTm :: Term -> ElabD Term
@@ -1753,14 +1755,18 @@
       = do solve
            returnUnit
       | n == tacN "prim__Goal", [] <- args
-      = do (h:_) <- get_holes
-           t <- goal
-           fmap fst . get_type_val $
-             rawPair (Var (reflm "TTName"), Var (reflm "TT"))
-                     (reflectName h,        reflect t)
+      = do hs <- get_holes
+           case hs of
+             (h : _) -> do t <- goal
+                           fmap fst . checkClosed $
+                             rawPair (Var (reflm "TTName"), Var (reflm "TT"))
+                                     (reflectName h,        reflect t)
+             [] -> lift . tfail . Msg $
+                     "Elaboration is complete. There are no goals."
+
       | n == tacN "prim__Holes", [] <- args
       = do hs <- get_holes
-           fmap fst . get_type_val $
+           fmap fst . checkClosed $
              mkList (Var $ reflm "TTName") (map reflectName hs)
       | n == tacN "prim__Guess", [] <- args
       = do ok <- is_guess
@@ -1770,7 +1776,7 @@
                         RApp (RApp (Var (sNS (sUN "Just") ["Maybe", "Prelude"]))
                                    (Var (reflm "TT")))
                              guess
-              else fmap fst . get_type_val $
+              else fmap fst . checkClosed $
                      RApp (Var (sNS (sUN "Nothing") ["Maybe", "Prelude"]))
                           (Var (reflm "TT"))
       | n == tacN "prim__LookupTy", [n] <- args
@@ -1790,7 +1796,7 @@
            let defs = [ reflectTriple (reflectName n, reflectNameType nt, reflect ty)
                         | (n, def) <- lookupNameDef n' ctxt
                         , let (nt, ty) = getNameTypeAndType def ]
-           fmap fst . get_type_val $
+           fmap fst . checkClosed $
              rawList (raw_apply (Var pairTy) [ Var (reflm "TTName")
                                              , raw_apply (Var pairTy) [ Var (reflm "NameType")
                                                                        , Var (reflm "TT")]])
@@ -1799,15 +1805,18 @@
       = do n' <- reifyTTName name
            datatypes <- get_datatypes
            ctxt <- get_context
-           fmap fst . get_type_val $
+           fmap fst . checkClosed $
              rawList (Var (tacN "Datatype"))
-                     (map reflectDatatype (buildDatatypes ctxt datatypes n'))
+                     (map reflectDatatype (buildDatatypes ist n'))
       | n == tacN "prim__SourceLocation", [] <- args
-      = fmap fst . get_type_val $
+      = fmap fst . checkClosed $
           reflectFC fc
+      | n == tacN "prim__Namespace", [] <- args
+      = fmap fst . checkClosed $
+          rawList (RConstant StrType) (map (RConstant . Str) ns)
       | n == tacN "prim__Env", [] <- args
       = do env <- get_env
-           fmap fst . get_type_val $ reflectEnv env
+           fmap fst . checkClosed $ reflectEnv env
       | n == tacN "prim__Fail", [_a, errs] <- args
       = do errs' <- eval errs
            parts <- reifyReportParts errs'
@@ -1827,10 +1836,20 @@
       = do raw' <- reifyRaw =<< eval raw
            fill raw'
            returnUnit
-      | n == tacN "prim__Apply", [raw] <- args
+      | n == tacN "prim__Apply" || n == tacN "prim__MatchApply"
+      , [raw, argSpec] <- args
       = do raw' <- reifyRaw =<< eval raw
-           apply raw' []
-           returnUnit
+           argSpec' <- reifyList (reifyPair reifyBool reifyInt) argSpec
+           let op = if n == tacN "prim__Apply"
+                       then apply
+                       else match_apply
+           ns <- op raw' argSpec'
+           fmap fst . checkClosed $
+             rawList (rawPairTy (Var $ reflm "TTName") (Var $ reflm "TTName"))
+                     [ rawPair (Var $ reflm "TTName", Var $ reflm "TTName")
+                               (reflectName n1, reflectName n2)
+                     | (n1, n2) <- ns
+                     ]
       | n == tacN "prim__Gensym", [hint] <- args
       = do hintStr <- eval hint
            case hintStr of
@@ -1843,9 +1862,17 @@
            ty' <- reifyRaw ty
            claim n' ty'
            returnUnit
+      | n == tacN "prim__Check", [raw] <- args
+      = do raw' <- reifyRaw =<< eval raw
+           ctxt <- get_context
+           env <- get_env
+           (tm, ty) <- lift $ check ctxt env raw'
+           fmap fst . checkClosed $
+             rawPair (Var (reflm "TT"), Var (reflm "TT"))
+                     (reflect tm,       reflect ty)
       | n == tacN "prim__Forget", [tt] <- args
       = do tt' <- reifyTT tt
-           fmap fst . get_type_val . reflectRaw $ forget tt'
+           fmap fst . checkClosed . reflectRaw $ forget tt'
       | n == tacN "prim__Attack", [] <- args
       = do attack
            returnUnit
@@ -1855,8 +1882,10 @@
            returnUnit
       | n == tacN "prim__Focus", [what] <- args
       = do n' <- reifyTTName what
-           focus n'
-           returnUnit
+           hs <- get_holes
+           if elem n' hs
+              then focus n' >> returnUnit
+              else lift . tfail . Msg $ "The name " ++ show n' ++ " does not denote a hole"
       | n == tacN "prim__Unfocus", [what] <- args
       = do n' <- reifyTTName what
            movelast n'
@@ -1874,14 +1903,30 @@
            returnUnit
       | n == tacN "prim__PatVar", [n] <- args
       = do n' <- reifyTTName n
-           patvar n'
+           patvar' n'
            returnUnit
       | n == tacN "prim__PatBind", [n] <- args
       = do n' <- reifyTTName n
            patbind n'
            returnUnit
+      | n == tacN "prim__LetBind", [n, ty, tm] <- args
+      = do n' <- reifyTTName n
+           ty' <- reifyRaw ty
+           tm' <- reifyRaw tm
+           letbind n' ty' tm'
+           returnUnit
       | n == tacN "prim__Compute", [] <- args
       = do compute ; returnUnit
+      | n == tacN "prim__Normalise", [env, tm] <- args
+      = do env' <- reifyEnv env
+           tm' <- reifyTT tm
+           ctxt <- get_context
+           let out = normaliseAll ctxt env' (finalise tm')
+           fmap fst . checkClosed $ reflect out
+      | n == tacN "prim__Whnf", [tm] <- args
+      = do tm' <- reifyTT tm
+           ctxt <- get_context
+           fmap fst . checkClosed . reflect $ whnf ctxt tm'
       | n == tacN "prim__DeclareType", [decl] <- args
       = do (RDeclare n args res) <- reifyTyDecl decl
            ctxt <- get_context
@@ -1902,7 +1947,7 @@
            let decl = TyDecl Ref checked
                ctxt' = addCtxtDef n decl ctxt
            set_context ctxt'
-           updateAux $ \e -> e { new_tyDecls = (RTyDeclInstrs n fc (map rArgToPArg args) checked) :
+           updateAux $ \e -> e { new_tyDecls = (RTyDeclInstrs n fc (map rFunArgToPArg args) checked) :
                                                new_tyDecls e }
            aux <- getAux
            returnUnit
@@ -1919,8 +1964,21 @@
       | n == tacN "prim__ResolveTC", [fn] <- args
       = do g <- goal
            fn <- reifyTTName fn
-           resolveTC False True 100 g fn ist
+           resolveTC' False True 100 g fn ist
            returnUnit
+      | n == tacN "prim__Search", [depth, hints] <- args
+      = do d <- eval depth
+           hints' <- eval hints
+           case (d, unList hints') of
+             (Constant (I i), Just hs) ->
+               do actualHints <- mapM reifyTTName hs
+                  unifyProblems
+                  let psElab = elab ist toplevel ERHS [] (sMN 0 "tac")
+                  proofSearch True True False False i psElab Nothing (sMN 0 "search ") [] actualHints ist
+                  returnUnit
+             (Constant (I _), Nothing ) ->
+               lift . tfail . InternalMsg $ "Not a list: " ++ show hints'
+             (_, _) -> lift . tfail . InternalMsg $ "Can't reify int " ++ show d
       | n == tacN "prim__RecursiveElab", [goal, script] <- args
       = do goal' <- reifyRaw goal
            ctxt <- get_context
@@ -1932,22 +1990,49 @@
            datatypes <- get_datatypes
            env <- get_env
            (_, ES (p, aux') _ _) <-
-              lift $ runElab aux (runTactical ist fc [] script)
-                             (newProof recH ctxt datatypes goalTT)
+              do (ES (current_p, _) _ _) <- get
+                 lift $ runElab aux (runElabAction ist fc [] script ns)
+                                 ((newProof recH ctxt datatypes goalTT)
+                                  { nextname = nextname current_p})
            let tm_out = getProofTerm (pterm p)
-           updateAux $ const aux'
+           do (ES (prf, _) s e) <- get
+              let p' = prf { nextname = nextname p }
+              put (ES (p', aux') s e)
            env' <- get_env
            (tm, ty, _) <- lift $ recheck ctxt env (forget tm_out) tm_out
            let (tm', ty') = (reflect tm, reflect ty)
-           fmap fst . get_type_val $
+           fmap fst . checkClosed $
              rawPair (Var $ reflm "TT", Var $ reflm "TT")
                      (tm', ty')
+      | n == tacN "prim__Metavar", [n] <- args
+      = do n' <- reifyTTName n
+           ctxt <- get_context
+           ptm <- get_term
+           -- See documentation above in the elab case for PMetavar
+           let unique_used = getUniqueUsed ctxt ptm
+           let mvn = metavarName (Just ns) n'
+           attack
+           defer unique_used mvn
+           solve
+           returnUnit
+      | n == tacN "prim__Fixity", [op'] <- args
+      = do opTm <- eval op'
+           case opTm of
+             Constant (Str op) -> 
+               let opChars = ":!#$%&*+./<=>?@\\^|-~"
+                   invalidOperators = [":", "=>", "->", "<-", "=", "?=", "|", "**", "==>", "\\", "%", "~", "?", "!"]
+                   fixities = idris_infixes ist
+               in if not (all (flip elem opChars) op) || elem op invalidOperators
+                     then lift . tfail . Msg $ "'" ++ op ++ "' is not a valid operator name."
+                     else case nub [f | Fix f someOp <- fixities, someOp == op] of
+                            []   -> lift . tfail . Msg $ "No fixity found for operator '" ++ op ++ "'."
+                            [f]  -> fmap fst . checkClosed $ reflectFixity f
+                            many -> lift . tfail . InternalMsg $ "Ambiguous fixity for '" ++ op ++ "'!  Found " ++ show many
+             _ -> lift . tfail . Msg $ "Not a constant string for an operator name: " ++ show opTm
       | n == tacN "prim__Debug", [ty, msg] <- args
-      = do let msg' = fromTTMaybe msg
-           case msg' of
-             Nothing -> debugElaborator Nothing
-             Just (Constant (Str m)) -> debugElaborator (Just m)
-             Just x -> lift . tfail . InternalMsg $ "Can't reify message for debugging: " ++ show x
+      = do msg' <- eval msg
+           parts <- reifyReportParts msg
+           debugElaborator parts
     runTacTm x = lift . tfail $ ElabScriptStuck x
 
 -- Running tactics directly
@@ -2079,8 +2164,8 @@
     runT Compute = compute
     runT Trivial = do trivial' ist; when autoSolve solveAll
     runT TCInstance = runT (Exact (PResolveTC emptyFC))
-    runT (ProofSearch rec prover depth top hints)
-         = do proofSearch' ist rec False depth prover top fn hints
+    runT (ProofSearch rec prover depth top psns hints)
+         = do proofSearch' ist rec False depth prover top fn psns hints
               when autoSolve solveAll
     runT (Focus n) = focus n
     runT Unfocus = do hs <- get_holes
@@ -2288,7 +2373,7 @@
          updateIState $ \i -> i { idris_implicits =
                                     addDef n impls (idris_implicits i) }
          addIBC (IBCImp n)
-         ds <- checkDef fc (\_ e -> e) [(n, (-1, Nothing, ty))]
+         ds <- checkDef fc (\_ e -> e) [(n, (-1, Nothing, ty, []))]
          addIBC (IBCDef n)
          ctxt <- getContext
          case lookupDef n ctxt of
@@ -2297,7 +2382,7 @@
              -- then it must be added as a metavariable. This needs guarding
              -- to prevent overwriting case defs with a metavar, if the case
              -- defs come after the type decl in the same script!
-             let ds' = map (\(n, (i, top, t)) -> (n, (i, top, t, True))) ds
+             let ds' = map (\(n, (i, top, t, ns)) -> (n, (i, top, t, ns, True))) ds
              in addDeferred ds'
            _ -> return ()
     RAddInstance className instName ->
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
@@ -49,13 +49,14 @@
 import Util.Pretty(pretty, text)
 
 elabTransform :: ElabInfo -> FC -> Bool -> PTerm -> PTerm -> Idris (Term, Term)
-elabTransform info fc safe lhs_in@(PApp _ (PRef _ tf) _) rhs_in
+elabTransform info fc safe lhs_in@(PApp _ (PRef _ _ tf) _) rhs_in
     = do ctxt <- getContext
          i <- getIState
          let lhs = addImplPat i lhs_in
+         logLvl 5 ("Transform LHS input: " ++ showTmImpls lhs)
          (ElabResult lhs' dlhs [] ctxt' newDecls highlights, _) <-
               tclift $ elaborate ctxt (idris_datatypes i) (sMN 0 "transLHS") infP initEState
-                       (erun fc (buildTC i info ELHS [] (sUN "transform")
+                       (erun fc (buildTC i info ETransLHS [] (sUN "transform")
                                    (infTerm lhs)))
          setContext ctxt'
          processTacticDecls info newDecls
@@ -67,8 +68,11 @@
          (clhs_tm_in, clhs_ty) <- recheckC fc id [] lhs_tm
          let clhs_tm = renamepats pnames clhs_tm_in
          logLvl 3 ("Transform LHS " ++ show clhs_tm)
-
+         logLvl 3 ("Transform type " ++ show clhs_ty)
+         
          let rhs = addImplBound i (map fst newargs) rhs_in
+         logLvl 5 ("Transform RHS input: " ++ showTmImpls rhs)
+
          ((rhs', defer, ctxt', newDecls), _) <-
               tclift $ elaborate ctxt (idris_datatypes i) (sMN 0 "transRHS") clhs_ty initEState
                        (do pbinds i lhs_tm
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
@@ -148,7 +148,7 @@
          rep <- useREPL
          when rep $ do
            addInternalApp (fc_fname fc) (fst . fc_start $ fc) ty' -- (mergeTy ty' (delab i nty')) -- TODO: Should use span instead of line and filename?
-           addIBC (IBCLineApp (fc_fname fc) (fst . fc_start $ fc) ty') -- (mergeTy ty' (delab i nty')))
+         addIBC (IBCLineApp (fc_fname fc) (fst . fc_start $ fc) ty') -- (mergeTy ty' (delab i nty')))
 
          let (fam, _) = unApply (getRetTy nty')
          let corec = case fam of
@@ -159,9 +159,9 @@
          -- Productivity checking now via checking for guarded 'Delay' 
          let opts' = opts -- if corec then (Coinductive : opts) else opts
          let usety = if norm then nty' else nty
-         ds <- checkDef fc iderr [(n, (-1, Nothing, usety))]
+         ds <- checkDef fc iderr [(n, (-1, Nothing, usety, []))]
          addIBC (IBCDef n)
-         let ds' = map (\(n, (i, top, fam)) -> (n, (i, top, fam, True))) ds
+         let ds' = map (\(n, (i, top, fam, ns)) -> (n, (i, top, fam, ns, True))) ds
          addDeferred ds'
          setFlags n opts'
          checkDocs fc argDocs ty
@@ -232,18 +232,19 @@
     tyIsHandler _                                           = False
 
 elabPostulate :: ElabInfo -> SyntaxInfo -> Docstring (Either Err PTerm) ->
-                 FC -> FnOpts -> Name -> PTerm -> Idris ()
-elabPostulate info syn doc fc opts n ty = do
+                 FC -> FC -> FnOpts -> Name -> PTerm -> Idris ()
+elabPostulate info syn doc fc nfc opts n ty = do
     elabType info syn doc [] fc opts n NoFC ty
     putIState . (\ist -> ist{ idris_postulates = S.insert n (idris_postulates ist) }) =<< getIState
     addIBC (IBCPostulate n)
+    sendHighlighting [(nfc, AnnName n (Just PostulateOutput) Nothing Nothing)]
 
     -- remove it from the deferred definitions list
     solveDeferred n
 
 elabExtern :: ElabInfo -> SyntaxInfo -> Docstring (Either Err PTerm) ->
-                 FC -> FnOpts -> Name -> PTerm -> Idris ()
-elabExtern info syn doc fc opts n ty = do
+                 FC -> FC -> FnOpts -> Name -> PTerm -> Idris ()
+elabExtern info syn doc fc nfc opts n ty = do
     cty <- elabType info syn doc [] fc opts n NoFC ty
     ist <- getIState
     let arity = length (getArgTys (normalise (tt_ctxt ist) [] cty))
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
@@ -40,21 +40,21 @@
 iderr :: Name -> Err -> Err
 iderr _ e = e
 
-checkDef :: FC -> (Name -> Err -> Err) -> [(Name, (Int, Maybe Name, Type))]
-         -> Idris [(Name, (Int, Maybe Name, Type))]
+checkDef :: FC -> (Name -> Err -> Err) -> [(Name, (Int, Maybe Name, Type, [Name]))]
+         -> Idris [(Name, (Int, Maybe Name, Type, [Name]))]
 checkDef fc mkerr ns = checkAddDef False True fc mkerr ns
 
 checkAddDef :: Bool -> Bool -> FC -> (Name -> Err -> Err)
-            -> [(Name, (Int, Maybe Name, Type))]
-            -> Idris [(Name, (Int, Maybe Name, Type))]
+            -> [(Name, (Int, Maybe Name, Type, [Name]))]
+            -> Idris [(Name, (Int, Maybe Name, Type, [Name]))]
 checkAddDef add toplvl fc mkerr [] = return []
-checkAddDef add toplvl fc mkerr ((n, (i, top, t)) : ns) 
+checkAddDef add toplvl fc mkerr ((n, (i, top, t, psns)) : ns) 
                = do ctxt <- getContext
                     (t', _) <- recheckC fc (mkerr n) [] t
-                    when add $ do addDeferred [(n, (i, top, t, toplvl))]
+                    when add $ do addDeferred [(n, (i, top, t, psns, toplvl))]
                                   addIBC (IBCDef n)
                     ns' <- checkAddDef add toplvl fc mkerr ns
-                    return ((n, (i, top, t')) : ns')
+                    return ((n, (i, top, t', psns)) : ns')
 
 -- | Get the list of (index, name) of inaccessible arguments from an elaborated
 -- type
@@ -66,8 +66,6 @@
 
 -- | Get the list of (index, name) of inaccessible arguments from the type.
 inaccessibleArgs :: Int -> PTerm -> [(Int, Name)]
-inaccessibleArgs i (PPi (Imp _ _ _ _) n _ Placeholder t)
-        = (i,n) : inaccessibleArgs (i+1) t  -- unbound implicit
 inaccessibleArgs i (PPi plicity n _ ty t)
     | InaccessibleArg `elem` pargopts plicity
         = (i,n) : inaccessibleArgs (i+1) t  -- an .{erased : Implicit}
@@ -131,7 +129,7 @@
           dc (PWith   fc n t as w pn ds)
                  = PWith fc (decorate n) (dappname t) as w pn
                             (map (decorateid decorate) ds)
-          dappname (PApp fc (PRef fc' n) as) = PApp fc (PRef fc' (decorate n)) as
+          dappname (PApp fc (PRef fc' hl n) as) = PApp fc (PRef fc' hl (decorate n)) as
           dappname t = t
 
 
@@ -139,7 +137,8 @@
 pbinds :: IState -> Term -> ElabD ()
 pbinds i (Bind n (PVar t) sc) 
     = do attack; patbind n
-         case unApply t of
+         env <- get_env
+         case unApply (normalise (tt_ctxt i) env t) of
               (P _ c _, args) -> case lookupCtxt c (idris_classes i) of
                                    [] -> return ()
                                    _ -> -- type class, set as injective
@@ -166,19 +165,19 @@
 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 t of
-                    P _ n _ -> if n `elem` env then [n] else []
+            ++ case unApply t of
+                    (P _ n _, _) -> if n `elem` env then [n] else []
                     _ -> []
 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
-       = case lookupCtxt tn (idris_datatypes i) of
-            [t] -> nub $ paramNames args env (param_pos t) ++
-                         getFixedInType i env is f ++
-                         getFixedInType i env is a
-            [] -> nub $ getFixedInType i env is f ++
-                        getFixedInType i env is a
+       = case lookupCtxtExact tn (idris_datatypes i) of
+            Just t -> nub $ paramNames args env (param_pos t) ++
+                            getFixedInType i env is f ++
+                            getFixedInType i env is a
+            Nothing -> nub $ getFixedInType i env is f ++
+                             getFixedInType i env is a
     | otherwise = nub $ getFixedInType i env is f ++
                         getFixedInType i env is a
 getFixedInType i _ _ _ = []
@@ -189,17 +188,16 @@
 
 getFlexInType i env ps tm@(App _ f a)
     | (P nt tn _, args) <- unApply tm, nt /= Bound
-       = case lookupCtxt tn (idris_datatypes i) of
-            [t] -> nub $ paramNames args env [x | x <- [0..length args],
-                                                  not (x `elem` param_pos t)] 
+       = case lookupCtxtExact tn (idris_datatypes i) of
+            Just t -> nub $ paramNames args env [x | x <- [0..length args],
+                                                     not (x `elem` param_pos t)] 
                           ++ getFlexInType i env ps f ++
                              getFlexInType i env ps a
-            [] -> let ppos = case lookupCtxtName tn (idris_fninfo i) of
-                                  [fi] -> fn_params (snd fi)
-                                  [] -> []
-                                  xs -> error ("Too much function info: " ++ show xs)
-                  in nub $ paramNames args env [x | x <- [0..length args],
-                                                    not (x `elem` ppos)] 
+            Nothing -> let ppos = case lookupCtxtExact tn (idris_fninfo i) of
+                                       Just fi -> fn_params fi
+                                       Nothing -> []
+                       in nub $ paramNames args env [x | x <- [0..length args],
+                                                         not (x `elem` ppos)] 
                            ++ getFlexInType i env ps f ++
                               getFlexInType i env ps a
     | otherwise = nub $ getFlexInType i env ps f ++
diff --git a/src/Idris/Elab/Value.hs b/src/Idris/Elab/Value.hs
--- a/src/Idris/Elab/Value.hs
+++ b/src/Idris/Elab/Value.hs
@@ -1,6 +1,7 @@
 {-# LANGUAGE PatternGuards #-}
 {-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
-module Idris.Elab.Value(elabVal, elabValBind, elabDocTerms, elabExec) where
+module Idris.Elab.Value(elabVal, elabValBind, elabDocTerms, 
+                        elabExec, elabREPL) where
 
 import Idris.AbsSyntax
 import Idris.ASTUtils
@@ -50,7 +51,7 @@
 
 import Util.Pretty(pretty, text)
 
--- Elaborate a value, returning any new bindings created (this will only
+-- | Elaborate a value, returning any new bindings created (this will only
 -- happen if elaborating as a pattern clause)
 elabValBind :: ElabInfo -> ElabMode -> Bool -> PTerm -> Idris (Term, Type, [(Name, Type)])
 elabValBind info aspat norm tm_in
@@ -75,7 +76,7 @@
         let vtm = orderPats (getInferTerm tm')
 
         def' <- checkDef (fileFC "(input)") iderr defer
-        let def'' = map (\(n, (i, top, t)) -> (n, (i, top, t, True))) def'
+        let def'' = map (\(n, (i, top, t, ns)) -> (n, (i, top, t, ns, True))) def'
         addDeferred def''
         mapM_ (elabCaseBlock info []) is
 
@@ -116,17 +117,24 @@
                                             else Checked tm
           | otherwise                   = Unchecked
 
--- Try running the term directly (as IO ()), then printing it as an Integer
+-- | Try running the term directly (as IO ()), then printing it as an Integer
 -- (as a default numeric tye), then printing it as any Showable thing
 elabExec :: FC -> PTerm -> PTerm
-elabExec fc tm = runtm (PAlternative FirstSuccess
-                   [printtm (PApp fc (PRef fc (sUN "the"))
+elabExec fc tm = runtm (PAlternative [] FirstSuccess
+                   [printtm (PApp fc (PRef fc [] (sUN "the"))
                      [pexp (PConstant NoFC (AType (ATInt ITBig))), pexp tm]),
                     tm,
                     printtm tm
                     ])
   where
-    runtm t = PApp fc (PRef fc (sUN "run__IO")) [pexp t]
-    printtm t = PApp fc (PRef fc (sUN "printLn"))
-                  [pimp (sUN "ffi") (PRef fc (sUN "FFI_C")) False, pexp t]
+    runtm t = PApp fc (PRef fc [] (sUN "run__IO")) [pexp t]
+    printtm t = PApp fc (PRef fc [] (sUN "printLn"))
+                  [pimp (sUN "ffi") (PRef fc [] (sUN "FFI_C")) False, pexp t]
 
+elabREPL :: ElabInfo -> ElabMode -> PTerm -> Idris (Term, Type)
+elabREPL info aspat tm
+    = idrisCatch (elabVal info aspat tm) catchAmbig
+  where
+    catchAmbig (CantResolveAlts _)
+       = elabVal info aspat (PDisamb [[txt "List"]] tm)
+    catchAmbig e = ierror e
diff --git a/src/Idris/ElabDecls.hs b/src/Idris/ElabDecls.hs
--- a/src/Idris/ElabDecls.hs
+++ b/src/Idris/ElabDecls.hs
@@ -29,6 +29,7 @@
 import Idris.Elab.Class
 import Idris.Elab.Instance
 import Idris.Elab.Provider
+import Idris.Elab.RunElab
 import Idris.Elab.Transform
 import Idris.Elab.Value
 
@@ -68,8 +69,8 @@
 -- | Return the elaborated term which calls 'main'
 elabMain :: Idris Term
 elabMain = do (m, _) <- elabVal recinfo ERHS
-                           (PApp fc (PRef fc (sUN "run__IO"))
-                                [pexp $ PRef fc (sNS (sUN "main") ["Main"])])
+                           (PApp fc (PRef fc [] (sUN "run__IO"))
+                                [pexp $ PRef fc [] (sNS (sUN "main") ["Main"])])
               return m
   where fc = fileFC "toplevel"
 
@@ -158,25 +159,25 @@
      = return () -- nothing to elaborate
 elabDecl' what info (PTy doc argdocs s f o n nfc ty)
   | what /= EDefns
-    = do iLOG $ "Elaborating type decl " ++ show n ++ show o
+    = do logLvl 1 $ "Elaborating type decl " ++ show n ++ show o
          elabType info s doc argdocs f o n nfc ty
          return ()
-elabDecl' what info (PPostulate b doc s f o n ty)
+elabDecl' what info (PPostulate b doc s f nfc o n ty)
   | what /= EDefns
-    = do iLOG $ "Elaborating postulate " ++ show n ++ show o
+    = do logLvl 1 $ "Elaborating postulate " ++ show n ++ show o
          if b 
-            then elabExtern info s doc f o n ty
-            else elabPostulate info s doc f o n ty
+            then elabExtern info s doc f nfc o n ty
+            else elabPostulate info s doc f nfc o n ty
 elabDecl' what info (PData doc argDocs s f co d)
   | what /= ETypes
-    = do iLOG $ "Elaborating " ++ show (d_name d)
+    = do logLvl 1 $ "Elaborating " ++ show (d_name d)
          elabData info s doc argDocs f co d
   | otherwise
-    = do iLOG $ "Elaborating [type of] " ++ show (d_name d)
+    = do logLvl 1 $ "Elaborating [type of] " ++ show (d_name d)
          elabData info s doc argDocs f co (PLaterdecl (d_name d) (d_name_fc d) (d_tcon d))
 elabDecl' what info d@(PClauses f o n ps)
   | what /= ETypes
-    = do iLOG $ "Elaborating clause " ++ show n
+    = do logLvl 1 $ "Elaborating clause " ++ show n
          i <- getIState -- get the type options too
          let o' = case lookupCtxt n (idris_flags i) of
                     [fs] -> fs
@@ -190,12 +191,14 @@
          -- record mutually defined data definitions
          let datans = concatMap declared (filter isDataDecl ps)
          mapM_ (setMutData datans) datans
-         iLOG $ "Rechecking for positivity " ++ show datans
+         logLvl 1 $ "Rechecking for positivity " ++ show datans
          mapM_ (\x -> do setTotality x Unchecked) datans
          -- Do totality checking after entire mutual block
          i <- get
          mapM_ (\n -> do logLvl 5 $ "Simplifying " ++ show n
-                         updateContext (simplifyCasedef n $ getErasureInfo i))
+                         ctxt' <- do ctxt <- getContext
+                                     tclift $ simplifyCasedef n (getErasureInfo i) ctxt
+                         setContext ctxt')
                  (map snd (idris_totcheck i))
          mapM_ buildSCG (idris_totcheck i)
          mapM_ checkDeclTotality (idris_totcheck i)
@@ -213,7 +216,7 @@
 
 elabDecl' what info (PParams f ns ps)
     = do i <- getIState
-         iLOG $ "Expanding params block with " ++ show ns ++ " decls " ++
+         logLvl 1 $ "Expanding params block with " ++ show ns ++ " decls " ++
                 show (concatMap tldeclared ps)
          let nblock = pblock i
          mapM_ (elabDecl' what info) nblock
@@ -237,18 +240,17 @@
 
 elabDecl' what info (PClass doc s f cs n nfc ps pdocs fds ds cn cd)
   | what /= EDefns
-    = do iLOG $ "Elaborating class " ++ show n
+    = do logLvl 1 $ "Elaborating class " ++ show n
          elabClass info (s { syn_params = [] }) doc f cs n nfc ps pdocs fds ds cn cd
 elabDecl' what info (PInstance doc argDocs s f cs n nfc ps t expn ds)
-    = do iLOG $ "Elaborating instance " ++ show n
+    = do logLvl 1 $ "Elaborating instance " ++ show n
          elabInstance info s doc argDocs what f cs n nfc ps t expn ds
 elabDecl' what info (PRecord doc rsyn fc opts name nfc ps pdocs fs cname cdoc csyn)
-  | what /= ETypes
-    = do iLOG $ "Elaborating record " ++ show name
-         elabRecord info doc rsyn fc opts name nfc ps pdocs fs cname cdoc csyn
+    = do logLvl 1 $ "Elaborating record " ++ show name
+         elabRecord info what doc rsyn fc opts name nfc ps pdocs fs cname cdoc csyn
 {-
   | otherwise
-    = do iLOG $ "Elaborating [type of] " ++ show tyn
+    = do logLvl 1 $ "Elaborating [type of] " ++ show tyn
          elabData info s doc [] f [] (PLaterdecl tyn ty)
 -}
 elabDecl' _ info (PDSL n dsl)
@@ -257,11 +259,14 @@
          addIBC (IBCDSL n)
 elabDecl' what info (PDirective i)
   | what /= EDefns = directiveAction i
-elabDecl' what info (PProvider doc syn fc provWhat n)
+elabDecl' what info (PProvider doc syn fc nfc provWhat n)
   | what /= EDefns
-    = do iLOG $ "Elaborating type provider " ++ show n
-         elabProvider doc info syn fc provWhat n
+    = do logLvl 1 $ "Elaborating type provider " ++ show n
+         elabProvider doc info syn fc nfc provWhat n
 elabDecl' what info (PTransform fc safety old new)
     = do elabTransform info fc safety old new
+         return ()
+elabDecl' what info (PRunElabDecl fc script ns)
+    = do elabRunElab info fc script ns
          return ()
 elabDecl' _ _ _ = return () -- skipped this time
diff --git a/src/Idris/ElabQuasiquote.hs b/src/Idris/ElabQuasiquote.hs
--- a/src/Idris/ElabQuasiquote.hs
+++ b/src/Idris/ElabQuasiquote.hs
@@ -116,19 +116,19 @@
          Just zz -> do (z', ex3) <- extractUnquotes n zz
                        return (PRewrite fc x' y' (Just z'), ex1 ++ ex2 ++ ex3)
          Nothing -> return (PRewrite fc x' y' Nothing, ex1 ++ ex2)
-extractUnquotes n (PPair fc info l r)
+extractUnquotes n (PPair fc hls info l r)
   = do (l', ex1) <- extractUnquotes n l
        (r', ex2) <- extractUnquotes n r
-       return (PPair fc info l' r', ex1 ++ ex2)
-extractUnquotes n (PDPair fc info a b c)
+       return (PPair fc hls info l' r', ex1 ++ ex2)
+extractUnquotes n (PDPair fc hls info a b c)
   = do (a', ex1) <- extractUnquotes n a
        (b', ex2) <- extractUnquotes n b
        (c', ex3) <- extractUnquotes n c
-       return (PDPair fc info a' b' c', ex1 ++ ex2 ++ ex3)
-extractUnquotes n (PAlternative b alts)
+       return (PDPair fc hls info a' b' c', ex1 ++ ex2 ++ ex3)
+extractUnquotes n (PAlternative ms b alts)
   = do alts' <- mapM (extractUnquotes n) alts
        let (alts'', exs) = unzip alts'
-       return (PAlternative b alts'', concat exs)
+       return (PAlternative ms b alts'', concat exs)
 extractUnquotes n (PHidden tm)
   = do (tm', ex) <- extractUnquotes n tm
        return (PHidden tm', ex)
@@ -163,11 +163,13 @@
   = fmap (\(tm', ex) -> (PQuasiquote tm' goal, ex)) $ extractUnquotes (n+1) tm
 extractUnquotes n (PUnquote tm)
   | n == 0 = do n <- getNameFrom (sMN 0 "unquotation")
-                return (PRef (fileFC "(unquote)") n, [(n, tm)])
+                return (PRef (fileFC "(unquote)") [] n, [(n, tm)])
   | otherwise = fmap (\(tm', ex) -> (PUnquote tm', ex)) $
                 extractUnquotes (n-1) tm
-extractUnquotes n (PRunElab fc tm)
-  = fmap (\(tm', ex) -> (PRunElab fc tm', ex)) $ extractUnquotes n tm
+extractUnquotes n (PRunElab fc tm ns)
+  = fmap (\(tm', ex) -> (PRunElab fc tm' ns, ex)) $ extractUnquotes n tm
+extractUnquotes n (PConstSugar fc tm)
+  = extractUnquotes n tm
 extractUnquotes n x = return (x, []) -- no subterms!
 
 
diff --git a/src/Idris/ErrReverse.hs b/src/Idris/ErrReverse.hs
--- a/src/Idris/ErrReverse.hs
+++ b/src/Idris/ErrReverse.hs
@@ -1,6 +1,6 @@
 {-# LANGUAGE PatternGuards #-}
 
-module Idris.ErrReverse where
+module Idris.ErrReverse(errReverse) where
 
 import Idris.AbsSyntax
 import Idris.Core.TT
diff --git a/src/Idris/Error.hs b/src/Idris/Error.hs
--- a/src/Idris/Error.hs
+++ b/src/Idris/Error.hs
@@ -88,8 +88,8 @@
 -- | Issue a warning on "with"-terms whose namespace is empty or nonexistent
 warnDisamb :: IState -> PTerm -> Idris ()
 warnDisamb ist (PQuote _) = return ()
-warnDisamb ist (PRef _ _) = return ()
-warnDisamb ist (PInferRef _ _) = return ()
+warnDisamb ist (PRef _ _ _) = return ()
+warnDisamb ist (PInferRef _ _ _) = return ()
 warnDisamb ist (PPatvar _ _) = return ()
 warnDisamb ist (PLam _ _ _ t b) = warnDisamb ist t >> warnDisamb ist b
 warnDisamb ist (PPi _ _ _ t b) = warnDisamb ist t >> warnDisamb ist b
@@ -107,9 +107,9 @@
 warnDisamb ist (PResolveTC _) = return ()
 warnDisamb ist (PRewrite _ x y z) = warnDisamb ist x >> warnDisamb ist y >>
                                     Foldable.mapM_ (warnDisamb ist) z
-warnDisamb ist (PPair _ _ x y) = warnDisamb ist x >> warnDisamb ist y
-warnDisamb ist (PDPair _ _ x y z) = warnDisamb ist x >> warnDisamb ist y >> warnDisamb ist z
-warnDisamb ist (PAlternative _ tms) = mapM_ (warnDisamb ist) tms
+warnDisamb ist (PPair _ _ _ x y) = warnDisamb ist x >> warnDisamb ist y
+warnDisamb ist (PDPair _ _ _ x y z) = warnDisamb ist x >> warnDisamb ist y >> warnDisamb ist z
+warnDisamb ist (PAlternative _ _ tms) = mapM_ (warnDisamb ist) tms
 warnDisamb ist (PHidden tm) = warnDisamb ist tm
 warnDisamb ist (PType _) = return ()
 warnDisamb ist (PUniverse _) = return ()
@@ -147,7 +147,8 @@
 warnDisamb ist (PQuasiquote tm goal) = warnDisamb ist tm >>
                                        Foldable.mapM_ (warnDisamb ist) goal
 warnDisamb ist (PUnquote tm) = warnDisamb ist tm
-warnDisamb ist (PQuoteName _) = return ()
+warnDisamb ist (PQuoteName _ _) = return ()
 warnDisamb ist (PAs _ _ tm) = warnDisamb ist tm
 warnDisamb ist (PAppImpl tm _) = warnDisamb ist tm
-warnDisamb ist (PRunElab _ tm) = warnDisamb ist tm
+warnDisamb ist (PRunElab _ tm _) = warnDisamb ist tm
+warnDisamb ist (PConstSugar _ tm) = warnDisamb ist tm
diff --git a/src/Idris/Help.hs b/src/Idris/Help.hs
--- a/src/Idris/Help.hs
+++ b/src/Idris/Help.hs
@@ -27,7 +27,7 @@
     show NumberArg        = "<number>"
     show NamespaceArg     = "<namespace>"
     show OptionArg        = "<option>"
-    show MetaVarArg       = "<metavar>"
+    show MetaVarArg       = "<hole>"
     show ColourArg        = "<option>"
     show NoArg            = ""
     show SpecialHeaderArg = "Arguments"
@@ -46,5 +46,5 @@
     , ([":makewith!", ":mw!"], NoArg, ":mw! <line> <name> destructively adds a with clause for the definition of the name on the line")
     , ([":proofsearch!", ":ps!"], NoArg, ":ps! <line> <name> <names> destructively does proof search for name on line, with names as hints")
     , ([":addproofclause!", ":apc!"], NoArg, ":apc! <line> <name> destructively adds a pattern-matching proof clause to name on line")
-    , ([":refine!", ":ref!"], NoArg, ":ref! <line> <name> <name'> destructively attempts to partially solve name on line, with name' as hint, introducing metavariables for arguments that aren't inferrable")
+    , ([":refine!", ":ref!"], NoArg, ":ref! <line> <name> <name'> destructively attempts to partially solve name on line, with name' as hint, introducing holes for arguments that aren't inferrable")
     ]
diff --git a/src/Idris/IBC.hs b/src/Idris/IBC.hs
--- a/src/Idris/IBC.hs
+++ b/src/Idris/IBC.hs
@@ -2,7 +2,8 @@
 {-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
 
 module Idris.IBC (loadIBC, loadPkgIndex,
-                  writeIBC, writePkgIndex) where
+                  writeIBC, writePkgIndex,
+                  hasValidIBCVersion) where
 
 import Idris.Core.Evaluate
 import Idris.Core.TT
@@ -36,16 +37,13 @@
 import qualified Control.Monad.State.Strict as ST
 import System.FilePath
 import System.Directory
-import Codec.Compression.Zlib (compress)
 import Codec.Archive.Zip
-import Util.Zlib (decompressEither)
 
 ibcVersion :: Word16
-ibcVersion = 110
+ibcVersion = 119
 
 data IBCFile = IBCFile { ver :: Word16,
                          sourcefile :: FilePath,
-                         symbols :: ![Name],
                          ibc_imports :: ![(Bool, FilePath)],
                          ibc_importdirs :: ![FilePath],
                          ibc_implicits :: ![(Name, [PArg])],
@@ -80,7 +78,7 @@
                          ibc_metainformation :: ![(Name, MetaInformation)],
                          ibc_errorhandlers :: ![Name],
                          ibc_function_errorhandlers :: ![(Name, Name, Name)], -- fn, arg, handler
-                         ibc_metavars :: ![(Name, (Maybe Name, Int, Bool))],
+                         ibc_metavars :: ![(Name, (Maybe Name, Int, [Name], Bool))],
                          ibc_patdefs :: ![(Name, ([([Name], Term, Term)], [PTerm]))],
                          ibc_postulates :: ![Name],
                          ibc_externs :: ![(Name, Int)],
@@ -95,8 +93,16 @@
 !-}
 
 initIBC :: IBCFile
-initIBC = IBCFile ibcVersion "" [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] Nothing [] [] []
+initIBC = IBCFile ibcVersion "" [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] Nothing [] [] []
 
+hasValidIBCVersion :: FilePath -> Idris Bool
+hasValidIBCVersion fp = do
+  archiveFile <- runIO $ B.readFile fp
+  case toArchiveOrFail archiveFile of
+    Left _ -> return False
+    Right archive -> do ver <- getEntry 0 "ver" archive
+                        return (ver == ibcVersion)
+
 loadIBC :: Bool -- ^ True = reexport, False = make everything private
         -> FilePath -> Idris ()
 loadIBC reexport fp
@@ -105,7 +111,7 @@
                                 Nothing -> True
                                 Just p -> not p && reexport
                 when redo $
-                  do iLOG $ "Loading ibc " ++ fp ++ " " ++ show reexport
+                  do logLvl 1 $ "Loading ibc " ++ fp ++ " " ++ show reexport
                      archiveFile <- runIO $ B.readFile fp
                      case toArchiveOrFail archiveFile of
                         Left _ -> ifail $ fp ++ " isn't loadable, it may have an old ibc format.\n"
@@ -130,7 +136,6 @@
 entries :: IBCFile -> [Entry]
 entries i = catMaybes [Just $ toEntry "ver" 0 (encode $ ver i),
                        makeEntry "sourcefile"  (sourcefile i),
-                       makeEntry "symbols"  (symbols i),
                        makeEntry "ibc_imports"  (ibc_imports i),
                        makeEntry "ibc_importdirs"  (ibc_importdirs i),
                        makeEntry "ibc_implicits"  (ibc_implicits i),
@@ -180,7 +185,7 @@
 
 writeIBC :: FilePath -> FilePath -> Idris ()
 writeIBC src f
-    = do iLOG $ "Writing ibc " ++ show f
+    = do logLvl 1 $ "Writing ibc " ++ show f
          i <- getIState
 --          case (Data.List.map fst (idris_metavars i)) \\ primDefs of
 --                 (_:_) -> ifail "Can't write ibc when there are unsolved metavariables"
@@ -189,8 +194,8 @@
          ibcf <- mkIBC (ibc_write i) (initIBC { sourcefile = src })
          idrisCatch (do runIO $ createDirectoryIfMissing True (dropFileName f)
                         writeArchive f ibcf
-                        iLOG "Written")
-            (\c -> do iLOG $ "Failed " ++ pshow i c)
+                        logLvl 1 "Written")
+            (\c -> do logLvl 1 $ "Failed " ++ pshow i c)
          return ()
 
 -- Write a package index containing all the imports in the current IState
@@ -199,14 +204,14 @@
 writePkgIndex f
     = do i <- getIState
          let imps = map (\ (x, y) -> (True, x)) $ idris_imported i
-         iLOG $ "Writing package index " ++ show f ++ " including\n" ++
+         logLvl 1 $ "Writing package index " ++ show f ++ " including\n" ++
                 show (map snd imps)
          resetNameIdx
          let ibcf = initIBC { ibc_imports = imps }
          idrisCatch (do runIO $ createDirectoryIfMissing True (dropFileName f)
                         writeArchive f ibcf
-                        iLOG "Written")
-            (\c -> do iLOG $ "Failed " ++ pshow i c)
+                        logLvl 1 "Written")
+            (\c -> do logLvl 1 $ "Failed " ++ pshow i c)
          return ()
 
 mkIBC :: [IBCWrite] -> IBCFile -> Idris IBCFile
@@ -305,7 +310,7 @@
 process reexp i fn = do
                 ver <- getEntry 0 "ver" i
                 when (ver /= ibcVersion) $ do
-                                    iLOG "ibc out of date"
+                                    logLvl 1 "ibc out of date"
                                     let e = if ver < ibcVersion
                                             then " an earlier " else " a later "
                                     ifail $ "Incompatible ibc version.\nThis library was built with"
@@ -314,7 +319,7 @@
                 srcok <- runIO $ doesFileExist source
                 when srcok $ timestampOlder source fn
                 pImportDirs =<< getEntry [] "ibc_importdirs" i
-                pImports =<< getEntry [] "ibc_imports" i
+                pImports reexp =<< getEntry [] "ibc_imports" i
                 pImps =<< getEntry [] "ibc_implicits" i
                 pFixes =<< getEntry [] "ibc_fixes" i
                 pStatics =<< getEntry [] "ibc_statics" i
@@ -330,9 +335,7 @@
                 pCGFlags =<< getEntry [] "ibc_cgflags" i
                 pDyLibs =<< getEntry [] "ibc_dynamic_libs" i
                 pHdrs =<< getEntry [] "ibc_hdrs" i
-                symbols <- getEntry [] "symbols" i
-                defs <- getEntry [] "ibc_defs" i
-                pDefs reexp symbols defs
+                pDefs reexp =<< getEntry [] "ibc_defs" i
                 pPatdefs =<< getEntry [] "ibc_patdefs" i
                 pAccess reexp =<< getEntry [] "ibc_access" i
                 pFlags =<< getEntry [] "ibc_flags" i
@@ -362,7 +365,7 @@
 timestampOlder src ibc = do srct <- runIO $ getModificationTime src
                             ibct <- runIO $ getModificationTime ibc
                             if (srct > ibct)
-                               then ifail "Needs reloading"
+                               then ifail $ "Needs reloading " ++ show (srct, ibct)
                                else return ()
 
 pPostulates :: [Name] -> Idris ()
@@ -387,22 +390,22 @@
 pImportDirs :: [FilePath] -> Idris ()
 pImportDirs fs = mapM_ addImportDir fs
 
-pImports :: [(Bool, FilePath)] -> Idris ()
-pImports fs
+pImports :: Bool -> [(Bool, FilePath)] -> Idris ()
+pImports reexp fs
   = do mapM_ (\(re, f) ->
                     do i <- getIState
                        ibcsd <- valIBCSubDir i
                        ids <- allImportDirs
                        fp <- findImport ids ibcsd f
 --                        if (f `elem` imported i)
---                         then iLOG $ "Already read " ++ f
+--                         then logLvl 1 $ "Already read " ++ f
                        putIState (i { imported = f : imported i })
                        case fp of
-                            LIDR fn -> do iLOG $ "Failed at " ++ fn
+                            LIDR fn -> do logLvl 1 $ "Failed at " ++ fn
                                           ifail "Must be an ibc"
-                            IDR fn -> do iLOG $ "Failed at " ++ fn
+                            IDR fn -> do logLvl 1 $ "Failed at " ++ fn
                                          ifail "Must be an ibc"
-                            IBC fn src -> loadIBC re fn)
+                            IBC fn src -> loadIBC (reexp && re) fn)
              fs
 
 pImps :: [(Name, [PArg])] -> Idris ()
@@ -485,19 +488,19 @@
 pPatdefs ds = mapM_ (\ (n, d) -> updateIState (\i ->
             i { idris_patdefs = addDef n (force d) (idris_patdefs i) })) ds
 
-pDefs :: Bool -> [Name] -> [(Name, Def)] -> Idris ()
-pDefs reexp syms ds
+pDefs :: Bool -> [(Name, Def)] -> Idris ()
+pDefs reexp ds
    = mapM_ (\ (n, d) ->
                do d' <- updateDef d
                   case d' of
                        TyDecl _ _ -> return ()
-                       _ -> do iLOG $ "SOLVING " ++ show n
+                       _ -> do logLvl 1 $ "SOLVING " ++ show n
                                solveDeferred n
                   updateIState (\i -> i { tt_ctxt = addCtxtDef n d' (tt_ctxt i) })
 --                   logLvl 1 $ "Added " ++ show (n, d')
-                  if (not reexp) then do iLOG $ "Not exporting " ++ show n
+                  if (not reexp) then do logLvl 1 $ "Not exporting " ++ show n
                                          setAccessibility n Hidden
-                                 else iLOG $ "Exporting " ++ show n) ds
+                                 else logLvl 1 $ "Exporting " ++ show n) ds
   where
     updateDef (CaseOp c t args o s cd)
       = do o' <- mapM updateOrig o
@@ -607,7 +610,7 @@
 pFunctionErrorHandlers ns =  mapM_ (\ (fn,arg,handler) ->
                                 addFunctionErrorHandlers fn arg [handler]) ns
 
-pMetavars :: [(Name, (Maybe Name, Int, Bool))] -> Idris ()
+pMetavars :: [(Name, (Maybe Name, Int, [Name], Bool))] -> Idris ()
 pMetavars ns = updateIState (\i -> i { idris_metavars = L.reverse ns ++ idris_metavars i })
 
 ----- For Cheapskate and docstrings
@@ -948,6 +951,7 @@
                                  put x1
                 Unchecked -> do putWord8 2
                 Productive -> do putWord8 3
+                Generated -> do putWord8 4
         get
           = do i <- getWord8
                case i of
@@ -957,6 +961,7 @@
                            return (Partial x1)
                    2 -> return Unchecked
                    3 -> return Productive
+                   4 -> return Generated
                    _ -> error "Corrupted binary data for Totality"
 
 instance Binary MetaInformation where
@@ -1007,6 +1012,7 @@
                 CExport x1 -> do putWord8 14
                                  put x1
                 AutoHint -> putWord8 15
+                PEGenerated -> putWord8 16
         get
           = do i <- getWord8
                case i of
@@ -1028,6 +1034,7 @@
                    14 -> do x1 <- get
                             return $ CExport x1
                    15 -> return AutoHint
+                   16 -> return PEGenerated
                    _ -> error "Corrupted binary data for FnOpt"
 
 instance Binary Fixity where
@@ -1228,7 +1235,7 @@
                 PMutual x1 x2  -> do putWord8 11
                                      put x1
                                      put x2
-                PPostulate x1 x2 x3 x4 x5 x6 x7
+                PPostulate x1 x2 x3 x4 x5 x6 x7 x8
                                    -> do putWord8 12
                                          put x1
                                          put x2
@@ -1237,22 +1244,28 @@
                                          put x5
                                          put x6
                                          put x7
+                                         put x8
                 PSyntax x1 x2 -> do putWord8 13
                                     put x1
                                     put x2
                 PDirective x1 -> error "Cannot serialize PDirective"
-                PProvider x1 x2 x3 x4 x5 ->
+                PProvider x1 x2 x3 x4 x5 x6 ->
                   do putWord8 15
                      put x1
                      put x2
                      put x3
                      put x4
                      put x5
+                     put x6
                 PTransform x1 x2 x3 x4 -> do putWord8 16
                                              put x1
                                              put x2
                                              put x3
                                              put x4
+                PRunElabDecl x1 x2 x3 -> do putWord8 17
+                                            put x1
+                                            put x2
+                                            put x3
         get
           = do i <- getWord8
                case i of
@@ -1344,7 +1357,8 @@
                             x5 <- get
                             x6 <- get
                             x7 <- get
-                            return (PPostulate x1 x2 x3 x4 x5 x6 x7)
+                            x8 <- get
+                            return (PPostulate x1 x2 x3 x4 x5 x6 x7 x8)
                    13 -> do x1 <- get
                             x2 <- get
                             return (PSyntax x1 x2)
@@ -1354,12 +1368,17 @@
                             x3 <- get
                             x4 <- get
                             x5 <- get
-                            return (PProvider x1 x2 x3 x4 x5)
+                            x6 <- get
+                            return (PProvider x1 x2 x3 x4 x5 x6)
                    16 -> do x1 <- get
                             x2 <- get
                             x3 <- get
                             x4 <- get
                             return (PTransform x1 x2 x3 x4)
+                   17 -> do x1 <- get
+                            x2 <- get
+                            x3 <- get
+                            return (PRunElabDecl x1 x2 x3)
                    _ -> error "Corrupted binary data for PDecl'"
 
 instance Binary t => Binary (ProvideWhat' t) where
@@ -1511,12 +1530,14 @@
           = case x of
                 PQuote x1 -> do putWord8 0
                                 put x1
-                PRef x1 x2 -> do putWord8 1
-                                 put x1
-                                 put x2
-                PInferRef x1 x2 -> do putWord8 2
-                                      put x1
-                                      put x2
+                PRef x1 x2 x3 -> do putWord8 1
+                                    put x1
+                                    put x2
+                                    put x3
+                PInferRef x1 x2 x3 -> do putWord8 2
+                                         put x1
+                                         put x2
+                                         put x3
                 PPatvar x1 x2 -> do putWord8 3
                                     put x1
                                     put x2
@@ -1568,20 +1589,23 @@
                                            put x2
                                            put x3
                                            put x4
-                PPair x1 x2 x3 x4 -> do putWord8 18
-                                        put x1
-                                        put x2
-                                        put x3
-                                        put x4
-                PDPair x1 x2 x3 x4 x5 -> do putWord8 19
+                PPair x1 x2 x3 x4 x5 -> do putWord8 18
+                                           put x1
+                                           put x2
+                                           put x3
+                                           put x4
+                                           put x5
+                PDPair x1 x2 x3 x4 x5 x6 -> do putWord8 19
+                                               put x1
+                                               put x2
+                                               put x3
+                                               put x4
+                                               put x5
+                                               put x6
+                PAlternative x1 x2 x3 -> do putWord8 20
                                             put x1
                                             put x2
                                             put x3
-                                            put x4
-                                            put x5
-                PAlternative x1 x2 -> do putWord8 20
-                                         put x1
-                                         put x2
                 PHidden x1 -> do putWord8 21
                                  put x1
                 PType x1 -> do putWord8 22
@@ -1621,9 +1645,10 @@
                                     put x2
                 PUniverse x1 -> do putWord8 38
                                    put x1
-                PRunElab x1 x2 -> do putWord8 39
-                                     put x1
-                                     put x2
+                PRunElab x1 x2 x3 -> do putWord8 39
+                                        put x1
+                                        put x2
+                                        put x3
                 PAs x1 x2 x3 -> do putWord8 40
                                    put x1
                                    put x2
@@ -1635,13 +1660,17 @@
                                         put x2
                 PUnquote x1 -> do putWord8 43
                                   put x1
-                PQuoteName x1 -> do putWord8 44
-                                    put x1
+                PQuoteName x1 x2 -> do putWord8 44
+                                       put x1
+                                       put x2
                 PIfThenElse x1 x2 x3 x4 -> do putWord8 45
                                               put x1
                                               put x2
                                               put x3
                                               put x4
+                PConstSugar x1 x2 -> do putWord8 46
+                                        put x1
+                                        put x2
 
         get
           = do i <- getWord8
@@ -1650,10 +1679,12 @@
                            return (PQuote x1)
                    1 -> do x1 <- get
                            x2 <- get
-                           return (PRef x1 x2)
+                           x3 <- get
+                           return (PRef x1 x2 x3)
                    2 -> do x1 <- get
                            x2 <- get
-                           return (PInferRef x1 x2)
+                           x3 <- get
+                           return (PInferRef x1 x2 x3)
                    3 -> do x1 <- get
                            x2 <- get
                            return (PPatvar x1 x2)
@@ -1708,16 +1739,19 @@
                             x2 <- get
                             x3 <- get
                             x4 <- get
-                            return (PPair x1 x2 x3 x4)
+                            x5 <- get
+                            return (PPair x1 x2 x3 x4 x5)
                    19 -> do x1 <- get
                             x2 <- get
                             x3 <- get
                             x4 <- get
                             x5 <- get
-                            return (PDPair x1 x2 x3 x4 x5)
+                            x6 <- get
+                            return (PDPair x1 x2 x3 x4 x5 x6)
                    20 -> do x1 <- get
                             x2 <- get
-                            return (PAlternative x1 x2)
+                            x3 <- get
+                            return (PAlternative x1 x2 x3)
                    21 -> do x1 <- get
                             return (PHidden x1)
                    22 -> do x1 <- get
@@ -1759,7 +1793,8 @@
                             return (PUniverse x1)
                    39 -> do x1 <- get
                             x2 <- get
-                            return (PRunElab x1 x2)
+                            x3 <- get
+                            return (PRunElab x1 x2 x3)
                    40 -> do x1 <- get
                             x2 <- get
                             x3 <- get
@@ -1772,12 +1807,16 @@
                    43 -> do x1 <- get
                             return (PUnquote x1)
                    44 -> do x1 <- get
-                            return (PQuoteName x1)
+                            x2 <- get
+                            return (PQuoteName x1 x2)
                    45 -> do x1 <- get
                             x2 <- get
                             x3 <- get
                             x4 <- get
                             return (PIfThenElse x1 x2 x3 x4)
+                   46 -> do x1 <- get
+                            x2 <- get
+                            return (PConstSugar x1 x2)
                    _ -> error "Corrupted binary data for PTerm"
 
 instance Binary PAltType where
@@ -1786,12 +1825,14 @@
                 ExactlyOne x1 -> do putWord8 0
                                     put x1
                 FirstSuccess -> putWord8 1
+                TryImplicit -> putWord8 2
         get
           = do i <- getWord8
                case i of
                    0 -> do x1 <- get
                            return (ExactlyOne x1)
                    1 -> return FirstSuccess
+                   2 -> return TryImplicit
                    _ -> error "Corrupted binary data for PAltType"
 
 
@@ -1836,12 +1877,13 @@
                                    put x1
                 ByReflection x1 -> do putWord8 20
                                       put x1
-                ProofSearch x1 x2 x3 x4 x5 -> do putWord8 21
-                                                 put x1
-                                                 put x2
-                                                 put x3
-                                                 put x4
-                                                 put x5
+                ProofSearch x1 x2 x3 x4 x5 x6 -> do putWord8 21
+                                                    put x1
+                                                    put x2
+                                                    put x3
+                                                    put x4
+                                                    put x5
+                                                    put x6
                 DoUnify -> putWord8 22
                 CaseTac x1 -> do putWord8 23
                                  put x1
@@ -1921,7 +1963,8 @@
                             x3 <- get
                             x4 <- get
                             x5 <- get
-                            return (ProofSearch x1 x2 x3 x4 x5)
+                            x6 <- get
+                            return (ProofSearch x1 x2 x3 x4 x5 x6)
                    22 -> return DoUnify
                    23 -> do x1 <- get
                             return (CaseTac x1)
@@ -2133,14 +2176,25 @@
 
 instance Binary Syntax where
         put (Rule x1 x2 x3)
-          = do put x1
+          = do putWord8 0
+               put x1
                put x2
                put x3
+        put (DeclRule x1 x2)
+          = do putWord8 1
+               put x1
+               put x2
         get
-          = do x1 <- get
-               x2 <- get
-               x3 <- get
-               return (Rule x1 x2 x3)
+          = do i <- getWord8
+               case i of
+                   0 -> do x1 <- get
+                           x2 <- get
+                           x3 <- get
+                           return (Rule x1 x2 x3)
+                   1 -> do x1 <- get
+                           x2 <- get
+                           return (DeclRule x1 x2)
+                   _ -> error "Corrupted binary data for Syntax"
 
 instance (Binary t) => Binary (DSL' t) where
         put (DSL x1 x2 x3 x4 x5 x6 x7 x8 x9 x10)
diff --git a/src/Idris/IdeMode.hs b/src/Idris/IdeMode.hs
--- a/src/Idris/IdeMode.hs
+++ b/src/Idris/IdeMode.hs
@@ -2,7 +2,7 @@
 
 {-# LANGUAGE FlexibleInstances, IncoherentInstances, PatternGuards #-}
 
-module Idris.IdeMode(parseMessage, convSExp, WhatDocs(..), IdeModeCommand(..), sexpToCommand, toSExp, SExp(..), SExpable, Opt(..), ideModeEpoch, getLen, getNChar) where
+module Idris.IdeMode(parseMessage, convSExp, WhatDocs(..), IdeModeCommand(..), sexpToCommand, toSExp, SExp(..), SExpable, Opt(..), ideModeEpoch, getLen, getNChar, sExpToString) where
 
 import Text.Printf
 import Numeric
@@ -148,7 +148,10 @@
                        BoldText      -> "bold"
                        ItalicText    -> "italic"
                        UnderlineText -> "underline"
-  toSExp (AnnTerm bnd tm) = toSExp [(SymbolAtom "tt-term", StringAtom (encodeTerm bnd tm))]
+  toSExp (AnnLink url) = toSExp [(SymbolAtom "link-href", StringAtom url)]
+  toSExp (AnnTerm bnd tm)
+    | termSmallerThan 1000 tm = toSExp [(SymbolAtom "tt-term", StringAtom (encodeTerm bnd tm))]
+    | otherwise = SexpList []
   toSExp (AnnSearchResult ordr) = toSExp [(SymbolAtom "doc-overview",
       StringAtom ("Result type is " ++ descr))]
       where descr = case ordr of
@@ -160,6 +163,8 @@
     toSExp $ [(SymbolAtom "namespace", StringAtom (intercalate "." (map T.unpack ns)))] ++
              [(SymbolAtom "decor", SymbolAtom $ if isJust file then "module" else "namespace")] ++
              maybeProps [("source-file", file)]
+  toSExp AnnQuasiquote = toSExp [(SymbolAtom "quasiquotation", True)]
+  toSExp AnnAntiquote = toSExp [(SymbolAtom "antiquotation", True)]
 
 encodeTerm :: [(Name, Bool)] -> Term -> String
 encodeTerm bnd tm = UTF8.toString . Base64.encode . Lazy.toStrict . Binary.encode $
@@ -224,6 +229,7 @@
                     | AddProofClause Int String
                     | AddMissing Int String
                     | MakeWithBlock Int String
+                    | MakeCaseBlock Int String
                     | ProofSearch Bool Int String [String] (Maybe Int) -- ^^ Recursive?, line, name, hints, depth
                     | MakeLemma Int String
                     | LoadFile String (Maybe Int)
@@ -256,6 +262,7 @@
 sexpToCommand (SexpList [SymbolAtom "add-proof-clause", IntegerAtom line, StringAtom name])   = Just (AddProofClause (fromInteger line) name)
 sexpToCommand (SexpList [SymbolAtom "add-missing", IntegerAtom line, StringAtom name])  = Just (AddMissing (fromInteger line) name)
 sexpToCommand (SexpList [SymbolAtom "make-with", IntegerAtom line, StringAtom name])    = Just (MakeWithBlock (fromInteger line) name)
+sexpToCommand (SexpList [SymbolAtom "make-case", IntegerAtom line, StringAtom name])    = Just (MakeCaseBlock (fromInteger line) name)
 -- The Boolean in ProofSearch means "search recursively"
 -- If it's False, that means "refine", i.e. apply the name and fill in any
 -- arguments which can be done by unification.
diff --git a/src/Idris/IdrisDoc.hs b/src/Idris/IdrisDoc.hs
--- a/src/Idris/IdrisDoc.hs
+++ b/src/Idris/IdrisDoc.hs
@@ -288,8 +288,8 @@
 --   TODO: Remove unnecessary cases
 extractPTermNames :: PTerm  -- ^ Where to extract names from
                   -> [Name] -- ^ Extracted names
-extractPTermNames (PRef _ n)         = [n]
-extractPTermNames (PInferRef _ n)    = [n]
+extractPTermNames (PRef _ _ n)       = [n]
+extractPTermNames (PInferRef _ _ n)  = [n]
 extractPTermNames (PPatvar _ n)      = [n]
 extractPTermNames (PLam _ n _ p1 p2) = n : concatMap extract [p1, p2]
 extractPTermNames (PPi _ n _ p1 p2)  = n : concatMap extract [p1, p2]
@@ -306,9 +306,9 @@
 extractPTermNames (PRewrite _ a b m) | Just c <- m =
                                        concatMap extract [a, b, c]
 extractPTermNames (PRewrite _ a b _) = concatMap extract [a, b]
-extractPTermNames (PPair _ _ p1 p2)  = concatMap extract [p1, p2]
-extractPTermNames (PDPair _ _ a b c) = concatMap extract [a, b, c]
-extractPTermNames (PAlternative _ l) = concatMap extract l
+extractPTermNames (PPair _ _ _ p1 p2)  = concatMap extract [p1, p2]
+extractPTermNames (PDPair _ _ _ a b c) = concatMap extract [a, b, c]
+extractPTermNames (PAlternative _ _ l) = concatMap extract l
 extractPTermNames (PHidden p)        = extract p
 extractPTermNames (PGoal _ p1 n p2)  = n : concatMap extract [p1, p2]
 extractPTermNames (PDoBlock pdos)    = concatMap extractPDo pdos
@@ -320,7 +320,8 @@
 extractPTermNames (PDisamb _ p)      = extract p
 extractPTermNames (PUnifyLog p)      = extract p
 extractPTermNames (PNoImplicits p)   = extract p
-extractPTermNames (PRunElab _ p)  = extract p
+extractPTermNames (PRunElab _ p _)   = extract p
+extractPTermNames (PConstSugar _ tm) = extract tm
 extractPTermNames _                  = []
 
 -- | Shorter name for extractPTermNames
@@ -359,8 +360,8 @@
 extractPTactic (LetTac n p)       = n : extract p
 extractPTactic (LetTacTy n p1 p2) = n : concatMap extract [p1, p2]
 extractPTactic (Exact p)          = extract p
-extractPTactic (ProofSearch _ _ _ m ns) | Just n <- m = n : ns
-extractPTactic (ProofSearch _ _ _ _ ns) = ns
+extractPTactic (ProofSearch _ _ _ m _ ns) | Just n <- m = n : ns
+extractPTactic (ProofSearch _ _ _ _ _ ns) = ns
 extractPTactic (Try t1 t2)        = concatMap extractPTactic [t1, t2]
 extractPTactic (TSeq t1 t2)       = concatMap extractPTactic [t1, t2]
 extractPTactic (ApplyTactic p)    = extract p
diff --git a/src/Idris/Imports.hs b/src/Idris/Imports.hs
--- a/src/Idris/Imports.hs
+++ b/src/Idris/Imports.hs
@@ -1,4 +1,5 @@
-module Idris.Imports where
+module Idris.Imports(IFileType(..), findImport, findInPath, findPkgIndex,
+                     ibcPathNoFallback, installedPackages, pkgIndex) where
 
 import Control.Applicative ((<$>))
 import Data.List (isSuffixOf)
diff --git a/src/Idris/Inliner.hs b/src/Idris/Inliner.hs
--- a/src/Idris/Inliner.hs
+++ b/src/Idris/Inliner.hs
@@ -1,6 +1,6 @@
 {-# LANGUAGE PatternGuards #-}
 
-module Idris.Inliner where
+module Idris.Inliner(inlineDef, inlineTerm) where
 
 import Idris.Core.TT
 import Idris.AbsSyntax
diff --git a/src/Idris/Interactive.hs b/src/Idris/Interactive.hs
--- a/src/Idris/Interactive.hs
+++ b/src/Idris/Interactive.hs
@@ -1,7 +1,7 @@
 {-# LANGUAGE PatternGuards #-}
 
 module Idris.Interactive(caseSplitAt, addClauseFrom, addProofClauseFrom,
-                         addMissing, makeWith, doProofSearch,
+                         addMissing, makeWith, makeCase, doProofSearch,
                          makeLemma) where
 
 {- Bits and pieces for editing source files interactively, called from
@@ -35,7 +35,7 @@
 caseSplitAt fn updatefile l n
    = do src <- runIO $ readSource fn
         res <- splitOnLine l n fn
-        iLOG (showSep "\n" (map show res))
+        logLvl 1 (showSep "\n" (map show res))
         let (before, (ap : later)) = splitAt (l-1) (lines src)
         res' <- replaceSplits ap res
         let new = concat res'
@@ -112,7 +112,7 @@
           else iPrintResult extras
     where showPat = show . stripNS
           stripNS tm = mapPT dens tm where
-              dens (PRef fc n) = PRef fc (nsroot n)
+              dens (PRef fc hls n) = PRef fc hls (nsroot n)
               dens t = t
 
           nsroot (NS n _) = nsroot n
@@ -120,7 +120,7 @@
           nsroot n = n
 
           getAppName (PApp _ r _) = getAppName r
-          getAppName (PRef _ r) = r
+          getAppName (PRef _ _ r) = r
           getAppName _ = n
 
           makeIndent ind | ".lidr" `isSuffixOf` fn = '>' : ' ' : replicate (ind-2) ' '
@@ -158,11 +158,52 @@
            else iPrintResult with
   where getIndent s = length (takeWhile isSpace s)
 
+-- Replace the given metavariable on the given line with a 'case'
+-- block, using a _ for the scrutinee
+makeCase :: FilePath -> Bool -> Int -> Name -> Idris ()
+makeCase fn updatefile l n
+   = do src <- runIO $ readSource fn
+        let (before, tyline : later) = splitAt (l-1) (lines src)
+        let newcase = addCaseSkel (show n) tyline
 
+        if updatefile then
+           do let fb = fn ++ "~"
+              runIO $ writeSource fb (unlines (before ++ newcase ++ later))
+              runIO $ copyFile fb fn
+           else iPrintResult (showSep "\n" newcase ++"\n")
+  where addCaseSkel n line =
+            let b = brackets False line in
+            case findSubstr ('?':n) line of
+                 Just (before, pos, after) ->
+                      [before ++ (if b then "(" else "") ++ "case _ of",
+                       take (pos + (if b then 6 else 5)) (repeat ' ') ++ 
+                             "case_val => ?" ++ n ++ (if b then ")" else "")
+                             ++ after]
+                 Nothing -> fail "No such metavariable"
+
+        -- Assume case needs to be bracketed unless the metavariable is
+        -- on its own after an =
+        brackets eq line | line == '?' : show n = not eq
+        brackets eq ('=':ls) = brackets True ls
+        brackets eq (' ':ls) = brackets eq ls
+        brackets eq (l : ls) = brackets False ls
+        brackets eq [] = True
+
+        findSubstr n xs = findSubstr' [] 0 n xs
+
+        findSubstr' acc i n xs | take (length n) xs == n 
+                = Just (reverse acc, i, drop (length n) xs)
+        findSubstr' acc i n [] = Nothing
+        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
-    = doProofSearch fn updatefile rec l n hints (Just 10)
+    = doProofSearch fn updatefile rec l n hints (Just 20)
 doProofSearch fn updatefile rec l n hints (Just depth)
     = do src <- runIO $ readSource fn
          let (before, tyline : later) = splitAt (l-1) (lines src)
@@ -172,16 +213,17 @@
                     [] -> return n
                     ns -> ierror (CantResolveAlts ns)
          i <- getIState
-         let (top, envlen, _) = case lookup mn (idris_metavars i) of
-                                  Just (t, e, False) -> (t, e, False)
-                                  _ -> (Nothing, 0, True)
+         let (top, envlen, psnames, _) 
+              = case lookup mn (idris_metavars i) of
+                     Just (t, e, ns, False) -> (t, e, ns, False)
+                     _ -> (Nothing, 0, [], True)
          let fc = fileFC fn
-         let body t = PProof [Try (TSeq Intros (ProofSearch rec False depth t hints))
-                                  (ProofSearch rec False depth t hints)]
-         let def = PClause fc mn (PRef fc mn) [] (body top) []
+         let body t = PProof [Try (TSeq Intros (ProofSearch rec False depth t psnames hints))
+                                  (ProofSearch rec False depth t psnames hints)]
+         let def = PClause fc mn (PRef fc [] mn) [] (body top) []
          newmv <- idrisCatch
              (do elabDecl' EAll recinfo (PClauses fc [] mn [def])
-                 (tm, ty) <- elabVal recinfo ERHS (PRef fc mn)
+                 (tm, ty) <- elabVal recinfo ERHS (PRef fc [] mn)
                  ctxt <- getContext
                  i <- getIState
                  return . flip displayS "" . renderPretty 1.0 80 $
@@ -204,7 +246,7 @@
           dropCtxt _ t = t
 
           stripNS tm = mapPT dens tm where
-              dens (PRef fc n) = PRef fc (nsroot n)
+              dens (PRef fc hls n) = PRef fc hls (nsroot n)
               dens t = t
 
           nsroot (NS n _) = nsroot n
@@ -250,19 +292,23 @@
         let isProv = checkProv tyline (show n)
 
         ctxt <- getContext
-        mty <- case lookupTyName n ctxt of
-                    [(_,t)] -> return t
-                    [] -> ierror (NoSuchVariable n)
-                    ns -> ierror (CantResolveAlts (map fst ns))
+        (fname, mty) <- case lookupTyName n ctxt of
+                          [t] -> return t
+                          [] -> ierror (NoSuchVariable n)
+                          ns -> ierror (CantResolveAlts (map fst ns))
         i <- getIState
-        margs <- case lookup n (idris_metavars i) of
-                      Just (_, arity, _) -> return arity
+        margs <- case lookup fname (idris_metavars i) of
+                      Just (_, arity, _, _) -> return arity
                       _ -> return (-1)
 
         if (not isProv) then do
-            let skip = guessImps (tt_ctxt i) mty
+            let skip = guessImps i (tt_ctxt i) mty
+            let classes = guessClasses i (tt_ctxt i) mty
 
-            let lem = show n ++ " : " ++ show (stripMNBind skip (delab i mty))
+            let lem = show n ++ " : " ++ 
+                            constraints i classes mty ++
+                            showTmOpts (defaultPPOption { ppopt_pinames = True })
+                                       (stripMNBind skip margs (delab i mty))
             let lem_app = show n ++ appArgs skip margs mty
 
             if updatefile then
@@ -305,22 +351,70 @@
         appArgs skip i (Bind _ (Pi _ _ _) sc) = appArgs skip (i - 1) sc
         appArgs skip i _ = ""
 
-        stripMNBind skip (PPi b n@(UN c) _ ty sc) 
-           | (thead c /= '_' && n `notElem` skip) ||
+        stripMNBind _ args t | args <= 0 = t
+        stripMNBind skip args (PPi b n@(UN c) _ ty sc) 
+           | n `notElem` skip ||
                take 4 (str c) == "__pi" -- keep in type, but not in app
-                = PPi b n NoFC ty (stripMNBind skip sc)
-        stripMNBind skip (PPi b _ _ ty sc) = stripMNBind skip sc
-        stripMNBind skip t = t
+                = PPi b n NoFC ty (stripMNBind skip (args - 1) sc)
+        stripMNBind skip args (PPi b _ _ ty sc) = stripMNBind skip (args - 1) sc
+        stripMNBind skip args t = t
 
+        constraints :: IState -> [Name] -> Type -> String
+        constraints i [] ty = ""
+        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)
+            | 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)
+        showConstraints _ _ _ = []
+
         -- Guess which binders should be implicits in the generated lemma.
         -- Make them implicit if they appear guarded by a top level constructor,
         -- or at the top level themselves.
-        guessImps :: Context -> Term -> [Name]
-        guessImps ctxt (Bind n (Pi _ _ _) sc)
+        -- Also, make type class instances implicit
+        guessImps :: IState -> Context -> Term -> [Name]
+        -- machine names aren't lifted
+        guessImps ist ctxt (Bind n@(MN _ _) (Pi _ ty _) sc) 
+           = n : guessImps ist ctxt sc
+        guessImps ist ctxt (Bind n (Pi _ ty _) sc)
            | guarded ctxt n (substV (P Bound n Erased) sc) 
-                = n : guessImps ctxt sc
-           | otherwise = guessImps ctxt sc
-        guessImps ctxt _ = []
+                = n : guessImps ist ctxt sc
+           | isClass ist ty
+                = n : guessImps ist ctxt sc
+           | TType _ <- ty = n : guessImps ist ctxt sc
+           | ignoreName n = n : guessImps ist ctxt sc
+           | otherwise = guessImps ist ctxt sc
+        guessImps ist ctxt _ = []
+        
+        -- TMP HACK unusable name so don't lift
+        ignoreName n = case show n of
+                            "_aX" -> True
+                            _ -> False
+
+        guessClasses :: IState -> Context -> Term -> [Name]
+        guessClasses ist ctxt (Bind n (Pi _ ty _) sc)
+           | isParamClass ist ty
+                = n : guessClasses ist ctxt sc
+           | otherwise = guessClasses ist ctxt sc
+        guessClasses ist ctxt _ = []
+
+        isClass ist t
+           | (P _ n _, args) <- unApply t
+                = case lookupCtxtExact n (idris_classes ist) of
+                       Just _ -> True
+                       _ -> False
+           | otherwise = False
+        
+        isParamClass ist t
+           | (P _ n _, args) <- unApply t
+                = case lookupCtxtExact n (idris_classes ist) of
+                       Just _ -> any isV args
+                       _ -> False
+           | otherwise = False
+          where isV (V _) = True
+                isV _ = False
 
         guarded ctxt n (P _ n' _) | n == n' = True
         guarded ctxt n ap@(App _ _ _)
diff --git a/src/Idris/Output.hs b/src/Idris/Output.hs
--- a/src/Idris/Output.hs
+++ b/src/Idris/Output.hs
@@ -6,6 +6,7 @@
 import Idris.Core.Evaluate (isDConName, isTConName, isFnName, normaliseAll)
 
 import Idris.AbsSyntax
+import Idris.Colours (hStartColourise, hEndColourise)
 import Idris.Delaborate
 import Idris.Docstrings
 import Idris.IdeMode
@@ -17,7 +18,8 @@
 
 import System.Console.Haskeline.MonadException
   (MonadException (controlIO), RunIO (RunIO))
-import System.IO (stdout, Handle, hPutStrLn)
+import System.IO (stdout, Handle, hPutStrLn, hPutStr)
+import System.FilePath (replaceExtension)
 
 import Prelude hiding ((<$>))
 
@@ -44,7 +46,7 @@
                       case fc of
                         FC fn _ _ | fn /= "" -> text (show fc) <> colon <//> err
                         _ -> err
-            runIO . hPutStrLn h $ displayDecorated (consoleDecorate i) err'
+            hWriteDoc h i err'
        IdeMode n h ->
          do err' <- iRender . fmap (fancifyAnnots i True) $ err
             let (str, spans) = displaySpans err'
@@ -67,13 +69,23 @@
                                 | otherwise -> do width <- runIO getScreenWidth
                                                   return $ renderPretty 0.8 width d
 
+hWriteDoc :: Handle -> IState -> SimpleDoc OutputAnnotation -> Idris ()
+hWriteDoc h ist rendered =
+    do runIO $ displayDecoratedA
+                 (hPutStr h)
+                 (maybe (return ()) (hStartColourise h))
+                 (maybe (return ()) (hEndColourise h))
+                 (fmap (annotationColour ist) rendered)
+       runIO $ hPutStr h "\n" -- newline translation on the output
+                              -- stream should take care of this for
+                              -- Windows
+
 -- | Write a pretty-printed term to the console with semantic coloring
 consoleDisplayAnnotated :: Handle -> Doc OutputAnnotation -> Idris ()
-consoleDisplayAnnotated h output = do ist <- getIState
-                                      rendered <- iRender $ output
-                                      runIO . hPutStrLn h .
-                                        displayDecorated (consoleDecorate ist) $
-                                        rendered
+consoleDisplayAnnotated h output =
+    do ist <- getIState
+       rendered <- iRender output
+       hWriteDoc h ist rendered
 
 iPrintTermWithType :: Doc OutputAnnotation -> Doc OutputAnnotation -> Idris ()
 iPrintTermWithType tm ty = iRenderResult (tm <+> colon <+> align ty)
@@ -86,16 +98,18 @@
                                     let infixes = idris_infixes ist
                                     let output = vsep (map (uncurry (ppOverload ppo infixes)) overloads)
                                     iRenderResult output
-  where fullName n = prettyName True True bnd n
+  where fullName ppo n | length overloads > 1 = prettyName True True bnd n
+                       | otherwise = prettyName True (ppopt_impl ppo) bnd n 
         ppOverload ppo infixes n tm =
-          fullName n <+> colon <+> align tm
+          fullName ppo n <+> colon <+> align tm
 
 iRenderOutput :: Doc OutputAnnotation -> Idris ()
 iRenderOutput doc =
   do i <- getIState
      case idris_outputmode i of
        RawOutput h -> do out <- iRender doc
-                         runIO $ putStrLn (displayDecorated (consoleDecorate i) out)
+                         hWriteDoc h i out
+
        IdeMode n h ->
         do (str, spans) <- fmap displaySpans . iRender . fmap (fancifyAnnots i True) $ doc
            let out = [toSExp str, toSExp spans]
@@ -166,7 +180,7 @@
 iputGoal :: SimpleDoc OutputAnnotation -> Idris ()
 iputGoal g = do i <- getIState
                 case idris_outputmode i of
-                  RawOutput h -> runIO $ hPutStrLn h (displayDecorated (consoleDecorate i) g)
+                  RawOutput h -> hWriteDoc h i g
                   IdeMode n h ->
                     let (str, spans) = displaySpans . fmap (fancifyAnnots i True) $ g
                         goal = [toSExp str, toSExp spans]
@@ -194,11 +208,23 @@
   where ppTm = pprintDelab ist
         norm = normaliseAll (tt_ctxt ist) []
 
+sendParserHighlighting :: Idris ()
+sendParserHighlighting =
+  do ist <- getIState
+     let hs = map unwrap . nub . map wrap $ idris_parserHighlights ist
+     sendHighlighting hs
+     ist <- getIState
+     putIState ist {idris_parserHighlights = []}
+  where wrap (fc, a) = (FC' fc, a)
+        unwrap (fc', a) = (unwrapFC fc', a)
+
 sendHighlighting :: [(FC, OutputAnnotation)] -> Idris ()
 sendHighlighting highlights =
   do ist <- getIState
      case idris_outputmode ist of
-       RawOutput _ -> return ()
+       RawOutput _ -> updateIState $
+                      \ist -> ist { idris_highlightedRegions =
+                                      highlights ++ idris_highlightedRegions ist }
        IdeMode n h ->
          let fancier = [ toSExp (fc, fancifyAnnots ist False annot)
                        | (fc, annot) <- highlights, fullFC fc
@@ -213,7 +239,21 @@
   where fullFC (FC _ _ _) = True
         fullFC _          = False
 
+-- | Write the highlighting information to a file, for use in external tools
+-- or in editors that don't support the IDE protocol
+writeHighlights :: FilePath -> Idris ()
+writeHighlights f =
+  do ist <- getIState
+     let hs = reverse $ idris_highlightedRegions ist
+     let hfile = replaceExtension f "idh"
+     let annots = toSExp [ (fc, fancifyAnnots ist False annot)
+                         | (fc@(FC _ _ _), annot) <- hs
+                         ]
+     runIO $ writeFile hfile $ sExpToString annots
 
+clearHighlights :: Idris ()
+clearHighlights = updateIState $ \ist -> ist { idris_highlightedRegions = [] }
+
 renderExternal :: OutputFmt -> Int -> Doc OutputAnnotation -> Idris String
 renderExternal fmt width doc
   | width < 1 = throwError . Msg $ "There must be at least one column for the pretty-printer."
@@ -256,6 +296,10 @@
     decorate HTMLOutput (AnnSearchResult _) = id
     decorate HTMLOutput (AnnErr _) = id
     decorate HTMLOutput (AnnNamespace _ _) = id
+    decorate HTMLOutput (AnnLink url) =
+      \txt -> "<a href=\"" ++ url ++ "\">" ++ txt ++ "</a>"
+    decorate HTMLOutput AnnQuasiquote = id
+    decorate HTMLOutput AnnAntiquote = id
 
     decorate LaTeXOutput (AnnName _ (Just TypeOutput) _ _) =
       latex "IdrisType"
@@ -284,6 +328,9 @@
     decorate LaTeXOutput (AnnSearchResult _) = id
     decorate LaTeXOutput (AnnErr _) = id
     decorate LaTeXOutput (AnnNamespace _ _) = id
+    decorate LaTeXOutput (AnnLink url) = (++ "(\\url{" ++ url ++ "})")
+    decorate LaTeXOutput AnnQuasiquote = id
+    decorate LaTeXOutput AnnAntiquote = id
 
     tag cls docs str = "<span class=\""++cls++"\""++title++">" ++ str ++ "</span>"
       where title = maybe "" (\d->" title=\"" ++ d ++ "\"") docs
diff --git a/src/Idris/ParseData.hs b/src/Idris/ParseData.hs
--- a/src/Idris/ParseData.hs
+++ b/src/Idris/ParseData.hs
@@ -57,7 +57,7 @@
                 let tyn = expandNS syn tyn_in
                 let rsyn = syn { syn_namespace = show (nsroot tyn) :
                                                     syn_namespace syn }
-                params <- manyTill (recordParameter rsyn) (reserved "where")
+                params <- manyTill (recordParameter rsyn) (reservedHL "where")
                 (fields, cname, cdoc) <- indentedBlockS $ recordBody rsyn tyn
                 case cname of
                      Just cn' -> accData acc tyn [fst cn']
@@ -86,28 +86,29 @@
 
         let constructorDoc' = annotate syn ist constructorDoc
 
-        fields <- many . indented $ field syn
+        fields <- many . indented $ fieldLine syn
 
-        return (fields, constructorName, constructorDoc')
+        return (concat fields, constructorName, constructorDoc')
       where
-        field :: SyntaxInfo -> IdrisParser ((Maybe (Name, FC)), Plicity, PTerm, Maybe (Docstring (Either Err PTerm)))
-        field syn = do doc <- optional docComment
-                       c <- optional $ lchar '{'
-                       n <- (do (n, nfc) <- fnName
-                                return $ Just (expandNS syn n, nfc))
-                        <|> (do symbol "_"
-                                return Nothing)
-                       lchar ':'
-                       t <- typeExpr (allowImp syn)
-                       p <- endPlicity c
-                       ist <- get
-                       let doc' = case doc of -- Temp: Throws away any possible arg docs
-                                   Just (d,_) -> Just $ annotate syn ist d
-                                   Nothing    -> Nothing
-                       return (n, p, t, doc')
+        fieldLine :: SyntaxInfo -> IdrisParser [(Maybe (Name, FC), Plicity, PTerm, Maybe (Docstring (Either Err PTerm)))]
+        fieldLine syn = do
+            doc <- optional docComment
+            c <- optional $ lchar '{'
+            let oneName = (do (n, nfc) <- fnName
+                              return $ Just (expandNS syn n, nfc))
+                          <|> (symbol "_" >> return Nothing)
+            ns <- commaSeparated oneName
+            lchar ':'
+            t <- typeExpr (allowImp syn)
+            p <- endPlicity c
+            ist <- get
+            let doc' = case doc of -- Temp: Throws away any possible arg docs
+                        Just (d,_) -> Just $ annotate syn ist d
+                        Nothing    -> Nothing
+            return $ map (\n -> (n, p, t, doc')) ns
 
         constructor :: IdrisParser (Name, FC)
-        constructor = (reserved "constructor") *> fnName
+        constructor = (reservedHL "constructor") *> fnName
 
 
         endPlicity :: Maybe Char -> IdrisParser Plicity
@@ -144,12 +145,12 @@
 DataI ::= 'data' | 'codata';
 -}
 dataI :: IdrisParser DataOpts
-dataI = do reserved "data"; return []
-    <|> do reserved "codata"; return [Codata]
+dataI = do reservedHL "data"; return []
+    <|> do reservedHL "codata"; return [Codata]
 
 recordI :: IdrisParser DataOpts
-recordI = do reserved "record"; return []
-          <|> do reserved "corecord"; return [Codata]
+recordI = do reservedHL "record"; return []
+          <|> do reservedHL "corecord"; return [Codata]
 
 {- | Parses if a data should not have a default eliminator
 DefaultEliminator ::= 'noelim'?
@@ -197,7 +198,7 @@
                    ty <- typeExpr (allowImp syn)
                    let tyn = expandNS syn tyn_in
                    option (PData doc argDocs syn fc dataOpts (PLaterdecl tyn nfc ty)) (do
-                     reserved "where"
+                     reservedHL "where"
                      cons <- indentedBlock (constructor syn)
                      accData acc tyn (map (\ (_, _, n, _, _, _, _) -> n) cons)
                      return $ PData doc argDocs syn fc dataOpts (PDatadecl tyn nfc ty cons))) <|> (do
@@ -205,7 +206,7 @@
                     let ty = bindArgs (map (const (PType fc)) args) (PType fc)
                     let tyn = expandNS syn tyn_in
                     option (PData doc argDocs syn fc dataOpts (PLaterdecl tyn nfc ty)) (do
-                      try (lchar '=') <|> do reserved "where"
+                      try (lchar '=') <|> do reservedHL "where"
                                              let kw = (if DefaultEliminator `elem` dataOpts then "%elim" else "") ++ (if Codata `elem` dataOpts then "co" else "") ++ "data "
                                              let n  = show tyn_in ++ " "
                                              let s  = kw ++ n
@@ -218,7 +219,7 @@
                                              fail $ fixErrorMsg "unexpected \"where\"" [fix1, fix2, fix3]
                       cons <- sepBy1 (simpleConstructor syn) (reservedOp "|")
                       terminator
-                      let conty = mkPApp fc (PRef fc tyn) (map (PRef fc) args)
+                      let conty = mkPApp fc (PRef fc [] tyn) (map (PRef fc []) args)
                       cons' <- mapM (\ (doc, argDocs, x, xfc, cargs, cfc, fs) ->
                                    do let cty = bindArgs cargs conty
                                       return (doc, argDocs, x, xfc, cty, cfc, fs)) cons
@@ -276,7 +277,7 @@
 DSL ::= 'dsl' FnName OpenBlock Overload'+ CloseBlock;
  -}
 dsl :: SyntaxInfo -> IdrisParser PDecl
-dsl syn = do reserved "dsl"
+dsl syn = do reservedHL "dsl"
              n <- fst <$> fnName
              bs <- indentedBlock (overload syn)
              let dsl = mkDSL bs (dsl_info syn)
@@ -314,11 +315,12 @@
 Overload ::= OverloadIdentifier '=' Expr;
 -}
 overload :: SyntaxInfo -> IdrisParser (String, PTerm)
-overload syn = do o <- (fst <$> identifier) <|> do reserved "let"
-                                                   return "let"
+overload syn = do (o, fc) <- identifier <|> do fc <- reservedFC "let"
+                                               return ("let", fc)
                   if o `notElem` overloadable
                      then fail $ show o ++ " is not an overloading"
                      else do
+                       highlightP fc AnnKeyword
                        lchar '='
                        t <- expr syn
                        return (o, t)
diff --git a/src/Idris/ParseExpr.hs b/src/Idris/ParseExpr.hs
--- a/src/Idris/ParseExpr.hs
+++ b/src/Idris/ParseExpr.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE GeneralizedNewtypeDeriving, ConstraintKinds, PatternGuards #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving, ConstraintKinds, PatternGuards, TupleSections #-}
 module Idris.ParseExpr where
 
 import Prelude hiding (pi)
@@ -91,8 +91,18 @@
 {- | Parses a user-defined expression -}
 externalExpr :: SyntaxInfo -> IdrisParser PTerm
 externalExpr syn = do i <- get
-                      extensions syn (syntaxRulesList $ syntax_rules i)
+                      (FC fn start _) <- getFC
+                      expr <- extensions syn (syntaxRulesList $ syntax_rules i)
+                      (FC _ _ end) <- getFC
+                      let outerFC = FC fn start end
+                      return (mapPTermFC (fixFC outerFC) (fixFCH fn outerFC) expr)
                    <?> "user-defined expression"
+  where -- Fix non-highlighting FCs by approximating with the span of the syntax application
+        fixFC outer inner | inner `fcIn` outer = inner
+                          | otherwise          = outer
+        -- Fix highlighting FCs by making them useless, to avoid spurious highlights
+        fixFCH fn outer inner | inner `fcIn` outer = inner
+                              | otherwise          = FileFC fn
 
 {- | Parses a simple user-defined expression -}
 simpleExternalExpr :: SyntaxInfo -> IdrisParser PTerm
@@ -118,8 +128,10 @@
     isValid (Rule _ _ AnySyntax) = True
     isValid (Rule _ _ PatternSyntax) = inPattern syn
     isValid (Rule _ _ TermSyntax) = not (inPattern syn)
+    isValid (DeclRule _ _) = False
 
-data SynMatch = SynTm PTerm | SynBind Name
+data SynMatch = SynTm PTerm | SynBind FC Name -- ^ the FC is for highlighting information
+  deriving Show
 
 extension :: SyntaxInfo -> [Maybe (Name, SynMatch)] -> [Syntax] -> IdrisParser PTerm
 extension syn ns rules =
@@ -130,79 +142,122 @@
         extension syn (n : ns) [Rule ss t ctx | (Rule (_:ss) t ctx) <- rs]
       -- If we have more than one Rule in this bucket, our grammar is
       -- nondeterministic.
-      Rule [] ptm _ -> return (flatten (update (mapMaybe id ns) ptm))
+      Rule [] ptm _ -> return (flatten (updateSynMatch (mapMaybe id ns) ptm))
   where
     ruleGroup [] [] = True
     ruleGroup (s1:_) (s2:_) = s1 == s2
     ruleGroup _ _ = False
 
     extensionSymbol :: SSymbol -> IdrisParser (Maybe (Name, SynMatch))
-    extensionSymbol (Keyword n)    = do reserved (show n); return Nothing
+    extensionSymbol (Keyword n)    = do fc <- reservedFC (show n)
+                                        highlightP fc AnnKeyword
+                                        return Nothing
     extensionSymbol (Expr n)       = do tm <- expr syn
                                         return $ Just (n, SynTm tm)
     extensionSymbol (SimpleExpr n) = do tm <- simpleExpr syn
                                         return $ Just (n, SynTm tm)
-    extensionSymbol (Binding n)    = do b <- fst <$> name
-                                        return $ Just (n, SynBind b)
-    extensionSymbol (Symbol s)     = do symbol s
+    extensionSymbol (Binding n)    = do (b, fc) <- name
+                                        return $ Just (n, SynBind fc b)
+    extensionSymbol (Symbol s)     = do fc <- symbolFC s
+                                        highlightP fc AnnKeyword
                                         return Nothing
-    dropn :: Name -> [(Name, a)] -> [(Name, a)]
-    dropn n [] = []
-    dropn n ((x,t) : xs) | n == x = xs
-                         | otherwise = (x,t):dropn n xs
-
+    
     flatten :: PTerm -> PTerm -- flatten application
     flatten (PApp fc (PApp _ f as) bs) = flatten (PApp fc f (as ++ bs))
     flatten t = t
 
-    updateB :: [(Name, SynMatch)] -> Name -> Name
-    updateB ns n = case lookup n ns of
-                     Just (SynBind t) -> t
-                     _ -> n
+updateSynMatch = update
+  where
+    updateB :: [(Name, SynMatch)] -> (Name, FC) -> (Name, FC)
+    updateB ns (n, fc) = case lookup n ns of
+                           Just (SynBind tfc t) -> (t, tfc)
+                           _ -> (n, fc)
 
     update :: [(Name, SynMatch)] -> PTerm -> PTerm
-    update ns (PRef fc n) = case lookup n ns of
-                              Just (SynTm t) -> t
-                              _ -> PRef fc n
+    update ns (PRef fc hls n) = case lookup n ns of
+                                  Just (SynTm t) -> t
+                                  _ -> PRef fc hls n
+    update ns (PPatvar fc n) = uncurry (flip PPatvar) $ updateB ns (n, fc)
     update ns (PLam fc n nfc ty sc)
-      = PLam fc (updateB ns n) nfc (update ns ty) (update (dropn n ns) sc)
+      = let (n', nfc') = updateB ns (n, nfc)
+        in PLam fc n' nfc' (update ns ty) (update (dropn n ns) sc)
     update ns (PPi p n fc ty sc)
-      = PPi (updTacImp ns p) (updateB ns n) fc
-            (update ns ty) (update (dropn n ns) sc)
-    update ns (PLet fc n nfc ty val sc) 
-      = PLet fc (updateB ns n) nfc (update ns ty)
-              (update ns val) (update (dropn n ns) sc)
+      = let (n', nfc') = updateB ns (n, fc)
+        in PPi (updTacImp ns p) n' nfc'
+               (update ns ty) (update (dropn n ns) sc)
+    update ns (PLet fc n nfc ty val sc)
+      = let (n', nfc') = updateB ns (n, nfc)
+        in PLet fc n' nfc' (update ns ty)
+                (update ns val) (update (dropn n ns) sc)
     update ns (PApp fc t args)
       = PApp fc (update ns t) (map (fmap (update ns)) args)
     update ns (PAppBind fc t args)
       = PAppBind fc (update ns t) (map (fmap (update ns)) args)
-    update ns (PCase fc c opts)
-      = PCase fc (update ns c) (map (pmap (update ns)) opts)
+    update ns (PMatchApp fc n) = let (n', nfc') = updateB ns (n, fc)
+                                 in PMatchApp nfc' n'
     update ns (PIfThenElse fc c t f)
       = PIfThenElse fc (update ns c) (update ns t) (update ns f)
-    update ns (PPair fc p l r) = PPair fc p (update ns l) (update ns r)
-    update ns (PDPair fc p l t r)
-      = PDPair fc p (update ns l) (update ns t) (update ns r)
-    update ns (PAlternative a as) = PAlternative a (map (update ns) as)
+    update ns (PCase fc c opts)
+      = PCase fc (update ns c) (map (pmap (update ns)) opts)
+    update ns (PRewrite fc eq tm mty)
+      = PRewrite fc (update ns eq) (update ns tm) (fmap (update ns) mty)
+    update ns (PPair fc hls p l r) = PPair fc hls p (update ns l) (update ns r)
+    update ns (PDPair fc hls p l t r)
+      = PDPair fc hls p (update ns l) (update ns t) (update ns r)
+    update ns (PAs fc n t) = PAs fc (fst $ updateB ns (n, NoFC)) (update ns t)
+    update ns (PAlternative ms a as) = PAlternative ms a (map (update ns) as)
     update ns (PHidden t) = PHidden (update ns t)
-    update ns (PDoBlock ds) = PDoBlock $ upd ns ds
-      where upd :: [(Name, SynMatch)] -> [PDo] -> [PDo]
-            upd ns (DoExp fc t : ds) = DoExp fc (update ns t) : upd ns ds
-            upd ns (DoBind fc n nfc t : ds) = DoBind fc n nfc (update ns t) : upd (dropn n ns) ds
-            upd ns (DoLet fc n nfc ty t : ds) = DoLet fc n nfc (update ns ty) (update ns t)
-                                                    : upd (dropn n ns) ds
-            upd ns (DoBindP fc i t ts : ds) 
-                    = DoBindP fc (update ns i) (update ns t) 
-                                 (map (\(l,r) -> (update ns l, update ns r)) ts)
-                                                : upd ns ds
-            upd ns (DoLetP fc i t : ds) = DoLetP fc (update ns i) (update ns t)
-                                                : upd ns ds
     update ns (PGoal fc r n sc) = PGoal fc (update ns r) n (update ns sc)
+    update ns (PDoBlock ds) = PDoBlock $ map (upd ns) ds
+      where upd :: [(Name, SynMatch)] -> PDo -> PDo
+            upd ns (DoExp fc t) = DoExp fc (update ns t)
+            upd ns (DoBind fc n nfc t) = DoBind fc n nfc (update ns t)
+            upd ns (DoLet fc n nfc ty t) = DoLet fc n nfc (update ns ty) (update ns t)
+            upd ns (DoBindP fc i t ts)
+                    = DoBindP fc (update ns i) (update ns t)
+                                 (map (\(l,r) -> (update ns l, update ns r)) ts)
+            upd ns (DoLetP fc i t) = DoLetP fc (update ns i) (update ns t)
+    update ns (PIdiom fc t) = PIdiom fc $ update ns t
+    update ns (PMetavar fc n) = uncurry (flip PMetavar) $ updateB ns (n, fc)
+    update ns (PProof tacs) = PProof $ map (updTactic ns) tacs
+    update ns (PTactics tacs) = PTactics $ map (updTactic ns) tacs
+    update ns (PDisamb nsps t) = PDisamb nsps $ update ns t
+    update ns (PUnifyLog t) = PUnifyLog $ update ns t
+    update ns (PNoImplicits t) = PNoImplicits $ update ns t
+    update ns (PQuasiquote tm mty) = PQuasiquote (update ns tm) (fmap (update ns) mty)
+    update ns (PUnquote t) = PUnquote $ update ns t
+    update ns (PQuoteName n fc) = uncurry PQuoteName (updateB ns (n, fc))
+    update ns (PRunElab fc t nsp) = PRunElab fc (update ns t) nsp
+    update ns (PConstSugar fc t) = PConstSugar fc $ update ns t
+    -- PConstSugar probably can't contain anything substitutable, but it's hard to track
     update ns t = t
 
+    updTactic :: [(Name, SynMatch)] -> PTactic -> PTactic
+    -- handle all the ones with Names explicitly, then use fmap for the rest with PTerms
+    updTactic ns (Intro ns') = Intro $ map (fst . updateB ns . (, NoFC)) ns'
+    updTactic ns (Focus n) = Focus . fst $ updateB ns (n, NoFC)
+    updTactic ns (Refine n bs) = Refine (fst $ updateB ns (n, NoFC)) bs
+    updTactic ns (Claim n t) = Claim (fst $ updateB ns (n, NoFC)) (update ns t)
+    updTactic ns (MatchRefine n) = MatchRefine (fst $ updateB ns (n, NoFC))
+    updTactic ns (LetTac n t) = LetTac (fst $ updateB ns (n, NoFC)) (update ns t)
+    updTactic ns (LetTacTy n ty tm) = LetTacTy (fst $ updateB ns (n, NoFC)) (update ns ty) (update ns tm)
+    updTactic ns (ProofSearch rec prover depth top psns hints) = ProofSearch rec prover depth
+      (fmap (fst . updateB ns . (, NoFC)) top) (map (fst . updateB ns . (, NoFC)) psns) (map (fst . updateB ns . (, NoFC)) hints)
+    updTactic ns (Try l r) = Try (updTactic ns l) (updTactic ns r)
+    updTactic ns (TSeq l r) = TSeq (updTactic ns l) (updTactic ns r)
+    updTactic ns (GoalType s tac) = GoalType s $ updTactic ns tac
+    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
+    
+    dropn :: Name -> [(Name, a)] -> [(Name, a)]
+    dropn n [] = []
+    dropn n ((x,t) : xs) | n == x = xs
+                         | otherwise = (x,t):dropn n xs
 
+
 {- | Parses a (normal) built-in expression
 @
 InternalExpr ::=
@@ -243,7 +298,9 @@
 @
 -}
 impossible :: IdrisParser PTerm
-impossible = PImpossible <$ reserved "impossible"
+impossible = do fc <- reservedFC "impossible"
+                highlightP fc AnnKeyword
+                return PImpossible
 
 {- | Parses a case expression
 @
@@ -252,9 +309,11 @@
 @
 -}
 caseExpr :: SyntaxInfo -> IdrisParser PTerm
-caseExpr syn = do reserved "case"; fc <- getFC
-                  scr <- expr syn; reserved "of";
+caseExpr syn = do kw1 <- reservedFC "case"; fc <- getFC
+                  scr <- expr syn; kw2 <- reservedFC "of";
                   opts <- indentedBlock1 (caseOption syn)
+                  highlightP kw1 AnnKeyword
+                  highlightP kw2 AnnKeyword
                   return (PCase fc scr opts)
                <?> "case expression"
 
@@ -279,8 +338,9 @@
 @
 -}
 proofExpr :: SyntaxInfo -> IdrisParser PTerm
-proofExpr syn = do reserved "proof"
+proofExpr syn = do kw <- reservedFC "proof"
                    ts <- indentedBlock1 (tactic syn)
+                   highlightP kw AnnKeyword
                    return $ PProof ts
                 <?> "proof block"
 
@@ -292,8 +352,9 @@
 @
 -}
 tacticsExpr :: SyntaxInfo -> IdrisParser PTerm
-tacticsExpr syn = do reserved "tactics"
+tacticsExpr syn = do kw <- reservedFC "tactics"
                      ts <- indentedBlock1 (tactic syn)
+                     highlightP kw AnnKeyword
                      return $ PTactics ts
                   <?> "tactics block"
 
@@ -327,7 +388,7 @@
         <|> do (x, FC f (l, c) end) <- try (lchar '?' *> name)
                return (PMetavar (FC f (l, c-1) end) x)
         <|> do lchar '%'; fc <- getFC; reserved "instance"; return (PResolveTC fc)
-        <|> do reserved "elim_for"; fc <- getFC; t <- fst <$> fnName; return (PRef fc (SN $ ElimN t))
+        <|> do reserved "elim_for"; fc <- getFC; t <- fst <$> fnName; return (PRef fc [] (SN $ ElimN t))
         <|> proofExpr syn
         <|> tacticsExpr syn
         <|> try (do reserved "Type"; symbol "*"; return $ PUniverse AllTypes)
@@ -339,16 +400,16 @@
                fc <- getFC
                return (modifyConst syn fc (PConstant cfc c))
         <|> do symbol "'"; fc <- getFC; str <- fst <$> name
-               return (PApp fc (PRef fc (sUN "Symbol_"))
+               return (PApp fc (PRef fc [] (sUN "Symbol_"))
                           [pexp (PConstant NoFC (Str (show str)))])
         <|> do (x, fc) <- fnName
                if inPattern syn
-                  then option (PRef fc x)
+                  then option (PRef fc [fc] x)
                               (do reservedOp "@"
                                   s <- simpleExpr syn
                                   fcIn <- getFC
                                   return (PAs fcIn x s))
-                  else return (PRef fc x)
+                  else return (PRef fc [fc] x)
         <|> idiom syn
         <|> listExpr syn
         <|> alt syn
@@ -369,9 +430,9 @@
 @
  -}
 bracketed :: SyntaxInfo -> IdrisParser PTerm
-bracketed syn = do fc <- getFC
+bracketed syn = do (FC fn (sl, sc) _) <- getFC
                    lchar '(' <?> "parenthesized expression"
-                   bracketed' fc syn
+                   bracketed' (FC fn (sl, sc) (sl, sc+1)) syn
 {- |Parses the rest of an expression in braces
 @
 Bracketed' ::=
@@ -390,52 +451,52 @@
             do (FC f start (l, c)) <- getFC
                lchar ')'
                return $ PTrue (spanFC open (FC f start (l, c+1))) TypeOrTerm
-        <|> try (do ln <- fst <$> name; lchar ':';
+        <|> try (do (ln, lnfc) <- name
+                    colonFC <- lcharFC ':'
                     lty <- expr syn
-                    reservedOp "**"
+                    starsFC <- reservedOpFC "**"
                     fc <- getFC
                     r <- expr syn
-                    lchar ')'
-                    return (PDPair fc TypeOrTerm (PRef fc ln) lty r))
+                    close <- lcharFC ')'
+                    return (PDPair fc [open, colonFC, starsFC, close] TypeOrTerm (PRef lnfc [] ln) lty r))
         <|> try (do fc <- getFC; o <- operator; e <- expr syn; lchar ')'
                     -- No prefix operators! (bit of a hack here...)
                     if (o == "-" || o == "!")
                       then fail "minus not allowed in section"
                       else return $ PLam fc (sMN 1000 "ARG") NoFC Placeholder
-                         (PApp fc (PRef fc (sUN o)) [pexp (PRef fc (sMN 1000 "ARG")),
-                                                     pexp e]))
+                         (PApp fc (PRef fc [] (sUN o)) [pexp (PRef fc [] (sMN 1000 "ARG")),
+                                                        pexp e]))
         <|> try (do l <- simpleExpr syn
                     op <- option Nothing (do o <- operator
                                              lchar ')'
                                              return (Just o)) 
                     fc0 <- getFC
                     case op of
-                         Nothing -> bracketedExpr syn l
+                         Nothing -> bracketedExpr syn open l
                          Just o -> return $ PLam fc0 (sMN 1000 "ARG") NoFC Placeholder
-                             (PApp fc0 (PRef fc0 (sUN o)) [pexp l,
-                                                           pexp (PRef fc0 (sMN 1000 "ARG"))]))
+                             (PApp fc0 (PRef fc0 [] (sUN o)) [pexp l,
+                                                              pexp (PRef fc0 [] (sMN 1000 "ARG"))]))
         <|> do l <- expr syn
-               bracketedExpr syn l
+               bracketedExpr syn open l
 
-bracketedExpr :: SyntaxInfo -> PTerm -> IdrisParser PTerm
-bracketedExpr syn e =
+-- | Parse the contents of parentheses, after an expression has been parsed.
+bracketedExpr :: SyntaxInfo -> FC -> PTerm -> IdrisParser PTerm
+bracketedExpr syn openParenFC e =
              do lchar ')'; return e
-        <|>  do fc <- do fc <- getFC
-                         lchar ','
-                         return fc
-                rs <- sepBy1 (do fc' <- getFC; r <- expr syn; return (r, fc')) (lchar ',')
-                lchar ')'
-                return $ PPair fc TypeOrTerm e (mergePairs rs)
-        <|>  do fc <- do fc <- getFC
-                         reservedOp "**"
-                         return fc
+        <|>  do exprs <- many (do comma <- lcharFC ','
+                                  r <- expr syn
+                                  return (r, comma))
+                closeParenFC <- lcharFC ')'
+                let hilite = [openParenFC, closeParenFC] ++ map snd exprs
+                return $ PPair openParenFC hilite TypeOrTerm e (mergePairs exprs)
+        <|>  do starsFC <- reservedOpFC "**"
                 r <- expr syn
-                lchar ')'
-                return (PDPair fc TypeOrTerm e Placeholder r)
+                closeParenFC <- lcharFC ')'
+                return (PDPair starsFC [openParenFC, starsFC, closeParenFC] TypeOrTerm e Placeholder r)
         <?> "end of bracketed expression"
   where mergePairs :: [(PTerm, FC)] -> PTerm
         mergePairs [(t, fc)]    = t
-        mergePairs ((t, fc):rs) = PPair fc TypeOrTerm t (mergePairs rs)
+        mergePairs ((t, fc):rs) = PPair fc [] TypeOrTerm t (mergePairs rs)
 
 -- bit of a hack here. If the integer doesn't fit in an Int, treat it as a
 -- big integer, otherwise try fromInteger and the constants as alternatives.
@@ -445,10 +506,12 @@
 modifyConst :: SyntaxInfo -> FC -> PTerm -> PTerm
 modifyConst syn fc (PConstant inFC (BI x))
     | not (inPattern syn)
-        = PAlternative FirstSuccess
-             (PApp fc (PRef fc (sUN "fromInteger")) [pexp (PConstant NoFC (BI (fromInteger x)))]
-             : consts)
-    | otherwise = PAlternative FirstSuccess consts
+        = PConstSugar inFC $ -- wrap in original location for highlighting
+            PAlternative [] FirstSuccess
+              (PApp fc (PRef fc [] (sUN "fromInteger")) [pexp (PConstant NoFC (BI (fromInteger x)))]
+              : consts)
+    | otherwise = PConstSugar inFC $
+                    PAlternative [] FirstSuccess consts
     where
       consts = [ PConstant inFC (BI x)
                , PConstant inFC (I (fromInteger x))
@@ -471,7 +534,7 @@
 -}
 alt :: SyntaxInfo -> IdrisParser PTerm
 alt syn = do symbol "(|"; alts <- sepBy1 (expr' syn) (lchar ','); symbol "|)"
-             return (PAlternative FirstSuccess alts)
+             return (PAlternative [] FirstSuccess alts)
 
 {- | Parses a possibly hidden simple expression
 @
@@ -495,8 +558,9 @@
   ;
 -}
 unifyLog :: SyntaxInfo -> IdrisParser PTerm
-unifyLog syn = do try (lchar '%' *> reserved "unifyLog")
+unifyLog syn = do (FC fn (sl, sc) kwEnd) <- try (lchar '%' *> reservedFC "unifyLog")
                   tm <- simpleExpr syn
+                  highlightP (FC fn (sl, sc-1) kwEnd) AnnKeyword
                   return (PUnifyLog tm)
                <?> "unification log expression"
 
@@ -506,11 +570,11 @@
   ;
 -}
 runElab :: SyntaxInfo -> IdrisParser PTerm
-runElab syn = do try (lchar '%' *> reserved "runElab")
+runElab syn = do (FC fn (sl, sc) kwEnd) <- try (lchar '%' *> reservedFC "runElab")
                  fc <- getFC
                  tm <- simpleExpr syn
-                 i <- get
-                 return $ PRunElab fc tm
+                 highlightP (FC fn (sl, sc-1) kwEnd) AnnKeyword
+                 return $ PRunElab fc tm (syn_namespace syn)
               <?> "new-style tactics expression"
 
 {- | Parses a disambiguation expression 
@@ -519,11 +583,12 @@
   ;
 -}
 disamb :: SyntaxInfo -> IdrisParser PTerm
-disamb syn = do reserved "with";
+disamb syn = do kw <- reservedFC "with"
                 ns <- sepBy1 (fst <$> name) (lchar ',')
                 tm <- expr' syn
+                highlightP kw AnnKeyword
                 return (PDisamb (map tons ns) tm)
-               <?> "unification log expression"
+               <?> "namespace disambiguation expression"
   where tons (NS n s) = txt (show n) : s
         tons n = [txt (show n)]
 {- | Parses a no implicits expression
@@ -559,16 +624,29 @@
                  return (PLet fc (sMN 0 "match") NoFC
                                f
                                (PMatchApp fc ff)
-                               (PRef fc (sMN 0 "match")))
+                               (PRef fc [] (sMN 0 "match")))
               <?> "matching application expression") <|> (do
              fc <- getFC
              i <- get
              args <- many (do notEndApp; arg syn)
              case args of
                [] -> return f
-               _  -> return (PApp fc f args))
+               _  -> return (flattenFromInt fc f args))
        <?> "function application"
+   where
+    -- bit of a hack to deal with the situation where we're applying a
+    -- literal to an argument, which we may want for obscure applications
+    -- of fromInteger, and this will help disambiguate better.
+    -- We know, at least, it won't be one of the constants!
+    flattenFromInt fc (PAlternative _ x alts) args
+      | Just i <- getFromInt alts
+           = PApp fc (PRef fc [] (sUN "fromInteger")) (i : args)
+    flattenFromInt fc f args = PApp fc f args
 
+    getFromInt ((PApp _ (PRef _ _ n) [a]) : _) | n == sUN "fromInteger" = Just a
+    getFromInt (_ : xs) = getFromInt xs
+    getFromInt _ = Nothing
+
 {-| Parses a function argument
 @
 Arg ::=
@@ -594,10 +672,10 @@
 -}
 implicitArg :: SyntaxInfo -> IdrisParser PArg
 implicitArg syn = do lchar '{'
-                     n <- fst <$> name
+                     (n, nfc) <- name
                      fc <- getFC
-                     v <- option (PRef fc n) (do lchar '='
-                                                 expr syn)
+                     v <- option (PRef nfc [nfc] n) (do lchar '='
+                                                        expr syn)
                      lchar '}'
                      return (pimp n v True)
                   <?> "implicit function argument"
@@ -622,14 +700,19 @@
 
 -}
 quasiquote :: SyntaxInfo -> IdrisParser PTerm
-quasiquote syn = do symbol "`("
+quasiquote syn = do startFC <- symbolFC "`("
                     e <- expr syn { syn_in_quasiquote = (syn_in_quasiquote syn) + 1 ,
                                     inPattern = False }
-                    g <- optional $ do
-                           symbol ":"
-                           expr syn { inPattern = False } -- don't allow antiquotes
-                    symbol ")"
-                    return $ PQuasiquote e g
+                    g <- optional $
+                           do fc <- symbolFC ":"
+                              ty <- expr syn { inPattern = False } -- don't allow antiquotes
+                              return (ty, fc)
+                    endFC <- symbolFC ")"
+                    mapM_ (uncurry highlightP) [(startFC, AnnKeyword), (endFC, AnnKeyword), (spanFC startFC endFC, AnnQuasiquote)]
+                    case g of
+                      Just (_, fc) -> highlightP fc AnnKeyword
+                      _ -> return ()
+                    return $ PQuasiquote e (fst <$> g)
                  <?> "quasiquotation"
 
 {-| Parses an unquoting inside a quasiquotation (for building reflected terms using the elaborator)
@@ -639,8 +722,11 @@
 -}
 unquote :: SyntaxInfo -> IdrisParser PTerm
 unquote syn = do guard (syn_in_quasiquote syn > 0)
-                 symbol "~"
+                 startFC <- symbolFC "~"
                  e <- simpleExpr syn { syn_in_quasiquote = syn_in_quasiquote syn - 1 }
+                 endFC <- getFC
+                 highlightP startFC AnnKeyword
+                 highlightP (spanFC startFC endFC) AnnAntiquote
                  return $ PUnquote e
               <?> "unquotation"
 
@@ -650,10 +736,15 @@
 
 -}
 namequote :: SyntaxInfo -> IdrisParser PTerm
-namequote syn = do symbol "`{"
-                   n <- fst <$> fnName
-                   symbol "}"
-                   return $ PQuoteName n
+namequote syn = do startFC <- symbolFC "`{"
+                   (n, nfc) <- fnName
+                   endFC <- symbolFC "}"
+                   mapM_ (uncurry highlightP)
+                         [ (startFC, AnnKeyword)
+                         , (endFC, AnnKeyword)
+                         , (spanFC startFC endFC, AnnQuasiquote)
+                         ]
+                   return $ PQuoteName n nfc
                 <?> "quoted name"
 
 
@@ -676,25 +767,26 @@
 -}
 recordType :: SyntaxInfo -> IdrisParser PTerm
 recordType syn =
-      do reserved "record"
+      do kw <- reservedFC "record"
          lchar '{'
          fgs <- fieldGetOrSet
          lchar '}'
          fc <- getFC
          rec <- optional (simpleExpr syn)
+         highlightP kw AnnKeyword
          case fgs of
               Left fields ->
                 case rec of
                    Nothing ->
                        return (PLam fc (sMN 0 "fldx") NoFC Placeholder
-                                   (applyAll fc fields (PRef fc (sMN 0 "fldx"))))
+                                   (applyAll fc fields (PRef fc [] (sMN 0 "fldx"))))
                    Just v -> return (applyAll fc fields v)
               Right fields ->
                 case rec of
                    Nothing ->
                        return (PLam fc (sMN 0 "fldx") NoFC Placeholder
-                                 (getAll fc (reverse fields) 
-                                     (PRef fc (sMN 0 "fldx"))))
+                                 (getAll fc (reverse fields)
+                                     (PRef fc [] (sMN 0 "fldx"))))
                    Just v -> return (getAll fc (reverse fields) v)
 
        <?> "record setting expression"
@@ -718,17 +810,17 @@
          applyAll fc [] x = x
          applyAll fc ((ns, e) : es) x
             = applyAll fc es (doUpdate fc ns e x)
-            
+
          doUpdate fc [n] e get
-              = PApp fc (PRef fc (mkType n)) [pexp e, pexp get]
+              = PApp fc (PRef fc [] (mkType n)) [pexp e, pexp get]
          doUpdate fc (n : ns) e get
-              = PApp fc (PRef fc (mkType n)) 
-                  [pexp (doUpdate fc ns e (PApp fc (PRef fc n) [pexp get])), 
+              = PApp fc (PRef fc [] (mkType n))
+                  [pexp (doUpdate fc ns e (PApp fc (PRef fc [] n) [pexp get])),
                    pexp get]
 
          getAll :: FC -> [Name] -> PTerm -> PTerm
-         getAll fc [n] e = PApp fc (PRef fc n) [pexp e]
-         getAll fc (n:ns) e = PApp fc (PRef fc n) [pexp (getAll fc ns e)]
+         getAll fc [n] e = PApp fc (PRef fc [] n) [pexp e]
+         getAll fc (n:ns) e = PApp fc (PRef fc [] n) [pexp (getAll fc ns e)]
 
 
 -- | Creates setters for record types on necessary functions
@@ -790,7 +882,7 @@
           pmList [] sc = sc
           pmList ((i, (fc, x)) : xs) sc
                 = PLam fc (sMN i "lamp") NoFC Placeholder
-                        (PCase fc (PRef fc (sMN i "lamp"))
+                        (PCase fc (PRef fc [] (sMN i "lamp"))
                                 [(x, pmList xs sc)])
           lambdaTail :: IdrisParser PTerm
           lambdaTail = impossible <|> symbol "=>" *> expr syn
@@ -803,13 +895,15 @@
 @
 -}
 rewriteTerm :: SyntaxInfo -> IdrisParser PTerm
-rewriteTerm syn = do reserved "rewrite"
+rewriteTerm syn = do kw <- reservedFC "rewrite"
                      fc <- getFC
                      prf <- expr syn
                      giving <- optional (do symbol "==>"; expr' syn)
-                     reserved "in";  sc <- expr syn
+                     kw' <- reservedFC "in";  sc <- expr syn
+                     highlightP kw AnnKeyword
+                     highlightP kw' AnnKeyword
                      return (PRewrite fc
-                             (PApp fc (PRef fc (sUN "sym")) [pexp prf]) sc
+                             (PApp fc (PRef fc [] (sUN "sym")) [pexp prf]) sc
                                giving)
                   <?> "term rewrite expression"
 
@@ -825,13 +919,14 @@
 @
  -}
 let_ :: SyntaxInfo -> IdrisParser PTerm
-let_ syn = try (do reserved "let"
+let_ syn = try (do kw <- reservedFC "let"
                    ls <- indentedBlock (let_binding syn)
-                   reserved "in";  sc <- expr syn
+                   kw' <- reservedFC "in";  sc <- expr syn
+                   highlightP kw AnnKeyword; highlightP kw' AnnKeyword
                    return (buildLets ls sc))
            <?> "let binding"
   where buildLets [] sc = sc
-        buildLets ((fc, PRef nfc n, ty, v, []) : ls) sc
+        buildLets ((fc, PRef nfc _ n, ty, v, []) : ls) sc
           = PLet fc n nfc ty v (buildLets ls sc)
         buildLets ((fc, pat, ty, v, alts) : ls) sc
           = PCase fc v ((pat, buildLets ls sc) : alts)
@@ -852,13 +947,14 @@
 
 -}
 if_ :: SyntaxInfo -> IdrisParser PTerm
-if_ syn = (do reserved "if"
+if_ syn = (do ifFC <- reservedFC "if"
               fc <- getFC
               c <- expr syn
-              reserved "then"
+              thenFC <- reservedFC "then"
               t <- expr syn
-              reserved "else"
+              elseFC <- reservedFC "else"
               f <- expr syn
+              mapM_ (flip highlightP AnnKeyword) [ifFC, thenFC, elseFC]
               return (PIfThenElse fc c t f))
           <?> "conditional expression"
 
@@ -872,12 +968,13 @@
 @
  -}
 quoteGoal :: SyntaxInfo -> IdrisParser PTerm
-quoteGoal syn = do reserved "quoteGoal"; n <- fst <$> name;
-                   reserved "by"
+quoteGoal syn = do kw1 <- reservedFC "quoteGoal"; n <- fst <$> name;
+                   kw2 <- reservedFC "by"
                    r <- expr syn
-                   reserved "in"
+                   kw3 <- reservedFC "in"
                    fc <- getFC
                    sc <- expr syn
+                   mapM_ (flip highlightP AnnKeyword) [kw1, kw2, kw3]
                    return (PGoal fc r n sc)
                 <?> "quote goal expression"
 
@@ -909,17 +1006,18 @@
         return (bindList (PPi binder) xt sc)
        
 autoImplicit opts st syn
-   = do reserved "auto"
+   = do kw <- reservedFC "auto"
         when (st == Static) $ fail "auto implicits can not be static"
         xt <- typeDeclList syn
         lchar '}'
         symbol "->"
         sc <- expr syn
+        highlightP kw AnnKeyword
         return (bindList (PPi
-          (TacImp [] Dynamic (PTactics [ProofSearch True True 100 Nothing []]))) xt sc) 
+          (TacImp [] Dynamic (PTactics [ProofSearch True True 100 Nothing [] []]))) xt sc) 
 
 defaultImplicit opts st syn = do
-   reserved "default"
+   kw <- reservedFC "default"
    when (st == Static) $ fail "default implicits can not be static"
    ist <- get
    script' <- simpleExpr syn
@@ -928,6 +1026,7 @@
    lchar '}'
    symbol "->"
    sc <- expr syn
+   highlightP kw AnnKeyword
    return (bindList (PPi (TacImp [] Dynamic script)) xt sc)
 
 normalImplicit opts st syn = do
@@ -1090,20 +1189,26 @@
                                qs <- sepBy1 (do_ syn) (lchar ',')
                                lchar ']'
                                return (PDoBlock (map addGuard qs ++
-                                          [DoExp fc (PApp fc (PRef fc (sUN "return"))
+                                          [DoExp fc (PApp fc (PRef fc [] (sUN "return"))
                                                        [pexp x])]))) <|>
-                            (do xs <- many ((lchar ',' <?> "list element") *> expr syn)
+                            (do xs <- many (do (FC fn (sl, sc) _) <- getFC
+                                               lchar ',' <?> "list element"
+                                               let commaFC = FC fn (sl, sc) (sl, sc + 1)
+                                               elt <- expr syn
+                                               return (elt, commaFC))
+                                (FC fn (sl, sc) _) <- getFC
                                 lchar ']' <?> "end of list expression"
-                                return (mkList fc (x:xs))))
+                                let rbrackFC = FC fn (sl, sc) (sl, sc+1)
+                                return (mkList fc rbrackFC ((x, (FC f (l, c) (l, c+1))) : xs))))
                 <?> "list expression"
   where
     mkNil :: FC -> PTerm
-    mkNil fc = PRef fc (sUN "Nil")
-    mkList :: FC -> [PTerm] -> PTerm
-    mkList fc [] = PRef NoFC (sUN "Nil")
-    mkList fc (x : xs) = PApp fc (PRef NoFC (sUN "::")) [pexp x, pexp (mkList fc xs)]
+    mkNil fc = PRef fc [fc] (sUN "Nil")
+    mkList :: FC -> FC -> [(PTerm, FC)] -> PTerm
+    mkList errFC nilFC [] = PRef nilFC [nilFC] (sUN "Nil")
+    mkList errFC nilFC ((x, fc) : xs) = PApp errFC (PRef fc [fc] (sUN "::")) [pexp x, pexp (mkList errFC nilFC xs)]
     addGuard :: PDo -> PDo
-    addGuard (DoExp fc e) = DoExp fc (PApp fc (PRef fc (sUN "guard"))
+    addGuard (DoExp fc e) = DoExp fc (PApp fc (PRef fc [] (sUN "guard"))
                                               [pexp e])
     addGuard x = x
 
@@ -1120,8 +1225,9 @@
  -}
 doBlock :: SyntaxInfo -> IdrisParser PTerm
 doBlock syn
-    = do reserved "do"
+    = do kw <- reservedFC "do"
          ds <- indentedBlock1 (do_ syn)
+         highlightP kw AnnKeyword
          return (PDoBlock ds)
       <?> "do block"
 
@@ -1138,19 +1244,21 @@
 -}
 do_ :: SyntaxInfo -> IdrisParser PDo
 do_ syn
-     = try (do reserved "let"
+     = try (do kw <- reservedFC "let"
                (i, ifc) <- name
                ty <- option Placeholder (do lchar ':'
                                             expr' syn)
                reservedOp "="
                fc <- getFC
                e <- expr syn
+               highlightP kw AnnKeyword
                return (DoLet fc i ifc ty e))
-   <|> try (do reserved "let"
+   <|> try (do kw <- reservedFC "let"
                i <- expr' syn
                reservedOp "="
                fc <- getFC
                sc <- expr syn
+               highlightP kw AnnKeyword
                return (DoLetP fc i sc))
    <|> try (do (i, ifc) <- name
                symbol "<-"
@@ -1159,7 +1267,7 @@
                option (DoBind fc i ifc e)
                       (do lchar '|'
                           ts <- sepBy1 (do_alt syn) (lchar '|')
-                          return (DoBindP fc (PRef ifc i) e ts)))
+                          return (DoBindP fc (PRef ifc [ifc] i) e ts)))
    <|> try (do i <- expr' syn
                symbol "<-"
                fc <- getFC
@@ -1371,14 +1479,14 @@
   , noArgs ["unify"] DoUnify
   , (["search"], Nothing, const $
       do depth <- option 10 $ fst <$> natural
-         return (ProofSearch True True (fromInteger depth) Nothing []))
+         return (ProofSearch True True (fromInteger depth) Nothing [] []))
   , noArgs ["instance"] TCInstance
   , noArgs ["solve"] Solve
   , noArgs ["attack"] Attack
-  , noArgs ["state"] ProofState
-  , noArgs ["term"] ProofTerm
-  , noArgs ["undo"] Undo
-  , noArgs ["qed"] Qed
+  , noArgs ["state", ":state"] ProofState
+  , noArgs ["term", ":term"] ProofTerm
+  , noArgs ["undo", ":undo"] Undo
+  , noArgs ["qed", ":qed"] Qed
   , noArgs ["abandon", ":q"] Abandon
   , noArgs ["skip"] Skip
   , noArgs ["sourceLocation"] SourceFC
diff --git a/src/Idris/ParseHelpers.hs b/src/Idris/ParseHelpers.hs
--- a/src/Idris/ParseHelpers.hs
+++ b/src/Idris/ParseHelpers.hs
@@ -79,6 +79,10 @@
   parseString (runInnerParser (evalStateT p i))
               (Directed (UTF8.fromString inputname) 0 0 0 0)
 
+highlightP :: FC -> OutputAnnotation -> IdrisParser ()
+highlightP fc annot = do ist <- get
+                         put ist { idris_parserHighlights = (fc, annot) : idris_parserHighlights ist}
+
 noDocCommentHere :: String -> IdrisParser ()
 noDocCommentHere msg =
   optional (do fc <- getFC
@@ -256,10 +260,21 @@
 lchar :: MonadicParsing m => Char -> m Char
 lchar = token . char
 
+-- | Parses a character as a token, returning the source span of the character
+lcharFC :: MonadicParsing m => Char -> m FC
+lcharFC ch = do (FC file (l, c) _) <- getFC
+                _ <- token (char ch)
+                return $ FC file (l, c) (l, c+1)
+
 -- | Parses string as a token
 symbol :: MonadicParsing m => String -> m String
 symbol = Tok.symbol
 
+symbolFC :: MonadicParsing m => String -> m FC
+symbolFC str = do (FC file (l, c) _) <- getFC
+                  Tok.symbol str
+                  return $ FC file (l, c) (l, c + length str)
+
 -- | Parses a reserved identifier
 reserved :: MonadicParsing m => String -> m ()
 reserved = Tok.reserve idrisStyle
@@ -271,6 +286,10 @@
                     Tok.reserve idrisStyle str
                     return $ FC file (l, c) (l, c + length str)
 
+-- | Parse a reserved identfier, highlighting its span as a keyword
+reservedHL :: String -> IdrisParser ()
+reservedHL str = reservedFC str >>= flip highlightP AnnKeyword
+
 -- Taken from Parsec (c) Daan Leijen 1999-2001, (c) Paolo Martini 2007
 -- | Parses a reserved operator
 reservedOp :: MonadicParsing m => String -> m ()
@@ -415,6 +434,11 @@
 bindList b []              sc = sc
 bindList b ((n, fc, t):bs) sc = b n fc t (bindList b bs sc)
 
+{- | @commaSeparated p@ parses one or more occurences of `p`,
+     separated by commas and optional whitespace. -}
+commaSeparated :: MonadicParsing m => m a -> m [a]
+commaSeparated p = p `sepBy1` (spaces >> char ',' >> spaces)
+
 {- * Layout helpers -}
 
 -- | Push indentation to stack
@@ -426,8 +450,9 @@
 -- | Pops indentation from stack
 popIndent :: IdrisParser ()
 popIndent = do ist <- get
-               let (x : xs) = indent_stack ist
-               put (ist { indent_stack = xs })
+               case indent_stack ist of
+                 [] -> error "The impossible happened! Tried to pop an indentation level where none was pushed (underflow)."
+                 (x : xs) -> put (ist { indent_stack = xs })
 
 
 -- | Gets current indentation
diff --git a/src/Idris/ParseOps.hs b/src/Idris/ParseOps.hs
--- a/src/Idris/ParseOps.hs
+++ b/src/Idris/ParseOps.hs
@@ -35,11 +35,11 @@
 -- using pre-build and user-defined operator/fixity declarations
 table :: [FixDecl] -> OperatorTable IdrisParser PTerm
 table fixes
-   = [[prefix "-" (\fc x -> PApp fc (PRef fc (sUN "negate")) [pexp x])]] ++
+   = [[prefix "-" (\fc x -> PApp fc (PRef fc [fc] (sUN "negate")) [pexp x])]] ++
      toTable (reverse fixes) ++
      [[backtick],
       [binary "$" (\fc x y -> flatten $ PApp fc x [pexp y]) AssocRight],
-      [binary "="  (\fc x y -> PApp fc (PRef fc eqTy) [pexp x, pexp y]) AssocLeft],
+      [binary "="  (\fc x y -> PApp fc (PRef fc [fc] eqTy) [pexp x, pexp y]) AssocLeft],
       [nofixityoperator]]
   where
     flatten :: PTerm -> PTerm -- flatten application
@@ -52,9 +52,9 @@
 toTable fs = map (map toBin)
                  (groupBy (\ (Fix x _) (Fix y _) -> prec x == prec y) fs)
    where toBin (Fix (PrefixN _) op) = prefix op
-                                       (\fc x -> PApp fc (PRef fc (sUN op)) [pexp x])
+                                       (\fc x -> PApp fc (PRef fc [] (sUN op)) [pexp x])
          toBin (Fix f op)
-            = binary op (\fc x y -> PApp fc (PRef fc (sUN op)) [pexp x,pexp y]) (assoc f)
+            = binary op (\fc x y -> PApp fc (PRef fc [] (sUN op)) [pexp x,pexp y]) (assoc f)
          assoc (Infixl _) = AssocLeft
          assoc (Infixr _) = AssocRight
          assoc (InfixN _) = AssocNone
@@ -79,7 +79,7 @@
                      lchar '`'; (n, fc) <- fnName
                      lchar '`'
                      indentPropHolds gtProp
-                     return (\x y -> PApp fc (PRef fc n) [pexp x, pexp y])) AssocNone
+                     return (\x y -> PApp fc (PRef fc [fc] n) [pexp x, pexp y])) AssocNone
 
 -- | Operator without fixity (throws an error)
 nofixityoperator :: Operator IdrisParser PTerm
diff --git a/src/Idris/Parser.hs b/src/Idris/Parser.hs
--- a/src/Idris/Parser.hs
+++ b/src/Idris/Parser.hs
@@ -62,6 +62,7 @@
 import Data.Monoid
 import Data.Char
 import Data.Ord
+import Data.Foldable (asum)
 import Data.Generics.Uniplate.Data (descendM)
 import qualified Data.Map as M
 import qualified Data.HashSet as HS
@@ -97,7 +98,7 @@
 moduleHeader :: IdrisParser (Maybe (Docstring ()), [String], [(FC, OutputAnnotation)])
 moduleHeader =     try (do docs <- optional docComment
                            noArgs docs
-                           reserved "module"
+                           reservedHL "module"
                            (i, ifc) <- identifier
                            option ';' (lchar ';')
                            let modName = moduleName i
@@ -129,10 +130,12 @@
  -}
 import_ :: IdrisParser ImportInfo
 import_ = do fc <- getFC
-             reserved "import"
-             reexport <- option False (do reserved "public"; return True)
+             reservedHL "import"
+             reexport <- option False (do reservedHL "public"
+                                          return True)
              (id, idfc) <- identifier
-             newName <- optional (reserved "as" *> identifier)
+             newName <- optional (do reservedHL "as"
+                                     identifier)
              option ';' (lchar ';')
              return $ ImportInfo reexport (toPath id)
                         (fmap (\(n, fc) -> (toPath n, fc)) newName)
@@ -176,11 +179,18 @@
   | Provider
   | Transform
   | Import!
+  | RunElabDecl
   ;
 @
 -}
 decl :: SyntaxInfo -> IdrisParser [PDecl]
-decl syn = do fc <- getFC
+decl syn = try (externalDecl syn)
+           <|> internalDecl syn
+           <?> "declaration"
+
+internalDecl :: SyntaxInfo -> IdrisParser [PDecl]
+internalDecl syn 
+         = do fc <- getFC
               -- if we're after maxline, stop here
               let continue = case maxline syn of
                                 Nothing -> True
@@ -228,8 +238,137 @@
            <|> fnDecl' syn
            <|> data_ syn
            <|> record syn
+           <|> runElabDecl syn
            <?> "declaration"
 
+externalDecl :: SyntaxInfo -> IdrisParser [PDecl]
+externalDecl syn = do i <- get
+                      notEndBlock
+                      FC fn start _ <- getFC
+                      decls <- declExtensions syn (syntaxRulesList $ syntax_rules i)
+                      FC _ _ end <- getFC
+                      let outerFC = FC fn start end
+                      return $ map (mapPDeclFC (fixFC outerFC)
+                                               (fixFCH fn outerFC))
+                                   decls
+  where
+    -- | Fix non-highlighting FCs to prevent spurious error location reports
+    fixFC :: FC -> FC -> FC
+    fixFC outer inner | inner `fcIn` outer = inner
+                      | otherwise          = outer
+    -- | Fix highlighting FCs by obliterating them, to avoid spurious highlights
+    fixFCH fn outer inner | inner `fcIn` outer = inner
+                          | otherwise          = FileFC fn
+
+declExtensions :: SyntaxInfo -> [Syntax] -> IdrisParser [PDecl]
+declExtensions syn rules = declExtension syn [] (filter isDeclRule rules)
+                           <?> "user-defined declaration"
+   where
+     isDeclRule (DeclRule _ _) = True
+     isDeclRule _ = False
+
+declExtension :: SyntaxInfo -> [Maybe (Name, SynMatch)] -> [Syntax] 
+                 -> IdrisParser [PDecl]
+declExtension syn ns rules =
+  choice $ flip map (groupBy (ruleGroup `on` syntaxSymbols) rules) $ \rs ->
+    case head rs of -- can never be []
+      DeclRule (symb:_) _ -> try $ do
+        n <- extSymbol symb
+        declExtension syn (n : ns) [DeclRule ss t | (DeclRule (_:ss) t) <- rs]
+      -- If we have more than one Rule in this bucket, our grammar is
+      -- nondeterministic.
+      DeclRule [] dec -> let r = map (update (mapMaybe id ns)) dec in
+                             return r
+
+  where
+    update :: [(Name, SynMatch)] -> PDecl -> PDecl
+    update ns = updateNs ns . fmap (updateRefs ns) . fmap (updateSynMatch ns)
+
+    updateRefs ns = mapPT newref
+      where
+        newref (PRef fc fcs n) = PRef fc fcs (updateB ns n)
+        newref t = t
+
+    -- Below is a lot of tedious boilerplate which updates any top level
+    -- names in the declaration. It will only change names which are bound in
+    -- the declaration (including method names in classes and field names in
+    -- record declarations, not including pattern variables)
+    updateB :: [(Name, SynMatch)] -> Name -> Name
+    updateB ns (NS n mods) = NS (updateB ns n) mods
+    updateB ns n = case lookup n ns of
+                        Just (SynBind tfc t) -> t
+                        _ -> n
+
+    updateNs :: [(Name, SynMatch)] -> PDecl -> PDecl
+    updateNs ns (PTy doc argdoc s fc o n fc' t)
+          = PTy doc argdoc s fc o (updateB ns n) fc' t
+    updateNs ns (PClauses fc o n cs) 
+         = PClauses fc o (updateB ns n) (map (updateClause ns) cs)
+    updateNs ns (PCAF fc n t) = PCAF fc (updateB ns n) t
+    updateNs ns (PData ds cds s fc o dat)
+         = PData ds cds s fc o (updateData ns dat)
+    updateNs ns (PParams fc ps ds) = PParams fc ps (map (updateNs ns) ds)
+    updateNs ns (PNamespace s fc ds) = PNamespace s fc (map (updateNs ns) ds)
+    updateNs ns (PRecord doc syn fc o n fc' ps pdocs fields cname cdoc s)
+         = PRecord doc syn fc o (updateB ns n) fc' ps pdocs
+                   (map (updateField ns) fields)
+                   (updateRecCon ns cname)
+                   cdoc
+                   s
+    updateNs ns (PClass docs s fc cs cn fc' ps pdocs pdets ds cname cdocs)
+         = PClass docs s fc cs (updateB ns cn) fc' ps pdocs pdets
+                  (map (updateNs ns) ds)
+                  (updateRecCon ns cname)
+                  cdocs
+    updateNs ns (PInstance docs pdocs s fc cs cn fc' ps ity ni ds)
+         = PInstance docs pdocs s fc cs (updateB ns cn) fc'
+                     ps ity (fmap (updateB ns) ni) 
+                            (map (updateNs ns) ds)
+    updateNs ns (PMutual fc ds) = PMutual fc (map (updateNs ns) ds)
+    updateNs ns (PProvider docs s fc fc' pw n) 
+        = PProvider docs s fc fc' pw (updateB ns n)
+    updateNs ns d = d
+
+    updateRecCon ns Nothing = Nothing
+    updateRecCon ns (Just (n, fc)) = Just (updateB ns n, fc)
+
+    updateField ns (m, p, t, doc) = (updateRecCon ns m, p, t, doc)
+
+    updateClause ns (PClause fc n t ts t' ds)
+       = PClause fc (updateB ns n) t ts t' (map (update ns) ds)
+    updateClause ns (PWith fc n t ts t' m ds)
+       = PWith fc (updateB ns n) t ts t' m (map (update ns) ds)
+    updateClause ns (PClauseR fc ts t ds)
+       = PClauseR fc ts t (map (update ns) ds)
+    updateClause ns (PWithR fc ts t m ds)
+       = PWithR fc ts t m (map (update ns) ds)
+
+    updateData ns (PDatadecl n fc t cs)
+       = PDatadecl (updateB ns n) fc t (map (updateCon ns) cs)
+    updateData ns (PLaterdecl n fc t)
+       = PLaterdecl (updateB ns n) fc t
+
+    updateCon ns (cd, ads, cn, fc, ty, fc', fns)
+       = (cd, ads, updateB ns cn, fc, ty, fc', fns)
+
+    ruleGroup [] [] = True
+    ruleGroup (s1:_) (s2:_) = s1 == s2
+    ruleGroup _ _ = False
+
+    extSymbol :: SSymbol -> IdrisParser (Maybe (Name, SynMatch))
+    extSymbol (Keyword n) = do fc <- reservedFC (show n)
+                               highlightP fc AnnKeyword
+                               return Nothing
+    extSymbol (Expr n) = do tm <- expr syn
+                            return $ Just (n, SynTm tm)
+    extSymbol (SimpleExpr n) = do tm <- simpleExpr syn
+                                  return $ Just (n, SynTm tm)
+    extSymbol (Binding n) = do (b, fc) <- name
+                               return $ Just (n, SynBind fc b)
+    extSymbol (Symbol s) = do fc <- symbolFC s
+                              highlightP fc AnnKeyword
+                              return Nothing
+
 {- | Parses a syntax extension declaration (and adds the rule to parser state)
 
 @
@@ -284,9 +423,10 @@
 syntaxRule syn
     = do sty <- try (do
             pushIndent
-            sty <- option AnySyntax (do reserved "term"; return TermSyntax
-                                  <|> do reserved "pattern"; return PatternSyntax)
-            reserved "syntax"
+            sty <- option AnySyntax
+                          (do reservedHL "term"; return TermSyntax
+                           <|> do reservedHL "pattern"; return PatternSyntax)
+            reservedHL "syntax"
             return sty)
          syms <- some syntaxSym
          when (all isExpr syms) $ unexpected "missing keywords in syntax rule"
@@ -297,6 +437,17 @@
          tm <- typeExpr (allowImp syn) >>= uniquifyBinders [n | Binding n <- syms]
          terminator
          return (Rule (mkSimple syms) tm sty)
+  <|> do reservedHL "decl"; reservedHL "syntax"
+         syms <- some syntaxSym
+         when (all isExpr syms) $ unexpected "missing keywords in syntax rule"
+         let ns = mapMaybe getName syms
+         when (length ns /= length (nub ns))
+            $ unexpected "repeated variable in syntax rule"
+         lchar '='
+         openBlock
+         dec <- some (decl syn)
+         closeBlock
+         return (DeclRule (mkSimple syms) (concat dec))
   where
     isExpr (Expr _) = True
     isExpr _ = False
@@ -311,7 +462,7 @@
                                            mkSimple es
     -- Can't parse a full expression followed by operator like characters due to ambiguity
     mkSimple' (Expr e : Symbol s : es)
-      | takeWhile (`elem` opChars) ts /= "" && ts `notElem` invalidOperators  = SimpleExpr e : Symbol s : mkSimple' es
+      | takeWhile (`elem` opChars) ts /= "" = SimpleExpr e : Symbol s : mkSimple' es
        where ts = dropWhile isSpace . dropWhileEnd isSpace $ s
     mkSimple' (e : es) = e : mkSimple' es
     mkSimple' [] = []
@@ -322,8 +473,8 @@
     uniquifyBinders userNames = fixBind []
       where
         fixBind :: [(Name, Name)] -> PTerm -> IdrisParser PTerm
-        fixBind rens (PRef fc n) | Just n' <- lookup n rens =
-          return $ PRef fc n'
+        fixBind rens (PRef fc hls n) | Just n' <- lookup n rens =
+          return $ PRef fc hls n'
         fixBind rens (PPatvar fc n) | Just n' <- lookup n rens =
           return $ PPatvar fc n'
         fixBind rens (PLam fc n nfc ty body)
@@ -480,31 +631,31 @@
 --     https://github.com/idris-lang/Idris-dev/issues/1574
 fnOpts :: [FnOpt] -> IdrisParser [FnOpt]
 fnOpts opts
-        = do reserved "total"; fnOpts (TotalFn : opts)
-      <|> do reserved "partial"; fnOpts (PartialFn : (opts \\ [TotalFn]))
-      <|> do reserved "covering"; fnOpts (CoveringFn : (opts \\ [TotalFn]))
-      <|> do try (lchar '%' *> reserved "export"); c <- fmap fst stringLiteral;
-                  fnOpts (CExport c : opts)
-      <|> do try (lchar '%' *> reserved "no_implicit");
-                  fnOpts (NoImplicit : opts)
-      <|> do try (lchar '%' *> reserved "inline");
-                  fnOpts (Inlinable : opts)
-      <|> do try (lchar '%' *> reserved "assert_total");
-                  fnOpts (AssertTotal : opts)
-      <|> do try (lchar '%' *> reserved "error_handler");
-                 fnOpts (ErrorHandler : opts)
-      <|> do try (lchar '%' *> reserved "error_reverse");
-                 fnOpts (ErrorReverse : opts)
-      <|> do try (lchar '%' *> reserved "reflection");
-                  fnOpts (Reflection : opts)
-      <|> do try (lchar '%' *> reserved "hint");
-                  fnOpts (AutoHint : opts)
-      <|> do lchar '%'; reserved "specialise";
-             lchar '['; ns <- sepBy nameTimes (lchar ','); lchar ']'
-             fnOpts (Specialise ns : opts)
-      <|> do reserved "implicit"; fnOpts (Implicit : opts)
-      <|> return opts
-      <?> "function modifier"
+        = do reservedHL "total"; fnOpts (TotalFn : opts)
+  <|> do reservedHL "partial"; fnOpts (PartialFn : (opts \\ [TotalFn]))
+  <|> do reservedHL "covering"; fnOpts (CoveringFn : (opts \\ [TotalFn]))
+  <|> do try (lchar '%' *> reserved "export"); c <- fmap fst stringLiteral;
+              fnOpts (CExport c : opts)
+  <|> do try (lchar '%' *> reserved "no_implicit");
+              fnOpts (NoImplicit : opts)
+  <|> do try (lchar '%' *> reserved "inline");
+              fnOpts (Inlinable : opts)
+  <|> do try (lchar '%' *> reserved "assert_total");
+              fnOpts (AssertTotal : opts)
+  <|> do try (lchar '%' *> reserved "error_handler");
+             fnOpts (ErrorHandler : opts)
+  <|> do try (lchar '%' *> reserved "error_reverse");
+             fnOpts (ErrorReverse : opts)
+  <|> do try (lchar '%' *> reserved "reflection");
+              fnOpts (Reflection : opts)
+  <|> do try (lchar '%' *> reserved "hint");
+              fnOpts (AutoHint : opts)
+  <|> do lchar '%'; reserved "specialise";
+         lchar '['; ns <- sepBy nameTimes (lchar ','); lchar ']'
+         fnOpts (Specialise ns : opts)
+  <|> do reservedHL "implicit"; fnOpts (Implicit : opts)
+  <|> return opts
+  <?> "function modifier"
   where nameTimes :: IdrisParser (Name, Maybe Int)
         nameTimes = do n <- fst <$> fnName
                        t <- option Nothing (do reds <- fmap fst natural
@@ -532,16 +683,16 @@
                    opts <- fnOpts initOpts
                    acc <- optional accessibility
                    opts' <- fnOpts opts
-                   n_in <- fst <$> fnName
+                   (n_in, nfc) <- fnName
                    let n = expandNS syn n_in
                    lchar ':'
                    ty <- typeExpr (allowImp syn)
                    fc <- getFC
                    terminator
                    addAcc n acc
-                   return (PPostulate ext doc syn fc opts' n ty)
+                   return (PPostulate ext doc syn fc nfc opts' n ty)
                  <?> "postulate"
-   where ppostDecl = do reserved "postulate"; return False
+   where ppostDecl = do fc <- reservedHL "postulate"; return False
                  <|> do lchar '%'; reserved "extern"; return True
 {- | Parses a using declaration
 
@@ -553,7 +704,8 @@
  -}
 using_ :: SyntaxInfo -> IdrisParser [PDecl]
 using_ syn =
-    do reserved "using"; lchar '('; ns <- usingDeclList syn; lchar ')'
+    do reservedHL "using"
+       lchar '('; ns <- usingDeclList syn; lchar ')'
        openBlock
        let uvars = using syn
        ds <- many (decl (syn { using = uvars ++ ns }))
@@ -571,7 +723,7 @@
  -}
 params :: SyntaxInfo -> IdrisParser [PDecl]
 params syn =
-    do reserved "parameters"; lchar '('; ns <- typeDeclList syn; lchar ')'
+    do reservedHL "parameters"; lchar '('; ns <- typeDeclList syn; lchar ')'
        let ns' = [(n, ty) | (n, _, ty) <- ns]
        openBlock
        let pvars = syn_params syn
@@ -591,7 +743,7 @@
 -}
 mutual :: SyntaxInfo -> IdrisParser [PDecl]
 mutual syn =
-    do reserved "mutual"
+    do reservedHL "mutual"
        openBlock
        let pvars = syn_params syn
        ds <- many (decl (syn { mut_nesting = mut_nesting syn + 1 } ))
@@ -610,7 +762,7 @@
 -}
 namespace :: SyntaxInfo -> IdrisParser [PDecl]
 namespace syn =
-    do reserved "namespace"
+    do reservedHL "namespace"
        (n, nfc) <- identifier
        openBlock
        ds <- some (decl syn { syn_namespace = n : syn_namespace syn })
@@ -625,7 +777,7 @@
 @
 -}
 instanceBlock :: SyntaxInfo -> IdrisParser [PDecl]
-instanceBlock syn = do reserved "where"
+instanceBlock syn = do reservedHL "where"
                        openBlock
                        ds <- many (fnDecl syn)
                        closeBlock
@@ -648,7 +800,7 @@
 @
 -}
 classBlock :: SyntaxInfo -> IdrisParser (Maybe (Name, FC), Docstring (Either Err PTerm), [PDecl])
-classBlock syn = do reserved "where"
+classBlock syn = do reservedHL "where"
                     openBlock
                     (cn, cd) <- option (Nothing, emptyDocstring) $
                                 try (do (doc, _) <- option noDocs docComment
@@ -664,7 +816,7 @@
 
   where
     constructor :: IdrisParser (Name, FC)
-    constructor = reserved "constructor" *> fnName
+    constructor = reservedHL "constructor" *> fnName
 
     annotate :: SyntaxInfo -> IState -> Docstring () -> Docstring (Either Err PTerm)
     annotate syn ist = annotCode $ tryFullExpr syn ist
@@ -688,7 +840,7 @@
 class_ syn = do (doc, argDocs, acc)
                   <- try (do (doc, argDocs) <- docstring syn
                              acc <- optional accessibility
-                             reserved "class"
+                             reservedHL "class"
                              return (doc, argDocs, acc))
                 fc <- getFC
                 cons <- constraintList syn
@@ -726,14 +878,14 @@
 -}
 instance_ :: SyntaxInfo -> IdrisParser [PDecl]
 instance_ syn = do (doc, argDocs)
-                     <- try (docstring syn <* reserved "instance")
+                     <- try (docstring syn <* reservedHL "instance")
                    fc <- getFC
                    en <- optional instanceName
                    cs <- constraintList syn
                    let cs' = [(c, ty) | (c, _, ty) <- cs]
                    (cn, cnfc) <- fnName
                    args <- many (simpleExpr syn)
-                   let sc = PApp fc (PRef cnfc cn) (map pexp args)
+                   let sc = PApp fc (PRef cnfc [cnfc] cn) (map pexp args)
                    let t = bindList (PPi constraint) cs sc
                    ds <- option [] (instanceBlock syn)
                    return [PInstance doc argDocs syn fc cs' cn cnfc args t en ds]
@@ -827,10 +979,11 @@
 @
 -}
 caf :: SyntaxInfo -> IdrisParser PDecl
-caf syn = do reserved "let"
+caf syn = do reservedHL "let"
              n_in <- fst <$> fnName; let n = expandNS syn n_in
+             pushIndent
              lchar '='
-             t <- expr syn
+             t <- indented $ expr syn
              terminator
              fc <- getFC
              return (PCAF fc n t)
@@ -925,7 +1078,7 @@
                                                return ([], [])]
                   return $ PClauseR fc wargs r wheres) <|> (do
                   popIndent
-                  reserved "with"
+                  reservedHL "with"
                   wval <- simpleExpr syn
                   pn <- optProof
                   openBlock
@@ -951,7 +1104,7 @@
               let capp = PLet fc (sMN 0 "match") NoFC
                               ty
                               (PMatchApp fc n)
-                              (PRef fc (sMN 0 "match"))
+                              (PRef fc [] (sMN 0 "match"))
               ist <- get
               put (ist { lastParse = Just n })
               return $ PClause fc n capp [] r wheres
@@ -974,18 +1127,18 @@
                                             do terminator
                                                return ([], [])]
                   ist <- get
-                  let capp = PApp fc (PRef nfc n) [pexp l, pexp r]
+                  let capp = PApp fc (PRef nfc [nfc] n) [pexp l, pexp r]
                   put (ist { lastParse = Just n })
                   return $ PClause fc n capp wargs rs wheres) <|> (do
                    popIndent
-                   reserved "with"
+                   reservedHL "with"
                    wval <- bracketed syn
                    pn <- optProof
                    openBlock
                    ds <- some $ fnDecl syn
                    closeBlock
                    ist <- get
-                   let capp = PApp fc (PRef fc n) [pexp l, pexp r]
+                   let capp = PApp fc (PRef fc [] n) [pexp l, pexp r]
                    let withs = map (fillLHSD n capp wargs) $ concat ds
                    put (ist { lastParse = Just n })
                    return $ PWith fc n capp wargs wval pn withs)
@@ -996,7 +1149,7 @@
               args <- many (try (implicitArg (syn { inPattern = True } ))
                             <|> (fmap pexp (argExpr syn)))
               wargs <- many (wExpr syn)
-              let capp = PApp fc (PRef nfc n)
+              let capp = PApp fc (PRef nfc [nfc] n)
                            (cargs ++ args)
               (do r <- rhs syn n
                   ist <- get
@@ -1010,7 +1163,7 @@
                   ist <- get
                   put (ist { lastParse = Just n })
                   return $ PClause fc n capp wargs r wheres) <|> (do
-                   reserved "with"
+                   reservedHL "with"
                    ist <- get
                    put (ist { lastParse = Just n })
                    wval <- bracketed syn
@@ -1023,7 +1176,7 @@
                    return $ PWith fc n capp wargs wval pn withs)
       <?> "function clause"
   where
-    optProof = option Nothing (do reserved "proof"
+    optProof = option Nothing (do reservedHL "proof"
                                   n <- fnName
                                   return (Just n))
 
@@ -1058,7 +1211,7 @@
 -}
 whereBlock :: Name -> SyntaxInfo -> IdrisParser ([PDecl], [(Name, Name)])
 whereBlock n syn
-    = do reserved "where"
+    = do reservedHL "where"
          ds <- indentedBlock1 (decl syn)
          let dns = concatMap (concatMap declared) ds
          return (concat ds, map (\x -> (x, decoration syn x)) dns)
@@ -1144,14 +1297,14 @@
                     libs <- sepBy1 (fmap fst stringLiteral) (lchar ',')
                     return [PDirective (DDynamicLibs libs)]
              <|> do try (lchar '%' *> reserved "name")
-                    ty <- fst <$> fnName
-                    ns <- sepBy1 (fst <$> name) (lchar ',')
-                    return [PDirective (DNameHint ty ns)]
+                    (ty, tyFC) <- fnName
+                    ns <- sepBy1 name (lchar ',')
+                    return [PDirective (DNameHint ty tyFC ns)]
              <|> do try (lchar '%' *> reserved "error_handlers")
-                    fn <- fst <$> fnName
-                    arg <- fst <$> fnName
-                    ns <- sepBy1 (fst <$> name) (lchar ',')
-                    return [PDirective (DErrorHandlers fn arg ns) ]
+                    (fn, nfc) <- fnName
+                    (arg, afc) <- fnName
+                    ns <- sepBy1 name (lchar ',')
+                    return [PDirective (DErrorHandlers fn nfc arg afc ns) ]
              <|> do try (lchar '%' *> reserved "language"); ext <- pLangExt;
                     return [PDirective (DLanguage ext)]
              <|> do fc <- getFC
@@ -1174,8 +1327,8 @@
 -}
 totality :: IdrisParser Bool
 totality
-        = do reserved "total";   return True
-      <|> do reserved "partial"; return False
+        = do reservedHL "total";   return True
+      <|> do reservedHL "partial"; return False
 
 {- | Parses a type provider
 
@@ -1186,24 +1339,26 @@
  -}
 provider :: SyntaxInfo -> IdrisParser [PDecl]
 provider syn = do doc <- try (do (doc, _) <- docstring syn
+                                 fc1 <- getFC
                                  lchar '%'
-                                 reserved "provide"
+                                 fc2 <- reservedFC "provide"
+                                 highlightP (spanFC fc1 fc2) AnnKeyword
                                  return doc)
                   provideTerm doc <|> providePostulate doc
                <?> "type provider"
   where provideTerm doc =
-          do lchar '('; n <- fst <$> fnName; lchar ':'; t <- typeExpr syn; lchar ')'
+          do lchar '('; (n, nfc) <- fnName; lchar ':'; t <- typeExpr syn; lchar ')'
              fc <- getFC
-             reserved "with"
+             reservedHL "with"
              e <- expr syn <?> "provider expression"
-             return  [PProvider doc syn fc (ProvTerm t e) n]
+             return  [PProvider doc syn fc nfc (ProvTerm t e) n]
         providePostulate doc =
-          do reserved "postulate"
-             n <- fst <$> fnName
+          do reservedHL "postulate"
+             (n, nfc) <- fnName
              fc <- getFC
-             reserved "with"
+             reservedHL "with"
              e <- expr syn <?> "provider expression"
-             return [PProvider doc syn fc (ProvPostulate e) n]
+             return [PProvider doc syn fc nfc (ProvPostulate e) n]
 
 {- | Parses a transform
 
@@ -1224,7 +1379,23 @@
                    return [PTransform fc False l r]
                 <?> "transform"
 
+{- | Parses a top-level reflected elaborator script
 
+@
+RunElabDecl ::= '%' 'runElab' Expr
+@
+-}
+runElabDecl :: SyntaxInfo -> IdrisParser PDecl
+runElabDecl syn =
+  do kwFC <- try (do fc <- getFC
+                     lchar '%'
+                     fc' <- reservedFC "runElab"
+                     return (spanFC fc fc'))
+     script <- expr syn <?> "elaborator script"
+     highlightP kwFC AnnKeyword
+     return $ PRunElabDecl kwFC script (syn_namespace syn)
+  <?> "top-level elaborator script"
+
 {- * Loading and parsing -}
 {- | Parses an expression from input -}
 parseExpr :: IState -> String -> Result PTerm
@@ -1238,6 +1409,30 @@
 parseTactic :: IState -> String -> Result PTactic
 parseTactic st = runparser (fullTactic defaultSyntax) st "(input)"
 
+{- | Parses a do-step from input (used in the elab shell) -}
+parseElabShellStep :: IState -> String -> Result (Either ElabShellCmd PDo)
+parseElabShellStep ist = runparser (fmap Right (do_ defaultSyntax) <|> fmap Left elabShellCmd) ist "(input)"
+  where elabShellCmd = char ':' >>
+                       (reserved "qed"     >> pure EQED       ) <|>
+                       (reserved "abandon" >> pure EAbandon   ) <|>
+                       (reserved "undo"    >> pure EUndo      ) <|>
+                       (reserved "state"   >> pure EProofState) <|>
+                       (reserved "term"    >> pure EProofTerm ) <|>
+                       (expressionTactic ["e", "eval"] EEval ) <|>
+                       (expressionTactic ["t", "type"] ECheck) <|>
+                       (expressionTactic ["search"] ESearch   ) <|>
+                       (do reserved "doc"
+                           doc <- (Right . fst <$> constant) <|> (Left . fst <$> fnName)
+                           eof
+                           return (EDocStr doc))
+                       <?> "elab command"
+        expressionTactic cmds tactic =
+           do asum (map reserved cmds)
+              t <- spaced (expr defaultSyntax)
+              i <- get
+              return $ tactic (desugar defaultSyntax i t)
+        spaced parser = indentPropHolds gtProp *> parser
+
 -- | Parse module header and imports
 parseImports :: FilePath -> String -> Idris (Maybe (Docstring ()), [String], [ImportInfo], Maybe Delta)
 parseImports fname input
@@ -1271,12 +1466,18 @@
 
 -- | There should be a better way of doing this...
 findFC :: Doc -> (FC, String)
-findFC x = let s = show (plain x) in
-             case span (/= ':') s of
-               (failname, ':':rest) -> case span isDigit rest of
-                 (line, ':':rest') -> case span isDigit rest' of
-                   (col, ':':msg) -> let pos = (read line, read col) in
-                                         (FC failname pos pos, msg)
+findFC x = let s = show (plain x) in findFC' s
+  where findFC' s = case span (/= ':') s of
+                      -- Horrid kludge to prevent crashes on Windows
+                      (prefix, ':':'\\':rest) ->
+                        case findFC' rest of
+                          (NoFC, msg) -> (NoFC, msg)
+                          (FileFC f, msg) -> (FileFC (prefix ++ ":\\" ++ f), msg)
+                          (FC f start end, msg) -> (FC (prefix ++ ":\\" ++ f) start end, msg)
+                      (failname, ':':rest) -> case span isDigit rest of
+                        (line, ':':rest') -> case span isDigit rest' of
+                          (col, ':':msg) -> let pos = (read line, read col) in
+                                                (FC failname pos pos, msg)
 
 -- | Check if the coloring matches the options and corrects if necessary
 fixColour :: Bool -> ANSI.Doc -> ANSI.Doc
@@ -1331,7 +1532,7 @@
         ids <- allImportDirs
         fp <- findImport ids ibcsd file
         if file `elem` imported i
-          then do iLOG $ "Already read " ++ file
+          then do logLvl 1 $ "Already read " ++ file
                   return Nothing
           else do putIState (i { imported = file : imported i })
                   case fp of
@@ -1339,7 +1540,7 @@
                     LIDR fn -> loadSource True  fn Nothing
                     IBC fn src ->
                       idrisCatch (loadIBC True fn)
-                                 (\c -> do iLOG $ fn ++ " failed " ++ pshow i c
+                                 (\c -> do logLvl 1 $ fn ++ " failed " ++ pshow i c
                                            case src of
                                              IDR sfn -> loadSource False sfn Nothing
                                              LIDR sfn -> loadSource True sfn Nothing)
@@ -1348,7 +1549,7 @@
 {- | Load idris code from file -}
 loadFromIFile :: Bool -> IFileType -> Maybe Int -> Idris ()
 loadFromIFile reexp i@(IBC fn src) maxline
-   = do iLOG $ "Skipping " ++ getSrcFile i
+   = do logLvl 1 $ "Skipping " ++ getSrcFile i
         idrisCatch (loadIBC reexp fn)
                 (\err -> ierror $ LoadingFailed fn err)
   where
@@ -1372,7 +1573,7 @@
 {- | Load Idris source code-}
 loadSource :: Bool -> FilePath -> Maybe Int -> Idris ()
 loadSource lidr f toline
-             = do iLOG ("Reading " ++ f)
+             = do logLvl 1 ("Reading " ++ f)
                   i <- getIState
                   let def_total = default_total i
                   file_in <- runIO $ readSource f
@@ -1399,6 +1600,7 @@
                                            sendHighlighting [(nfc, AnnNamespace ns srcFnAbs)])
                         [(re, fn, ns, nfc) | ImportInfo re fn _ ns _ nfc <- imports]
                   reportParserWarnings
+                  sendParserHighlighting
 
                   -- process and check module aliases
                   let modAliases = M.fromList
@@ -1449,6 +1651,7 @@
                                                      ibc_write ist
                                        }
                     _ -> return ()
+                  sendParserHighlighting
 
                   -- Parsing done, now process declarations
 
@@ -1468,17 +1671,20 @@
                   -- simplify every definition do give the totality checker
                   -- a better chance
                   mapM_ (\n -> do logLvl 5 $ "Simplifying " ++ show n
-                                  updateContext (simplifyCasedef n $ getErasureInfo i))
+                                  ctxt' <-
+                                    do ctxt <- getContext
+                                       tclift $ simplifyCasedef n (getErasureInfo i) ctxt
+                                  setContext ctxt')
                            (map snd (idris_totcheck i))
                   -- build size change graph from simplified definitions
-                  iLOG "Totality checking"
+                  logLvl 1 "Totality checking"
                   i <- getIState
                   mapM_ buildSCG (idris_totcheck i)
                   mapM_ checkDeclTotality (idris_totcheck i)
 
                   -- Redo totality check for deferred names
                   let deftots = idris_defertotcheck i
-                  iLOG $ "Totality checking " ++ show deftots
+                  logLvl 1 $ "Totality checking " ++ show deftots
                   mapM_ (\x -> do tot <- getTotality x
                                   case tot of
                                        Total _ -> setTotality x Unchecked
@@ -1486,9 +1692,9 @@
                   mapM_ buildSCG deftots
                   mapM_ checkDeclTotality deftots
 
-                  iLOG ("Finished " ++ f)
+                  logLvl 1 ("Finished " ++ f)
                   ibcsd <- valIBCSubDir i
-                  iLOG "Universe checking"
+                  logLvl 1 "Universe checking"
                   iucheck
                   let ibc = ibcPathNoFallback ibcsd f
                   i <- getIState
@@ -1501,11 +1707,16 @@
                     Just docs -> addModDoc syntax mname docs
 
 
-                  -- Finally, write an ibc if checking was successful
+                  -- Finally, write an ibc and highlights if checking was successful
                   ok <- noErrors
                   when ok $
-                    idrisCatch (do writeIBC f ibc; clearIBC)
-                               (\c -> return ()) -- failure is harmless
+                    do idrisCatch (do writeIBC f ibc; clearIBC)
+                                  (\c -> return ()) -- failure is harmless
+                       hl <- getDumpHighlighting
+                       when hl $
+                         idrisCatch (writeHighlights f)
+                                    (const $ return ()) -- failure is harmless
+                  clearHighlights
                   i <- getIState
                   putIState (i { default_total = def_total,
                                  hide_list = [] })
diff --git a/src/Idris/PartialEval.hs b/src/Idris/PartialEval.hs
--- a/src/Idris/PartialEval.hs
+++ b/src/Idris/PartialEval.hs
@@ -8,6 +8,7 @@
 import Idris.Delaborate
 
 import Idris.Core.TT
+import Idris.Core.CaseTree
 import Idris.Core.Evaluate
 
 import Control.Monad.State
@@ -197,6 +198,7 @@
         dynArgs (_ : ns) (V _     : as) = dynArgs ns as
         dynArgs (_ : ns) (P _ _ _ : as) = dynArgs ns as
         dynArgs _ _ = False -- and now we'll get stuck 
+
 mkNewPats ist d ns newname sname lhs rhs =
     PEDecl lhs rhs (map mkClause d) False
   where 
@@ -204,8 +206,8 @@
     mkClause (oldlhs, oldrhs)
          = let (_, as) = unApply oldlhs 
                lhsargs = mkLHSargs [] ns as
-               lhs = PApp emptyFC (PRef emptyFC newname) lhsargs
-               rhs = PApp emptyFC (PRef emptyFC sname) 
+               lhs = PApp emptyFC (PRef emptyFC [] newname) lhsargs
+               rhs = PApp emptyFC (PRef emptyFC [] sname) 
                                   (mkRHSargs ns lhsargs) in
                      (lhs, rhs)
 
@@ -235,7 +237,7 @@
     mkSubst :: (Term, Term) -> Maybe (Name, Term)
     mkSubst (P _ n _, t) = Just (n, t)
     mkSubst _ = Nothing
-
+        
 -- | Creates a new declaration for a specialised function application.
 -- Simple version at the moment: just create a version which is a direct
 -- application of the function to be specialised.
@@ -243,7 +245,7 @@
 mkPE_TermDecl :: IState -> Name -> Name ->
                  [(PEArgType, Term)] -> PEDecl
 mkPE_TermDecl ist newname sname ns 
-    = let lhs = PApp emptyFC (PRef emptyFC newname) (map pexp (mkp ns)) 
+    = let lhs = PApp emptyFC (PRef emptyFC [] newname) (map pexp (mkp ns)) 
           rhs = eraseImps $ delab ist (mkApp (P Ref sname Erased) (map snd ns)) 
           patdef = lookupCtxtExact sname (idris_patdefs ist)
           newpats = case patdef of
@@ -297,7 +299,8 @@
           case (lookupCtxtExact n (idris_statics ist),
                   lookupCtxtExact n (idris_implicits ist)) of
                (Just statics, Just imps) ->
-                   if (length statics == length args && or statics) then
+                   if (length statics == length args && or statics
+                          && specialisable (tt_ctxt ist) n) then
                       case buildApp env statics imps args [0..] of
                            args -> [(n, args)]
 --                            _ -> []
@@ -307,4 +310,29 @@
     ga env (Bind n t sc) = ga (n : env) sc
     ga env t = []
 
+    -- A function is only specialisable if there are no overlapping
+    -- cases in the case tree (otherwise the partial evaluation could
+    -- easily get stuck)
+    specialisable :: Context -> Name -> Bool
+    specialisable ctxt n = case lookupDefExact n ctxt of
+                                Just (CaseOp _ _ _ _ _ cds) ->
+                                     noOverlap (snd (cases_compiletime cds))
+                                _ -> False
+
+    noOverlap :: SC -> Bool
+    noOverlap (Case _ _ [DefaultCase sc]) = noOverlap sc
+    noOverlap (Case _ _ alts) = noOverlapAlts alts
+    noOverlap _ = True
+
+    -- There's an overlap if the case tree has a default case along with
+    -- some other cases. It's fine if there's a default case on its own.
+    noOverlapAlts (ConCase _ _ _ sc : rest) 
+        = noOverlapAlts rest && noOverlap sc
+    noOverlapAlts (FnCase _ _ sc : rest) = noOverlapAlts rest
+    noOverlapAlts (ConstCase _ sc : rest)
+        = noOverlapAlts rest && noOverlap sc
+    noOverlapAlts (SucCase _ sc : rest)
+        = noOverlapAlts rest && noOverlap sc
+    noOverlapAlts (DefaultCase _ : _) = False
+    noOverlapAlts _ = True
 
diff --git a/src/Idris/ProofSearch.hs b/src/Idris/ProofSearch.hs
--- a/src/Idris/ProofSearch.hs
+++ b/src/Idris/ProofSearch.hs
@@ -1,9 +1,10 @@
 {-# LANGUAGE PatternGuards #-}
 
-module Idris.ProofSearch(trivial, trivialHoles, proofSearch) where
+module Idris.ProofSearch(trivial, trivialHoles, proofSearch, resolveTC) where
 
 import Idris.Core.Elaborate hiding (Tactic(..))
 import Idris.Core.TT
+import Idris.Core.Unify
 import Idris.Core.Evaluate
 import Idris.Core.CaseTree
 import Idris.Core.Typecheck
@@ -22,16 +23,18 @@
 -- Pass in a term elaborator to avoid a cyclic dependency with ElabTerm
 
 trivial :: (PTerm -> ElabD ()) -> IState -> ElabD ()
-trivial = trivialHoles []
+trivial = trivialHoles [] []
 
-trivialHoles :: [(Name, Int)] -> (PTerm -> ElabD ()) -> IState -> ElabD ()
-trivialHoles ok elab ist 
-                 = try' (do elab (PApp (fileFC "prf") (PRef (fileFC "prf") eqCon) [pimp (sUN "A") Placeholder False, pimp (sUN "x") Placeholder False])
-                            return ())
-                        (do env <- get_env
-                            g <- goal
-                            tryAll env
-                            return ()) True
+trivialHoles :: [Name] -> -- user visible names, when working
+                          -- in interactive mode
+                [(Name, Int)] -> (PTerm -> ElabD ()) -> IState -> ElabD ()
+trivialHoles psnames ok elab ist
+     = try' (do elab (PApp (fileFC "prf") (PRef (fileFC "prf") [] eqCon) [pimp (sUN "A") Placeholder False, pimp (sUN "x") Placeholder False])
+                return ())
+            (do env <- get_env
+                g <- goal
+                tryAll env
+                return ()) True
       where
         tryAll []     = fail "No trivial solution"
         tryAll ((x, b):xs)
@@ -41,8 +44,8 @@
                 g <- goal
                 -- anywhere but the top is okay for a hole, if holesOK set
                 if -- all (\n -> not (n `elem` badhs)) (freeNames (binderTy b))
-                   holesOK hs (binderTy b)
-                   then try' (elab (PRef (fileFC "prf") x))
+                   (holesOK hs (binderTy b) && (null psnames || x `elem` psnames))
+                   then try' (elab (PRef (fileFC "prf") [] x))
                              (tryAll xs) True
                    else tryAll xs
         
@@ -60,6 +63,50 @@
            | (n, p) `elem` ok = holeArgsOK hs n (p + 1) as
            | otherwise = holesOK hs a && holeArgsOK hs n (p + 1) as
 
+trivialTCs :: [(Name, Int)] -> (PTerm -> ElabD ()) -> IState -> ElabD ()
+trivialTCs ok elab ist
+     = try' (do elab (PApp (fileFC "prf") (PRef (fileFC "prf") [] eqCon) [pimp (sUN "A") Placeholder False, pimp (sUN "x") Placeholder False])
+                return ())
+            (do env <- get_env
+                g <- goal
+                tryAll env
+                return ()) True
+      where
+        tryAll []     = fail "No trivial solution"
+        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
+                g <- goal
+                env <- get_env
+                -- anywhere but the top is okay for a hole, if holesOK set
+                if -- all (\n -> not (n `elem` badhs)) (freeNames (binderTy b))
+                   (holesOK hs (binderTy b) && tcArg env (binderTy b))
+                   then try' (elab (PRef (fileFC "prf") [] x))
+                             (tryAll xs) True
+                   else tryAll xs
+       
+        tcArg env ty 
+           | (P _ n _, args) <- unApply (getRetTy (normalise (tt_ctxt ist) env ty))
+                 = case lookupCtxtExact n (idris_classes ist) of
+                        Just _ -> True
+                        _ -> False
+           | otherwise = False
+
+        holesOK hs ap@(App _ _ _)
+           | (P _ n _, args) <- unApply ap
+                = holeArgsOK hs n 0 args
+        holesOK hs (App _ f a) = holesOK hs f && holesOK hs a
+        holesOK hs (P _ n _) = not (n `elem` hs)
+        holesOK hs (Bind n b sc) = holesOK hs (binderTy b) && 
+                                   holesOK hs sc
+        holesOK hs _ = True
+
+        holeArgsOK hs n p [] = True
+        holeArgsOK hs n p (a : as)
+           | (n, p) `elem` ok = holeArgsOK hs n (p + 1) as
+           | otherwise = holesOK hs a && holeArgsOK hs n (p + 1) as
+
 cantSolveGoal :: ElabD a
 cantSolveGoal = do g <- goal
                    env <- get_env
@@ -73,9 +120,11 @@
                Bool -> -- ambiguity ok
                Bool -> -- defer on failure
                Int -> -- maximum depth
-               (PTerm -> ElabD ()) -> Maybe Name -> Name -> [Name] ->
+               (PTerm -> ElabD ()) -> Maybe Name -> Name -> 
+               [Name] ->
+               [Name] ->
                IState -> ElabD ()
-proofSearch False fromProver ambigok deferonfail depth elab _ nroot [fn] ist
+proofSearch False fromProver ambigok deferonfail depth elab _ nroot psnames [fn] ist
        = do -- get all possible versions of the name, take the first one that
             -- works
             let all_imps = lookupCtxtName fn (idris_implicits ist)
@@ -106,7 +155,7 @@
 
     isImp (PImp p _ _ _ _) = (True, p)
     isImp arg = (True, priority arg) -- try to get all of them by unification
-proofSearch rec fromProver ambigok deferonfail maxDepth elab fn nroot hints ist 
+proofSearch rec fromProver ambigok deferonfail maxDepth elab fn nroot psnames hints ist 
        = do compute
             ty <- goal
             hs <- get_holes
@@ -149,12 +198,20 @@
                             return $ and (map (notHole hs) (zip as cs))
               Nothing -> fail "Can't happen"
 
+    -- if n is a metavariable, and c is a constructor form, we're not ready
+    -- to run yet
     notHole hs (P _ n _, c)
        | (P _ cn _, _) <- unApply c,
          n `elem` hs && isConName cn (tt_ctxt ist) = False
        | Constant _ <- c = not (n `elem` hs)
+    -- if fa is a metavariable applied to anything, we're not ready to run yet.
+    notHole hs (fa, c)
+       | (P _ fn _, args) <- unApply fa = fn `notElem` hs
     notHole _ _ = True
 
+    inHS hs (P _ n _) = n `elem` hs
+    isHS _ _ = False
+
     toUN t@(P nt (MN i n) ty) 
        | ('_':xs) <- str n = t
        | otherwise = P nt (UN n) ty
@@ -177,7 +234,9 @@
                       ty <- goal
                       when (S.member ty tys) $ fail "Been here before"
                       let tys' = S.insert ty tys
-                      try' (trivial elab ist)
+                      try' (try' (trivialHoles psnames [] elab ist)
+                                 (resolveTC False False 20 ty nroot elab ist)
+                                 True)
                            (try' (try' (resolveByCon (d - 1) locs tys') 
                                        (resolveByLocals (d - 1) locs tys')
                                  True)
@@ -186,10 +245,15 @@
                              then fail "cantSolveGoal"
                              else do attack; defer [] nroot; solve) True) True
 
-    getFn d Nothing = []
-    getFn d (Just f) | d < maxDepth-1 = [f]
+    -- get recursive function name. Only user given names make sense.
+    getFn d (Just f) | d < maxDepth-1 && usersname f = [f]
                      | otherwise = []
+    getFn d _ = []
 
+    usersname (UN _) = True
+    usersname (NS n _) = usersname n
+    usersname _ = False
+
     resolveByCon d locs tys
         = do t <- goal
              let (f, _) = unApply t
@@ -199,11 +263,14 @@
                                            Nothing -> []
                                            Just hs -> hs
                       case lookupCtxtExact n (idris_datatypes ist) of
-                          Just t -> tryCons d locs tys 
-                                                   (hints ++ 
-                                                    con_names t ++ 
-                                                    autohints ++ 
-                                                    getFn d fn)
+                          Just t -> do
+                             let others = hints ++ con_names t ++ autohints
+                             when (not fromProver && length (con_names t) > 1)
+                                   -- in interactive mode,
+                                   -- don't just guess (fine for 'auto',
+                                   -- since that's part of the point...)
+                                   $ checkConstructor ist others
+                             tryCons d locs tys (others ++ getFn d fn)
                           Nothing -> fail "Not a data type"
                 _ -> fail "Not a data type"
 
@@ -215,7 +282,7 @@
 
     tryLocals d locs tys [] = fail "Locals failed"
     tryLocals d locs tys ((x, t) : xs) 
-       | x `elem` locs = tryLocals d locs tys 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
 
@@ -227,7 +294,7 @@
           = do let a = getPArity (delab ist (binderTy t))
                tryLocalArg d locs tys n a
 
-    tryLocalArg d locs tys n 0 = elab (PRef (fileFC "prf") n)
+    tryLocalArg d locs tys n 0 = elab (PRef (fileFC "prf") [] n)
     tryLocalArg d locs tys n i 
         = simple_app False (tryLocalArg d locs tys n (i - 1))
                 (psRec True d locs tys) "proof search local apply"
@@ -245,12 +312,206 @@
             ps' <- get_probs
             hs' <- get_holes
             when (length ps < length ps') $ fail "Can't apply constructor"
+            let newhs = filter (\ (x, y) -> not x) (zip (map fst imps) args)
             mapM_ (\ (_, h) -> do focus h
                                   aty <- goal
-                                  psRec True d locs tys)
-                  (filter (\ (x, y) -> not x) (zip (map fst imps) args))
+                                  psRec True d locs tys) newhs      
             solve
 
     isImp (PImp p _ _ _ _) = (True, p)
     isImp arg = (False, priority arg) 
+
+-- In interactive mode, only search for things if there is some 
+-- index to help pick a relevant constructor
+checkConstructor :: IState -> [Name] -> ElabD ()
+checkConstructor ist [] = return ()
+checkConstructor ist (n : ns) =
+    case lookupTyExact n (tt_ctxt ist) of
+         Just t -> if not (conIndexed t)
+                      then fail "Overlapping constructor types"
+                      else checkConstructor ist ns
+  where
+    conIndexed t = let (_, args) = unApply (getRetTy t) in
+                       any conHead args
+    conHead t | (P _ n _, _) <- unApply t = case lookupDefExact n (tt_ctxt ist) of
+                                                 Just _ -> True
+                                                 _ -> False
+              | otherwise = False
+
+-- | Resolve type classes. This will only pick up 'normal' instances, never
+-- named instances (which is enforced by 'findInstances').
+resolveTC :: Bool -- ^ using default Int
+          -> Bool -- ^ allow metavariables in the goal
+          -> Int -- ^ depth
+          -> Term -- ^ top level goal, for error messages
+          -> Name -- ^ top level function name, to prevent loops
+          -> (PTerm -> ElabD ()) -- ^ top level elaborator
+          -> IState -> ElabD ()
+resolveTC def mvok depth top fn elab ist
+   = do hs <- get_holes
+        resTC' [] def hs depth top fn elab ist
+
+resTC' tcs def topholes 0 topg fn elab ist = fail $ "Can't resolve type class"
+resTC' tcs def topholes 1 topg fn elab ist = try' (trivial elab ist) (resolveTC def False 0 topg fn elab ist) True
+resTC' tcs defaultOn topholes depth topg fn elab ist
+  = do compute
+       g <- goal
+       -- Resolution can proceed only if there is something concrete in the
+       -- determining argument positions. Keep track of the holes in the
+       -- non-determining position, because it's okay for 'trivial' to solve
+       -- those holes and no others.
+       let (argsok, okholePos) = case tcArgsOK g topholes of
+                                    Nothing -> (False, [])
+                                    Just hs -> (True, hs)
+       if not argsok -- && not mvok)
+         then lift $ tfail $ CantResolve True topg
+         else do
+           ptm <- get_term
+           ulog <- getUnifyLog
+           hs <- get_holes
+           env <- get_env
+           t <- goal
+           let (tc, ttypes) = unApply (getRetTy t)
+           let okholes = case tc of
+                              P _ n _ -> zip (repeat n) okholePos
+                              _ -> []
+
+           traceWhen ulog ("Resolving class " ++ show g ++ "\nin" ++ show env ++ "\n" ++ show okholes) $
+            try' (trivialTCs okholes elab ist) 
+                (do addDefault t tc ttypes
+                    let stk = map fst (filter snd $ elab_stack ist)
+                    let insts = findInstances ist t
+                    blunderbuss t depth stk (stk ++ insts)) True
+  where
+    -- returns Just hs if okay, where hs are holes which are okay in the
+    -- goal, or Nothing if not okay to proceed
+    tcArgsOK ty hs | (P _ nc _, as) <- unApply (getRetTy ty), nc == numclass && defaultOn
+       = Just []
+    tcArgsOK ty hs -- if any determining arguments are metavariables, postpone
+       = let (f, as) = unApply (getRetTy ty) in
+             case f of
+                  P _ cn _ -> case lookupCtxtExact cn (idris_classes ist) of
+                                   Just ci -> tcDetArgsOK 0 (class_determiners ci) hs as
+                                   Nothing -> if any (isMeta hs) as
+                                                 then Nothing
+                                                 else Just []
+                  _ -> if any (isMeta hs) as
+                          then Nothing
+                          else Just []
+
+    -- return the list of argument positions which can safely be a hole
+    -- or Nothing if one of the determining arguments is a hole
+    tcDetArgsOK i ds hs (x : xs)
+        | i `elem` ds = if isMeta hs x
+                           then Nothing
+                           else tcDetArgsOK (i + 1) ds hs xs
+        | otherwise = do rs <- tcDetArgsOK (i + 1) ds hs xs
+                         case x of
+                              P _ n _ -> Just (i : rs)
+                              _ -> Just rs
+    tcDetArgsOK _ _ _ [] = Just []
+
+    isMeta :: [Name] -> Term -> Bool
+    isMeta ns (P _ n _) = n `elem` ns 
+    isMeta _ _ = False
+
+    notHole hs (P _ n _, c)
+       | (P _ cn _, _) <- unApply (getRetTy c),
+         n `elem` hs && isConName cn (tt_ctxt ist) = False
+       | Constant _ <- c = not (n `elem` hs)
+    notHole _ _ = True
+
+    -- HACK! Rather than giving a special name, better to have some kind
+    -- of flag in ClassInfo structure
+    chaser (UN nm)
+        | ('@':'@':_) <- str nm = True -- old way
+    chaser (SN (ParentN _ _)) = True
+    chaser (NS n _) = chaser n
+    chaser _ = False
+
+    numclass = sNS (sUN "Num") ["Classes","Prelude"]
+
+    addDefault t num@(P _ nc _) [P Bound a _] | nc == numclass && defaultOn
+        = do focus a
+             fill (RConstant (AType (ATInt ITBig))) -- default Integer
+             solve
+    addDefault t f as
+          | all boundVar as = return () -- True -- fail $ "Can't resolve " ++ show t
+    addDefault t f a = return () -- trace (show t) $ return ()
+
+    boundVar (P Bound _ _) = True
+    boundVar _ = False
+
+    blunderbuss t d stk [] = do -- c <- get_env
+                            -- ps <- get_probs
+                            lift $ tfail $ CantResolve False topg
+    blunderbuss t d stk (n:ns)
+        | n /= fn -- && (n `elem` stk)
+              = tryCatch (resolve n d)
+                    (\e -> case e of
+                             CantResolve True _ -> lift $ tfail e
+                             _ -> blunderbuss t d stk ns)
+        | otherwise = blunderbuss t d stk ns
+
+    introImps = do g <- goal
+                   case g of
+                        (Bind _ (Pi _ _ _) sc) -> do attack; intro Nothing
+                                                     num <- introImps
+                                                     return (num + 1)
+                        _ -> return 0
+
+    solven 0 = return ()
+    solven n = do solve; solven (n - 1)
+
+    resolve n depth
+       | depth == 0 = fail $ "Can't resolve type class"
+       | otherwise
+           = do lams <- introImps
+                t <- goal
+                let (tc, ttypes) = trace (show t) $ unApply (getRetTy t)
+--                 if (all boundVar ttypes) then resolveTC (depth - 1) fn insts ist
+--                   else do
+                   -- if there's a hole in the goal, don't even try
+                let imps = case lookupCtxtName n (idris_implicits ist) of
+                                [] -> []
+                                [args] -> map isImp (snd args) -- won't be overloaded!
+                                xs -> error "The impossible happened - overloading is not expected here!"
+                ps <- get_probs
+                tm <- get_term
+                args <- map snd <$> apply (Var n) imps
+                solven lams -- close any implicit lambdas we introduced
+                ps' <- get_probs
+                when (length ps < length ps' || unrecoverable ps') $
+                     fail "Can't apply type class"
+--                 traceWhen (all boundVar ttypes) ("Progress: " ++ show t ++ " with " ++ show n) $
+                mapM_ (\ (_,n) -> do focus n
+                                     t' <- goal
+                                     let (tc', ttype) = unApply (getRetTy t')
+                                     let got = fst (unApply (getRetTy t))
+                                     let depth' = if tc' `elem` tcs
+                                                     then depth - 1 else depth
+                                     resTC' (got : tcs) defaultOn topholes depth' topg fn elab ist)
+                      (filter (\ (x, y) -> not x) (zip (map fst imps) args))
+                -- if there's any arguments left, we've failed to resolve
+                hs <- get_holes
+                ulog <- getUnifyLog
+                solve
+                traceWhen ulog ("Got " ++ show n) $ return ()
+       where isImp (PImp p _ _ _ _) = (True, p)
+             isImp arg = (False, priority arg)
+
+-- | Find the names of instances that have been designeated for
+-- searching (i.e. non-named instances or instances from Elab scripts)
+findInstances :: IState -> Term -> [Name]
+findInstances ist t
+    | (P _ n _, _) <- unApply (getRetTy t)
+        = case lookupCtxt n (idris_classes ist) of
+            [CI _ _ _ _ _ ins _] ->
+              [n | (n, True) <- ins, accessible n]
+            _ -> []
+    | otherwise = []
+  where accessible n = case lookupDefAccExact n False (tt_ctxt ist) of
+                            Just (_, Hidden) -> False
+                            _ -> True
+
 
diff --git a/src/Idris/Prover.hs b/src/Idris/Prover.hs
--- a/src/Idris/Prover.hs
+++ b/src/Idris/Prover.hs
@@ -1,6 +1,14 @@
 {-# LANGUAGE PatternGuards #-}
-module Idris.Prover where
+module Idris.Prover (prover, showProof, showRunElab) where
 
+-- Hack for GHC 7.10 and earlier compat without CPP or warnings
+-- This exludes (<$>) as fmap, because wl-pprint uses it for newline
+import Prelude (Eq(..), Show(..),
+                Bool(..), Either(..), Maybe(..), String,
+                (.), ($), (++), (||),
+                concatMap, id, elem, error, fst, flip, foldl, foldr, init,
+                length, lines, map, not, null, repeat, reverse, tail, zip)
+
 import Idris.Core.Elaborate hiding (Tactic(..))
 import Idris.Core.TT
 import Idris.Core.Evaluate
@@ -35,15 +43,16 @@
 import Util.Pretty
 import Debug.Trace
 
-prover :: Bool -> Name -> Idris ()
-prover lit x =
+-- | Launch the proof shell
+prover :: Bool -> Bool -> Name -> Idris ()
+prover mode lit x =
            do ctxt <- getContext
               i <- getIState
               case lookupTy x ctxt of
                   [t] -> if elem x (map fst (idris_metavars i))
-                               then prove (idris_optimisation i) ctxt lit x t
-                               else ifail $ show x ++ " is not a metavariable"
-                  _ -> fail "No such metavariable"
+                               then prove mode (idris_optimisation i) ctxt lit x t
+                               else ifail $ show x ++ " is not a hole"
+                  _ -> fail "No such hole"
 
 showProof :: Bool -> Name -> [String] -> String
 showProof lit n ps
@@ -53,6 +62,15 @@
   where bird = if lit then "> " else ""
         break = "\n" ++ bird
 
+showRunElab :: Bool -> Name -> [String] -> String
+showRunElab lit n ps = birdify (displayS (renderPretty 1.0 80 doc) "")
+  where doc = text (show n) <+> text "=" <+> text "%runElab" <+>
+              enclose lparen rparen
+                (text "do" <+> (align $ vsep (map text ps)))
+        birdify = if lit
+                     then concatMap ("> " ++) . lines
+                     else id
+
 proverSettings :: ElabState EState -> Settings Idris
 proverSettings e = setComplete (proverCompletion (assumptionNames e)) defaultSettings
 
@@ -64,18 +82,24 @@
         names ((MN _ _, _) : bs) = names bs
         names ((n, _) : bs) = show n : names bs
 
-prove :: Ctxt OptInfo -> Context -> Bool -> Name -> Type -> Idris ()
-prove opt ctxt lit n ty
+prove :: Bool -> Ctxt OptInfo -> Context -> Bool -> Name -> Type -> Idris ()
+prove mode opt ctxt lit n ty
     = do ps <- fmap (\ist -> initElaborator n ctxt (idris_datatypes ist) ty) getIState
          idemodePutSExp "start-proof-mode" n
-         (tm, prf) <- ploop n True ("-" ++ show n) [] (ES (ps, initEState) "" Nothing) Nothing
-         iLOG $ "Adding " ++ show tm
+         (tm, prf) <-
+            if mode
+              then elabloop n True ("-" ++ show n) [] (ES (ps, initEState) "" Nothing) [] Nothing []
+              else ploop n True ("-" ++ show n) [] (ES (ps, initEState) "" Nothing) Nothing
+         logLvl 1 $ "Adding " ++ show tm
          i <- getIState
+         let shower = if mode
+                         then showRunElab
+                         else showProof
          case idris_outputmode i of
-           IdeMode _ _ -> idemodePutSExp "end-proof-mode" (n, showProof lit n prf)
-           _            -> iputStrLn $ showProof lit n prf
+           IdeMode _ _ -> idemodePutSExp "end-proof-mode" (n, shower lit n prf)
+           _            -> iputStrLn $ shower lit n prf
          let proofs = proof_list i
-         putIState (i { proof_list = (n, prf) : proofs })
+         putIState (i { proof_list = (n, (mode, prf)) : proofs })
          let tree = simpleCase False (STerm Erased) False CompileTime (fileFC "proof") [] [] [([], P Ref n ty, tm)]
          logLvl 3 (show tree)
          (ptm, pty) <- recheckC (fileFC "proof") id [] tm
@@ -86,13 +110,16 @@
               Error e -> ierror (CantUnify False (ty, Nothing) (pty, Nothing) e [] 0)
          ptm' <- applyOpts ptm
          ei <- getErasureInfo `fmap` getIState
-         updateContext (addCasedef n ei (CaseInfo True True False) False (STerm Erased) True False
-                                 [] []  -- argtys, inaccArgs
-                                 [Right (P Ref n ty, ptm)]
-                                 [([], P Ref n ty, ptm)]
-                                 [([], P Ref n ty, ptm)]
-                                 [([], P Ref n ty, ptm)]
-                                 [([], P Ref n ty, ptm')] ty)
+         ctxt' <- do ctxt <- getContext
+                     tclift $ addCasedef n ei (CaseInfo True True False) False (STerm Erased) True False
+                                [] []  -- argtys, inaccArgs
+                                [Right (P Ref n ty, ptm)]
+                                [([], P Ref n ty, ptm)]
+                                [([], P Ref n ty, ptm)]
+                                [([], P Ref n ty, ptm)]
+                                [([], P Ref n ty, ptm')] ty
+                                ctxt
+         setContext ctxt'
          solveDeferred n
          case idris_outputmode i of
            IdeMode n h ->
@@ -114,16 +141,17 @@
                                   return res
                          ((_,_,_,_,e,_,_):_) -> lift $ Error e
 
-dumpState :: IState -> ProofState -> Idris ()
-dumpState ist ps | [] <- holes ps =
+dumpState :: IState -> [(Name, Type, Term)] -> ProofState -> Idris ()
+dumpState ist menv ps | [] <- holes ps =
   do let nm = thname ps
      rendered <- iRender $ prettyName True False [] nm <> colon <+> text "No more goals."
      iputGoal rendered
-dumpState ist ps | (h : hs) <- holes ps = do
+dumpState ist menv ps | (h : hs) <- holes ps = do
   let OK ty  = goalAtFocus ps
   let OK env = envAtFocus ps
   let state = prettyOtherGoals hs <> line <>
-              prettyAssumptions env <> line <>
+              prettyAssumptions ty env <> line <>
+              prettyMetaValues (reverse menv) <>
               prettyGoal (zip (assumptionNames env) (repeat False)) ty
   rendered <- iRender state
   iputGoal rendered
@@ -140,19 +168,37 @@
     assumptionNames :: Env -> [Name]
     assumptionNames = map fst
 
-    prettyPs :: [(Name, Bool)] -> Env -> Doc OutputAnnotation
-    prettyPs bnd [] = empty
-    prettyPs bnd ((n@(MN _ r), _) : bs)
-        | r == txt "rewrite_rule" = prettyPs ((n, False):bnd) bs
-    prettyPs bnd ((n@(MN _ _), _) : bs)
-        | not (n `elem` freeEnvNames bs) = prettyPs bnd bs
-    prettyPs bnd ((n, Let t v) : bs) =
+    prettyPs :: Binder Type -> [(Name, Bool)] -> Env -> Doc OutputAnnotation
+    prettyPs g bnd [] = empty
+    prettyPs g bnd ((n@(MN _ r), _) : bs)
+        | r == txt "rewrite_rule" = prettyPs g ((n, False):bnd) bs
+    prettyPs g bnd ((n@(MN _ _), _) : bs)
+        | not (n `elem` freeEnvNames bs || n `elem` goalNames g) = prettyPs g bnd bs
+    prettyPs g bnd ((n, Let t v) : bs) =
       line <> bindingOf n False <+> text "=" <+> tPretty bnd v <+> colon <+>
-        align (tPretty bnd t) <> prettyPs ((n, False):bnd) bs
-    prettyPs bnd ((n, b) : bs) =
+        align (tPretty bnd t) <> prettyPs g ((n, False):bnd) bs
+    prettyPs g bnd ((n, b) : bs) =
       line <> bindingOf n False <+> colon <+>
-      align (tPretty bnd (binderTy b)) <> prettyPs ((n, False):bnd) bs
+      align (tPretty bnd (binderTy b)) <> prettyPs g ((n, False):bnd) bs
 
+    prettyMetaValues [] = empty
+    prettyMetaValues mvs =
+      text "----------              Meta-values:               ----------" <$$>
+      prettyMetaValues' [] mvs <> line <> line
+    prettyMetaValues' _   [] = empty
+    prettyMetaValues' bnd [mv] = ppMv bnd mv
+    prettyMetaValues' bnd ((mv@(n, ty, tm)) : mvs) =
+      ppMv bnd mv <$>
+      prettyMetaValues' ((n, False):bnd) mvs
+
+    ppMv bnd (n, ty, tm) = kwd "let" <+> bindingOf n False <+> colon <+>
+                           tPretty bnd ty <+> text "=" <+> tPretty bnd tm
+
+    kwd = annotate AnnKeyword . text
+
+    goalNames (Guess t v) = freeNames t ++ freeNames v
+    goalNames b = freeNames (binderTy b)
+
     prettyG bnd (Guess t v) = tPretty bnd t <+> text "=?=" <+> tPretty bnd v
     prettyG bnd b = tPretty bnd $ binderTy b
 
@@ -160,12 +206,12 @@
       text "----------                 Goal:                  ----------" <$$>
       bindingOf h False <+> colon <+> align (prettyG bnd ty)
 
-    prettyAssumptions env =
+    prettyAssumptions g env =
       if length env == 0 then
         empty
       else
         text "----------              Assumptions:              ----------" <>
-        nest nestingSize (prettyPs [] $ reverse env)
+        nest nestingSize (prettyPs g [] $ reverse env)
 
     prettyOtherGoals hs =
       if length hs == 0 then
@@ -205,11 +251,141 @@
        Just (IdeMode.DocsFor str _) -> return (Just (":doc " ++ str))
        _ -> return Nothing
 
+data ElabShellHistory = ElabStep | LetStep | BothStep
+
+undoStep :: [String] -> [(Name, Type, Term)] -> ElabState EState -> ElabShellHistory -> Idris ([String], [(Name, Type, Term)], ElabState EState)
+undoStep prf env st ElabStep = do (_, st') <- elabStep st loadState
+                                  return (init prf, env, st')
+undoStep prf env st LetStep = return (init prf, tail env, st)
+undoStep prf env st BothStep = do (_, st') <- elabStep st loadState
+                                  return (init prf, tail env, st')
+
+undoElab :: [String] -> [(Name, Type, Term)] -> ElabState EState -> [ElabShellHistory] -> Idris ([String], [(Name, Type, Term)], ElabState EState, [ElabShellHistory])
+undoElab prf env st [] = ifail "Nothing to undo"
+undoElab prf env st (h:hs) = do (prf', env', st') <- undoStep prf env st h
+                                return (prf', env', st', hs)
+
+elabloop :: Name -> Bool -> String -> [String] -> ElabState EState -> [ElabShellHistory] -> Maybe History -> [(Name, Type, Term)] -> Idris (Term, [String])
+elabloop fn d prompt prf e prev h env
+  = do ist <- getIState
+       when d $ dumpState ist env (proof e)
+       (x, h') <-
+         case idris_outputmode ist of
+           RawOutput _ ->
+             runInputT (proverSettings e) $
+               do case h of
+                    Just history -> putHistory history
+                    Nothing -> return ()
+                  l <- getInputLine (prompt ++ "> ")
+                  h' <- getHistory
+                  return (l, Just h')
+           IdeMode _ handle ->
+             do isetPrompt prompt
+                i <- receiveInput handle e
+                return (i, h)
+       (cmd, step) <- case x of
+                        Nothing -> do iPrintError "" ; ifail "Abandoned"
+                        Just input -> return (parseElabShellStep ist input, input)
+
+       -- if we're abandoning, it has to be outside the scope of the catch
+       case cmd of
+         Success (Left EAbandon) -> do iPrintError ""; ifail "Abandoned"
+         _ -> return ()
+
+       (d, prev', st, done, prf', env', res) <-
+         idrisCatch
+           (case cmd of
+              Failure err ->
+                return (False, prev, e, False, prf, env, Left . Msg . show . fixColour (idris_colourRepl ist) $ err)
+              Success (Left cmd') ->
+                case cmd' of
+                  EQED -> do hs <- lifte e get_holes
+                             when (not (null hs)) $ ifail "Incomplete proof"
+                             iputStrLn "Proof completed!"
+                             return (False, prev, e, True, prf, env, Right $ iPrintResult "")
+                  EUndo -> do (prf', env', st', prev') <- undoElab prf env e prev
+                              return (True, prev', st', False, prf', env', Right $ iPrintResult "")
+                  EAbandon ->
+                    error "the impossible happened - should have been matched on outer scope"
+                  EProofState -> return (True, prev, e, False, prf, env, Right $ iPrintResult "")
+                  EProofTerm ->
+                    do tm <- lifte e get_term
+                       return (False, prev, e, False, prf, env, Right $ iRenderResult (text "TT:" <+> pprintTT [] tm))
+                  EEval tm -> do (d', st', done, prf', go) <- evalTerm e prf tm
+                                 return (d', prev, st', done, prf', env, go)
+                  ECheck (PRef _ _ n) ->
+                    do (d', st', done, prf', go) <- checkNameType e prf n
+                       return (d', prev, st', done, prf', env, go)
+                  ECheck tm -> do (d', st', done, prf', go) <- checkType e prf tm
+                                  return (d', prev, st', done, prf', env, go)
+                  ESearch ty -> do (d', st', done, prf', go) <- search e prf ty
+                                   return (d', prev, st', done, prf', env, go)
+                  EDocStr d -> do (d', st', done, prf', go) <- docStr e prf d
+                                  return (d', prev, st', done, prf', env, go)
+              Success (Right cmd') ->
+                case cmd' of
+                  DoLetP _ _ _ -> ifail "Pattern-matching let not supported here"
+                  DoBindP _ _ _ _ -> ifail "Pattern-matching <- not supported here"
+                  DoLet fc i ifc Placeholder expr ->
+                    do (tm, ty) <- elabVal recinfo ERHS (inLets ist env expr)
+                       ctxt <- getContext
+                       let tm' = normaliseAll ctxt [] tm
+                           ty' = normaliseAll ctxt [] ty
+                       return (True, LetStep:prev, e, False, prf ++ [step], (i, ty', tm' ) : env, Right (iPrintResult ""))
+                  DoLet fc i ifc ty expr ->
+                    do (tm, ty) <- elabVal recinfo ERHS
+                                     (PApp NoFC (PRef NoFC [] (sUN "the"))
+                                                [ pexp (inLets ist env ty)
+                                                , pexp (inLets ist env expr)
+                                                ])
+                       ctxt <- getContext
+                       let tm' = normaliseAll ctxt [] tm
+                           ty' = normaliseAll ctxt [] ty
+                       return (True, LetStep:prev, e, False, prf ++ [step], (i, ty', tm' ) : env, Right (iPrintResult ""))
+                  DoBind fc i ifc expr ->
+                    do (tm, ty) <- elabVal recinfo ERHS (inLets ist env expr)
+                       (_, e') <- elabStep e saveState -- enable :undo
+                       (res, e'') <- elabStep e' $
+                                       runElabAction ist NoFC [] tm ["Shell"]
+                       ctxt <- getContext
+                       (v, vty) <- tclift $ check ctxt [] (forget res)
+                       let v'   = normaliseAll ctxt [] v
+                           vty' = normaliseAll ctxt [] vty
+                       return (True, BothStep:prev, e'', False, prf ++ [step], (i, vty', v') : env, Right (iPrintResult ""))
+                  DoExp fc expr ->
+                    do (tm, ty) <- elabVal recinfo ERHS (inLets ist env expr)
+                       -- TODO: call elaborator with Elab () as goal here
+                       (_, e') <- elabStep e saveState -- enable :undo
+                       (_, e'') <- elabStep e' $
+                                     runElabAction ist NoFC [] tm ["Shell"]
+                       return (True, ElabStep:prev, e'', False, prf ++ [step], env, Right (iPrintResult "")))
+           (\err -> return (False, prev, e, False, prf, env, Left err))
+       idemodePutSExp "write-proof-state" (prf', length prf')
+       case res of
+         Left err -> do ist <- getIState
+                        iRenderError $ pprintErr ist err
+                        elabloop fn d prompt prf' st prev' h' env'
+         Right ok ->
+           if done then do (tm, _) <- elabStep st get_term
+                           return (tm, prf')
+                   else do ok
+                           elabloop fn d prompt prf' st prev' h' env'
+
+  where 
+    -- A bit of a hack: wrap the value up in a let binding, which will
+    -- normalise away. It would be better to figure out how to call
+    -- the elaborator with a custom environment here to avoid the
+    -- delab step.
+    inLets :: IState -> [(Name, Type, Term)] -> PTerm -> PTerm
+    inLets ist lets tm = foldr (\(n, ty, v) b -> PLet NoFC n NoFC (delab ist ty) (delab ist v) b) tm (reverse lets)
+
+
+
 ploop :: Name -> Bool -> String -> [String] -> ElabState EState -> Maybe History -> Idris (Term, [String])
 ploop fn d prompt prf e h
     = do i <- getIState
          let autoSolve = opt_autoSolve (idris_options i)
-         when d $ dumpState i (proof e)
+         when d $ dumpState i [] (proof e)
          (x, h') <-
            case idris_outputmode i of
              RawOutput _ ->
@@ -244,11 +420,11 @@
                                 when (not (null hs)) $ ifail "Incomplete proof"
                                 iputStrLn "Proof completed!"
                                 return (False, e, True, prf, Right $ iPrintResult "")
-              Success (TCheck (PRef _ n)) -> checkNameType n
-              Success (TCheck t) -> checkType t
-              Success (TEval t)  -> evalTerm t e
-              Success (TDocStr x) -> docStr x
-              Success (TSearch t) -> search t
+              Success (TCheck (PRef _ _ n)) -> checkNameType e prf n
+              Success (TCheck t) -> checkType e prf t
+              Success (TEval t)  -> evalTerm e prf t
+              Success (TDocStr x) -> docStr e prf x
+              Success (TSearch t) -> search e prf t
               Success tac ->
                 do (_, e) <- elabStep e saveState
                    (_, st) <- elabStep e (runTac autoSolve i (Just proverFC) fn tac)
@@ -264,80 +440,87 @@
                              return (tm, prf')
                      else do ok
                              ploop fn d prompt prf' st h'
-  where envCtxt env ctxt = foldl (\c (n, b) -> addTyDecl n Bound (binderTy b) c) ctxt env
-        checkNameType n = do
-          ctxt <- getContext
-          ist <- getIState
-          imp <- impShow
-          idrisCatch (do
-              let OK env = envAtFocus (proof e)
-                  ctxt'  = envCtxt env ctxt
-                  bnd    = map (\x -> (fst x, False)) env
-                  ist'   = ist { tt_ctxt = ctxt' }
-              putIState ist'
-              -- Unlike the REPL, metavars have no special treatment, to
-              -- make it easier to see how to prove with them.
-              let action = case lookupNames n ctxt' of
-                             [] -> iPrintError $ "No such variable " ++ show n
-                             ts -> iPrintFunTypes bnd n (map (\n -> (n, pprintDelabTy ist' n)) ts)
-              putIState ist
-              return (False, e, False, prf, Right action))
-            (\err -> do putIState ist ; ierror err)
 
-        checkType t = do
-          ist <- getIState
-          ctxt <- getContext
-          idrisCatch (do
-              let OK env = envAtFocus (proof e)
-                  ctxt'  = envCtxt env ctxt
-              putIState ist { tt_ctxt = ctxt' }
-              (tm, ty) <- elabVal recinfo ERHS t
-              let ppo = ppOptionIst ist
-                  ty'     = normaliseC ctxt [] ty
-                  infixes = idris_infixes ist
-                  action = case tm of
-                    TType _ ->
-                      iPrintTermWithType (prettyImp ppo (PType emptyFC)) type1Doc
-                    _ -> let bnd = map (\x -> (fst x, False)) env in
-                         iPrintTermWithType (pprintPTerm ppo bnd [] infixes (delab ist tm))
-                                             (pprintPTerm ppo bnd [] infixes (delab ist ty))
-              putIState ist
-              return (False, e, False, prf, Right action))
-            (\err -> do putIState ist { tt_ctxt = ctxt } ; ierror err)
 
-        proverFC = FC "(prover shell)" (0, 0) (0, 0)
+envCtxt env ctxt = foldl (\c (n, b) -> addTyDecl n Bound (binderTy b) c) ctxt env
 
-        evalTerm t e = withErrorReflection $
-          do ctxt <- getContext
-             ist <- getIState
-             idrisCatch (do
-               let OK env = envAtFocus (proof e)
-                   ctxt'  = envCtxt env ctxt
-                   ist'   = ist { tt_ctxt = ctxt' }
-                   bnd    = map (\x -> (fst x, False)) env
-               putIState ist'
-               (tm, ty) <- elabVal recinfo ERHS t
-               let tm'     = force (normaliseAll ctxt' env tm)
-                   ty'     = force (normaliseAll ctxt' env ty)
-                   ppo     = ppOption (idris_options ist')
-                   infixes = idris_infixes ist
-                   tmDoc   = pprintPTerm ppo bnd [] infixes (delab ist' tm')
-                   tyDoc   = pprintPTerm ppo bnd [] infixes (delab ist' ty')
-                   action  = iPrintTermWithType tmDoc tyDoc
-               putIState ist
-               return (False, e, False, prf, Right action))
-              (\err -> do putIState ist ; ierror err)
-        docStr :: Either Name Const -> Idris (Bool, ElabState EState, Bool, [String], Either Err (Idris ()))
-        docStr (Left n) = do ist <- getIState
-                             idrisCatch (case lookupCtxtName n (idris_docstrings ist) of
-                                           [] -> return (False, e, False, prf,
-                                                         Left . Msg $ "No documentation for " ++ show n)
-                                           ns -> do toShow <- mapM (showDoc ist) ns
-                                                    return (False,  e, False, prf,
-                                                            Right $ iRenderResult (vsep toShow)))
-                                        (\err -> do putIState ist ; ierror err)
-               where showDoc ist (n, d) = do doc <- getDocs n FullDocs
-                                             return $ pprintDocs ist doc
-        docStr (Right c) = do ist <- getIState
-                              return (False, e, False, prf, Right . iRenderResult $ pprintConstDocs ist c (constDocs c))
-        search t = return (False, e, False, prf, Right $ searchByType [] t)
+checkNameType :: ElabState EState -> [String] -> Name -> Idris (Bool, ElabState EState, Bool, [String], Either Err (Idris ()))
+checkNameType e prf n = do
+    ctxt <- getContext
+    ist <- getIState
+    imp <- impShow
+    idrisCatch (do
+        let OK env = envAtFocus (proof e)
+            ctxt'  = envCtxt env ctxt
+            bnd    = map (\x -> (fst x, False)) env
+            ist'   = ist { tt_ctxt = ctxt' }
+        putIState ist'
+        -- Unlike the REPL, metavars have no special treatment, to
+        -- make it easier to see how to prove with them.
+        let action = case lookupNames n ctxt' of
+                       [] -> iPrintError $ "No such variable " ++ show n
+                       ts -> iPrintFunTypes bnd n (map (\n -> (n, pprintDelabTy ist' n)) ts)
+        putIState ist
+        return (False, e, False, prf, Right action))
+      (\err -> do putIState ist ; ierror err)
+
+checkType :: ElabState EState -> [String] -> PTerm -> Idris (Bool, ElabState EState, Bool, [String], Either Err (Idris ()))
+checkType e prf t = do
+    ist <- getIState
+    ctxt <- getContext
+    idrisCatch (do
+        let OK env = envAtFocus (proof e)
+            ctxt'  = envCtxt env ctxt
+        putIState ist { tt_ctxt = ctxt' }
+        (tm, ty) <- elabVal recinfo ERHS t
+        let ppo = ppOptionIst ist
+            ty'     = normaliseC ctxt [] ty
+            infixes = idris_infixes ist
+            action = case tm of
+              TType _ ->
+                iPrintTermWithType (prettyImp ppo (PType emptyFC)) type1Doc
+              _ -> let bnd = map (\x -> (fst x, False)) env in
+                   iPrintTermWithType (pprintPTerm ppo bnd [] infixes (delab ist tm))
+                                       (pprintPTerm ppo bnd [] infixes (delab ist ty))
+        putIState ist
+        return (False, e, False, prf, Right action))
+      (\err -> do putIState ist { tt_ctxt = ctxt } ; ierror err)
+
+proverFC = FC "(prover shell)" (0, 0) (0, 0)
+
+evalTerm :: ElabState EState -> [String] -> PTerm -> Idris (Bool, ElabState EState, Bool, [String], Either Err (Idris ()))
+evalTerm e prf t = withErrorReflection $
+    do ctxt <- getContext
+       ist <- getIState
+       idrisCatch (do
+         let OK env = envAtFocus (proof e)
+             ctxt'  = envCtxt env ctxt
+             ist'   = ist { tt_ctxt = ctxt' }
+             bnd    = map (\x -> (fst x, False)) env
+         putIState ist'
+         (tm, ty) <- elabVal recinfo ERHS t
+         let tm'     = force (normaliseAll ctxt' env tm)
+             ty'     = force (normaliseAll ctxt' env ty)
+             ppo     = ppOption (idris_options ist')
+             infixes = idris_infixes ist
+             tmDoc   = pprintPTerm ppo bnd [] infixes (delab ist' tm')
+             tyDoc   = pprintPTerm ppo bnd [] infixes (delab ist' ty')
+             action  = iPrintTermWithType tmDoc tyDoc
+         putIState ist
+         return (False, e, False, prf, Right action))
+        (\err -> do putIState ist ; ierror err)
+
+docStr :: ElabState EState -> [String] -> Either Name Const -> Idris (Bool, ElabState EState, Bool, [String], Either Err (Idris ()))
+docStr e prf (Left n) = do ist <- getIState
+                           idrisCatch (case lookupCtxtName n (idris_docstrings ist) of
+                                         [] -> return (False, e, False, prf,
+                                                       Left . Msg $ "No documentation for " ++ show n)
+                                         ns -> do toShow <- mapM (showDoc ist) ns
+                                                  return (False,  e, False, prf,
+                                                          Right $ iRenderResult (vsep toShow)))
+                                      (\err -> do putIState ist ; ierror err)
+         where showDoc ist (n, d) = do doc <- getDocs n FullDocs
+                                       return $ pprintDocs ist doc
+docStr e prf (Right c) = do ist <- getIState
+                            return (False, e, False, prf, Right . iRenderResult $ pprintConstDocs ist c (constDocs c))
+search e prf t = return (False, e, False, prf, Right $ searchByType [] t)
diff --git a/src/Idris/Providers.hs b/src/Idris/Providers.hs
--- a/src/Idris/Providers.hs
+++ b/src/Idris/Providers.hs
@@ -10,7 +10,7 @@
 -- | Wrap a type provider in the type of type providers
 providerTy :: FC -> PTerm -> PTerm
 providerTy fc tm
-  = PApp fc (PRef fc $ sNS (sUN "Provider" ) ["Providers", "Prelude"]) [PExp 0 [] (sMN 0 "pvarg") tm]
+  = PApp fc (PRef fc [] $ sNS (sUN "Provider" ) ["Providers", "Prelude"]) [PExp 0 [] (sMN 0 "pvarg") tm]
 
 ioret :: Name
 ioret = sUN "prim_io_return"
diff --git a/src/Idris/REPL.hs b/src/Idris/REPL.hs
--- a/src/Idris/REPL.hs
+++ b/src/Idris/REPL.hs
@@ -1,7 +1,9 @@
 {-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, DeriveFunctor,
              PatternGuards, CPP #-}
 
-module Idris.REPL where
+module Idris.REPL(getClient, getPkg, getPkgCheck, getPkgClean, getPkgMkDoc,
+                  getPkgREPL, getPkgTest, getPort, idris, idrisMain, loadInputs,
+                  opt, runClient, runMain, ver) where
 
 import Idris.AbsSyntax
 import Idris.ASTUtils
@@ -52,6 +54,7 @@
 import Idris.Core.Execute (execute)
 import Idris.Core.TT
 import Idris.Core.Unify
+import Idris.Core.WHNF
 import Idris.Core.Constraints
 
 import IRTS.Compiler
@@ -68,10 +71,6 @@
 
 import Text.Trifecta.Result(Result(..))
 
--- import RTS.SC
--- import RTS.Bytecode
--- import RTS.PreC
--- import RTS.CodegenC
 import System.Console.Haskeline as H
 import System.FilePath
 import System.Exit
@@ -115,7 +114,9 @@
                         then ""
                         else showMVs colour theme mvs ++
                              let str = mkPrompt mods ++ ">" in
-                             (if colour then colourisePrompt theme str else str) ++ " "
+                             (if colour && not isWindows
+                                then colourisePrompt theme str
+                                else str) ++ " "
         x <- H.catch (getInputLine prompt)
                      (ctrlC (return Nothing))
         case x of
@@ -137,7 +138,7 @@
                           act -- repl orig mods
 
          showMVs c thm [] = ""
-         showMVs c thm ms = "Metavariables: " ++
+         showMVs c thm ms = "Holes: " ++
                                  show' 4 c thm (map fst ms) ++ "\n"
 
          show' 0 c thm ms = let l = length ms in
@@ -296,9 +297,9 @@
      i <- getIState
      case parseCmd i "(input)" cmd of
        Failure err -> iPrintError $ show (fixColour False err)
-       Success (Right (Prove n')) ->
+       Success (Right (Prove mode n')) ->
          idrisCatch
-           (do process fn (Prove n')
+           (do process fn (Prove mode n')
                isetPrompt (mkPrompt mods)
                case idris_outputmode i of
                  IdeMode n h -> -- signal completion of proof to ide
@@ -347,7 +348,7 @@
   case splitName name of
     Left err -> iPrintError err
     Right n -> process "(idemode)"
-                 (Check (PRef (FC "(idemode)" (0,0) (0,0)) n))
+                 (Check (PRef (FC "(idemode)" (0,0) (0,0)) [] n))
 runIdeModeCommand h id orig fn mods (IdeMode.DocsFor name w) =
   case parseConst orig name of
     Success c -> process "(idemode)" (DocStr (Right c) (howMuch w))
@@ -367,6 +368,8 @@
   process fn (AddMissing False line (sUN name))
 runIdeModeCommand h id orig fn mods (IdeMode.MakeWithBlock line name) =
   process fn (MakeWith False line (sUN name))
+runIdeModeCommand h id orig fn mods (IdeMode.MakeCaseBlock line name) =
+  process fn (MakeCase False line (sUN name))
 runIdeModeCommand h id orig fn mods (IdeMode.ProofSearch r line name hints depth) =
   doProofSearch fn False r line (sUN name) (map sUN hints) depth
 runIdeModeCommand h id orig fn mods (IdeMode.MakeLemma line name) =
@@ -496,7 +499,7 @@
 runIdeModeCommand h id orig fn modes (IdeMode.TermNormalise bnd tm) =
   do ctxt <- getContext
      ist <- getIState
-     let tm' = force (normaliseAll ctxt [] tm)
+     let tm' = normaliseAll ctxt [] tm
          ptm = annotate (AnnTerm bnd tm')
                (pprintPTerm (ppOptionIst ist)
                             bnd
@@ -573,15 +576,17 @@
 idemodeProcess :: FilePath -> Command -> Idris ()
 idemodeProcess fn Warranty = process fn Warranty
 idemodeProcess fn Help = process fn Help
-idemodeProcess fn (ChangeDirectory f) = do process fn (ChangeDirectory f)
-                                           iPrintResult "changed directory to"
+idemodeProcess fn (ChangeDirectory f) =
+  do process fn (ChangeDirectory f)
+     dir <- runIO $ getCurrentDirectory
+     iPrintResult $ "changed directory to " ++ dir
 idemodeProcess fn (ModImport f) = process fn (ModImport f)
 idemodeProcess fn (Eval t) = process fn (Eval t)
 idemodeProcess fn (NewDefn decls) = do process fn (NewDefn decls)
                                        iPrintResult "defined"
 idemodeProcess fn (Undefine n) = process fn (Undefine n)
 idemodeProcess fn (ExecVal t) = process fn (ExecVal t)
-idemodeProcess fn (Check (PRef x n)) = process fn (Check (PRef x n))
+idemodeProcess fn (Check (PRef x hls n)) = process fn (Check (PRef x hls n))
 idemodeProcess fn (Check t) = process fn (Check t)
 idemodeProcess fn (Core t) = process fn (Core t)
 idemodeProcess fn (DocStr n w) = process fn (DocStr n w)
@@ -595,7 +600,7 @@
 idemodeProcess fn (Spec t) = process fn (Spec t)
 -- RmProof and AddProof not supported!
 idemodeProcess fn (ShowProof n') = process fn (ShowProof n')
-idemodeProcess fn (HNF t) = process fn (HNF t)
+idemodeProcess fn (WHNF t) = process fn (WHNF t)
 --idemodeProcess fn TTShell = process fn TTShell -- need some prove mode!
 idemodeProcess fn (TestInline t) = process fn (TestInline t)
 
@@ -631,9 +636,12 @@
 idemodeProcess fn (AddClauseFrom False pos str) = process fn (AddClauseFrom False pos str)
 idemodeProcess fn (AddMissing False pos str) = process fn (AddMissing False pos str)
 idemodeProcess fn (MakeWith False pos str) = process fn (MakeWith False pos str)
+idemodeProcess fn (MakeCase False pos str) = process fn (MakeCase False pos str)
 idemodeProcess fn (DoProofSearch False r pos str xs) = process fn (DoProofSearch False r pos str xs)
 idemodeProcess fn (SetConsoleWidth w) = do process fn (SetConsoleWidth w)
                                            iPrintResult ""
+idemodeProcess fn (SetPrinterDepth d) = do process fn (SetPrinterDepth d)
+                                           iPrintResult ""
 idemodeProcess fn (Apropos pkg a) = do process fn (Apropos pkg a)
                                        iPrintResult ""
 idemodeProcess fn (WhoCalls n) = process fn (WhoCalls n)
@@ -767,21 +775,23 @@
                                 Just pr -> isetPrompt pr
                                 Nothing -> iPrintError $ "Can't find import " ++ f
 process fn (Eval t)
-                 = withErrorReflection $ do logLvl 5 $ show t
-                                            getIState >>= flip warnDisamb t
-                                            (tm, ty) <- elabVal recinfo ERHS t
-                                            ctxt <- getContext
-                                            let tm' = force (normaliseAll ctxt [] tm)
-                                            let ty' = force (normaliseAll ctxt [] ty)
-                                            -- Add value to context, call it "it"
-                                            updateContext (addCtxtDef (sUN "it") (Function ty' tm'))
-                                            ist <- getIState
-                                            logLvl 3 $ "Raw: " ++ show (tm', ty')
-                                            logLvl 10 $ "Debug: " ++ showEnvDbg [] tm'
-                                            let tmDoc = pprintDelab ist tm'
-                                                tyDoc = pprintDelab ist ty'
-                                            iPrintTermWithType tmDoc tyDoc
-
+                 = withErrorReflection $
+                   do logLvl 5 $ show t
+                      getIState >>= flip warnDisamb t
+                      (tm, ty) <- elabREPL recinfo ERHS t
+                      ctxt <- getContext
+                      let tm' = perhapsForce $ normaliseAll ctxt [] tm
+                      let ty' = perhapsForce $ normaliseAll ctxt [] ty
+                      -- Add value to context, call it "it"
+                      updateContext (addCtxtDef (sUN "it") (Function ty' tm'))
+                      ist <- getIState
+                      logLvl 3 $ "Raw: " ++ show (tm', ty')
+                      logLvl 10 $ "Debug: " ++ showEnvDbg [] tm'
+                      let tmDoc = pprintDelab ist tm'
+                          tyDoc = pprintDelab ist ty'
+                      iPrintTermWithType tmDoc tyDoc
+  where perhapsForce tm | termSmallerThan 100 tm = force tm
+                        | otherwise = tm
 
 process fn (NewDefn decls) = do
         logLvl 3 ("Defining names using these decls: " ++ show (showDecls verbosePPOption decls))
@@ -889,15 +899,15 @@
                                               prettyIst ist (delab ist ty'))
                        iPrintTermWithType resOut tyOut
 
-process fn (Check (PRef _ n))
+process fn (Check (PRef _ _ n))
    = do ctxt <- getContext
         ist <- getIState
         let ppo = ppOptionIst ist
         case lookupNames n ctxt of
           ts@(t:_) ->
             case lookup t (idris_metavars ist) of
-                Just (_, i, _) -> iRenderResult . fmap (fancifyAnnots ist True) $
-                                  showMetavarInfo ppo ist n i
+                Just (_, i, _, _) -> iRenderResult . fmap (fancifyAnnots ist True) $
+                                     showMetavarInfo ppo ist n i
                 Nothing -> iPrintFunTypes [] n (map (\n -> (n, pprintDelabTy ist n)) ts)
           [] -> iPrintError $ "No such variable " ++ show n
   where
@@ -925,23 +935,27 @@
 
 
 process fn (Check t)
-   = do (tm, ty) <- elabVal recinfo ERHS t
+   = do (tm, ty) <- elabREPL recinfo ERHS t
         ctxt <- getContext
         ist <- getIState
         let ppo = ppOptionIst ist
-            ty' = normaliseC ctxt [] ty
+            ty' = if opt_evaltypes (idris_options ist)
+                     then normaliseC ctxt [] ty
+                     else ty
         case tm of
            TType _ ->
              iPrintTermWithType (prettyIst ist (PType emptyFC)) type1Doc
            _ -> iPrintTermWithType (pprintDelab ist tm)
-                                   (pprintDelab ist ty)
+                                   (pprintDelab ist ty')
 
 process fn (Core t)
-   = do (tm, ty) <- elabVal recinfo ERHS t
+   = do (tm, ty) <- elabREPL recinfo ERHS t
         iPrintTermWithType (pprintTT [] tm) (pprintTT [] ty)
 
 process fn (DocStr (Left n) w)
-   = do ist <- getIState
+  | UN ty <- n, ty == T.pack "Type" = getIState >>= iRenderResult . pprintTypeDoc  
+  | otherwise = do    
+        ist <- getIState
         let docs = lookupCtxtName n (idris_docstrings ist) ++
                    map (\(n,d)-> (n, (d, [])))
                        (lookupCtxtName (modDocN n) (idris_moduledocs ist))
@@ -1040,6 +1054,8 @@
     = addMissing fn updatefile l n
 process fn (MakeWith updatefile l n)
     = makeWith fn updatefile l n
+process fn (MakeCase updatefile l n)
+    = makeCase fn updatefile l n
 process fn (MakeLemma updatefile l n)
     = makeLemma fn updatefile l n
 process fn (DoProofSearch updatefile rec l n hints)
@@ -1065,7 +1081,7 @@
                             insertMetavar n =
                               do i <- getIState
                                  let ms = idris_metavars i
-                                 putIState $ i { idris_metavars = (n, (Nothing, 0, False)) : ms }
+                                 putIState $ i { idris_metavars = (n, (Nothing, 0, [], False)) : ms }
 
 process fn' (AddProof prf)
   = do fn <- do
@@ -1086,16 +1102,20 @@
        n' <- case prf of
                 Nothing -> case proofs of
                              [] -> ifail "No proof to add"
-                             ((x, p) : _) -> return x
+                             ((x, _) : _) -> return x
                 Just nm -> return nm
        n <- resolveProof n'
        case lookup n proofs of
             Nothing -> iputStrLn "No proof to add"
-            Just p  -> do let prog' = insertScript (showProof (lit fn) n p) ls
-                          runIO $ writeSource fn (unlines prog')
-                          removeProof n
-                          iputStrLn $ "Added proof " ++ show n
-                          where ls = (lines prog)
+            Just (mode, prf) ->
+              do let script = if mode
+                                 then showRunElab (lit fn) n prf
+                                 else showProof (lit fn) n prf
+                 let prog' = insertScript script ls
+                 runIO $ writeSource fn (unlines prog')
+                 removeProof n
+                 iputStrLn $ "Added proof " ++ show n
+             where ls = (lines prog)
 
 process fn (ShowProof n')
   = do i <- getIState
@@ -1103,19 +1123,21 @@
        let proofs = proof_list i
        case lookup n proofs of
             Nothing -> iPrintError "No proof to show"
-            Just p  -> iPrintResult $ showProof False n p
+            Just (m, p)  -> iPrintResult $ if m
+                                             then showRunElab False n p
+                                             else showProof False n p
 
-process fn (Prove n')
+process fn (Prove mode n')
      = do ctxt <- getContext
           ist <- getIState
           let ns = lookupNames n' ctxt
           let metavars = mapMaybe (\n -> do c <- lookup n (idris_metavars ist); return (n, c)) ns
           n <- case metavars of
               [] -> ierror (Msg $ "Cannot find metavariable " ++ show n')
-              [(n, (_,_,False))] -> return n
-              [(_, (_,_,True))]  -> ierror (Msg $ "Declarations not solvable using prover")
+              [(n, (_,_,_,False))] -> return n
+              [(_, (_,_,_,True))]  -> ierror (Msg $ "Declarations not solvable using prover")
               ns -> ierror (CantResolveAlts (map fst ns))
-          prover (lit fn) n
+          prover mode (lit fn) n
           -- recheck totality
           i <- getIState
           totcheck (fileFC "(input)", n)
@@ -1123,11 +1145,11 @@
           mapM_ checkDeclTotality (idris_totcheck i)
           warnTotality
 
-process fn (HNF t)
+process fn (WHNF t)
                     = do (tm, ty) <- elabVal recinfo ERHS t
                          ctxt <- getContext
                          ist <- getIState
-                         let tm' = hnf ctxt [] tm
+                         let tm' = whnf ctxt tm
                          iPrintResult (show (delab ist tm'))
 process fn (TestInline t)
                            = do (tm, ty) <- elabVal recinfo ERHS t
@@ -1161,8 +1183,8 @@
                        let iface = Interface `elem` opts
                        m <- if iface then return Nothing else
                             do (m', _) <- elabVal recinfo ERHS
-                                            (PApp fc (PRef fc (sUN "run__IO"))
-                                            [pexp $ PRef fc (sNS (sUN "main") ["Main"])])
+                                            (PApp fc (PRef fc [] (sUN "run__IO"))
+                                            [pexp $ PRef fc [] (sNS (sUN "main") ["Main"])])
                                return (Just m')
                        ir <- compile codegen f m
                        i <- getIState
@@ -1191,7 +1213,7 @@
                                   Nothing -> iPrintError $ "Could not load dynamic lib \"" ++ l ++ "\""
                                   Just x -> do let libs = idris_dynamic_libs i
                                                if x `elem` libs
-                                                  then do iLOG ("Tried to load duplicate library " ++ lib_name x)
+                                                  then do logLvl 1 ("Tried to load duplicate library " ++ lib_name x)
                                                           return ()
                                                   else putIState $ i { idris_dynamic_libs = x:libs }
     where trim = reverse . dropWhile isSpace . reverse . dropWhile isSpace
@@ -1205,8 +1227,8 @@
                  = do ist <- getIState
                       let mvs = map fst (idris_metavars ist) \\ primDefs
                       case mvs of
-                        [] -> iPrintError "No global metavariables to solve"
-                        _ -> iPrintResult $ "Global metavariables:\n\t" ++ show mvs
+                        [] -> iPrintError "No global holes to solve"
+                        _ -> iPrintResult $ "Global holes:\n\t" ++ show mvs
 process fn NOP      = return ()
 
 process fn (SetOpt   ErrContext)  = setErrContext True
@@ -1221,6 +1243,8 @@
 process fn (UnsetOpt NoBanner)    = setNoBanner False
 process fn (SetOpt WarnReach)     = fmodifyState opts_idrisCmdline $ nub . (WarnReach:)
 process fn (UnsetOpt WarnReach)   = fmodifyState opts_idrisCmdline $ delete WarnReach
+process fn (SetOpt EvalTypes)     = setEvalTypes True
+process fn (UnsetOpt EvalTypes)   = setEvalTypes False
 
 process fn (SetOpt _) = iPrintError "Not a valid option"
 process fn (UnsetOpt _) = iPrintError "Not a valid option"
@@ -1237,7 +1261,7 @@
        []       -> "No registered error handlers"
        handlers -> "Registered error handlers: " ++ (concat . intersperse ", " . map show) handlers
 process fn (SetConsoleWidth w) = setWidth w
-
+process fn (SetPrinterDepth d) = setDepth d
 process fn (Apropos pkgs a) =
   do orig <- getIState
      when (not (null pkgs)) $
@@ -1333,7 +1357,7 @@
 --                    iputStrLn "---------------"
 --                    showTrans i ts
 
-process fn (PPrint fmt width (PRef _ n))
+process fn (PPrint fmt width (PRef _ _ n))
    = do outs <- pprintDef n
         iPrintResult =<< renderExternal fmt width (vsep outs)
 
@@ -1462,8 +1486,8 @@
                                    (map snd (take (num-1) ninputs))
                                    input
                    let ifiles = getModuleFiles modTree
-                   iLOG ("MODULE TREE : " ++ show modTree)
-                   iLOG ("RELOAD: " ++ show ifiles)
+                   logLvl 1 ("MODULE TREE : " ++ show modTree)
+                   logLvl 1 ("RELOAD: " ++ show ifiles)
                    when (not (all ibc ifiles) || loadCode) $
                         tryLoad False (filter (not . ibc) ifiles)
                    -- return the files that need rechecking
@@ -1588,6 +1612,8 @@
        let cgn = case opt getCodegen opts of
                    [] -> Via "c"
                    xs -> last xs
+       let cgFlags = opt getCodegenArgs opts
+
        -- Now set/unset specifically chosen optimisations
        sequence_ (opt getOptimisation opts)
        script <- case opt getExecScript opts of
@@ -1600,7 +1626,8 @@
 
        when (DefaultTotal `elem` opts) $ do i <- getIState
                                             putIState (i { default_total = True })
-       setColourise $ not quiet && last ((not isWindows) : opt getColour opts)
+       tty <- runIO $ isATTY
+       setColourise $ not quiet && last (tty : opt getColour opts)
 
 
 
@@ -1612,6 +1639,7 @@
        setOutputTy outty
        setNoBanner nobanner
        setCodegen cgn
+       mapM_ (addFlag cgn) cgFlags
        mapM_ makeOption opts
        -- if we have the --bytecode flag, drop into the bytecode assembler
        case bcs of
@@ -1682,7 +1710,7 @@
        -- Create Idris data dir + repl history and config dir
        idrisCatch (do dir <- getIdrisUserDataDir
                       exists <- runIO $ doesDirectoryExist dir
-                      unless exists $ iLOG ("Creating " ++ dir)
+                      unless exists $ logLvl 1 ("Creating " ++ dir)
                       runIO $ createDirectoryIfMissing True (dir </> "repl"))
          (\e -> return ())
 
@@ -1826,6 +1854,9 @@
 getCodegen (UseCodegen x) = Just x
 getCodegen _ = Nothing
 
+getCodegenArgs :: Opt -> Maybe String
+getCodegenArgs (CodegenArgs args) = Just args
+getCodegenArgs _ = Nothing
 
 getConsoleWidth :: Opt -> Maybe ConsoleWidth
 getConsoleWidth (UseConsoleWidth x) = Just x
diff --git a/src/Idris/REPLParser.hs b/src/Idris/REPLParser.hs
--- a/src/Idris/REPLParser.hs
+++ b/src/Idris/REPLParser.hs
@@ -25,7 +25,9 @@
 import qualified Data.ByteString.UTF8 as UTF8
 
 parseCmd :: IState -> String -> String -> Result (Either String Command)
-parseCmd i inputname = P.runparser pCmd i inputname . dropWhile isSpace
+parseCmd i inputname = P.runparser pCmd i inputname . trim
+    where trim = f . f
+              where f = reverse . dropWhile isSpace
 
 type CommandTable = [ ( [String], CmdArg, String
                     , String -> P.IdrisParser (Either String Command) ) ]
@@ -39,7 +41,7 @@
           | (names, args, text, _) <- parserCommandsForHelp ++ parserCommands ]
 
 parserCommandsForHelp :: CommandTable
-parserCommandsForHelp = 
+parserCommandsForHelp =
   [ exprArgCmd ["t", "type"] Check "Check the type of an expression"
   , exprArgCmd ["core"] Core "View the core language representation of a term"
   , nameArgCmd ["miss", "missing"] Missing "Show missing clauses"
@@ -61,9 +63,11 @@
     , strArg ChangeDirectory)
   , (["module"], ModuleArg, "Import an extra module", moduleArg ModImport) -- NOTE: dragons
   , noArgCmd ["e", "edit"] Edit "Edit current file using $EDITOR or $VISUAL"
-  , noArgCmd ["m", "metavars"] Metavars "Show remaining proof obligations (metavariables)"
+  , noArgCmd ["m", "metavars"] Metavars "Show remaining proof obligations (metavariables or holes)"
   , (["p", "prove"], MetaVarArg, "Prove a metavariable"
-    , nameArg Prove)
+    , nameArg (Prove False))
+  , (["elab"], MetaVarArg, "Build a metavariable using the elaboration shell"
+    , nameArg (Prove True))
   , (["a", "addproof"], NameArg, "Add proof to source file", cmd_addproof)
   , (["rmproof"], NameArg, "Remove proof from proof stack"
     , nameArg RmProof)
@@ -82,6 +86,7 @@
     , "Turn REPL colours on or off; set a specific colour"
     , cmd_colour)
   , (["consolewidth"], ConsoleWidthArg, "Set the width of the console", cmd_consolewidth)
+  , (["printerdepth"], OptionalArg NumberArg, "Set the maximum pretty-printer depth (no arg for infinite)", cmd_printdepth)
   , noArgCmd ["q", "quit"] Quit "Exit the Idris system"
   , noArgCmd ["w", "warranty"] Warranty "Displays warranty information"
   , (["let"], ManyArgs DeclArg
@@ -96,7 +101,7 @@
     , cmd_pprint)
   ]
 
-parserCommands = 
+parserCommands =
   [ noArgCmd ["u", "universes"] Universes "Display universe constraints"
   , noArgCmd ["errorhandlers"] ListErrorHandlers "List registered error handlers"
 
@@ -106,7 +111,7 @@
 
   , exprArgCmd ["patt"] Pattelab "(Debugging) Elaborate pattern expression"
   , exprArgCmd ["spec"] Spec "?"
-  , exprArgCmd ["hnf"] HNF "?"
+  , exprArgCmd ["whnf"] WHNF "(Debugging) Show weak head normal form of an expression"
   , exprArgCmd ["inline"] TestInline "?"
   , proofArgCmd ["cs", "casesplit"] CaseSplitAt 
       ":cs <line> <name> splits the pattern variable on the line"
@@ -118,6 +123,8 @@
       ":am <line> <name> adds all missing pattern matches for the name on the line"
   , proofArgCmd ["mw", "makewith"] MakeWith
       ":mw <line> <name> adds a with clause for the definition of the name on the line"
+  , 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)
   , (["lto", "loadto"], SeqArgs NumberArg FileArg
@@ -252,6 +259,7 @@
               <|> do discard (P.symbol "autosolve"); return AutoSolve
               <|> do discard (P.symbol "nobanner") ; return NoBanner
               <|> do discard (P.symbol "warnreach"); return WarnReach
+              <|> do discard (P.symbol "evaltypes"); return EvalTypes
 
 proofArg :: (Bool -> Int -> Name -> Command) -> String -> P.IdrisParser (Either String Command)
 proofArg cmd name = do
@@ -268,10 +276,15 @@
         c <- fmap fst P.constant
         eof
         return $ Right (DocStr (Right c) FullDocs)
+    
+    let pType = do
+        P.reserved "Type"
+        eof
+        return $ Right (DocStr (Left $ P.mkName ("Type", "")) FullDocs)
 
     let fnName = fnNameArg (\n -> DocStr (Left n) FullDocs) name
 
-    try constant <|> fnName
+    try constant <|> pType <|> fnName
 
 cmd_consolewidth :: String -> P.IdrisParser (Either String Command)
 cmd_consolewidth name = do
@@ -285,24 +298,28 @@
                     <|> do n <- fmap (fromInteger . fst) P.natural
                            return (ColsWide n)
 
+cmd_printdepth :: String -> P.IdrisParser (Either String Command)
+cmd_printdepth _ = do d <- optional (fmap (fromInteger . fst) P.natural)
+                      return (Right $ SetPrinterDepth d)
+
 cmd_execute :: String -> P.IdrisParser (Either String Command)
 cmd_execute name = do
     tm <- option maintm (P.fullExpr defaultSyntax)
     return (Right (Execute tm))
   where
-    maintm = PRef (fileFC "(repl)") (sNS (sUN "main") ["Main"])
+    maintm = PRef (fileFC "(repl)") [] (sNS (sUN "main") ["Main"])
 
 
 cmd_dynamic :: String -> P.IdrisParser (Either String Command)
 cmd_dynamic name = do
-    let emptyArgs = noArgs ListDynamic name
-
-    let oneArg = do l <- many anyChar
-                    return $ Right (DynamicLink l)
+    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 emptyArgs <|> try oneArg <|> failure
+    try optArg <|> failure
 
 cmd_pprint :: String -> P.IdrisParser (Either String Command)
 cmd_pprint name = do
@@ -443,14 +460,14 @@
 
 packageBasedCmd :: P.IdrisParser a -> ([String] -> a -> Command)
                 -> String -> P.IdrisParser (Either String Command)
-packageBasedCmd valParser cmd name = do
-  pkgs <- option [] . try $ do
-    P.lchar '('
-    pks <- sepBy (some idChar) (P.lchar ',')
-    P.lchar ')'
-    return pks
-  val <- valParser
-  return (Right (cmd pkgs val))
+packageBasedCmd valParser cmd name =
+  try (do P.lchar '('
+          pkgs <- sepBy (some idChar) (P.lchar ',')
+          P.lchar ')'
+          val <- valParser
+          return (Right (cmd pkgs val)))
+   <|> do val <- valParser
+          return (Right (cmd [] val))
 
 cmd_search :: String -> P.IdrisParser (Either String Command)
 cmd_search = packageBasedCmd
diff --git a/src/Idris/Reflection.hs b/src/Idris/Reflection.hs
--- a/src/Idris/Reflection.hs
+++ b/src/Idris/Reflection.hs
@@ -6,38 +6,51 @@
 module Idris.Reflection where
 
 import Control.Applicative ((<$>), (<*>), pure)
-import Control.Monad (liftM, liftM2)
+import Control.Monad (liftM, liftM2, liftM4)
 import Data.Maybe (catMaybes)
-import Data.List ((\\))
+import Data.List ((\\), findIndex)
 import qualified Data.Text as T
 
 import Idris.Core.Elaborate (claim, fill, focus, getNameFrom, initElaborator,
                              movelast, runElab, solve)
-import Idris.Core.Evaluate (Context, Def(TyDecl), initContext, lookupDefExact, lookupTyExact)
+import Idris.Core.Evaluate (Def(TyDecl), initContext, lookupDefExact, lookupTyExact)
 import Idris.Core.TT
 
-import Idris.AbsSyntaxTree (ElabD, IState, PArg'(..), PArg, PTactic, PTactic'(..),
-                            PTerm(..), initEState, pairCon, pairTy)
+import Idris.AbsSyntaxTree (ArgOpt(..),ElabD, IState(tt_ctxt, idris_implicits,idris_datatypes),
+                            PArg'(..), PArg, PTactic, PTactic'(..), PTerm(..), Fixity (..),
+                            initEState, pairCon, pairTy)
 import Idris.Delaborate (delab)
 
-data RArg = RExplicit   { argName :: Name, argTy :: Raw }
-          | RImplicit   { argName :: Name, argTy :: Raw }
-          | RConstraint { argName :: Name, argTy :: Raw }
+data RErasure = RErased | RNotErased deriving Show
+
+data RPlicity = RExplicit | RImplicit | RConstraint deriving Show
+
+data RFunArg = RFunArg { argName    :: Name
+                       , argTy      :: Raw
+                       , argPlicity :: RPlicity
+                       , erasure    :: RErasure
+                       }
   deriving Show
 
-data RTyDecl = RDeclare Name [RArg] Raw deriving Show
+data RTyDecl = RDeclare Name [RFunArg] Raw deriving Show
 
-data RTyConArg = RParameter { tcArgName :: Name, tcArgTy :: Raw }
-               | RIndex     { tcArgName :: Name, tcArgTy :: Raw }
+data RTyConArg = RParameter RFunArg
+               | RIndex     RFunArg
   deriving Show
 
-data RDatatype = RDatatype Name [RTyConArg] Raw [(Name, Raw)] deriving Show
+data RCtorArg = RCtorParameter RFunArg | RCtorField RFunArg deriving Show
 
-rArgToPArg :: RArg -> PArg
-rArgToPArg (RExplicit n _) = PExp 0 [] n Placeholder
-rArgToPArg (RImplicit n _) = PImp 0 False [] n Placeholder
-rArgToPArg (RConstraint n _) = PConstraint 0 [] n Placeholder
+data RDatatype = RDatatype Name [RTyConArg] Raw [(Name, [RCtorArg], Raw)] deriving Show
 
+rArgOpts :: RErasure -> [ArgOpt]
+rArgOpts RErased = [InaccessibleArg]
+rArgOpts _ = []
+
+rFunArgToPArg :: RFunArg -> PArg
+rFunArgToPArg (RFunArg n _ RExplicit e) = PExp 0 (rArgOpts e) n Placeholder
+rFunArgToPArg (RFunArg n _ RImplicit e) = PImp 0 False (rArgOpts e) n Placeholder
+rFunArgToPArg (RFunArg n _ RConstraint e) = PConstraint 0 (rArgOpts e) n Placeholder
+
 data RFunClause = RMkFunClause Raw Raw
                 | RMkImpossibleClause Raw
                 deriving Show
@@ -69,7 +82,7 @@
 reifyApp :: IState -> Name -> [Term] -> ElabD PTactic
 reifyApp ist t [l, r] | t == reflm "Try" = liftM2 Try (reify ist l) (reify ist r)
 reifyApp _ t [Constant (I i)]
-           | t == reflm "Search" = return (ProofSearch True True i Nothing [])
+           | t == reflm "Search" = return (ProofSearch True True i Nothing [] [])
 reifyApp _ t [x]
            | t == reflm "Refine" = do n <- reifyTTName x
                                       return $ Refine n []
@@ -81,7 +94,7 @@
              | t == reflm "GoalType" = liftM (GoalType n) (reify ist x)
 reifyApp _ t [n] | t == reflm "Intro" = liftM (Intro . (:[])) (reifyTTName n)
 reifyApp ist t [t'] | t == reflm "Induction" = liftM (Induction . delab ist) (reifyTT t')
-reifyApp ist t [t'] | t == reflm "Case" = liftM (Induction . delab ist) (reifyTT t')
+reifyApp ist t [t'] | t == reflm "Case" = liftM (CaseTac . delab ist) (reifyTT t')
 reifyApp ist t [t']
              | t == reflm "ApplyTactic" = liftM (ApplyTactic . delab ist) (reifyTT t')
 reifyApp ist t [t']
@@ -109,6 +122,26 @@
              | t == reflm "Fail" = fmap TFail (reifyReportParts errs)
 reifyApp _ f args = fail ("Unknown tactic " ++ show (f, args)) -- shouldn't happen
 
+reifyBool :: Term -> ElabD Bool
+reifyBool (P _ n _) | n == sNS (sUN "True") ["Bool", "Prelude"] = return True
+                    | n == sNS (sUN "False") ["Bool", "Prelude"] = return False
+reifyBool tm = fail $ "Not a Boolean: " ++ show tm
+
+reifyInt :: Term -> ElabD Int
+reifyInt (Constant (I i)) = return i
+reifyInt tm = fail $ "Not an Int: " ++ show tm
+
+reifyPair :: (Term -> ElabD a) -> (Term -> ElabD b) -> Term -> ElabD (a, b)
+reifyPair left right (App _ (App _ (App _ (App _ (P _ n _) _) _) x) y)
+  | n == pairCon = liftM2 (,) (left x) (right y)
+reifyPair left right tm = fail $ "Not a pair: " ++ show tm
+
+reifyList :: (Term -> ElabD a) -> Term -> ElabD [a]
+reifyList getElt lst =
+  case unList lst of
+    Nothing -> fail "Couldn't reify a list"
+    Just xs -> mapM getElt xs
+
 reifyReportParts :: Term -> ElabD [ErrorReportPart]
 reifyReportParts errs =
   case unList errs of
@@ -154,8 +187,16 @@
                                     return $ Proj t'' i
 reifyTTApp t [tt]
            | t == reflm "TType" = liftM TType (reifyTTUExp tt)
+reifyTTApp t [tt]
+           | t == reflm "UType" = liftM UType (reifyUniverse tt)
 reifyTTApp t args = fail ("Unknown reflection term: " ++ show (t, args))
 
+reifyUniverse :: Term -> ElabD Universe
+reifyUniverse (P _ n _) | n == reflm "AllTypes" = return AllTypes
+                        | n == reflm "UniqueType" = return UniqueType
+                        | n == reflm "NullType" = return NullType
+reifyUniverse tm = fail ("Unknown reflection universe: " ++ show tm)
+
 -- | Reify raw terms from their reflected representation
 reifyRaw :: Term -> ElabD Raw
 reifyRaw t@(App _ _ _)
@@ -272,7 +313,7 @@
 reifyTTBinderApp reif f [t]
                       | f == reflm "Hole" = liftM Hole (reif t)
 reifyTTBinderApp reif f [t]
-                      | f == reflm "GHole" = liftM (GHole 0) (reif t)
+                      | f == reflm "GHole" = liftM (GHole 0 []) (reif t)
 reifyTTBinderApp reif f [x, y]
                       | f == reflm "Guess" = liftM2 Guess (reif x) (reif y)
 reifyTTBinderApp reif f [t]
@@ -298,7 +339,7 @@
                 | f == reflm "BI"  = return $ c
 reifyTTConstApp f (Constant c@(Fl _))
                 | f == reflm "Fl"  = return $ c
-reifyTTConstApp f (Constant c@(I _))
+reifyTTConstApp f (Constant c@(Ch _))
                 | f == reflm "Ch"  = return $ c
 reifyTTConstApp f (Constant c@(Str _))
                 | f == reflm "Str" = return $ c
@@ -352,11 +393,24 @@
 reflectRaw :: Raw -> Raw
 reflectRaw = reflectRawQuote []
 
-claimTT :: Name -> ElabD Name
-claimTT n = do n' <- getNameFrom n
-               claim n' (Var (sNS (sUN "TT") ["Reflection", "Language"]))
-               return n'
+claimTy :: Name -> Raw -> ElabD Name
+claimTy n ty = do n' <- getNameFrom n
+                  claim n' ty
+                  return n'
 
+intToReflectedNat :: Int -> Raw
+intToReflectedNat i = if i <= 0
+                        then Var (natN "Z")
+                        else RApp (Var (natN "S")) (intToReflectedNat (i - 1))
+  where natN :: String -> Name
+        natN n = sNS (sUN n) ["Nat", "Prelude"]
+
+reflectFixity :: Fixity -> Raw
+reflectFixity (Infixl  p) = RApp (Var (tacN "Infixl")) (intToReflectedNat p)
+reflectFixity (Infixr  p) = RApp (Var (tacN "Infixr")) (intToReflectedNat p)
+reflectFixity (InfixN  p) = RApp (Var (tacN "InfixN")) (intToReflectedNat p)
+reflectFixity (PrefixN p) = RApp (Var (tacN "PrefixN")) (intToReflectedNat p)
+
 -- | Convert a reflected term to a more suitable form for pattern-matching.
 -- In particular, the less-interesting bits are elaborated to _ patterns. This
 -- happens to NameTypes, universe levels, names that are bound but not used,
@@ -366,7 +420,7 @@
   | n `elem` unq = -- the unquoted names have been claimed as TT already - just use them
     do fill (Var n) ; solve
   | otherwise =
-    do tyannot <- claimTT (sMN 0 "pTyAnnot")
+    do tyannot <- claimTy (sMN 0 "pTyAnnot") (Var (reflm "TT"))
        movelast tyannot  -- use a _ pattern here
        nt <- getNameFrom (sMN 0 "nt")
        claim nt (Var (reflm "NameType"))
@@ -380,7 +434,7 @@
   = do fill $ reflCall "V" [RConstant (I n)]
        solve
 reflectTTQuotePattern unq (Bind n b x)
-  = do x' <- claimTT (sMN 0 "sc")
+  = do x' <- claimTy (sMN 0 "sc") (Var (reflm "TT"))
        movelast x'
        b' <- getNameFrom (sMN 0 "binder")
        claim b' (RApp (Var (sNS (sUN "Binder") ["Reflection", "Language"]))
@@ -400,10 +454,10 @@
                                   Var x']
                  solve
        focus x'; reflectTTQuotePattern unq x
-       focus b'; reflectBinderQuotePattern reflectTTQuotePattern unq b
+       focus b'; reflectBinderQuotePattern reflectTTQuotePattern (Var $ reflm "TT") unq b
 reflectTTQuotePattern unq (App _ f x)
-  = do f' <- claimTT (sMN 0 "f"); movelast f'
-       x' <- claimTT (sMN 0 "x"); movelast x'
+  = do f' <- claimTy (sMN 0 "f") (Var (reflm "TT")) ; movelast f'
+       x' <- claimTy (sMN 0 "x") (Var (reflm "TT")) ; movelast x'
        fill $ reflCall "App" [Var f', Var x']
        solve
        focus f'; reflectTTQuotePattern unq f
@@ -412,12 +466,12 @@
   = do fill $ reflCall "TConst" [reflectConstant c]
        solve
 reflectTTQuotePattern unq (Proj t i)
-  = do t' <- claimTT (sMN 0 "t"); movelast t'
+  = do t' <- claimTy (sMN 0 "t") (Var (reflm "TT")) ; movelast t'
        fill $ reflCall "Proj" [Var t', RConstant (I i)]
        solve
        focus t'; reflectTTQuotePattern unq t
 reflectTTQuotePattern unq (Erased)
-  = do erased <- claimTT (sMN 0 "erased")
+  = do erased <- claimTy (sMN 0 "erased") (Var (reflm "TT"))
        movelast erased
        fill $ (Var erased)
        solve
@@ -466,7 +520,7 @@
                 fill $ reflCall "RBind" [Var any, Var bH, Var scH]
                 solve
      focus scH; reflectRawQuotePattern unq sc
-     focus bH; reflectBinderQuotePattern reflectRawQuotePattern unq b
+     focus bH; reflectBinderQuotePattern reflectRawQuotePattern (Var $ reflm "Raw") unq b
   where freeNamesR (Var n) = [n]
         freeNamesR (RBind n (Let t v) body) = concat [freeNamesR v,
                                                       freeNamesR body \\ [n],
@@ -514,57 +568,57 @@
      focus cH
      fill (reflectConstant c); solve
 
-reflectBinderQuotePattern :: ([Name] -> a -> ElabD ()) -> [Name] -> Binder a -> ElabD ()
-reflectBinderQuotePattern q unq (Lam t)
-   = do t' <- claimTT (sMN 0 "ty"); movelast t'
-        fill $ reflCall "Lam" [Var (reflm "TT"), Var t']
+reflectBinderQuotePattern :: ([Name] -> a -> ElabD ()) -> Raw -> [Name] -> Binder a -> ElabD ()
+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 unq (Pi _ t k)
-   = do t' <- claimTT (sMN 0 "ty") ; movelast t'
-        k' <- claimTT (sMN 0 "k"); movelast k';
-        fill $ reflCall "Pi" [Var (reflm "TT"), Var t', Var 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']
         solve
         focus t'; q unq t
-reflectBinderQuotePattern q unq (Let x y)
-   = do x' <- claimTT (sMN 0 "ty"); movelast x';
-        y' <- claimTT (sMN 0 "v"); movelast y';
-        fill $ reflCall "Let" [Var (reflm "TT"), Var x', Var y']
+reflectBinderQuotePattern q ty unq (Let x y)
+   = do x' <- claimTy (sMN 0 "ty") ty; movelast x';
+        y' <- claimTy (sMN 0 "v")ty; movelast y';
+        fill $ reflCall "Let" [ty, Var x', Var y']
         solve
         focus x'; q unq x
         focus y'; q unq y
-reflectBinderQuotePattern q unq (NLet x y)
-   = do x' <- claimTT (sMN 0 "ty"); movelast x'
-        y' <- claimTT (sMN 0 "v"); movelast y'
-        fill $ reflCall "NLet" [Var (reflm "TT"), Var x', Var y']
+reflectBinderQuotePattern q ty unq (NLet x y)
+   = do x' <- claimTy (sMN 0 "ty") ty; movelast x'
+        y' <- claimTy (sMN 0 "v") ty; movelast y'
+        fill $ reflCall "NLet" [ty, Var x', Var y']
         solve
         focus x'; q unq x
         focus y'; q unq y
-reflectBinderQuotePattern q unq (Hole t)
-   = do t' <- claimTT (sMN 0 "ty"); movelast t'
-        fill $ reflCall "Hole" [Var (reflm "TT"), Var t']
+reflectBinderQuotePattern q ty unq (Hole t)
+   = do t' <- claimTy (sMN 0 "ty") ty; movelast t'
+        fill $ reflCall "Hole" [ty, Var t']
         solve
         focus t'; q unq t
-reflectBinderQuotePattern q unq (GHole _ t)
-   = do t' <- claimTT (sMN 0 "ty"); movelast t'
-        fill $ reflCall "GHole" [Var (reflm "TT"), Var t']
+reflectBinderQuotePattern q ty unq (GHole _ _ t)
+   = do t' <- claimTy (sMN 0 "ty") ty; movelast t'
+        fill $ reflCall "GHole" [ty, Var t']
         solve
         focus t'; q unq t
-reflectBinderQuotePattern q unq (Guess x y)
-   = do x' <- claimTT (sMN 0 "ty"); movelast x'
-        y' <- claimTT (sMN 0 "v"); movelast y'
-        fill $ reflCall "Guess" [Var (reflm "TT"), Var x', Var y']
+reflectBinderQuotePattern q ty unq (Guess x y)
+   = do x' <- claimTy (sMN 0 "ty") ty; movelast x'
+        y' <- claimTy (sMN 0 "v") ty; movelast y'
+        fill $ reflCall "Guess" [ty, Var x', Var y']
         solve
         focus x'; q unq x
         focus y'; q unq y
-reflectBinderQuotePattern q unq (PVar t)
-   = do t' <- claimTT (sMN 0 "ty"); movelast t'
-        fill $ reflCall "PVar" [Var (reflm "TT"), Var t']
+reflectBinderQuotePattern q ty unq (PVar t)
+   = do t' <- claimTy (sMN 0 "ty") ty; movelast t'
+        fill $ reflCall "PVar" [ty, Var t']
         solve
         focus t'; q unq t
-reflectBinderQuotePattern q unq (PVTy t)
-   = do t' <- claimTT (sMN 0 "ty"); movelast t'
-        fill $ reflCall "PVTy" [Var (reflm "TT"), Var t']
+reflectBinderQuotePattern q ty unq (PVTy t)
+   = do t' <- claimTy (sMN 0 "ty") ty; movelast t'
+        fill $ reflCall "PVTy" [ty, Var t']
         solve
         focus t'; q unq t
 
@@ -696,7 +750,7 @@
    = reflCall "NLet" [Var ty, q unq x, q unq y]
 reflectBinderQuote q ty unq (Hole t)
    = reflCall "Hole" [Var ty, q unq t]
-reflectBinderQuote q ty unq (GHole _ t)
+reflectBinderQuote q ty unq (GHole _ _ t)
    = reflCall "GHole" [Var ty, q unq t]
 reflectBinderQuote q ty unq (Guess x y)
    = reflCall "Guess" [Var ty, q unq x, q unq y]
@@ -760,6 +814,9 @@
     emptyEnvList = raw_apply (Var (sNS (sUN "Nil") ["List", "Prelude"]))
                              [envTupleType]
 
+reifyEnv :: Term -> ElabD Env
+reifyEnv = reifyList (reifyPair reifyTTName (reifyTTBinder reifyTT (reflm "TT")))
+
 -- | Reflect an error into the internal datatype of Idris -- TODO
 rawBool :: Bool -> Raw
 rawBool True  = Var (sNS (sUN "True") ["Bool", "Prelude"])
@@ -780,6 +837,13 @@
 rawPair :: (Raw, Raw) -> (Raw, Raw) -> Raw
 rawPair (a, b) (x, y) = raw_apply (Var pairCon) [a, b, x, y]
 
+-- | Idris tuples nest to the right
+rawTripleTy :: Raw -> Raw -> Raw -> Raw
+rawTripleTy a b c = rawPairTy a (rawPairTy b c)
+
+rawTriple :: (Raw, Raw, Raw) -> (Raw, Raw, Raw) -> Raw
+rawTriple (a, b, c) (x, y, z) = rawPair (a, rawPairTy b c) (x, rawPair (b, c) (y, z))
+
 reflectCtxt :: [(Name, Type)] -> Raw
 reflectCtxt ctxt = rawList (rawPairTy  (Var $ reflm "TTName") (Var $ reflm "TT"))
                            (map (\ (n, t) -> (rawPair (Var $ reflm "TTName", Var $ reflm "TT")
@@ -914,6 +978,14 @@
       " when reflecting an error:" ++ show e
     OK (tm', _) -> Right $ TermPart tm'
 reifyReportPart (App _ (P (DCon _ _ _) n _) tm)
+  | n == reflm "RawPart" =
+  case runElab initEState (reifyRaw tm) (initElaborator NErased initContext emptyContext Erased) of
+    Error e -> Left . InternalMsg $
+      "could not reify reflected raw term " ++
+      show tm ++
+      " when reflecting an error: " ++ show e
+    OK (tm', _) -> Right $ RawPart tm'
+reifyReportPart (App _ (P (DCon _ _ _) n _) tm)
   | n == reflm "SubReport" =
   case unList tm of
     Just xs -> do subParts <- mapM reifyReportPart xs
@@ -921,26 +993,37 @@
     Nothing -> Left . InternalMsg $ "could not reify subreport " ++ show tm
 reifyReportPart x = Left . InternalMsg $ "could not reify " ++ show x
 
+reifyErasure :: Term -> ElabD RErasure
+reifyErasure (P (DCon _ _ _) n _)
+  | n == tacN "Erased" = return RErased
+  | n == tacN "NotErased" = return RNotErased
+reifyErasure tm = fail $ "Can't reify " ++ show tm ++ " as erasure info."
+
+reifyPlicity :: Term -> ElabD RPlicity
+reifyPlicity (P (DCon _ _ _) n _)
+  | n == tacN "Explicit" = return RExplicit
+  | n == tacN "Implicit" = return RImplicit
+  | n == tacN "Constraint" = return RConstraint
+reifyPlicity tm = fail $ "Couldn't reify " ++ show tm ++ " as RPlicity."
+
+reifyRFunArg :: Term -> ElabD RFunArg
+reifyRFunArg (App _ (App _ (App _ (App _ (P (DCon _ _ _) n _) argN) argTy) argPl) argE)
+  | n == tacN "MkFunArg" = liftM4 RFunArg
+                             (reifyTTName argN)
+                             (reifyRaw argTy)
+                             (reifyPlicity argPl)
+                             (reifyErasure argE)
+reifyRFunArg aTm = fail $ "Couldn't reify " ++ show aTm ++ " as an RArg."
+
 reifyTyDecl :: Term -> ElabD RTyDecl
 reifyTyDecl (App _ (App _ (App _ (P (DCon _ _ _) n _) tyN) args) ret)
   | n == tacN "Declare" =
   do tyN'  <- reifyTTName tyN
      args' <- case unList args of
                 Nothing -> fail $ "Couldn't reify " ++ show args ++ " as an arglist."
-                Just xs -> mapM reifyRArg xs
+                Just xs -> mapM reifyRFunArg xs
      ret'  <- reifyRaw ret
      return $ RDeclare tyN' args' ret'
-  where reifyRArg :: Term -> ElabD RArg
-        reifyRArg (App _ (App _ (P (DCon _ _ _) n _) argN) argTy)
-          | n == tacN "Explicit"   = liftM2 RExplicit
-                                            (reifyTTName argN)
-                                            (reifyRaw argTy)
-          | n == tacN "Implicit"   = liftM2 RImplicit
-                                            (reifyTTName argN)
-                                            (reifyRaw argTy)                               | n == tacN "Constraint" = liftM2 RConstraint
-                                            (reifyTTName argN)
-                                            (reifyRaw argTy)
-        reifyRArg aTm = fail $ "Couldn't reify " ++ show aTm ++ " as an RArg."
 reifyTyDecl tm = fail $ "Couldn't reify " ++ show tm ++ " as a type declaration."
 
 reifyFunDefn :: Term -> ElabD RFunDefn
@@ -967,38 +1050,113 @@
                            , (RApp (Var $ reflm "Binder") (Var $ reflm "TT"))
                            ]
 
+-- | Apply Idris's implicit info to get a signature. The [PArg] should
+-- 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) =
+  let (args, res) = getArgs as sc
+      erased = if InaccessibleArg `elem` argopts a then RErased else RNotErased
+      arg' = case a of
+               PImp {} -> RFunArg n ty RImplicit erased
+               PExp {} -> RFunArg n ty RExplicit erased
+               PConstraint {} -> RFunArg n ty RConstraint erased
+               PTacImplicit {} -> RFunArg n ty RImplicit erased
+  in (arg':args, res)
+getArgs _ r = ([], r)
+
+unApplyRaw :: Raw -> (Raw, [Raw])
+unApplyRaw tm = ua [] tm
+  where
+    ua args (RApp f a) = ua (a:args) f
+    ua args t         = (t, args)
+
 -- | Build the reflected datatype definition(s) that correspond(s) to
 -- a provided unqualified name
-buildDatatypes :: Context -> Ctxt TypeInfo -> Name -> [RDatatype]
-buildDatatypes ctxt datatypes n =
+buildDatatypes :: IState -> Name -> [RDatatype]
+buildDatatypes ist n =
   catMaybes [ mkDataType dn ti
             | (dn, ti) <- lookupCtxtName n datatypes
             ]
-  where mkDataType name (TI {param_pos = params, con_names = constrs}) =
+  where datatypes = idris_datatypes ist
+        ctxt      = tt_ctxt ist
+        impls     = idris_implicits ist
+
+        ctorSig params cn = do cty <- fmap forget (lookupTyExact cn ctxt)
+                               argInfo <- lookupCtxtExact cn impls
+                               let (args, res) = getArgs argInfo cty
+                               return (cn, ctorArgsStatus args res params, res)
+
+        argPos n [] res = findPos n res
+          where findPos n app = case unApplyRaw app of
+                                  (_, argL) -> findIndex (== Var n) argL
+        argPos n (arg:args) res = if n == argName arg
+                                     then Nothing
+                                     else argPos n args res
+
+        ctorArgsStatus :: [RFunArg] -> Raw -> [Int] -> [RCtorArg]
+        ctorArgsStatus [] _ _ = []
+        ctorArgsStatus (arg:args) res params =
+          case argPos (argName arg) args res of
+            Nothing -> RCtorField arg : ctorArgsStatus args res params
+            Just i -> if i `elem` params
+                         then RCtorParameter arg : ctorArgsStatus args res params
+                         else RCtorField arg : ctorArgsStatus args res params
+
+        mkDataType name (TI {param_pos = params, con_names = constrs}) =
           do (TyDecl (TCon _ _) ty) <- lookupDefExact name ctxt
-             let (tcargs, tcres) = getArgs params (forget ty) 0
-             conTys <- mapM (fmap forget . flip lookupTyExact ctxt) constrs
-             return $ RDatatype name tcargs tcres $ zip constrs conTys
+             implInfo <- lookupCtxtExact name impls
+             let (tcargs, tcres) = getTCArgs params implInfo (forget ty)
+             ctors <- mapM (ctorSig params) constrs
+             return $ RDatatype name tcargs tcres ctors
 
-        getArgs params (RBind an (Pi _ ty _) body) i =
-          let (args, res) = getArgs params body (i+1)
-          in if i `elem` params
-               then (RParameter an ty : args, res )
-               else (RIndex an ty : args, res)
-        getArgs _ tm _ = ([], tm)
+        getTCArgs :: [Int] -> [PArg] -> Raw -> ([RTyConArg], Raw)
+        getTCArgs params implInfo tcTy =
+          let (args, res) = getArgs implInfo tcTy
+          in (tcArg args 0, res)
+            where tcArg [] _ = []
+                  tcArg (arg:args) i | i `elem` params = RParameter arg : tcArg args (i+1)
+                                     | otherwise       = RIndex arg : tcArg args (i+1)
 
+
+reflectErasure :: RErasure -> Raw
+reflectErasure RErased    = Var (tacN "Erased")
+reflectErasure RNotErased = Var (tacN "NotErased")
+
+reflectPlicity :: RPlicity -> Raw
+reflectPlicity RExplicit = Var (tacN "Explicit")
+reflectPlicity RImplicit = Var (tacN "Implicit")
+reflectPlicity RConstraint = Var (tacN "Constraint")
+
+reflectArg :: RFunArg -> Raw
+reflectArg (RFunArg n ty plic erasure) =
+  RApp (RApp (RApp (RApp (Var $ tacN "MkFunArg") (reflectName n))
+                   (reflectRaw ty))
+              (reflectPlicity plic))
+       (reflectErasure erasure)
+
+reflectCtorArg :: RCtorArg -> Raw
+reflectCtorArg (RCtorParameter arg) = RApp (Var $ tacN "CtorParameter") (reflectArg arg)
+reflectCtorArg (RCtorField arg) = RApp (Var $ tacN "CtorField") (reflectArg arg)
+
 reflectDatatype :: RDatatype -> Raw
 reflectDatatype (RDatatype tyn tyConArgs tyConRes constrs) =
   raw_apply (Var $ tacN "MkDatatype") [ reflectName tyn
                                       , rawList (Var $ tacN "TyConArg") (map reflectConArg tyConArgs)
                                       , reflectRaw tyConRes
-                                      , rawList (rawPairTy (Var $ reflm "TTName") (Var $ reflm "Raw"))
-                                                [ rawPair ((Var $ reflm "TTName"), (Var $ reflm "Raw"))
-                                                          (reflectName cn, reflectRaw cty)
-                                                | (cn, cty) <- constrs
+                                      , rawList (rawTripleTy (Var $ reflm "TTName")
+                                                             (RApp (Var (sNS (sUN "List") ["List", "Prelude"])) (Var $ tacN "CtorArg"))
+                                                             (Var $ reflm "Raw"))
+                                                [ rawTriple ((Var $ reflm "TTName"),
+                                                             (RApp (Var (sNS (sUN "List") ["List", "Prelude"])) (Var $ tacN "CtorArg")),
+                                                             (Var $ reflm "Raw"))
+                                                            (reflectName cn,
+                                                             rawList (Var $ tacN "CtorArg") (map reflectCtorArg cargs),
+                                                             reflectRaw cty)
+                                                | (cn, cargs, cty) <- constrs
                                                 ]
                                       ]
-  where reflectConArg (RParameter n t) =
-          raw_apply (Var $ tacN "Parameter") [reflectName n, reflectRaw t]
-        reflectConArg (RIndex n t) =
-          raw_apply (Var $ tacN "Index")     [reflectName n, reflectRaw t]
+  where reflectConArg (RParameter a) =
+          RApp (Var $ tacN "TyConParameter") (reflectArg a)
+        reflectConArg (RIndex a) =
+          RApp (Var $ tacN "TyConIndex") (reflectArg a)
diff --git a/src/Pkg/PParser.hs b/src/Pkg/PParser.hs
--- a/src/Pkg/PParser.hs
+++ b/src/Pkg/PParser.hs
@@ -66,10 +66,7 @@
 pClause = do reserved "executable"; lchar '=';
              exec <- fst <$> iName []
              st <- get
-             put (st { execout = Just (if isWindows
-                                          then ((show exec) ++ ".exe")
-                                          else ( show exec )
-                                      ) })
+             put (st { execout = Just (show exec) })
       <|> do reserved "main"; lchar '=';
              main <- fst <$> iName []
              st <- get
diff --git a/src/Pkg/Package.hs b/src/Pkg/Package.hs
--- a/src/Pkg/Package.hs
+++ b/src/Pkg/Package.hs
@@ -42,20 +42,19 @@
 buildPkg :: Bool -> (Bool, FilePath) -> IO ()
 buildPkg warnonly (install, fp)
      = do pkgdesc <- parseDesc fp
+          dir <- getCurrentDirectory
           let idx = PkgIndex (pkgIndex (pkgname pkgdesc))
           ok <- mapM (testLib warnonly (pkgname pkgdesc)) (libdeps pkgdesc)
           when (and ok) $
-            do dir <- getCurrentDirectory
-               setCurrentDirectory $ dir </> sourcedir pkgdesc
-               make (makefile pkgdesc)
-               m_ist <- case (execout pkgdesc) of
-                   Nothing -> buildMods (idx : NoREPL : Verbose : idris_opts pkgdesc)
-                                    (modules pkgdesc)
-                   Just o -> do let exec = dir </> o
-                                buildMods
-                                    (idx : NoREPL : Verbose : Output exec : idris_opts pkgdesc)
-                                    [idris_main pkgdesc]
-               setCurrentDirectory dir
+            do m_ist <- inPkgDir pkgdesc $
+                          do make (makefile pkgdesc)
+                             case (execout pkgdesc) of
+                               Nothing -> buildMods (idx : NoREPL : Verbose : idris_opts pkgdesc)
+                                                    (modules pkgdesc)
+                               Just o -> do let exec = dir </> o
+                                            buildMods
+                                              (idx : NoREPL : Verbose : Output exec : idris_opts pkgdesc)
+                                              [idris_main pkgdesc]
                case m_ist of
                     Nothing -> exitWith (ExitFailure 1)
                     Just ist -> do
@@ -77,12 +76,10 @@
   = do pkgdesc <- parseDesc fpath
        ok <- mapM (testLib warnonly (pkgname pkgdesc)) (libdeps pkgdesc)
        when (and ok) $
-         do dir <- getCurrentDirectory
-            setCurrentDirectory $ dir </> sourcedir pkgdesc
-            make (makefile pkgdesc)
-            res <- buildMods (NoREPL : Verbose : idris_opts pkgdesc)
-                             (modules pkgdesc)
-            setCurrentDirectory dir
+         do res <- inPkgDir pkgdesc $
+                     do make (makefile pkgdesc)
+                        buildMods (NoREPL : Verbose : idris_opts pkgdesc)
+                                  (modules pkgdesc)
             when quit $ case res of
                           Nothing -> exitWith (ExitFailure 1)
                           Just res' -> do
@@ -115,13 +112,13 @@
 cleanPkg fp
      = do pkgdesc <- parseDesc fp
           dir <- getCurrentDirectory
-          setCurrentDirectory $ dir </> sourcedir pkgdesc
-          clean (makefile pkgdesc)
-          mapM_ rmIBC (modules pkgdesc)
-          rmIdx (pkgname pkgdesc)
-          case execout pkgdesc of
-               Nothing -> return ()
-               Just s -> rmFile $ dir </> s
+          inPkgDir pkgdesc $
+            do clean (makefile pkgdesc)
+               mapM_ rmIBC (modules pkgdesc)
+               rmIdx (pkgname pkgdesc)
+               case execout pkgdesc of
+                    Nothing -> return ()
+                    Just s -> rmFile $ dir </> s
 
 -- | Generate IdrisDoc for package
 -- TODO: Handle case where module does not contain a matching namespace
@@ -135,17 +132,17 @@
   do pkgdesc        <- parseDesc fp
      cd             <- getCurrentDirectory
      let pkgDir      = cd </> takeDirectory fp
-         outputDir   = cd </> (pkgname pkgdesc) ++ "_doc"
+         outputDir   = cd </> pkgname pkgdesc ++ "_doc"
          opts        = NoREPL : Verbose : idris_opts pkgdesc
          mods        = modules pkgdesc
          fs          = map (foldl1' (</>) . splitOn "." . showCG) mods
      setCurrentDirectory $ pkgDir </> sourcedir pkgdesc
      make (makefile pkgdesc)
-     setCurrentDirectory $ pkgDir
+     setCurrentDirectory pkgDir
      let run l       = runExceptT . execStateT l
          load []     = return ()
          load (f:fs) = do loadModule f; load fs
-         loader      = do idrisMain opts; load fs
+         loader      = do idrisMain opts; addImportDir (sourcedir pkgdesc); load fs
      idrisInstance  <- run loader idrisInit
      setCurrentDirectory cd
      case idrisInstance of
@@ -163,26 +160,25 @@
      = do pkgdesc <- parseDesc fp
           ok <- mapM (testLib True (pkgname pkgdesc)) (libdeps pkgdesc)
           when (and ok) $
-            do dir <- getCurrentDirectory
-               setCurrentDirectory $ dir </> sourcedir pkgdesc
-               make (makefile pkgdesc)
-               -- Get a temporary file to save the tests' source in
-               (tmpn, tmph) <- tempIdr
-               hPutStrLn tmph $
-                 "module Test_______\n" ++
-                 concat ["import " ++ show m ++ "\n"
-                         | m <- modules pkgdesc] ++
-                 "namespace Main\n" ++
-                 "  main : IO ()\n" ++
-                 "  main = do " ++
-                 concat [show t ++ "\n            "
-                         | t <- idris_tests pkgdesc]
-               hClose tmph
-               (tmpn', tmph') <- tempfile
-               hClose tmph'
-               m_ist <- idris (Filename tmpn : NoREPL : Verbose : Output tmpn' : idris_opts pkgdesc)
-               rawSystem tmpn' []
-               setCurrentDirectory dir
+            do m_ist <- inPkgDir pkgdesc $
+                          do make (makefile pkgdesc)
+                             -- Get a temporary file to save the tests' source in
+                             (tmpn, tmph) <- tempIdr
+                             hPutStrLn tmph $
+                               "module Test_______\n" ++
+                               concat ["import " ++ show m ++ "\n"
+                                       | m <- modules pkgdesc] ++
+                               "namespace Main\n" ++
+                               "  main : IO ()\n" ++
+                               "  main = do " ++
+                               concat [show t ++ "\n            "
+                                       | t <- idris_tests pkgdesc]
+                             hClose tmph
+                             (tmpn', tmph') <- tempfile
+                             hClose tmph'
+                             m_ist <- idris (Filename tmpn : NoREPL : Verbose : Output tmpn' : idris_opts pkgdesc)
+                             rawSystem tmpn' []
+                             return m_ist
                case m_ist of
                  Nothing -> exitWith (ExitFailure 1)
                  Just ist -> do
@@ -197,13 +193,12 @@
 -- | Install package
 installPkg :: PkgDesc -> IO ()
 installPkg pkgdesc
-     = do dir <- getCurrentDirectory
-          setCurrentDirectory $ dir </> sourcedir pkgdesc
-          case (execout pkgdesc) of
+     = inPkgDir pkgdesc $
+         do case (execout pkgdesc) of
               Nothing -> do mapM_ (installIBC (pkgname pkgdesc)) (modules pkgdesc)
                             installIdx (pkgname pkgdesc)
               Just o -> return () -- do nothing, keep executable locally, for noe
-          mapM_ (installObj (pkgname pkgdesc)) (objs pkgdesc)
+            mapM_ (installObj (pkgname pkgdesc)) (objs pkgdesc)
 
 -- ---------------------------------------------------------- [ Helper Methods ]
 -- Methods for building, testing, installing, and removal of idris
@@ -274,6 +269,18 @@
 #else
 mkDirCmd = "mkdir -p "
 #endif
+
+inPkgDir :: PkgDesc -> IO a -> IO a
+inPkgDir pkgdesc action =
+  do dir <- getCurrentDirectory
+     when (sourcedir pkgdesc /= "") $
+       do putStrLn $ "Entering directory `" ++ ("." </> sourcedir pkgdesc) ++ "'"
+          setCurrentDirectory $ dir </> sourcedir pkgdesc
+     res <- action
+     when (sourcedir pkgdesc /= "") $
+       do putStrLn $ "Leaving directory `" ++ ("." </> sourcedir pkgdesc) ++ "'"
+          setCurrentDirectory dir
+     return res
 
 -- ------------------------------------------------------- [ Makefile Commands ]
 -- | Invoke a Makefile's default target.
diff --git a/src/Util/ScreenSize.hs b/src/Util/ScreenSize.hs
--- a/src/Util/ScreenSize.hs
+++ b/src/Util/ScreenSize.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE CPP #-}
-module Util.ScreenSize where
+module Util.ScreenSize(getScreenWidth) where
 
 import Debug.Trace
 
diff --git a/src/Util/System.hs b/src/Util/System.hs
--- a/src/Util/System.hs
+++ b/src/Util/System.hs
@@ -1,9 +1,17 @@
-{-# LANGUAGE CPP #-}
+{-# LANGUAGE CPP, ForeignFunctionInterface #-}
 module Util.System(tempfile,withTempdir,rmFile,catchIO, isWindows,
-                writeSource, readSource, setupBundledCC) where
+                   writeSource, writeSourceText, readSource,
+                   setupBundledCC, isATTY) where
 
 -- System helper functions.
+
+import Control.Exception as CE
 import Control.Monad (when)
+import qualified Data.Text as T
+import qualified Data.Text.IO as TIO
+
+import Foreign.C
+
 import System.Directory (getTemporaryDirectory
                         , removeFile
                         , removeDirectoryRecursive
@@ -14,7 +22,6 @@
 import System.IO
 import System.Info
 import System.IO.Error
-import Control.Exception as CE
 
 #ifdef FREESTANDING
 import Tools_idris
@@ -43,6 +50,17 @@
 -- | Write a source file, same as writeFile except the encoding is set to utf-8
 writeSource :: FilePath -> String -> IO ()
 writeSource f s = withFile f WriteMode (\h -> hSetEncoding h utf8 >> hPutStr h s)
+
+-- | Write a utf-8 source file from Text
+writeSourceText :: FilePath -> T.Text -> IO ()
+writeSourceText f s = withFile f WriteMode (\h -> hSetEncoding h utf8 >> TIO.hPutStr h s)
+
+foreign import ccall "isatty" isATTYRaw :: CInt -> IO CInt
+
+isATTY :: IO Bool
+isATTY = do
+            tty <- isATTYRaw 1 -- fd stdout
+            return $ tty /= 0
 
 withTempdir :: String -> (FilePath -> IO a) -> IO a
 withTempdir subdir callback
diff --git a/src/Util/Zlib.hs b/src/Util/Zlib.hs
deleted file mode 100644
--- a/src/Util/Zlib.hs
+++ /dev/null
@@ -1,15 +0,0 @@
-module Util.Zlib (decompressEither) where
-
--- From http://stackoverflow.com/questions/10043102/how-to-catch-the-decompress-ioerror/10045963#10045963
-import Codec.Compression.Zlib.Internal
-import Data.ByteString.Lazy (ByteString, fromChunks)
-import Control.Arrow (right)
-
-decompressEither :: ByteString -> Either (DecompressError, String) ByteString
-decompressEither = finalise
-                            . foldDecompressStream cons nil err
-                            . decompressWithErrors zlibFormat defaultDecompressParams
-  where err errorCode errorString = Left (errorCode, errorString)
-        nil = Right []
-        cons chunk = right (chunk :)
-        finalise = right fromChunks
diff --git a/test/Makefile b/test/Makefile
--- a/test/Makefile
+++ b/test/Makefile
@@ -8,7 +8,7 @@
 	@perl ./runtest.pl $(patsubst %.test,%,$@)
 
 test_js:
-	@perl ./runtest.pl without disambig001 sugar004 reg029 reg052 io001 dsl002 io003 effects001 effects002 effects003 effects004 basic007 basic011 primitives004 ffi006 --codegen node
+	@perl ./runtest.pl without sugar004 reg029 reg052 io001 dsl002 io003 effects001 effects002 basic007 basic011 ffi006 --codegen node
 
 update:
 	/usr/bin/env perl ./runtest.pl all -u
diff --git a/test/basic006/expected b/test/basic006/expected
--- a/test/basic006/expected
+++ b/test/basic006/expected
@@ -1,8 +1,8 @@
-test020a.idr:16:18:When elaborating right hand side of foo:
-When elaborating an application of function Prelude.List.reverse:
-        Can't unify
+test020a.idr:16:18:When checking right hand side of foo:
+When checking an application of function Prelude.List.reverse:
+        Type mismatch between
                 Vect n a (Type of xs)
-        with
+        and
                 List a (Expected type)
 [3, 2, 1]
 "Number 42"
diff --git a/test/basic009/expected b/test/basic009/expected
--- a/test/basic009/expected
+++ b/test/basic009/expected
@@ -1,4 +1,4 @@
 MAIN-PASS
-Faulty.idr:6:7:When elaborating type of Faulty.fault:
+Faulty.idr:6:7:When checking type of Faulty.fault:
 Can't disambiguate name: A.num, B.C.num
 Multiple.idr:3:1:import alias not unique: "X"
diff --git a/test/classes001/expected b/test/classes001/expected
--- a/test/classes001/expected
+++ b/test/classes001/expected
@@ -8,6 +8,7 @@
     myShow : MyShow a => (x : a) -> String
         The shower
         
+        The function is Total
 Instance constructor:
     MkMyShow : (myShow : a -> String) -> MyShow a
         Build a MyShow
@@ -25,3 +26,4 @@
         
         myShow : a -> String  -- The shower
         
+    The function is Total
diff --git a/test/disambig001/disambig001.idr b/test/disambig001/disambig001.idr
deleted file mode 100644
--- a/test/disambig001/disambig001.idr
+++ /dev/null
@@ -1,12 +0,0 @@
-module Main
-
-import Prelude.Monad
-
-import System
-import Effect.System
-
-main : IO ()
-main = do 
-    args <- System.getArgs
-    putStrLn (concat (drop 1 args))
-
diff --git a/test/disambig001/expected b/test/disambig001/expected
deleted file mode 100644
--- a/test/disambig001/expected
+++ /dev/null
@@ -1,1 +0,0 @@
-foobar
diff --git a/test/disambig001/run b/test/disambig001/run
deleted file mode 100644
--- a/test/disambig001/run
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/usr/bin/env bash
-idris $@ disambig001.idr -p effects -o disambig001
-./disambig001 foo bar
-rm -f disambig001 *.ibc
diff --git a/test/docs001/expected b/test/docs001/expected
--- a/test/docs001/expected
+++ b/test/docs001/expected
@@ -8,6 +8,7 @@
     m : C t => t
         member of class
         
+        The function is Total
 Instances:
     C A
         instance of class
diff --git a/test/docs002/expected b/test/docs002/expected
--- a/test/docs002/expected
+++ b/test/docs002/expected
@@ -1,9 +1,12 @@
 T1 : Type
     Some documentation
     
+    The function is Total
 T2 : Type
     Some other documentation
     
+    The function is Total
 T3 : Int
     Some provided postulate
     
+    The function is not yet checked for totality
diff --git a/test/docs003/expected b/test/docs003/expected
--- a/test/docs003/expected
+++ b/test/docs003/expected
@@ -8,13 +8,14 @@
     map : Functor f => (m : a -> b) -> f a -> f b
         The action of the functor on morphisms
         
+        The function is Total
 Instances:
     Functor List
+    Functor (IO' ffi)
     Functor Stream
     Functor Provider
     Functor Binder
     Functor PrimIO
-    Functor (IO' ffi)
     Functor Maybe
     Functor (Either e)
 
@@ -27,10 +28,10 @@
     Traversable f
     Applicative f
 Named instance:
-    mine : Functor List
+    docs003.mine : Functor List
         
         
 Named instance:
-    another : Functor List
+    docs003.another : Functor List
         More functors!
         
diff --git a/test/dsl002/Resimp.idr b/test/dsl002/Resimp.idr
--- a/test/dsl002/Resimp.idr
+++ b/test/dsl002/Resimp.idr
@@ -1,6 +1,6 @@
 module Resimp
 
-import Data.Vect
+import public Data.Vect
 import public Data.Fin
 
 -- IO operations which read a resource
diff --git a/test/dsl004/Door0.idr b/test/dsl004/Door0.idr
new file mode 100644
--- /dev/null
+++ b/test/dsl004/Door0.idr
@@ -0,0 +1,33 @@
+import IOu
+
+data Result : (a : Type) -> (a -> Type) -> Type* where
+     Res : {k : a -> Type} -> (val : a) -> k val -> Result a k
+
+
+
+
+
+
+
+------
+data DoorState = OPEN | CLOSED
+
+data DoorH : DoorState -> Type where
+  MkDH : {s : DoorState} -> DoorH s
+
+data DoorCmd : Type -> Type where
+     Open : DoorH CLOSED -> DoorCmd (DoorH OPEN)
+     Knock : DoorH CLOSED -> DoorCmd (DoorH CLOSED)
+     Close : DoorH OPEN -> DoorCmd (DoorH CLOSED)
+
+data DoorLang : Type -> Type where
+     Return : a -> DoorLang a
+     Action : DoorCmd a -> DoorLang a
+     (>>=) : DoorLang a -> (a -> DoorLang b) -> DoorLang b
+
+testProg : DoorH CLOSED -> DoorLang ()
+testProg h = do h <- Action (Knock h)
+                h <- Action (Open h)
+                h <- Action (Close h)
+                Return ()
+
diff --git a/test/dsl004/Door1.idr b/test/dsl004/Door1.idr
new file mode 100644
--- /dev/null
+++ b/test/dsl004/Door1.idr
@@ -0,0 +1,37 @@
+import IOu
+
+import Data.Vect
+
+data Result : (a : AnyType) -> (a -> AnyType) -> AnyType where
+     Res : {k : a -> AnyType} -> (val : a) -> (h : k val) -> Result a k
+
+
+
+
+
+------
+data DoorState = OPEN | CLOSED
+
+data DoorH : DoorState -> UniqueType where
+     MkDH : DoorH s
+
+data DoorCmd : AnyType -> AnyType where
+     Open : DoorH CLOSED -> DoorCmd (DoorH OPEN)
+     Knock : DoorH CLOSED -> DoorCmd (DoorH CLOSED)
+     Close : DoorH OPEN -> DoorCmd (DoorH CLOSED)
+
+data DoorLang : AnyType -> AnyType where
+     Return : {a : AnyType} -> a -> DoorLang a
+     Action : DoorCmd a -> DoorLang a
+     (>>=) : DoorLang a -> (a -> DoorLang b) -> DoorLang b
+
+implicit
+action : DoorCmd a -> DoorLang a
+action = Action
+
+testProg : DoorH CLOSED -> DoorLang ()
+testProg h = with Main, Show do -- h <- Knock h
+                h <- Open h
+                -- h <- Close h
+                Return ()
+
diff --git a/test/dsl004/Door2.idr b/test/dsl004/Door2.idr
new file mode 100644
--- /dev/null
+++ b/test/dsl004/Door2.idr
@@ -0,0 +1,37 @@
+import IOu
+
+data DoorState = OPEN | CLOSED
+
+data DoorH : DoorState -> UniqueType where
+     MkDH : DoorH s
+
+infix 5 @@
+
+data Res : (a : AnyType) -> (a -> AnyType) -> AnyType where
+     (@@) : (val : a) -> (h : k val) -> Res a k
+
+data DoorCmd : AnyType -> AnyType where
+     Open : DoorH CLOSED -> 
+            DoorCmd (Res Bool (\ok => case ok of
+                                        True => DoorH OPEN
+                                        False => DoorH CLOSED))
+     Knock : DoorH CLOSED -> DoorCmd (DoorH CLOSED)
+     Close : DoorH OPEN -> DoorCmd (DoorH CLOSED)
+
+data DoorLang : AnyType -> AnyType where
+     Return : a -> DoorLang a
+     Action : DoorCmd a -> DoorLang a
+     (>>=) : DoorLang a -> (a -> DoorLang b) -> DoorLang b
+
+implicit
+action : DoorCmd a -> DoorLang a
+action = Action
+
+covering
+testProg : DoorH CLOSED -> DoorLang ()
+testProg h = do h <- Action (Knock h)
+                (True @@ h) <- Action (Open h) 
+                     | (False @@ h) => testProg h 
+                h <- Action (Close h)
+                Return ()
+
diff --git a/test/dsl004/Door3.idr b/test/dsl004/Door3.idr
new file mode 100644
--- /dev/null
+++ b/test/dsl004/Door3.idr
@@ -0,0 +1,30 @@
+import IOu
+
+data DoorState = OPEN | CLOSED
+
+data DoorH : DoorState -> UniqueType where
+     MkDH : DoorH s
+
+infix 5 @@
+
+data Res : (a : AnyType) -> (a -> AnyType) -> AnyType where
+     (@@) : {k : a -> AnyType} -> (val : a) -> k val -> Res a k
+
+data DoorCmd : AnyType -> AnyType where
+     Open : DoorH CLOSED -> 
+            DoorCmd (Res Bool (\ok => if ok then DoorH OPEN
+                                            else DoorH CLOSED))
+     Knock : DoorH CLOSED -> DoorCmd (DoorH CLOSED)
+     Close : DoorH OPEN -> DoorCmd (DoorH CLOSED)
+
+data DoorLang : AnyType -> AnyType where
+     Return : {a : AnyType} -> a -> DoorLang a
+     Action : DoorCmd a -> DoorLang a
+     (>>=) : DoorLang a -> (a -> DoorLang b) -> DoorLang b
+
+testProg : DoorH CLOSED -> DoorLang (DoorH CLOSED)
+testProg h = do h <- Action (Knock h)
+                (True @@ h) <- Action (Open h) 
+                   | (False @@ h) => Return h
+                Action (Close h)
+
diff --git a/test/dsl004/IOu.idr b/test/dsl004/IOu.idr
new file mode 100644
--- /dev/null
+++ b/test/dsl004/IOu.idr
@@ -0,0 +1,19 @@
+module IOu
+
+-------- An IO type supporting possibly unique values
+
+data IOu : AnyType -> AnyType where
+     MkIOu : IO a -> IOu a
+
+(>>=) : {a,b: AnyType} -> IOu a -> (a -> IOu b) -> IOu b
+(>>=) (MkIOu x) k = MkIOu (do x' <- x
+                              case k x' of
+                                   MkIOu k' => k')
+
+pure : {a : AnyType} -> a -> IOu a
+pure x = MkIOu (pure x)
+
+run : IOu a -> IO a
+run (MkIOu x) = x
+
+
diff --git a/test/dsl004/expected b/test/dsl004/expected
new file mode 100644
--- /dev/null
+++ b/test/dsl004/expected
diff --git a/test/dsl004/run b/test/dsl004/run
new file mode 100644
--- /dev/null
+++ b/test/dsl004/run
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+idris $@ Door0.idr --check
+idris $@ Door1.idr --check
+idris $@ Door2.idr --check
+rm -f *.ibc
diff --git a/test/effects005/defaultlog.idr b/test/effects005/defaultlog.idr
new file mode 100644
--- /dev/null
+++ b/test/effects005/defaultlog.idr
@@ -0,0 +1,18 @@
+import Effects
+import Effect.Logging.Default
+
+func : Nat -> Eff () [LOG String]
+func x = do
+  log WARN Nil $ unwords ["I do nothing with", show x]
+  pure ()
+
+doubleFunc : Nat -> Eff Nat [LOG String]
+doubleFunc x = do
+  log WARN ["NumOPS"] $ unwords ["Doing the double with", show x ]
+  func x
+  pure (x+x)
+
+main : IO ()
+main = do
+   x <- runInit [(ALL,["NumOPS"])] (doubleFunc 3)
+   printLn x
diff --git a/test/effects005/expected b/test/effects005/expected
new file mode 100644
--- /dev/null
+++ b/test/effects005/expected
@@ -0,0 +1,5 @@
+"3 : Doing the double with 3"
+6
+8
+"3 : [\"NumOPS\"] : Doing the double with 3"
+6
diff --git a/test/effects005/run b/test/effects005/run
new file mode 100644
--- /dev/null
+++ b/test/effects005/run
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+idris $@ simplelog.idr -o simple -p effects
+./simple
+idris $@ defaultlog.idr -o default -p effects
+./default
+rm -f simple default *.ibc
diff --git a/test/effects005/simplelog.idr b/test/effects005/simplelog.idr
new file mode 100644
--- /dev/null
+++ b/test/effects005/simplelog.idr
@@ -0,0 +1,14 @@
+import Effects
+import Effect.Logging.Simple
+
+doubleFunc : Nat -> Eff Nat [LOG]
+doubleFunc x = do
+  log WARN $ unwords ["Doing the double with", show x ]
+  pure (x+x)
+
+main : IO ()
+main = do
+   x <- runInit [ALL] (doubleFunc 3)
+   printLn x
+   y <- runInit [OFF] (doubleFunc 4)
+   printLn y
diff --git a/test/error003/expected b/test/error003/expected
--- a/test/error003/expected
+++ b/test/error003/expected
@@ -1,3 +1,2 @@
-ErrorReflection.idr:68:5:
-When elaborating right hand side of bad:
+ErrorReflection.idr:68:5:When checking right hand side of bad:
 DSL type error: (t(503) => t'(504)) doesn't match ()
diff --git a/test/error004/FunErrTest.idr b/test/error004/FunErrTest.idr
--- a/test/error004/FunErrTest.idr
+++ b/test/error004/FunErrTest.idr
@@ -8,16 +8,16 @@
 
 total
 cadr :  (xs : List a)
-     -> {auto cons1 : isCons xs = True}
-     -> {auto cons2 : isCons (tail xs) = True}
+     -> {auto cons1 : NonEmpty xs}
+     -> {auto cons2 : NonEmpty (tail xs)}
      -> a
-cadr (x :: (y :: _)) {cons1=Refl} {cons2=Refl} = y
-cadr (x :: [])       {cons1=Refl} {cons2=Refl} impossible
-cadr []              {cons1=Refl} {cons2=Refl} impossible
+cadr (x :: (y :: _)) {cons1=IsNonEmpty} {cons2=IsNonEmpty} = y
+cadr (x :: [])       {cons1=IsNonEmpty} {cons2=IsNonEmpty} impossible
+cadr []              {cons1=IsNonEmpty} {cons2=IsNonEmpty} impossible
 
 extractList : TT -> Maybe TT
-extractList (App (App reflCon (App isCons lst)) _) = Just lst
-extractList _ = Nothing
+extractList (App (App neType _) lst) = Just lst
+extractList t = Just t -- Nothing
 
 total
 has2elts : Err -> Maybe (List ErrorReportPart)
@@ -39,3 +39,4 @@
 
 goodCadr : Int
 goodCadr = cadr [1, 2]
+
diff --git a/test/error004/expected b/test/error004/expected
--- a/test/error004/expected
+++ b/test/error004/expected
@@ -1,9 +1,6 @@
-FunErrTest.idr:35:10:
-When elaborating right hand side of badCadr1:
-When elaborating argument cons1 to function FunErrTest.cadr:
+FunErrTest.idr:35:10:When checking right hand side of badCadr1:
+When checking argument cons1 to function FunErrTest.cadr:
         Could not prove that [] has at least two elements.
-FunErrTest.idr:38:10:
-When elaborating right hand side of badCadr2:
-When elaborating argument cons2 to function FunErrTest.cadr:
-        Could not prove that tail [(fromInteger 1)] has at least two
-        elements.
+FunErrTest.idr:38:10:When checking right hand side of badCadr2:
+When checking argument cons2 to function FunErrTest.cadr:
+        Could not prove that tail [1] has at least two elements.
diff --git a/test/error004/idx.idr b/test/error004/idx.idr
new file mode 100644
--- /dev/null
+++ b/test/error004/idx.idr
@@ -0,0 +1,4 @@
+idx : (n : Nat) -> (l : List a) -> {auto ok : n < length l = True} -> a
+idx Z     (x::xs) {ok=p}    = x
+idx (S n) (x::xs) {ok=p}    = idx n xs {ok=rewrite p in Refl}
+idx _     []      {ok=Refl} impossible --   = ?foo
diff --git a/test/error005/expected b/test/error005/expected
--- a/test/error005/expected
+++ b/test/error005/expected
@@ -1,21 +1,21 @@
-error005.idr:13:1:When elaborating right hand side of two:
-When elaborating argument prf to function Data.Fin.fromInteger:
+error005.idr:13:1:When checking right hand side of two:
+When checking argument prf to function Data.Fin.fromInteger:
         When using 2 as a literal for a Fin 2 
                 2 is not strictly less than 2
-error005.idr:16:1:When elaborating right hand side of hahaha:
-When elaborating argument prf to function Data.Fin.fromInteger:
+error005.idr:16:1:When checking right hand side of hahaha:
+When checking argument prf to function Data.Fin.fromInteger:
         When using 0 as a literal for a Fin n 
                 0 is not strictly less than n
-error005.idr:22:1:When elaborating right hand side of notOk:
-When elaborating argument prf to function Data.Fin.fromInteger:
+error005.idr:22:1:When checking right hand side of notOk:
+When checking argument prf to function Data.Fin.fromInteger:
         When using 2 as a literal for a Fin (S (S n)) 
                 2 is not strictly less than S (S n)
-error005.idr:23:24:When elaborating right hand side of b0rken:
-When elaborating argument prf to function Data.Fin.fromInteger:
+error005.idr:23:24:When checking right hand side of b0rken:
+When checking argument prf to function Data.Fin.fromInteger:
         When using n as a literal for a Fin 3 
                 Could not show that n is less than 3 because n is a bound
                 variable instead of a constant Integer
-error005.idr:28:1:When elaborating right hand side of x:
-When elaborating argument prf to function Data.Fin.fromInteger:
+error005.idr:28:1:When checking right hand side of x:
+When checking argument prf to function Data.Fin.fromInteger:
         When using 5 as a literal for a Fin 4 
                 5 is not strictly less than 4
diff --git a/test/idrisdoc009/expected b/test/idrisdoc009/expected
--- a/test/idrisdoc009/expected
+++ b/test/idrisdoc009/expected
@@ -1,4 +1,4 @@
-Data type Test : Type
+Data type Test.Test : Type
     Docs for datatype Test.
     
 Constructors:
diff --git a/test/interactive003/expected b/test/interactive003/expected
--- a/test/interactive003/expected
+++ b/test/interactive003/expected
@@ -2,3 +2,4 @@
 x :: app xs ys
 []
 f x y :: vzipWith f xs ys
+?word_length_rhs_3 :: word_length xs
diff --git a/test/interactive003/input b/test/interactive003/input
--- a/test/interactive003/input
+++ b/test/interactive003/input
@@ -2,3 +2,4 @@
 :ps 5 app_rhs_2
 :ps 8 vzipWith_rhs_3
 :ps 9 vzipWith_rhs_1
+:ps 13 word_length_rhs_2
diff --git a/test/interactive003/interactive003.idr b/test/interactive003/interactive003.idr
--- a/test/interactive003/interactive003.idr
+++ b/test/interactive003/interactive003.idr
@@ -8,3 +8,8 @@
 vzipWith f [] [] = ?vzipWith_rhs_3
 vzipWith f (x :: xs) (y :: ys) = ?vzipWith_rhs_1
 
+word_length : Vect n String -> Vect n Nat
+word_length [] = []
+word_length (x :: xs) = ?word_length_rhs_2
+
+
diff --git a/test/interactive005/expected b/test/interactive005/expected
--- a/test/interactive005/expected
+++ b/test/interactive005/expected
@@ -1,13 +1,14 @@
 3 : Nat
 Hello, World
-main : IO ()
+Main.main : IO ()
     This is a docstring
     
+    The function is Total
 Main.main is Total
 Hello, World
-Prelude.Basics.id : a -> a
-Prelude.Basics.id : {a : Type} -> (__pi_arg : a) -> a
-Prelude.Basics.id : a -> a
+id : a -> a
+Prelude.Basics.id : {a : Type} -> a -> a
+id : a -> a
 
 	 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY  
 	 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE     
@@ -21,13 +22,15 @@
 	 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 	 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-main : IO ()
+Main.main : IO ()
     This
     is a
     docstring
     
-main : IO ()
+    The function is Total
+Main.main : IO ()
     This is a docstring
     
+    The function is Total
 Nat2 : Type
 Invalid filename for compiler output "Test.idr"
diff --git a/test/interactive008/expected b/test/interactive008/expected
new file mode 100644
--- /dev/null
+++ b/test/interactive008/expected
@@ -0,0 +1,204 @@
+Idris> Idris> Idris> 1 ::
+2 :: 3 :: 4 :: 5 :: ... : List Integer
+Idris> Idris> [1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+ 32,
+ 33,
+ 34,
+ 35,
+ 36,
+ 37,
+ 38,
+ 39,
+ 40,
+ 41,
+ 42,
+ 43,
+ 44,
+ 45,
+ 46,
+ 47,
+ 48,
+ 49,
+ 50,
+ 51,
+ 52,
+ 53,
+ 54,
+ 55,
+ 56,
+ 57,
+ 58,
+ 59,
+ 60,
+ 61,
+ 62,
+ 63,
+ 64,
+ 65,
+ 66,
+ 67,
+ 68,
+ 69,
+ 70,
+ 71,
+ 72,
+ 73,
+ 74,
+ 75,
+ 76,
+ 77,
+ 78,
+ 79,
+ 80,
+ 81,
+ 82,
+ 83,
+ 84,
+ 85,
+ 86,
+ 87,
+ 88,
+ 89,
+ 90,
+ 91,
+ 92,
+ 93,
+ 94,
+ 95,
+ 96,
+ 97,
+ 98,
+ 99,
+ 100] : List Integer
+Idris> Idris> ... : ...
+Idris> Idris> [1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+ 32,
+ 33,
+ 34,
+ 35,
+ 36,
+ 37,
+ 38,
+ 39,
+ 40,
+ 41,
+ 42,
+ 43,
+ 44,
+ 45,
+ 46,
+ 47,
+ 48,
+ 49,
+ 50,
+ 51,
+ 52,
+ 53,
+ 54,
+ 55,
+ 56,
+ 57,
+ 58,
+ 59,
+ 60,
+ 61,
+ 62,
+ 63,
+ 64,
+ 65,
+ 66,
+ 67,
+ 68,
+ 69,
+ 70,
+ 71,
+ 72,
+ 73,
+ 74,
+ 75,
+ 76,
+ 77,
+ 78,
+ 79,
+ 80,
+ 81,
+ 82,
+ 83,
+ 84,
+ 85,
+ 86,
+ 87,
+ 88,
+ 89,
+ 90,
+ 91,
+ 92,
+ 93,
+ 94,
+ 95,
+ 96,
+ 97,
+ 98,
+ 99,
+ 100] : List Integer
+Idris> Bye bye
diff --git a/test/interactive008/input b/test/interactive008/input
new file mode 100644
--- /dev/null
+++ b/test/interactive008/input
@@ -0,0 +1,9 @@
+:consolewidth 50
+:printerdepth 5
+the (List Integer) [1..20]
+:printerdepth 1000
+the (List Integer) [1..100]
+:printerdepth 0
+the (List Integer) [1..100]
+:printerdepth
+the (List Integer) [1..100]
diff --git a/test/interactive008/run b/test/interactive008/run
new file mode 100644
--- /dev/null
+++ b/test/interactive008/run
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+idris --nobanner --nocolor < input
diff --git a/test/interactive009/expected b/test/interactive009/expected
new file mode 100644
--- /dev/null
+++ b/test/interactive009/expected
@@ -0,0 +1,1 @@
+IsSetCons pf prfRec
diff --git a/test/interactive009/input b/test/interactive009/input
new file mode 100644
--- /dev/null
+++ b/test/interactive009/input
@@ -0,0 +1,1 @@
+:ps 26 rec
diff --git a/test/interactive009/interactive009.idr b/test/interactive009/interactive009.idr
new file mode 100644
--- /dev/null
+++ b/test/interactive009/interactive009.idr
@@ -0,0 +1,27 @@
+import Data.Vect
+
+%default total
+
+data ElemBool : Eq t => t -> Vect n t -> Bool -> Type where
+  ElemBoolNil : Eq t => ElemBool {t=t} a [] False
+  ElemBoolCons : Eq t => ElemBool {t=t} x1 xs b -> ElemBool x1 (x2 :: xs) ((x1 == x2) || b)
+
+data IsSet : Eq t => Vect n t -> Type where
+  IsSetNil : Eq t => IsSet {t=t} []
+  IsSetCons : Eq t => ElemBool {t=t} x xs False -> IsSet xs -> IsSet (x :: xs)
+
+fun_1 : Eq t => (x : t) -> (xs : Vect n t) -> (b : Bool ** ElemBool x xs b)
+fun_1 x [] = (False ** ElemBoolNil)
+fun_1 x1 (x2 :: xs) = 
+  let (b ** prfRec) = fun_1 x1 xs
+  in (((x1 == x2) || b) ** (ElemBoolCons prfRec))  
+
+fun_2 : Eq t => (xs : Vect n t) -> Maybe (IsSet xs)
+fun_2 [] = Just IsSetNil
+fun_2 (x :: xs) with (fun_1 x xs)
+  fun_2 (x :: xs) | (True ** pf) = Nothing 
+  fun_2 (x :: xs) | (False ** pf) with (fun_2 xs)
+    fun_2 (x :: xs) | (False ** pf) | Nothing = Nothing 
+    fun_2 (x :: xs) | (False ** pf) | (Just prfRec) 
+        = Just ?rec 
+
diff --git a/test/interactive009/run b/test/interactive009/run
new file mode 100644
--- /dev/null
+++ b/test/interactive009/run
@@ -0,0 +1,3 @@
+#!/usr/bin/env bash
+idris --quiet interactive009.idr < input
+rm -f *.ibc
diff --git a/test/io003/test018.idr b/test/io003/test018.idr
--- a/test/io003/test018.idr
+++ b/test/io003/test018.idr
@@ -11,9 +11,11 @@
           putStrLn x
           putStrLn "Received"
           sendToThread sender "Hello to you too!"
+          return ()
 
 ping : Ptr -> IO ()
-ping thread = sendToThread thread (prim__vm, "Hello!")
+ping thread = do sendToThread thread (prim__vm, "Hello!")
+                 return ()
 
 pingpong : IO ()
 pingpong
diff --git a/test/io003/test018a.idr b/test/io003/test018a.idr
--- a/test/io003/test018a.idr
+++ b/test/io003/test018a.idr
@@ -11,12 +11,14 @@
         msg <- recv
         Lift (putStrLn ("Reply: " ++ show msg))
         send main "Done"
+        return ()
 
 pong : Process String ()
 pong = do -- Lift (putStrLn "Waiting for message")
           (sender, m) <- recvWithSender
           Lift $ putStrLn ("Received " ++ m)
           send sender ("Hello back!")
+          return ()
 
 mainProc : Process String ()
 mainProc = do mainID <- myID
diff --git a/test/meta001/Finite.idr b/test/meta001/Finite.idr
--- a/test/meta001/Finite.idr
+++ b/test/meta001/Finite.idr
@@ -27,42 +27,44 @@
 mkFin (S k) (S j) = do i <- mkFin k j
                        return `(FS {k=~(quote k)} ~i)
 
-mkToClause : TTName -> (size, i : Nat) -> (constr : (TTName, Raw)) -> Elab FunClause
-mkToClause fn size i (n, Var ty) =
+mkToClause : TTName -> (size, i : Nat) ->
+             (constr : (TTName, List CtorArg, Raw)) ->
+             Elab FunClause
+mkToClause fn size i (n, [], Var ty) =
   MkFunClause (RApp (Var fn) (Var n)) <$> mkFin size i
-mkToClause fn size i (n, ty) =
+mkToClause fn size i (n, _, ty) =
   fail [TextPart "unsupported constructor", NamePart n]
 
 
 mkFromClause : TTName -> (size, i : Nat) ->
-               (constr : (TTName, Raw)) ->
+               (constr : (TTName, List CtorArg, Raw)) ->
                Elab FunClause
-mkFromClause fn size i (n, Var ty) =
+mkFromClause fn size i (n, [], Var ty) =
   return $ MkFunClause (RApp (Var fn) !(mkFin size i)) (Var n)
-mkFromClause fn size i (n, ty) =
+mkFromClause fn size i (n, _, ty) =
   fail [TextPart "unsupported constructor", NamePart n]
 
 
-mkOk1Clause : TTName -> (size, i : Nat) -> (constr : (TTName, Raw)) -> Elab FunClause
-mkOk1Clause fn size i (n, Var ty) =
+mkOk1Clause : TTName -> (size, i : Nat) -> (constr : (TTName, List CtorArg, Raw)) -> Elab FunClause
+mkOk1Clause fn size i (n, [], Var ty) =
   return $ MkFunClause (RApp (Var fn) (Var n))
                        [| (Var (UN "Refl")) (Var ty) (Var n) |]
-mkOk1Clause fn size i (n, ty) =
+mkOk1Clause fn size i (n, _, ty) =
   fail [TextPart "unsupported constructor", NamePart n]
 
 
-mkOk2Clause : TTName -> (size, i : Nat) -> (constr : (TTName, Raw)) -> Elab FunClause
-mkOk2Clause fn size i (n, Var ty) =
+mkOk2Clause : TTName -> (size, i : Nat) -> (constr : (TTName, List CtorArg, Raw)) -> Elab FunClause
+mkOk2Clause fn size i (n, [], Var ty) =
   return $ MkFunClause (RApp (Var fn) !(mkFin size i))
                        [| (Var "Refl") `(Fin ~(quote size))
                                        !(mkFin size i) |]
-mkOk2Clause fn size i (n, ty) =
+mkOk2Clause fn size i (n, _, ty) =
   fail [TextPart "unsupported constructor", NamePart n]
 
 
-mkToClauses : TTName -> Nat -> List (TTName, Raw) -> Elab (List FunClause)
+mkToClauses : TTName -> Nat -> List (TTName, List CtorArg, Raw) -> Elab (List FunClause)
 mkToClauses fn size xs = mkToClauses' Z xs
-  where mkToClauses' : Nat -> List (TTName, Raw) -> Elab (List FunClause)
+  where mkToClauses' : Nat -> List (TTName, List CtorArg, Raw) -> Elab (List FunClause)
         mkToClauses' k []        = return []
         mkToClauses' k (x :: xs) = do rest <- mkToClauses' (S k) xs
                                       clause <- mkToClause fn size k x
@@ -90,26 +92,26 @@
 
 
 mkFromClauses : TTName -> TTName -> Nat ->
-                List (TTName, Raw) -> Elab (List FunClause)
+                List (TTName, List CtorArg, Raw) -> Elab (List FunClause)
 mkFromClauses fn ty size xs = mkFromClauses' Z xs
-  where mkFromClauses' : Nat -> List (TTName, Raw) -> Elab (List FunClause)
+  where mkFromClauses' : Nat -> List (TTName, List CtorArg, Raw) -> Elab (List FunClause)
         mkFromClauses' k []        =
              return [!(mkAbsurdFinClause fn (const (Var ty)) size)]
         mkFromClauses' k (x :: xs) = do rest <- mkFromClauses' (S k) xs
                                         clause <- mkFromClause fn size k x
                                         return $ clause :: rest
 
-mkOk1Clauses : TTName -> Nat -> List (TTName, Raw) -> Elab (List FunClause)
+mkOk1Clauses : TTName -> Nat -> List (TTName, List CtorArg, Raw) -> Elab (List FunClause)
 mkOk1Clauses fn size xs = mkOk1Clauses' Z xs
-  where mkOk1Clauses' : Nat -> List (TTName, Raw) -> Elab (List FunClause)
+  where mkOk1Clauses' : Nat -> List (TTName, List CtorArg, Raw) -> Elab (List FunClause)
         mkOk1Clauses' k []        = return []
         mkOk1Clauses' k (x :: xs) = do rest <- mkOk1Clauses' (S k) xs
                                        clause <- mkOk1Clause fn size k x
                                        return $ clause :: rest
 
-mkOk2Clauses : TTName -> Nat -> List (TTName, Raw) -> (Raw -> Raw) -> Elab (List FunClause)
+mkOk2Clauses : TTName -> Nat -> List (TTName, List CtorArg, Raw) -> (Raw -> Raw) -> Elab (List FunClause)
 mkOk2Clauses fn size xs resTy = mkOk2Clauses' Z xs
-  where mkOk2Clauses' : Nat -> List (TTName, Raw) -> Elab (List FunClause)
+  where mkOk2Clauses' : Nat -> List (TTName, List CtorArg, Raw) -> Elab (List FunClause)
         mkOk2Clauses' k []        = return [!(mkAbsurdFinClause fn resTy size)]
         mkOk2Clauses' k (x :: xs) = do rest <- mkOk2Clauses' (S k) xs
                                        clause <- mkOk2Clause fn size k x
@@ -121,19 +123,19 @@
   do (MkDatatype famn tcargs tcres constrs) <- lookupDatatypeExact ty
      let size = length constrs
      argn <- gensym "arg"
-     declareType $ Declare to [Explicit argn (Var ty)]
+     declareType $ Declare to [MkFunArg argn (Var ty) Explicit NotErased]
                            `(Fin ~(quote size))
      toClauses <- mkToClauses to size constrs
      defineFunction $ DefineFun to toClauses
 
      argn' <- gensym "arg"
-     declareType $ Declare from [Explicit argn' `(Fin ~(quote size))]
+     declareType $ Declare from [MkFunArg argn' `(Fin ~(quote size)) Explicit NotErased ]
                            (Var ty)
      fromClauses <- mkFromClauses from ty size constrs
      defineFunction $ DefineFun from fromClauses
 
      argn'' <- gensym "arg"
-     declareType $ Declare ok1 [Explicit argn'' (Var ty)]
+     declareType $ Declare ok1 [MkFunArg argn'' (Var ty) Explicit NotErased]
                            `((=) {A=~(Var ty)} {B=~(Var ty)}
                                  ~(RApp (Var from) (RApp (Var to) (Var argn'')))
                                  ~(Var argn''))
@@ -146,7 +148,7 @@
        (\n => `((=) {A=~fty} {B=~fty}
                    ~(RApp (Var to) (RApp (Var from) n))
                    ~n))
-     declareType $ Declare ok2 [Explicit argn''' fty]
+     declareType $ Declare ok2 [MkFunArg argn''' fty Explicit NotErased]
                            (ok2ResTy (Var argn'''))
      ok2Clauses <- mkOk2Clauses ok2 size constrs ok2ResTy
      defineFunction $ DefineFun ok2 ok2Clauses
diff --git a/test/meta002/Tacs.idr b/test/meta002/Tacs.idr
--- a/test/meta002/Tacs.idr
+++ b/test/meta002/Tacs.idr
@@ -24,11 +24,11 @@
 intros : Elab ()
 intros = do g <- getGoal
             case snd g of
-              `(~_ -> ~_) => intro Nothing
+              `(~_ -> ~_) => intro'
               _ => return ()
 
 foo : Nat -> Nat
-foo = %runElab (do intro (Just (UN "fnord"))
+foo = %runElab (do intro (UN "fnord")
                    fill `(plus ~(Var (UN "fnord")) ~(Var (UN "fnord")))
                    solve)
 
@@ -181,7 +181,7 @@
               mkIx : Fin n -> Elab ()
               mkIx FZ = do envH <- mkEnvH
                            tH <- mkTyH
-                           apply `(Z {t=~(Var tH)} {env=~(Var envH)})
+                           apply `(Z {t=~(Var tH)} {env=~(Var envH)}) []
                            solve
               mkIx (FS i) = do envH <- mkEnvH
                                tH <- mkTyH
@@ -189,7 +189,7 @@
                                argH <- gensym "arg"
                                claim argH `(Ix ~(Var envH) ~(Var tH))
                                unfocus argH
-                               apply `(S {env=~(Var envH)} {t=~(Var tH)} {t'=~(Var vH)} ~(Var argH))
+                               apply `(S {env=~(Var envH)} {t=~(Var tH)} {t'=~(Var vH)} ~(Var argH)) []
                                solve
                                focus argH
                                mkIx i
@@ -203,6 +203,7 @@
                                         apply `(Lam {env=~(Var envH)}
                                                     {t=~(Var tH)} {t'=~(Var tH')}
                                                     ~(Var bodyH))
+                                              []
 
                                         solve
                                         focus bodyH
@@ -219,6 +220,7 @@
                                           apply `(App {env=~(Var envH)}
                                                       {t=~(Var tH)} {t'=~(Var tH')}
                                                       ~(Var fH) ~(Var argH))
+                                                []
                                           solve
                                           focus fH
                                           mkTerm xs tm
@@ -230,11 +232,13 @@
                                      claim ixH `(Ix ~(Var envH) ~(Var tH))
                                      unfocus ixH
                                      apply `(Var {env=~(Var envH)} {t=~(Var tH)} ~(Var ixH))
+                                           []
                                      solve
                                      focus ixH
                                      mkIx i
               mkTerm xs UnitCon = do envH <- mkEnvH
                                      apply `(UnitCon {env=~(Var envH)})
+                                           []
                                      solve
     testElab : Sigma Ty (Tm [])
     testElab = %runElab (elaborateSTLC (App (Lam "x" UnitCon) UnitCon))
diff --git a/test/meta002/expected b/test/meta002/expected
--- a/test/meta002/expected
+++ b/test/meta002/expected
@@ -1,3 +1,3 @@
-Tacs.idr:247:15:
-When elaborating right hand side of testElab3:
+Tacs.idr:251:15:
+When checking right hand side of testElab3:
 Unifying ty and ARR ty t would lead to infinite value
diff --git a/test/primitives002/expected b/test/primitives002/expected
--- a/test/primitives002/expected
+++ b/test/primitives002/expected
@@ -1,15 +1,15 @@
 prim__floatToStr 0.0
-"0.0"
-prim__strToFloat "0.0"
-0.0
+"0"
+prim__strToFloat 0.0
+0
 prim__addFloat 1.0 1.0
-2.0
+2
 prim__subFloat 1.0 1.0
-0.0
+0
 prim__mulFloat 1.0 1.0
-1.0
+1
 prim__divFloat 1.0 1.0
-1.0
+1
 prim__slteFloat 1.0 1.0
 1
 prim__sltFloat 1.0 1.0
@@ -21,13 +21,13 @@
 prim__eqFloat 1.0 1.0
 1
 prim__floatACos 1.0
-0.0
+0
 prim__floatATan 1.0
 0.78539816
 prim__floatCos 1.0
 0.54030230
 prim__floatFloor 1.0
-1.0
+1
 prim__floatSin 1.0
 0.84147098
 prim__floatTan 1.0
@@ -35,12 +35,12 @@
 prim__floatASin 1.0
 1.57079632
 prim__floatCeil 1.0
-1.0
+1
 prim__floatExp 1.0
 2.71828182
 prim__floatLog 1.0
-0.0
+0
 prim__floatSqrt 1.0
-1.0
+1
 prim__negFloat 1.0
--1.0
+-1
diff --git a/test/primitives002/run b/test/primitives002/run
--- a/test/primitives002/run
+++ b/test/primitives002/run
@@ -1,37 +1,41 @@
 #!/usr/bin/env bash
 
-HEAD="module Main
+HEAD='module Main
 
 import Data.Floats
 
 strtake : Nat -> String -> String
 strtake n str = pack (take n (unpack str))
 
-main : IO ()"
+getf : IO Double
+getf = map cast getLine
 
-TESTS=("prim__floatToStr 0.0"
-"prim__strToFloat \"0.0\""
-"prim__addFloat 1.0 1.0"
-"prim__subFloat 1.0 1.0"
-"prim__mulFloat 1.0 1.0"
-"prim__divFloat 1.0 1.0"
-"prim__slteFloat 1.0 1.0"
-"prim__sltFloat 1.0 1.0"
-"prim__sgteFloat 1.0 1.0"
-"prim__sgtFloat 1.0 1.0"
-"prim__eqFloat 1.0 1.0"
-"prim__floatACos 1.0"
-"prim__floatATan 1.0"
-"prim__floatCos 1.0"
-"prim__floatFloor 1.0"
-"prim__floatSin 1.0"
-"prim__floatTan 1.0"
-"prim__floatASin 1.0"
-"prim__floatCeil 1.0"
-"prim__floatExp 1.0"
-"prim__floatLog 1.0"
-"prim__floatSqrt 1.0"
-"prim__negFloat 1.0"
+main : IO ()'
+
+# code separated from input with '#'
+TESTS=('prim__floatToStr !getf#0.0'
+ 'prim__strToFloat !getLine#0.0'
+$'prim__addFloat !getf !getf#1.0\n1.0'
+$'prim__subFloat !getf !getf#1.0\n1.0'
+$'prim__mulFloat !getf !getf#1.0\n1.0'
+$'prim__divFloat !getf !getf#1.0\n1.0'
+$'prim__slteFloat !getf !getf#1.0\n1.0'
+$'prim__sltFloat !getf !getf#1.0\n1.0'
+$'prim__sgteFloat !getf !getf#1.0\n1.0'
+$'prim__sgtFloat !getf !getf#1.0\n1.0'
+$'prim__eqFloat !getf !getf#1.0\n1.0'
+ 'prim__floatACos !getf#1.0'
+ 'prim__floatATan !getf#1.0'
+ 'prim__floatCos !getf#1.0'
+ 'prim__floatFloor !getf#1.0'
+ 'prim__floatSin !getf#1.0'
+ 'prim__floatTan !getf#1.0'
+ 'prim__floatASin !getf#1.0'
+ 'prim__floatCeil !getf#1.0'
+ 'prim__floatExp !getf#1.0'
+ 'prim__floatLog !getf#1.0'
+ 'prim__floatSqrt !getf#1.0'
+ 'prim__negFloat !getf#1.0'
 )
 
 generate_testfile()
@@ -44,9 +48,9 @@
 
 for T in "${TESTS[@]}"
 do
-    echo ${T}
-    generate_testfile "tmptest.idr" "${T}"
-    idris $@ --quiet tmptest.idr -o tmptest || echo "missing primitive in ${CG}"
-    ./tmptest
+    echo ${T%% *} ${T##*#}
+    generate_testfile "tmptest.idr" "${T%%#*}"
+    idris "$@" --quiet tmptest.idr -o tmptest || echo "missing primitive in ${CG}"
+    ./tmptest <<<"${T##*#}"
     rm tmptest.idr tmptest.ibc tmptest
 done
diff --git a/test/proof001/test029.idr b/test/proof001/test029.idr
--- a/test/proof001/test029.idr
+++ b/test/proof001/test029.idr
@@ -29,7 +29,7 @@
 simple.append_lemma_2 = proof {
   intros;
   compute;
-  rewrite (plusSuccRightSucc m n);
+  rewrite (plusSuccRightSucc m k);
   trivial;
 }
 
diff --git a/test/proof002/expected b/test/proof002/expected
--- a/test/proof002/expected
+++ b/test/proof002/expected
@@ -1,13 +1,13 @@
-Reflect.idr:208:38:
-When elaborating right hand side of testReflect1:
-When elaborating an application of function Reflect.getJust:
-        Can't unify
+test030a.idr:12:26-14:1:
+When checking right hand side of testReflect1:
+When checking an application of function Reflect.getJust:
+        Type mismatch between
                 IsJust (Just x1) (Type of ItIsJust)
-        with
+        and
                 IsJust (prove (getProof x)) (Expected type)
         
         Specifically:
-                Can't unify
+                Type mismatch between
                         Just x
-                with
+                and
                         Nothing
diff --git a/test/proof003/test015.idr b/test/proof003/test015.idr
--- a/test/proof003/test015.idr
+++ b/test/proof003/test015.idr
@@ -106,9 +106,7 @@
 -- There is almost certainly an easier proof. I don't care, for now :)
 
 Main.adc_lemma_2 = proof {
-    intro w,v,num0,bit0
-    intro b0,v1,num1,bit1,b1
-    intro c,bc,x,bX,x1,bX1
+    intro w,v,num0,v1,num1,x,bx,x1,bx1,bit0,b0,bit1,b1,c,bc
     rewrite sym (plusZeroRightNeutral x);
     rewrite sym (plusZeroRightNeutral v1);
     rewrite sym (plusZeroRightNeutral (plus (plus x v) v1));
diff --git a/test/proof007/expected b/test/proof007/expected
--- a/test/proof007/expected
+++ b/test/proof007/expected
@@ -1,4 +1,4 @@
 DefaultArgUnknownName.idr:9:6:
-When elaborating right hand side of test:
-When elaborating argument arg to function DefaultArgUnknownName.funWithBadDefArg:
+When checking right hand side of test:
+When checking argument arg to function DefaultArgUnknownName.funWithBadDefArg:
         No such variable sadgjhsag
diff --git a/test/quasiquote001/expected b/test/quasiquote001/expected
--- a/test/quasiquote001/expected
+++ b/test/quasiquote001/expected
@@ -1,5 +1,5 @@
-(App (App (App (P (DCon 1 3) (NS (UN "::") ["List", "Prelude"]) (Bind (UN "a") (Pi (TType (UVar -1))) (Bind (MN 0 "_t") (Pi (V 0)) (Bind (MN 2 "_t") (Pi (App (P (TCon 0 0) (NS (UN "List") ["List", "Prelude"]) Erased) (V 1))) (App (P (TCon 0 0) (NS (UN "List") ["List", "Prelude"]) Erased) (V 2)))))) (P (TCon 8 0) (UN "Unit") (TType (UVar -1)))) (P (DCon 0 0) (UN "MkUnit") (P (TCon 0 0) (UN "Unit") Erased))) (App (App (App (P (DCon 1 3) (NS (UN "::") ["List", "Prelude"]) (Bind (UN "a") (Pi (TType (UVar -1))) (Bind (MN 0 "_t") (Pi (V 0)) (Bind (MN 2 "_t") (Pi (App (P (TCon 0 0) (NS (UN "List") ["List", "Prelude"]) Erased) (V 1))) (App (P (TCon 0 0) (NS (UN "List") ["List", "Prelude"]) Erased) (V 2)))))) (P (TCon 8 0) (UN "Unit") (TType (UVar -1)))) (P (DCon 0 0) (UN "MkUnit") (P (TCon 0 0) (UN "Unit") Erased))) (App (P (DCon 0 1) (NS (UN "Nil") ["List", "Prelude"]) (Bind (UN "a") (Pi (TType (UVar -1))) (App (P (TCon 0 0) (NS (UN "List") ["List", "Prelude"]) Erased) (V 0)))) (P (TCon 8 0) (UN "Unit") (TType (UVar -1))))))
+App (App (App (P (DCon 1 3) (NS (UN "::") ["List", "Prelude"]) (Bind (UN "elem") (Pi (TType (UVar (-1))) (TType (UVar (-1)))) (Bind (MN 0 "_t") (Pi (V 0) (TType (UVar (-1)))) (Bind (MN 2 "_t") (Pi (App (P (TCon 0 0) (NS (UN "List") ["List", "Prelude"]) Erased) (V 1)) (TType (UVar (-1)))) (App (P (TCon 0 0) (NS (UN "List") ["List", "Prelude"]) Erased) (V 2)))))) (P (TCon 8 0) (UN "Unit") (TType (UVar (-1))))) (P (DCon 0 0) (UN "MkUnit") (P (TCon 0 0) (UN "Unit") Erased))) (App (App (App (P (DCon 1 3) (NS (UN "::") ["List", "Prelude"]) (Bind (UN "elem") (Pi (TType (UVar (-1))) (TType (UVar (-1)))) (Bind (MN 0 "_t") (Pi (V 0) (TType (UVar (-1)))) (Bind (MN 2 "_t") (Pi (App (P (TCon 0 0) (NS (UN "List") ["List", "Prelude"]) Erased) (V 1)) (TType (UVar (-1)))) (App (P (TCon 0 0) (NS (UN "List") ["List", "Prelude"]) Erased) (V 2)))))) (P (TCon 8 0) (UN "Unit") (TType (UVar (-1))))) (P (DCon 0 0) (UN "MkUnit") (P (TCon 0 0) (UN "Unit") Erased))) (App (P (DCon 0 1) (NS (UN "Nil") ["List", "Prelude"]) (Bind (UN "elem") (Pi (TType (UVar (-1))) (TType (UVar (-1)))) (App (P (TCon 0 0) (NS (UN "List") ["List", "Prelude"]) Erased) (V 0)))) (P (TCon 8 0) (UN "Unit") (TType (UVar (-1))))))
 --------------
-(App (App (App (P (DCon 1 3) (NS (UN "::") ["List", "Prelude"]) (Bind (UN "a") (Pi (TType (UVar -1))) (Bind (MN 0 "_t") (Pi (V 0)) (Bind (MN 2 "_t") (Pi (App (P (TCon 0 0) (NS (UN "List") ["List", "Prelude"]) Erased) (V 1))) (App (P (TCon 0 0) (NS (UN "List") ["List", "Prelude"]) Erased) (V 2)))))) (TType (UVar 24))) (TType (UVar 25))) (App (App (App (P (DCon 1 3) (NS (UN "::") ["List", "Prelude"]) (Bind (UN "a") (Pi (TType (UVar -1))) (Bind (MN 0 "_t") (Pi (V 0)) (Bind (MN 2 "_t") (Pi (App (P (TCon 0 0) (NS (UN "List") ["List", "Prelude"]) Erased) (V 1))) (App (P (TCon 0 0) (NS (UN "List") ["List", "Prelude"]) Erased) (V 2)))))) (TType (UVar 26))) (App (App (App (App (P (DCon 0 4) (NS (UN "MkPair") ["Builtins"]) (Bind (UN "A") (Pi (TType (UVar -1))) (Bind (UN "B") (Pi (TType (UVar -1))) (Bind (UN "a") (Pi (V 1)) (Bind (UN "b") (Pi (V 1)) (App (App (P (TCon 0 0) (NS (UN "Pair") ["Builtins"]) Erased) (V 3)) (V 2))))))) (TType (UVar 22))) (TType (UVar 23))) (P (TCon 8 0) (NS (UN "Nat") ["Nat", "Prelude"]) (TType (UVar -1)))) (P (TCon 8 0) (NS (UN "Nat") ["Nat", "Prelude"]) (TType (UVar -1))))) (App (P (DCon 0 1) (NS (UN "Nil") ["List", "Prelude"]) (Bind (UN "a") (Pi (TType (UVar -1))) (App (P (TCon 0 0) (NS (UN "List") ["List", "Prelude"]) Erased) (V 0)))) (TType (UVar 27)))))
+App (App (App (P (DCon 1 3) (NS (UN "::") ["List", "Prelude"]) (Bind (UN "elem") (Pi (TType (UVar (-1))) (TType (UVar (-1)))) (Bind (MN 0 "_t") (Pi (V 0) (TType (UVar (-1)))) (Bind (MN 2 "_t") (Pi (App (P (TCon 0 0) (NS (UN "List") ["List", "Prelude"]) Erased) (V 1)) (TType (UVar (-1)))) (App (P (TCon 0 0) (NS (UN "List") ["List", "Prelude"]) Erased) (V 2)))))) (TType (UVar 24))) (TType (UVar 25))) (App (App (App (P (DCon 1 3) (NS (UN "::") ["List", "Prelude"]) (Bind (UN "elem") (Pi (TType (UVar (-1))) (TType (UVar (-1)))) (Bind (MN 0 "_t") (Pi (V 0) (TType (UVar (-1)))) (Bind (MN 2 "_t") (Pi (App (P (TCon 0 0) (NS (UN "List") ["List", "Prelude"]) Erased) (V 1)) (TType (UVar (-1)))) (App (P (TCon 0 0) (NS (UN "List") ["List", "Prelude"]) Erased) (V 2)))))) (TType (UVar 26))) (App (App (App (App (P (DCon 0 4) (NS (UN "MkPair") ["Builtins"]) (Bind (UN "A") (Pi (TType (UVar (-1))) (TType (UVar (-1)))) (Bind (UN "B") (Pi (TType (UVar (-1))) (TType (UVar (-1)))) (Bind (UN "a") (Pi (V 1) (TType (UVar (-1)))) (Bind (UN "b") (Pi (V 1) (TType (UVar (-1)))) (App (App (P (TCon 0 0) (NS (UN "Pair") ["Builtins"]) Erased) (V 3)) (V 2))))))) (TType (UVar 22))) (TType (UVar 23))) (P (TCon 8 0) (NS (UN "Nat") ["Nat", "Prelude"]) (TType (UVar (-1))))) (P (TCon 8 0) (NS (UN "Nat") ["Nat", "Prelude"]) (TType (UVar (-1)))))) (App (P (DCon 0 1) (NS (UN "Nil") ["List", "Prelude"]) (Bind (UN "elem") (Pi (TType (UVar (-1))) (TType (UVar (-1)))) (App (P (TCon 0 0) (NS (UN "List") ["List", "Prelude"]) Erased) (V 0)))) (TType (UVar 27))))
 --------------
-(App (App (App (App (P (DCon 0 4) (NS (UN "MkPair") ["Builtins"]) (Bind (UN "A") (Pi (TType (UVar -1))) (Bind (UN "B") (Pi (TType (UVar -1))) (Bind (UN "a") (Pi (V 1)) (Bind (UN "b") (Pi (V 1)) (App (App (P (TCon 0 0) (NS (UN "Pair") ["Builtins"]) Erased) (V 3)) (V 2))))))) (TType (UVar 22))) (TType (UVar 23))) (App (App (App (App (P (DCon 0 4) (NS (UN "MkPair") ["Builtins"]) (Bind (UN "A") (Pi (TType (UVar -1))) (Bind (UN "B") (Pi (TType (UVar -1))) (Bind (UN "a") (Pi (V 1)) (Bind (UN "b") (Pi (V 1)) (App (App (P (TCon 0 0) (NS (UN "Pair") ["Builtins"]) Erased) (V 3)) (V 2))))))) (TType (UVar 22))) (TType (UVar 23))) (TType (UVar 24))) (TType (UVar 24)))) (App (App (App (App (P (DCon 0 4) (NS (UN "MkPair") ["Builtins"]) (Bind (UN "A") (Pi (TType (UVar -1))) (Bind (UN "B") (Pi (TType (UVar -1))) (Bind (UN "a") (Pi (V 1)) (Bind (UN "b") (Pi (V 1)) (App (App (P (TCon 0 0) (NS (UN "Pair") ["Builtins"]) Erased) (V 3)) (V 2))))))) (TType (UVar 22))) (TType (UVar 23))) (TType (UVar 24))) (TType (UVar 24))))
+App (App (App (App (P (DCon 0 4) (NS (UN "MkPair") ["Builtins"]) (Bind (UN "A") (Pi (TType (UVar (-1))) (TType (UVar (-1)))) (Bind (UN "B") (Pi (TType (UVar (-1))) (TType (UVar (-1)))) (Bind (UN "a") (Pi (V 1) (TType (UVar (-1)))) (Bind (UN "b") (Pi (V 1) (TType (UVar (-1)))) (App (App (P (TCon 0 0) (NS (UN "Pair") ["Builtins"]) Erased) (V 3)) (V 2))))))) (TType (UVar 22))) (TType (UVar 23))) (App (App (App (App (P (DCon 0 4) (NS (UN "MkPair") ["Builtins"]) (Bind (UN "A") (Pi (TType (UVar (-1))) (TType (UVar (-1)))) (Bind (UN "B") (Pi (TType (UVar (-1))) (TType (UVar (-1)))) (Bind (UN "a") (Pi (V 1) (TType (UVar (-1)))) (Bind (UN "b") (Pi (V 1) (TType (UVar (-1)))) (App (App (P (TCon 0 0) (NS (UN "Pair") ["Builtins"]) Erased) (V 3)) (V 2))))))) (TType (UVar 22))) (TType (UVar 23))) (TType (UVar 24))) (TType (UVar 24)))) (App (App (App (App (P (DCon 0 4) (NS (UN "MkPair") ["Builtins"]) (Bind (UN "A") (Pi (TType (UVar (-1))) (TType (UVar (-1)))) (Bind (UN "B") (Pi (TType (UVar (-1))) (TType (UVar (-1)))) (Bind (UN "a") (Pi (V 1) (TType (UVar (-1)))) (Bind (UN "b") (Pi (V 1) (TType (UVar (-1)))) (App (App (P (TCon 0 0) (NS (UN "Pair") ["Builtins"]) Erased) (V 3)) (V 2))))))) (TType (UVar 22))) (TType (UVar 23))) (TType (UVar 24))) (TType (UVar 24)))
diff --git a/test/quasiquote003/expected b/test/quasiquote003/expected
--- a/test/quasiquote003/expected
+++ b/test/quasiquote003/expected
@@ -1,2 +1,2 @@
-NoInfer.idr:11:5:When elaborating right hand side of zzz:
+NoInfer.idr:11:5:When checking right hand side of zzz:
 No such variable k
diff --git a/test/quasiquote004/expected b/test/quasiquote004/expected
--- a/test/quasiquote004/expected
+++ b/test/quasiquote004/expected
@@ -1,3 +1,3 @@
 Quasiquote004.idr:50:25:
-When elaborating right hand side of Quasiquote004.getMeNat':
+When checking right hand side of Quasiquote004.getMeNat':
 Not a Nat goal
diff --git a/test/quasiquote006/expected b/test/quasiquote006/expected
--- a/test/quasiquote006/expected
+++ b/test/quasiquote006/expected
@@ -1,12 +1,12 @@
 quasiquote006.idr:9:3:
-When elaborating right hand side of b:
+When checking right hand side of b:
 Can't disambiguate name: ForeignEnv.Nil, 
                          Prelude.List.Nil
 quasiquote006.idr:12:3:
-When elaborating right hand side of c:
+When checking right hand side of c:
 No such variable alsdkjflkj
 quasiquote006.idr:15:3:
-When elaborating right hand side of d:
+When checking right hand side of d:
 Can't disambiguate name: ForeignEnv.::, 
                          Prelude.List.::, 
                          Prelude.Stream.::
diff --git a/test/reg001/reg001.idr b/test/reg001/reg001.idr
--- a/test/reg001/reg001.idr
+++ b/test/reg001/reg001.idr
@@ -6,3 +6,4 @@
 
 testVal : Imp
 testVal = MkImp (apply id Z)
+
diff --git a/test/reg003/expected b/test/reg003/expected
--- a/test/reg003/expected
+++ b/test/reg003/expected
@@ -1,6 +1,6 @@
-reg003a.idr:4:11:When elaborating type of Main.ECons:
+reg003a.idr:4:11:When checking type of Main.ECons:
 No such variable OddList
-reg003a.idr:7:11:When elaborating type of Main.OCons:
+reg003a.idr:7:11:When checking type of Main.OCons:
 No such variable EvenList
-reg003a.idr:9:6:When elaborating type of Main.test:
+reg003a.idr:9:6:When checking type of Main.test:
 No such variable EvenList
diff --git a/test/reg007/expected b/test/reg007/expected
--- a/test/reg007/expected
+++ b/test/reg007/expected
@@ -1,12 +1,12 @@
 reg007.lidr:8:1:A.n is already defined
-reg007.lidr:12:11-17:When elaborating right hand side of hurrah:
-Can't unify
+reg007.lidr:12:11-17:When checking right hand side of hurrah:
+Type mismatch between
         n = lala (Type of isSame)
-with
+and
         0 = 1 (Expected type)
 
 Specifically:
-        Can't unify
+        Type mismatch between
                 1
-        with
+        and
                 0
diff --git a/test/reg010/expected b/test/reg010/expected
--- a/test/reg010/expected
+++ b/test/reg010/expected
@@ -1,3 +1,3 @@
 reg010.idr:5:15:
-When elaborating left hand side of with block in usubst.unsafeSubst:
+When checking left hand side of with block in usubst.unsafeSubst:
 Can't match on with block in usubst.unsafeSubst warg a P x x px
diff --git a/test/reg023/expected b/test/reg023/expected
--- a/test/reg023/expected
+++ b/test/reg023/expected
@@ -1,5 +1,5 @@
-reg023.idr:7:5:When elaborating right hand side of bad:
-Can't unify
+reg023.idr:7:5:When checking right hand side of bad:
+Type mismatch between
         Nat (Type of 0)
-with
+and
         f Nat (Expected type)
diff --git a/test/reg034/expected b/test/reg034/expected
--- a/test/reg034/expected
+++ b/test/reg034/expected
@@ -1,4 +1,4 @@
-reg034.idr:6:5:When elaborating left hand side of bar:
+reg034.idr:6:5:When checking left hand side of bar:
 Can't match on bar xs xs Refl
-reg034.idr:9:5:When elaborating left hand side of foo:
+reg034.idr:9:5:When checking left hand side of foo:
 Can't match on foo f x x Refl
diff --git a/test/reg044/expected b/test/reg044/expected
--- a/test/reg044/expected
+++ b/test/reg044/expected
@@ -1,11 +1,11 @@
-reg044.idr:4:4:When elaborating right hand side of Main.pf:
-Can't unify
+reg044.idr:4:4:When checking right hand side of Main.pf:
+Type mismatch between
         b = b (Type of Refl)
-with
+and
         a = b (Expected type)
 
 Specifically:
-        Can't unify
+        Type mismatch between
                 b
-        with
+        and
                 a
diff --git a/test/reg049/expected b/test/reg049/expected
--- a/test/reg049/expected
+++ b/test/reg049/expected
@@ -1,4 +1,4 @@
-reg049.idr:2:9:When elaborating constructor Main.Bogus:
+reg049.idr:2:9:When checking constructor Main.Bogus:
 Void is not Main.Foo
-reg049.idr:5:6:When elaborating right hand side of uhOh:
+reg049.idr:5:6:When checking right hand side of uhOh:
 No such variable Bogus
diff --git a/test/reg054/expected b/test/reg054/expected
--- a/test/reg054/expected
+++ b/test/reg054/expected
@@ -1,12 +1,13 @@
-reg054.idr:18:5:When elaborating left hand side of inf:
-When elaborating an application of constructor Main.MkInfer:
+reg054.idr:18:5:When checking left hand side of inf:
+When checking an application of constructor Main.MkInfer:
         Attempting concrete match on polymorphic argument: 0
-reg054.idr:34:7:When elaborating left hand side of weird:
-When elaborating argument x to Main.weird:
-        No explicit types on left hand side: Char
-reg054.idr:37:1-8:When elaborating left hand side of tctrick:
-When elaborating an application of Main.tctrick:
-        Can't unify
+reg054.idr:34:7:When checking left hand side of weird:
+No explicit types on left hand side: Char
+reg054.idr:37:8:When checking left hand side of weird':
+No explicit types on left hand side: Nat
+reg054.idr:40:1-8:When checking left hand side of tctrick:
+When checking an application of Main.tctrick:
+        Type mismatch between
                 Maybe a1 (Type of Just x)
-        with
+        and
                 a (Expected type)
diff --git a/test/reg054/reg054.idr b/test/reg054/reg054.idr
--- a/test/reg054/reg054.idr
+++ b/test/reg054/reg054.idr
@@ -33,6 +33,9 @@
 weird : Weird x -> x
 weird {x = Char} y = '5'
 
+weird' : Weird x -> x
+weird' {x = Prelude.Nat.Nat} y = Z
+
 tctrick : a -> Int
 tctrick (Just x) = x
 tctrick Nothing = 42
diff --git a/test/reg055/expected b/test/reg055/expected
--- a/test/reg055/expected
+++ b/test/reg055/expected
@@ -1,9 +1,9 @@
-reg055.idr:5:3:When elaborating left hand side of g:
+reg055.idr:5:3:When checking left hand side of g:
 Can't match on g (f 0)
-reg055.idr:8:3:When elaborating left hand side of h:
+reg055.idr:8:3:When checking left hand side of h:
 Can't match on h x x
-reg055a.idr:8:5:When elaborating left hand side of foo:
-When elaborating an application of constructor Foo.CAny:
+reg055a.idr:8:5:When checking left hand side of foo:
+When checking an application of constructor Foo.CAny:
         Attempting concrete match on polymorphic argument: Nothing
-reg055a.idr:13:7:When elaborating left hand side of Foo.apply:
+reg055a.idr:13:7:When checking left hand side of Foo.apply:
 Can't match on apply (\x => \y => x) a
diff --git a/test/reg066/expected b/test/reg066/expected
new file mode 100644
--- /dev/null
+++ b/test/reg066/expected
diff --git a/test/reg066/reg066.idr b/test/reg066/reg066.idr
new file mode 100644
--- /dev/null
+++ b/test/reg066/reg066.idr
@@ -0,0 +1,7 @@
+foo : Reflection.Raw -> Bool
+foo `(~_ -> ~_) = True
+foo _ = False
+
+foo' : TT -> Bool
+foo' `(~_ -> ~_) = True
+foo' _ = False
diff --git a/test/reg066/run b/test/reg066/run
new file mode 100644
--- /dev/null
+++ b/test/reg066/run
@@ -0,0 +1,3 @@
+#!/usr/bin/env bash
+idris $@ reg066.idr --check --nocolor
+rm -f *.ibc
diff --git a/test/syntax001/Syntax.idr b/test/syntax001/Syntax.idr
new file mode 100644
--- /dev/null
+++ b/test/syntax001/Syntax.idr
@@ -0,0 +1,8 @@
+module Syntax
+
+syntax "fnord" [y] = y + y + y
+
+foo : Nat
+foo = fnord "argh"
+
+
diff --git a/test/syntax001/SyntaxOk.idr b/test/syntax001/SyntaxOk.idr
new file mode 100644
--- /dev/null
+++ b/test/syntax001/SyntaxOk.idr
@@ -0,0 +1,6 @@
+module SyntaxOk
+
+syntax "fnord" [y] = y + y + y
+
+
+
diff --git a/test/syntax001/SyntaxTest.idr b/test/syntax001/SyntaxTest.idr
new file mode 100644
--- /dev/null
+++ b/test/syntax001/SyntaxTest.idr
@@ -0,0 +1,5 @@
+module SyntaxTest
+import SyntaxOk
+
+foo : Nat
+foo = fnord "argh"
diff --git a/test/syntax001/expected b/test/syntax001/expected
new file mode 100644
--- /dev/null
+++ b/test/syntax001/expected
@@ -0,0 +1,12 @@
+Syntax.idr:6:7-9:1:When checking right hand side of foo:
+When checking an application of function Prelude.Classes.+:
+        Type mismatch between
+                String (Type of "argh")
+        and
+                Nat (Expected type)
+SyntaxTest.idr:5:7-6:1:When checking right hand side of foo:
+When checking an application of function Prelude.Classes.+:
+        Type mismatch between
+                String (Type of "argh")
+        and
+                Nat (Expected type)
diff --git a/test/syntax001/run b/test/syntax001/run
new file mode 100644
--- /dev/null
+++ b/test/syntax001/run
@@ -0,0 +1,4 @@
+#!/usr/bin/env bash
+idris $@ Syntax.idr --nocolour --consolewidth 80 --check
+idris $@ SyntaxTest.idr --nocolour --consolewidth 80 --check
+rm -f *.ibc
diff --git a/test/syntax002/expected b/test/syntax002/expected
new file mode 100644
--- /dev/null
+++ b/test/syntax002/expected
@@ -0,0 +1,2 @@
+Nothing
+7
diff --git a/test/syntax002/run b/test/syntax002/run
new file mode 100644
--- /dev/null
+++ b/test/syntax002/run
@@ -0,0 +1,4 @@
+#!/usr/bin/env bash
+idris $@ syntax002.idr -o syntax002
+./syntax002
+rm -f syntax002 *.ibc
diff --git a/test/syntax002/syntax002.idr b/test/syntax002/syntax002.idr
new file mode 100644
--- /dev/null
+++ b/test/syntax002/syntax002.idr
@@ -0,0 +1,22 @@
+
+decl syntax fun {n} ":" [ty] "=" [def] 
+            = n : ty
+              n = def
+
+decl syntax newtype {tname} "=" {conname} [tysyn]
+     = data tname = conname tysyn
+
+decl syntax EmptyShow {n} =
+     instance Show n where
+        show x = "Nothing" 
+
+fun add : (Int -> Int -> Int) = \x, y => x + y
+
+newtype Foo = MkFoo Int 
+
+EmptyShow Foo
+
+main : IO ()
+main = do printLn (MkFoo 42)
+          printLn (add 3 4)
+
diff --git a/test/tactics001/Tactics.idr b/test/tactics001/Tactics.idr
--- a/test/tactics001/Tactics.idr
+++ b/test/tactics001/Tactics.idr
@@ -33,7 +33,7 @@
 
 mkDecl : ()
 mkDecl = %runElab (do declareType $ Declare (NS (UN "repUnit") ["Tactics"])
-                                               [Implicit (UN "z") `(Nat)]
+                                               [MkFunArg (UN "z") `(Nat) Implicit NotErased]
                                                `(Vect ~(Var (UN "z")) ())
                       fill `(() : ())
                       solve)
diff --git a/test/totality007/expected b/test/totality007/expected
--- a/test/totality007/expected
+++ b/test/totality007/expected
@@ -1,3 +1,5 @@
+Entering directory `./src'
 Totality.idr:4:1:
 Totality.foo is not total as there are missing cases
 Totality.idr:4:1:Could not build: Totality.foo is not total as there are missing cases
+Leaving directory `./src'
diff --git a/test/tutorial006/expected b/test/tutorial006/expected
--- a/test/tutorial006/expected
+++ b/test/tutorial006/expected
@@ -1,25 +1,24 @@
-tutorial006a.idr:5:23-25:
-When elaborating right hand side of vapp:
-When elaborating argument xs to constructor Data.VectType.Vect.:::
-        Can't unify
-                Vect (n + n) a (Type of vapp xs xs)
-        with
-                Vect (plus n m) a (Expected type)
+tutorial006a.idr:5:23-25:When checking right hand side of vapp:
+When checking argument xs to constructor Data.VectType.Vect.:::
+        Type mismatch between
+                Vect (k + k) a (Type of vapp xs xs)
+        and
+                Vect (plus k m) a (Expected type)
         
         Specifically:
-                Can't unify
-                        plus n n
-                with
-                        plus n m
+                Type mismatch between
+                        plus k k
+                and
+                        plus k m
 tutorial006b.idr:10:10:
-When elaborating right hand side of with block in Main.parity:
-Can't unify
+When checking right hand side of with block in Main.parity:
+Type mismatch between
         Parity (plus (S j) (S j)) (Type of even)
-with
+and
         Parity (S (S (plus j j))) (Expected type)
 
 Specifically:
-        Can't unify
+        Type mismatch between
                 plus (S j) (S j)
-        with
+        and
                 S (S (plus j j))
diff --git a/test/unique001/expected b/test/unique001/expected
--- a/test/unique001/expected
+++ b/test/unique001/expected
@@ -2,17 +2,17 @@
 19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,END
 38,36,34,32,30,28,26,24,22,20,18,16,14,12,10,8,6,4,2,0,END
 38,36,34,32,30,28,26,24,22,20,18,16,14,12,10,8,6,4,2,0,END
-unique001a.idr:33:11:Can't convert
+unique001a.idr:33:11:Type mismatch between
         Int -> String
-with
+and
         UniqueType (Int -> String)
-unique001a.idr:44:12:Can't convert
+unique001a.idr:44:12:Type mismatch between
         Int -> String
-with
+and
         UniqueType (Int -> String)
-unique001a.idr:55:12:Can't convert
+unique001a.idr:55:12:Type mismatch between
         UniqueType (Int -> String)
-with
+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
diff --git a/test/unique002/expected b/test/unique002/expected
--- a/test/unique002/expected
+++ b/test/unique002/expected
@@ -1,5 +1,5 @@
 unique002.idr:15:5:Unique name xs is used more than once
-unique002a.idr:15:5:Can't convert
+unique002a.idr:15:5:Type mismatch between
         Int -> String
-with
+and
         UniqueType (Int -> String)
diff --git a/test/unique003/expected b/test/unique003/expected
--- a/test/unique003/expected
+++ b/test/unique003/expected
@@ -1,4 +1,4 @@
-unique003.idr:18:5:Can't convert
+unique003.idr:18:5:Type mismatch between
         Int -> String
-with
+and
         UniqueType (Int -> String)
