diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -8,7 +8,7 @@
 
 Please follow the following guidelines:
 
-- Add at least a test to `examples/passing/` and possibly to `examples/failing/`.
+- Add at least a test to `tests/purs/passing/` and possibly to `tests/purs/failing/`.
 - Build the binaries and libs with `stack build`
 - Make sure that all test suites are passing. Run the test suites with `stack test`.
 - Build the core libraries by running the script in `core-tests`.
@@ -17,15 +17,15 @@
 
 Run all test suites with `stack test`. You will need `npm`, `bower` and `node` on your PATH to run the tests.
 
-To build and run a specific test in `examples/passing/` or `examples/failing/`, execute the following commands.
+You can run individual test suites using `stack test --test-arguments="-p
+PATTERN"` where `PATTERN` is one of `compiler`, `repl`, `ide`, `docs`, `corefn`,
+or `hierarchy`.
 
-``` bash
-# Build
-stack exec purs -- compile 'tests/support/bower_components/purescript-*/src/**/*.purs' examples/blah/Blah.purs
+To build and run a specific test in `tests/purs/passing/` or `tests/purs/failing/`, add test arguments like so:
 
-# Run
-node -e "require('./output/Main/').main()"
-```
+`stack test --fast --test-arguments="-p compiler/**1110.purs*"`
+
+This will run whatever test uses the example file `1110.purs`.
 
 ## Code Review
 
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -26,11 +26,13 @@
 | [@balajirrao](https://github.com/balajirrao) | Balaji Rao | MIT license |
 | [@bbqbaron](https://github.com/bbqbaron) | Eric Loren | [MIT license](http://opensource.org/licenses/MIT) |
 | [@bergmark](https://github.com/bergmark) | Adam Bergmark | MIT license |
+| [@bitemyapp](https://github.com/bitemyapp) | Chris Allen | [MIT license](http://opensource.org/licenses/MIT) |
 | [@bmjames](https://github.com/bmjames) | Ben James | [MIT license](http://opensource.org/licenses/MIT) |
 | [@Bogdanp](https://github.com/Bogdanp) | Bogdan Paul Popa | [MIT license](http://opensource.org/licenses/MIT) |
 | [@brandonhamilton](https://github.com/brandonhamilton) | Brandon Hamilton | [MIT license](http://opensource.org/licenses/MIT) |
 | [@bsermons](https://github.com/bsermons) | Brian Sermons | [MIT license](http://opensource.org/licenses/MIT) |
 | [@cdepillabout](https://github.com/cdepillabout) | Dennis Gosnell | [MIT license](http://opensource.org/licenses/MIT) |
+| [@chexxor](https://github.com/chexxor) | Alex Berg | [MIT license](http://opensource.org/licenses/MIT) |
 | [@chrisdone](https://github.com/chrisdone) | Chris Done | MIT license |
 | [@cmdv](https://github.com/cmdv) | Vincent Orr | MIT license |
 | [@codedmart](https://github.com/codedmart) | Brandon Martin | [MIT license](http://opensource.org/licenses/MIT) |
@@ -44,6 +46,7 @@
 | [@erdeszt](https://github.com/erdeszt) | Tibor Erdesz | [MIT license](http://opensource.org/licenses/MIT) |
 | [@etrepum](https://github.com/etrepum) | Bob Ippolito | [MIT license](http://opensource.org/licenses/MIT) |
 | [@faineance](https://github.com/faineance) | faineance | [MIT license](http://opensource.org/licenses/MIT) |
+| [@fehrenbach](https://github.com/fehrenbach) | Stefan Fehrenbach | [MIT license](http://opensource.org/licenses/MIT) |
 | [@felixSchl](https://github.com/felixSchl) | Felix Schlitter | [MIT license](http://opensource.org/licenses/MIT) |
 | [@FrigoEU](https://github.com/FrigoEU) | Simon Van Casteren | [MIT license](http://opensource.org/licenses/MIT) |
 | [@garyb](https://github.com/garyb) | Gary Burgess | [MIT license](http://opensource.org/licenses/MIT) |
@@ -65,6 +68,7 @@
 | [@lukerandall](https://github.com/lukerandall) | Luke Randall | [MIT license](http://opensource.org/licenses/MIT) |
 | [@matthewleon](https://github.com/matthewleon) | Matthew Leon | [MIT license](http://opensource.org/licenses/MIT) |
 | [@mcoffin](https://github.com/mcoffin) | Matt Coffin | [MIT license](http://opensource.org/licenses/MIT) |
+| [@MiracleBlue](https://github.com/MiracleBlue) | Nicholas Kircher | [MIT license](http://opensource.org/licenses/MIT) |
 | [@mrkgnao](https://github.com/mrkgnao) | Soham Chowdhury | [MIT license](http://opensource.org/licenses/MIT) |
 | [@mgmeier](https://github.com/mgmeier) | Michael Gilliland | [MIT license](http://opensource.org/licenses/MIT) |
 | [@michaelficarra](https://github.com/michaelficarra) | Michael Ficarra | [MIT license](http://opensource.org/licenses/MIT) |
@@ -79,6 +83,7 @@
 | [@nwolverson](https://github.com/nwolverson) | Nicholas Wolverson | [MIT license](http://opensource.org/licenses/MIT) |
 | [@osa1](https://github.com/osa1) | Ömer Sinan Ağacan | MIT license |
 | [@paf31](https://github.com/paf31) | Phil Freeman | [MIT license](http://opensource.org/licenses/MIT) |
+| [@parsonsmatt](https://github.com/parsonsmatt) | Matt Parsons | [MIT license](http://opensource.org/licenses/MIT) |
 | [@passy](https://github.com/passy) | Pascal Hartig | [MIT license](http://opensource.org/licenses/MIT) |
 | [@paulyoung](https://github.com/paulyoung) | Paul Young | [MIT license](http://opensource.org/licenses/MIT) |
 | [@pelotom](https://github.com/pelotom) | Thomas Crockett | [MIT license](http://opensource.org/licenses/MIT) |
@@ -86,7 +91,9 @@
 | [@phiggins](https://github.com/phiggins) | Pete Higgins | [MIT license](http://opensource.org/licenses/MIT) |
 | [@philopon](https://github.com/philopon) | Hirotomo Moriwaki | [MIT license](http://opensource.org/licenses/MIT) |
 | [@pseudonom](https://github.com/pseudonom) | Eric Easley | [MIT license](http://opensource.org/licenses/MIT) |
+| [@quesebifurcan](https://github.com/quesebifurcan) | Fredrik Wallberg | [MIT license](http://opensource.org/licenses/MIT) |
 | [@rightfold](https://github.com/rightfold) | rightfold | [MIT license](https://opensource.org/licenses/MIT) |
+| [@rndnoise](https://github.com/rndnoise) | rndnoise | [MIT license](http://opensource.org/licenses/MIT) |
 | [@robdaemon](https://github.com/robdaemon) | Robert Roland | [MIT license](http://opensource.org/licenses/MIT) |
 | [@RossMeikleham](https://github.com/RossMeikleham) | Ross Meikleham | [MIT license](http://opensource.org/licenses/MIT) |
 | [@Rufflewind](https://github.com/Rufflewind) | Phil Ruffwind | [MIT license](https://opensource.org/licenses/MIT) |
@@ -109,11 +116,16 @@
 | [@trofi](https://github.com/trofi) | Sergei Trofimovich | [MIT license](http://opensource.org/licenses/MIT) |
 | [@utkarshkukreti](https://github.com/utkarshkukreti) | Utkarsh Kukreti | [MIT license](http://opensource.org/licenses/MIT) |
 | [@vkorablin](https://github.com/vkorablin) | Vladimir Korablin | MIT license |
+| [@vladciobanu](https://github.com/vladciobanu) | Vladimir Ciobanu | [MIT license](http://opensource.org/licenses/MIT) |
 | [@zudov](https://github.com/zudov) | Konstantin Zudov | [MIT license](http://opensource.org/licenses/MIT) |
 | [@b123400](https://github.com/b123400) | b123400 | [MIT license](https://opensource.org/licenses/MIT) |
+| [@kcsongor](https://github.com/kcsongor) | Csongor Kiss | [MIT license](http://opensource.org/licenses/MIT) |
 | [@drets](https://github.com/drets) | Dmytro Rets | [MIT license](http://opensource.org/licenses/MIT) |
 | [@bjornmelgaaard](https://github.com/BjornMelgaard) | Sergey Homa | [MIT license](http://opensource.org/licenses/MIT) |
 | [@thimoteus](https://github.com/Thimoteus) | thimoteus | [MIT license](http://opensource.org/licenses/MIT) |
+| [@sloosch](https://github.com/sloosch) | Simon Looschen | [MIT license](http://opensource.org/licenses/MIT) |
+| [@rgrinberg](https://github.com/rgrinberg) | Rudi Grinberg | [MIT license](http://opensource.org/licenses/MIT) |
+| [@gabejohnson](https://github.com/gabejohnson) | Gabe Johnson | [MIT license](http://opensource.org/licenses/MIT) |
 
 ### Contributors using Modified Terms
 
diff --git a/INSTALL.md b/INSTALL.md
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -1,24 +1,33 @@
 # Installation information
 
 If you are having difficulty installing the PureScript compiler, feel free to
-ask for help! A good place is the #purescript IRC channel on Freenode, or
+ask for help! A good place is the #purescript IRC channel on Freenode, the #purescript channel on [FPChat Slack](https://fpchat-invite.herokuapp.com/), or
 alternatively Stack Overflow.
 
 ## Using prebuilt binaries
 
-The prebuilt binaries are compiled with GHC 8.0.2 and therefore they should
-run on any operating system supported by GHC 8.0.2, such as:
+The prebuilt binaries are compiled with GHC 8.2.2 and therefore they should
+run on any operating system supported by GHC 8.2.2, such as:
 
 * Windows Vista or later,
 * OS X 10.7 or later,
-* Linux ??? (we're not sure what the minimum version is).
+* Linux ??? (we're not sure what the minimum version is)
 
-This list is not exhaustive. If your OS is too old or not listed, or if the
-binaries fail to run, you may be able to install the compiler by building it
-from source; see below.
+This list is not exhaustive. If your OS is too old or not listed, or if the binaries fail to run, you may be able to install the compiler by building it from source; see below. See also <https://www.haskell.org/ghc/download_ghc_8_2_2.html> for more details about the operating systems which GHC 8.2.2 supports.
 
 Other prebuilt distributions (eg, Homebrew, AUR, npm) will probably have the
 same requirements.
+
+## Installing a pre-built distribution
+
+There are several options available for aquiring a pre-built binary of the PureScript compiler.  This is by no means an exhaustive list, and is presented in no particular order. Each example is expected to install the latest available compiler version at the time of running the command. Many of these are provided and maintained by the community, and may not be immediately up to date.
+
+* NPM: `npm install -g purescript`
+* Homebrew (for OS X): `brew install purescript`
+* [PSVM](https://github.com/ThomasCrevoisier/psvm-js) (PS Version Manager): 
+  1) `psvm install-latest` will install the latest version available
+  2) `psvm latest` will print the latest version number available
+  3) `psvm use <latest version number>` will enable the version we just installed. For example, if the version is `v0.11.7`, you'd run `psvm use v0.11.7`
 
 ## Compiling from source
 
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -20,6 +20,7 @@
 ## Help!
 
 - [#purescript @ FP Slack](https://functionalprogramming.slack.com/)
+- [PureScript Language Forum](https://purescript-users.ml/)
 - [PureScript on StackOverflow](http://stackoverflow.com/questions/tagged/purescript)
 - [Google Group](https://groups.google.com/forum/#!forum/purescript)
 - [Gitter Channel](https://gitter.im/purescript/purescript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
diff --git a/app/Command/Compile.hs b/app/Command/Compile.hs
--- a/app/Command/Compile.hs
+++ b/app/Command/Compile.hs
@@ -13,8 +13,12 @@
 import           Data.Bool (bool)
 import qualified Data.ByteString.Lazy as B
 import qualified Data.ByteString.UTF8 as BU8
+import           Data.List (intercalate)
 import qualified Data.Map as M
+import qualified Data.Set as S
 import           Data.Text (Text)
+import qualified Data.Text as T
+import           Data.Traversable (for)
 import qualified Language.PureScript as P
 import           Language.PureScript.Errors.JSON
 import           Language.PureScript.Make
@@ -89,7 +93,7 @@
 inputFile :: Opts.Parser FilePath
 inputFile = Opts.strArgument $
      Opts.metavar "FILE"
-  <> Opts.help "The input .purs file(s)"
+  <> Opts.help "The input .purs file(s)."
 
 outputDirectory :: Opts.Parser FilePath
 outputDirectory = Opts.strOption $
@@ -122,21 +126,46 @@
      Opts.long "json-errors"
   <> Opts.help "Print errors to stderr as JSON"
 
-sourceMaps :: Opts.Parser Bool
-sourceMaps = Opts.switch $
-     Opts.long "source-maps"
-  <> Opts.help "Generate source maps"
+codegenTargets :: Opts.Parser [P.CodegenTarget]
+codegenTargets = Opts.option targetParser $
+     Opts.short 'g'
+  <> Opts.long "codegen"
+  <> Opts.value [P.JS]
+  <> Opts.help
+      ( "Specifies comma-separated codegen targets to include. "
+      <> targetsMessage
+      <> " The default target is 'js', but if this option is used only the targets specified will be used."
+      )
 
-dumpCoreFn :: Opts.Parser Bool
-dumpCoreFn = Opts.switch $
-     Opts.long "dump-corefn"
-  <> Opts.help "Dump the (functional) core representation of the compiled code at output/*/corefn.json"
+targets :: M.Map String P.CodegenTarget
+targets = M.fromList
+  [ ("js", P.JS)
+  , ("sourcemaps", P.JSSourceMap)
+  , ("corefn", P.CoreFn)
+  ]
 
+targetsMessage :: String
+targetsMessage = "Accepted codegen targets are '" <> intercalate "', '" (M.keys targets) <> "'."
+
+targetParser :: Opts.ReadM [P.CodegenTarget]
+targetParser =
+  Opts.str >>= \s ->
+    for (T.split (== ',') s)
+      $ maybe (Opts.readerError targetsMessage) pure
+      . flip M.lookup targets
+      . T.unpack
+      . T.strip
+
 options :: Opts.Parser P.Options
-options = P.Options <$> verboseErrors
-                    <*> (not <$> comments)
-                    <*> sourceMaps
-                    <*> dumpCoreFn
+options =
+  P.Options
+    <$> verboseErrors
+    <*> (not <$> comments)
+    <*> (handleTargets <$> codegenTargets)
+  where
+    -- Ensure that the JS target is included if sourcemaps are
+    handleTargets :: [P.CodegenTarget] -> S.Set P.CodegenTarget
+    handleTargets ts = S.fromList (if elem P.JSSourceMap ts then P.JS : ts else ts)
 
 pscMakeOptions :: Opts.Parser PSCMakeOptions
 pscMakeOptions = PSCMakeOptions <$> many inputFile
diff --git a/app/Command/Docs.hs b/app/Command/Docs.hs
--- a/app/Command/Docs.hs
+++ b/app/Command/Docs.hs
@@ -2,34 +2,29 @@
 
 module Command.Docs (command, infoModList) where
 
-import           Protolude (ordNub)
-
-import           Command.Docs.Etags
-import           Command.Docs.Ctags
 import           Command.Docs.Html
 import           Control.Applicative
 import           Control.Arrow (first, second)
 import           Control.Category ((>>>))
 import           Control.Monad.Writer
 import           Control.Monad.Trans.Except (runExceptT)
-import           Data.Text (Text)
 import qualified Data.Text as T
 import qualified Data.Text.IO as T
 import           Data.Function (on)
 import           Data.List
-import           Data.Maybe (fromMaybe)
 import           Data.Tuple (swap)
 import qualified Language.PureScript as P
 import qualified Language.PureScript.Docs as D
 import qualified Language.PureScript.Docs.AsMarkdown as D
+import           Language.PureScript.Docs.Tags (dumpCtags, dumpEtags)
 import qualified Options.Applicative as Opts
 import qualified Text.PrettyPrint.ANSI.Leijen as PP
 import           System.Directory (createDirectoryIfMissing)
 import           System.Exit (exitFailure)
 import           System.FilePath (takeDirectory)
 import           System.FilePath.Glob (glob)
-import           System.IO (hPutStrLn, hPrint, stderr)
-import           System.IO.UTF8 (readUTF8FileT, writeUTF8FileT)
+import           System.IO (hPutStrLn, stderr)
+import           System.IO.UTF8 (writeUTF8FileT)
 
 -- | Available output formats
 data Format
@@ -60,19 +55,18 @@
     hPutStrLn stderr "purs docs: no input files."
     exitFailure
 
+  fileMs <- parseAndConvert input
+  let ms = map snd fileMs
   case fmt of
-    Etags -> dumpTags input dumpEtags
-    Ctags -> dumpTags input dumpCtags
+    Etags -> mapM_ putStrLn $ dumpEtags fileMs
+    Ctags -> mapM_ putStrLn $ dumpCtags fileMs
     Html -> do
       let outputDir = "./generated-docs" -- TODO: make this configurable
-      ms <- parseAndConvert input
-      let msHtml = map asHtml (D.primDocsModule : ms)
+      let msHtml = map asHtml (D.primModules ++ ms)
       createDirectoryIfMissing False outputDir
       writeHtmlModules outputDir msHtml
 
-    Markdown -> do
-      ms <- parseAndConvert input
-
+    Markdown ->
       case output of
         EverythingToStdOut ->
           T.putStrLn (D.runDocs (D.modulesAsMarkdown ms))
@@ -115,7 +109,7 @@
 
   parseAndConvert input =
     runExceptT (D.parseFilesInPackages input []
-               >>= uncurry D.convertModulesInPackage)
+                >>= uncurry D.convertTaggedModulesInPackage)
     >>= successOrExit
 
 -- |
@@ -138,26 +132,6 @@
     case find ((== name) . getModuleName) modules of
       Just m  -> ((m, x) : ms, missing)
       Nothing -> (ms, name : missing)
-
-dumpTags :: [FilePath] -> ([(String, P.Module)] -> [String]) -> IO ()
-dumpTags input renderTags = do
-  e <- P.parseModulesFromFiles (fromMaybe "") <$> mapM (fmap (first Just) . parseFile) (ordNub input)
-  case e of
-    Left err -> do
-      hPrint stderr err
-      exitFailure
-    Right ms ->
-      ldump (renderTags (pairs ms))
-
-  where
-  pairs :: [(Maybe String, m)] -> [(String, m)]
-  pairs = map (first (fromMaybe ""))
-
-  ldump :: [String] -> IO ()
-  ldump = mapM_ putStrLn
-
-parseFile :: FilePath -> IO (FilePath, Text)
-parseFile input = (,) input <$> readUTF8FileT input
 
 inputFile :: Opts.Parser FilePath
 inputFile = Opts.strArgument $
diff --git a/app/Command/Docs/Ctags.hs b/app/Command/Docs/Ctags.hs
deleted file mode 100644
--- a/app/Command/Docs/Ctags.hs
+++ /dev/null
@@ -1,13 +0,0 @@
-module Command.Docs.Ctags (dumpCtags) where
-
-import           Command.Docs.Tags
-import           Data.List (sort)
-import qualified Language.PureScript as P
-
-dumpCtags :: [(String, P.Module)] -> [String]
-dumpCtags = sort . concatMap renderModCtags
-
-renderModCtags :: (String, P.Module) -> [String]
-renderModCtags (path, mdl) = sort tagLines
-  where tagLines = map tagLine $ tags mdl
-        tagLine (name, line) = name ++ "\t" ++ path ++ "\t" ++ show line
diff --git a/app/Command/Docs/Etags.hs b/app/Command/Docs/Etags.hs
deleted file mode 100644
--- a/app/Command/Docs/Etags.hs
+++ /dev/null
@@ -1,13 +0,0 @@
-module Command.Docs.Etags (dumpEtags) where
-
-import           Command.Docs.Tags
-import qualified Language.PureScript as P
-
-dumpEtags :: [(String, P.Module)] -> [String]
-dumpEtags = concatMap renderModEtags
-
-renderModEtags :: (String, P.Module) -> [String]
-renderModEtags (path, mdl) = ["\x0c", path ++ "," ++ show tagsLen] ++ tagLines
-  where tagsLen = sum $ map length tagLines
-        tagLines = map tagLine $ tags mdl
-        tagLine (name, line) = "\x7f" ++ name ++ "\x01" ++ show line ++ ","
diff --git a/app/Command/Docs/Tags.hs b/app/Command/Docs/Tags.hs
deleted file mode 100644
--- a/app/Command/Docs/Tags.hs
+++ /dev/null
@@ -1,21 +0,0 @@
-module Command.Docs.Tags where
-
-import           Control.Arrow (first)
-import qualified Data.Text as T
-import qualified Language.PureScript as P
-
-tags :: P.Module -> [(String, Int)]
-tags = map (first T.unpack) . concatMap dtags . P.exportedDeclarations
-  where
-    dtags :: P.Declaration -> [(P.Text, Int)]
-    dtags (P.DataDeclaration (ss, _) _ name _ dcons) = (P.runProperName name, pos ss) : consNames
-      where consNames = map (\(cname, _) -> (P.runProperName cname, pos ss)) dcons
-    dtags (P.TypeDeclaration (P.TypeDeclarationData (ss, _) ident _)) = [(P.showIdent ident, pos ss)]
-    dtags (P.ExternDeclaration (ss, _) ident _) = [(P.showIdent ident, pos ss)]
-    dtags (P.TypeSynonymDeclaration (ss, _) name _ _) = [(P.runProperName name, pos ss)]
-    dtags (P.TypeClassDeclaration (ss, _) name _ _ _ _) = [(P.runProperName name, pos ss)]
-    dtags (P.TypeInstanceDeclaration (ss, _) name _ _ _ _) = [(P.showIdent name, pos ss)]
-    dtags (P.ExternKindDeclaration (ss, _) name) = [(P.runProperName name, pos ss)]
-    dtags _ = []
-    pos :: P.SourceSpan -> Int
-    pos = P.sourcePosLine . P.spanStart
diff --git a/app/Command/REPL.hs b/app/Command/REPL.hs
--- a/app/Command/REPL.hs
+++ b/app/Command/REPL.hs
@@ -330,7 +330,7 @@
               Right (modules, externs, env) -> do
                 historyFilename <- getHistoryFilename
                 let settings = defaultSettings { historyFile = Just historyFilename }
-                    initialState = PSCiState [] [] (zip (map snd modules) externs)
+                    initialState = updateLoadedExterns (const (zip (map snd modules) externs)) initialPSCiState
                     config = PSCiConfig psciInputGlob env
                     runner = flip runReaderT config
                              . flip evalStateT initialState
@@ -360,13 +360,10 @@
                       configFile <- (</> ".purs-repl") <$> liftIO getCurrentDirectory
                       exists <- liftIO $ doesFileExist configFile
                       when exists $ do
-                        ls <- lines <$> liftIO (readUTF8File configFile)
-                        for_ ls $ \l -> do
-                          liftIO (putStrLn l)
-                          case parseCommand l of
-                            Left err -> liftIO (putStrLn err >> exitFailure)
-                            Right cmd@Import{} -> handleCommand' state cmd
-                            Right _ -> liftIO (putStrLn "The .purs-repl file only supports import declarations")
+                        cf <- liftIO (readUTF8File configFile)
+                        case parseDotFile configFile cf of
+                          Left err -> liftIO (putStrLn err >> exitFailure)
+                          Right cmds -> liftIO (putStrLn cf) >> for_ cmds (handleCommand' state)
 
                     handleCommandWithInterrupts
                       :: state
diff --git a/app/Main.hs b/app/Main.hs
--- a/app/Main.hs
+++ b/app/Main.hs
@@ -19,6 +19,7 @@
 import qualified Options.Applicative as Opts
 import           System.Environment (getArgs)
 import qualified System.IO as IO
+import qualified Text.PrettyPrint.ANSI.Leijen as Doc
 import           Version (versionString)
 
 
@@ -32,8 +33,21 @@
     opts        = Opts.info (versionInfo <*> Opts.helper <*> commands) infoModList
     infoModList = Opts.fullDesc <> headerInfo <> footerInfo
     headerInfo  = Opts.progDesc "The PureScript compiler and tools"
-    footerInfo  = Opts.footer $ "purs " ++ versionString
+    footerInfo  = Opts.footerDoc (Just footer)
 
+    footer =
+      mconcat
+        [ para $
+            "For help using each individual command, run `purs COMMAND --help`. " ++
+            "For example, `purs compile --help` displays options specific to the `compile` command."
+        , Doc.hardline
+        , Doc.hardline
+        , Doc.text $ "purs " ++ versionString
+        ]
+
+    para :: String -> Doc.Doc
+    para = foldr (Doc.</>) Doc.empty . map Doc.text . words
+
     -- | Displays full command help when invoked with no arguments.
     execParserPure :: Opts.ParserInfo a -> [String] -> Opts.ParserResult a
     execParserPure pinfo [] = Opts.Failure $
@@ -55,7 +69,7 @@
               (Opts.progDesc "Compile PureScript source files"))
         , Opts.command "docs"
             (Opts.info Docs.command
-              (Opts.progDesc "Generate Markdown documentation from PureScript source files" <> Docs.infoModList))
+              (Opts.progDesc "Generate documentation from PureScript source files in a variety of formats, including Markdown and HTML" <> Docs.infoModList))
         , Opts.command "hierarchy"
             (Opts.info Hierarchy.command
               (Opts.progDesc "Generate a GraphViz directed graph of PureScript type classes"))
diff --git a/examples/docs/bower.json b/examples/docs/bower.json
deleted file mode 100644
--- a/examples/docs/bower.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-  "name": "docs-test-package",
-  "version": "1.0.0",
-  "moduleType": [
-    "node"
-  ],
-  "repository": {
-    "type": "git",
-    "url": "git://github.com/not-real/not-a-real-repo.git"
-  },
-  "ignore": [
-    "**/.*",
-    "node_modules",
-    "bower_components",
-    "output"
-  ],
-  "dependencies": {
-    "purescript-prelude": "./bower_components/purescript-prelude"
-  },
-  "license": "MIT"
-}
diff --git a/examples/docs/bower_components/purescript-prelude/src/Prelude.purs b/examples/docs/bower_components/purescript-prelude/src/Prelude.purs
deleted file mode 100644
--- a/examples/docs/bower_components/purescript-prelude/src/Prelude.purs
+++ /dev/null
@@ -1,8 +0,0 @@
-module Prelude where
-
-newtype Unit = Unit {}
-
-unit :: Unit
-unit = Unit {}
-
-data Boolean2 = True | False
diff --git a/examples/docs/resolutions.json b/examples/docs/resolutions.json
deleted file mode 100644
--- a/examples/docs/resolutions.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-  "canonicalDir": ".",
-  "pkgMeta": {
-    "dependencies": {
-      "purescript-prelude": "./bower_components/purescript-prelude"
-    }
-  },
-  "dependencies": {
-    "purescript-prelude": {
-      "canonicalDir": "bower_components/purescript-prelude",
-      "pkgMeta": {
-        "_resolution": {
-          "type": "version",
-          "tag": "v2.4.0",
-          "commit": "21067a4c782f42d08bc877214f85b92ce6769b21"
-        }
-      },
-      "dependencies": {}
-    }
-  }
-}
diff --git a/examples/docs/src/ChildDeclOrder.purs b/examples/docs/src/ChildDeclOrder.purs
deleted file mode 100644
--- a/examples/docs/src/ChildDeclOrder.purs
+++ /dev/null
@@ -1,27 +0,0 @@
--- Tests should ensure that, in the docs:
---  - First should come before Second
---  - foo1 should be listed before foo2
---  - the instances should be listed in the same order as this source file
-module ChildDeclOrder where
-
-data Two
-  = First
-  | Second
-
-class Show a where
-  show :: a -> String
-
-class Foo a where
-  foo1 :: a
-  foo2 :: a
-
-instance showTwo :: Show Two where
-  show _  = ""
-
-instance fooTwo :: Foo Two where
-  foo1 = First
-  foo2 = Second
-
-instance fooInt :: Foo Int where
-  foo1 = 1
-  foo2 = 2
diff --git a/examples/docs/src/Clash.purs b/examples/docs/src/Clash.purs
deleted file mode 100644
--- a/examples/docs/src/Clash.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module Clash (module Clash1) where
-
-import Clash1 as Clash1
-import Clash2 as Clash2
diff --git a/examples/docs/src/Clash1.purs b/examples/docs/src/Clash1.purs
deleted file mode 100644
--- a/examples/docs/src/Clash1.purs
+++ /dev/null
@@ -1,3 +0,0 @@
-module Clash1 (module Clash1a) where
-
-import Clash1a
diff --git a/examples/docs/src/Clash1a.purs b/examples/docs/src/Clash1a.purs
deleted file mode 100644
--- a/examples/docs/src/Clash1a.purs
+++ /dev/null
@@ -1,9 +0,0 @@
-module Clash1a where
-
-value :: Int
-value = 0
-
-type Type = Int
-
-class TypeClass a where
-  typeClassMember :: a
diff --git a/examples/docs/src/Clash2.purs b/examples/docs/src/Clash2.purs
deleted file mode 100644
--- a/examples/docs/src/Clash2.purs
+++ /dev/null
@@ -1,3 +0,0 @@
-module Clash2 (module Clash2a) where
-
-import Clash2a
diff --git a/examples/docs/src/Clash2a.purs b/examples/docs/src/Clash2a.purs
deleted file mode 100644
--- a/examples/docs/src/Clash2a.purs
+++ /dev/null
@@ -1,9 +0,0 @@
-module Clash2a where
-
-value :: String
-value = "hello"
-
-type Type = String
-
-class TypeClass a b where
-  typeClassMember :: a -> b
diff --git a/examples/docs/src/ConstrainedArgument.purs b/examples/docs/src/ConstrainedArgument.purs
deleted file mode 100644
--- a/examples/docs/src/ConstrainedArgument.purs
+++ /dev/null
@@ -1,8 +0,0 @@
-module ConstrainedArgument where
-
-class Foo t
-
-type WithoutArgs      = forall a. (Partial => a) -> a
-type WithArgs         = forall a. (Foo a => a) -> a
-type MultiWithoutArgs = forall a. (Partial => Partial => a) -> a
-type MultiWithArgs    = forall a b. (Foo a => Foo b => a) -> a
diff --git a/examples/docs/src/DeclOrder.purs b/examples/docs/src/DeclOrder.purs
deleted file mode 100644
--- a/examples/docs/src/DeclOrder.purs
+++ /dev/null
@@ -1,17 +0,0 @@
-module DeclOrder
-  ( class A
-  , x1
-  , X2
-  , x3
-  , X4
-  , class B
-  ) where
-
-x1 = 0
-x3 = 0
-
-data X2
-data X4
-
-class A
-class B
diff --git a/examples/docs/src/DeclOrderNoExportList.purs b/examples/docs/src/DeclOrderNoExportList.purs
deleted file mode 100644
--- a/examples/docs/src/DeclOrderNoExportList.purs
+++ /dev/null
@@ -1,10 +0,0 @@
-module DeclOrderNoExportList where
-
-x1 = 0
-x3 = 0
-
-data X2
-data X4
-
-class A
-class B
diff --git a/examples/docs/src/Desugar.purs b/examples/docs/src/Desugar.purs
deleted file mode 100644
--- a/examples/docs/src/Desugar.purs
+++ /dev/null
@@ -1,8 +0,0 @@
-module Desugar where
-
-data X a b = X a b
-
-test :: forall a b. X (a -> b) a -> b
-test x =
-  let X a b = x
-  in a b
diff --git a/examples/docs/src/DocComments.purs b/examples/docs/src/DocComments.purs
deleted file mode 100644
--- a/examples/docs/src/DocComments.purs
+++ /dev/null
@@ -1,11 +0,0 @@
-module DocComments where
-
--- | This declaration has a code block:
--- |
--- |     example == 0
--- |
--- | Here we are really testing that the leading whitespace is not stripped, as
--- | this ensures that we don't accidentally change code blocks into normal
--- | paragraphs.
-example :: Int
-example = 0
diff --git a/examples/docs/src/DuplicateNames.purs b/examples/docs/src/DuplicateNames.purs
deleted file mode 100644
--- a/examples/docs/src/DuplicateNames.purs
+++ /dev/null
@@ -1,9 +0,0 @@
-module DuplicateNames
-  ( module DuplicateNames
-  , module Prelude
-  ) where
-
-import Prelude (Unit)
-
-unit :: Int
-unit = 0
diff --git a/examples/docs/src/Example.purs b/examples/docs/src/Example.purs
deleted file mode 100644
--- a/examples/docs/src/Example.purs
+++ /dev/null
@@ -1,7 +0,0 @@
-module Example
-  ( module Prelude
-  , module Example2
-  ) where
-
-import Prelude (Unit())
-import Example2 (one)
diff --git a/examples/docs/src/Example2.purs b/examples/docs/src/Example2.purs
deleted file mode 100644
--- a/examples/docs/src/Example2.purs
+++ /dev/null
@@ -1,7 +0,0 @@
-module Example2 where
-
-one :: Int
-one = 1
-
-two :: Int
-two = 2
diff --git a/examples/docs/src/ExplicitTypeSignatures.purs b/examples/docs/src/ExplicitTypeSignatures.purs
deleted file mode 100644
--- a/examples/docs/src/ExplicitTypeSignatures.purs
+++ /dev/null
@@ -1,16 +0,0 @@
-
-module ExplicitTypeSignatures where
-
--- This should use the explicit type signature so that the type variable name
--- is preserved.
-explicit :: forall something. something -> something
-explicit x
-  | true = x
-  | false = x
-
--- This should use the inferred type.
-anInt :: _
-anInt = 0
-
--- This should infer a type.
-aNumber = 1.0
diff --git a/examples/docs/src/ImportedTwice.purs b/examples/docs/src/ImportedTwice.purs
deleted file mode 100644
--- a/examples/docs/src/ImportedTwice.purs
+++ /dev/null
@@ -1,13 +0,0 @@
--- See also an example in the wild: purescript-transformers v0.8.4.
--- Control.Monad.RWS.Trans re-exports `lift` from both Control.Monad.Trans
--- (where it is originally defined) and Control.Monad.RWS.Class (which
--- re-exports it from Control.Monad.Trans).
-
-module ImportedTwice
-  ( module ImportedTwiceA
-  , module ImportedTwiceB
-  )
-  where
-
-import ImportedTwiceA
-import ImportedTwiceB
diff --git a/examples/docs/src/ImportedTwiceA.purs b/examples/docs/src/ImportedTwiceA.purs
deleted file mode 100644
--- a/examples/docs/src/ImportedTwiceA.purs
+++ /dev/null
@@ -1,8 +0,0 @@
-module ImportedTwiceA
-  ( module ImportedTwiceB )
-  where
-
-import ImportedTwiceB
-
-bar :: Int
-bar = 1
diff --git a/examples/docs/src/ImportedTwiceB.purs b/examples/docs/src/ImportedTwiceB.purs
deleted file mode 100644
--- a/examples/docs/src/ImportedTwiceB.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module ImportedTwiceB where
-
-foo :: Int
-foo = 0
diff --git a/examples/docs/src/MultiVirtual.purs b/examples/docs/src/MultiVirtual.purs
deleted file mode 100644
--- a/examples/docs/src/MultiVirtual.purs
+++ /dev/null
@@ -1,6 +0,0 @@
-module MultiVirtual
-  ( module X )
-  where
-
-import MultiVirtual1 as X
-import MultiVirtual2 as X
diff --git a/examples/docs/src/MultiVirtual1.purs b/examples/docs/src/MultiVirtual1.purs
deleted file mode 100644
--- a/examples/docs/src/MultiVirtual1.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module MultiVirtual1 where
-
-foo :: Int
-foo = 1
diff --git a/examples/docs/src/MultiVirtual2.purs b/examples/docs/src/MultiVirtual2.purs
deleted file mode 100644
--- a/examples/docs/src/MultiVirtual2.purs
+++ /dev/null
@@ -1,9 +0,0 @@
-module MultiVirtual2
-  ( module MultiVirtual2
-  , module MultiVirtual3
-  ) where
-
-import MultiVirtual3
-
-bar :: Int
-bar = 2
diff --git a/examples/docs/src/MultiVirtual3.purs b/examples/docs/src/MultiVirtual3.purs
deleted file mode 100644
--- a/examples/docs/src/MultiVirtual3.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module MultiVirtual3 where
-
-baz :: Int
-baz = 3
diff --git a/examples/docs/src/NewOperators.purs b/examples/docs/src/NewOperators.purs
deleted file mode 100644
--- a/examples/docs/src/NewOperators.purs
+++ /dev/null
@@ -1,5 +0,0 @@
-module NewOperators
-  ( module NewOperators2 )
-  where
-
-import NewOperators2
diff --git a/examples/docs/src/NewOperators2.purs b/examples/docs/src/NewOperators2.purs
deleted file mode 100644
--- a/examples/docs/src/NewOperators2.purs
+++ /dev/null
@@ -1,6 +0,0 @@
-module NewOperators2 where
-
-infixl 8 _compose as >>>
-
-_compose :: forall a b c. (b -> c) -> (a -> b) -> (a -> c)
-_compose f g x = f (g x)
diff --git a/examples/docs/src/NotAllCtors.purs b/examples/docs/src/NotAllCtors.purs
deleted file mode 100644
--- a/examples/docs/src/NotAllCtors.purs
+++ /dev/null
@@ -1,5 +0,0 @@
-module NotAllCtors
-  ( module Prelude )
-  where
-
-import Prelude (Boolean2(True))
diff --git a/examples/docs/src/ReExportedTypeClass.purs b/examples/docs/src/ReExportedTypeClass.purs
deleted file mode 100644
--- a/examples/docs/src/ReExportedTypeClass.purs
+++ /dev/null
@@ -1,5 +0,0 @@
-module ReExportedTypeClass
-  ( module SomeTypeClass )
-  where
-
-import SomeTypeClass
diff --git a/examples/docs/src/SolitaryTypeClassMember.purs b/examples/docs/src/SolitaryTypeClassMember.purs
deleted file mode 100644
--- a/examples/docs/src/SolitaryTypeClassMember.purs
+++ /dev/null
@@ -1,6 +0,0 @@
-module SolitaryTypeClassMember
-  ( module SomeTypeClass )
-  where
-
-import SomeTypeClass (member)
-
diff --git a/examples/docs/src/SomeTypeClass.purs b/examples/docs/src/SomeTypeClass.purs
deleted file mode 100644
--- a/examples/docs/src/SomeTypeClass.purs
+++ /dev/null
@@ -1,5 +0,0 @@
-
-module SomeTypeClass where
-
-class SomeClass a where
-  member :: a
diff --git a/examples/docs/src/Transitive1.purs b/examples/docs/src/Transitive1.purs
deleted file mode 100644
--- a/examples/docs/src/Transitive1.purs
+++ /dev/null
@@ -1,5 +0,0 @@
-module Transitive1
-  ( module Transitive2 )
-  where
-
-import Transitive2
diff --git a/examples/docs/src/Transitive2.purs b/examples/docs/src/Transitive2.purs
deleted file mode 100644
--- a/examples/docs/src/Transitive2.purs
+++ /dev/null
@@ -1,5 +0,0 @@
-module Transitive2
-  ( module Transitive3 )
-  where
-
-import Transitive3
diff --git a/examples/docs/src/Transitive3.purs b/examples/docs/src/Transitive3.purs
deleted file mode 100644
--- a/examples/docs/src/Transitive3.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module Transitive3 where
-
-transitive3 :: Int
-transitive3 = 0
diff --git a/examples/docs/src/TypeClassWithFunDeps.purs b/examples/docs/src/TypeClassWithFunDeps.purs
deleted file mode 100644
--- a/examples/docs/src/TypeClassWithFunDeps.purs
+++ /dev/null
@@ -1,5 +0,0 @@
-
-module TypeClassWithFunDeps where
-
-class TypeClassWithFunDeps a b c d e | a b -> c, c -> d e where
-  aMember :: a -> b
diff --git a/examples/docs/src/TypeClassWithoutMembers.purs b/examples/docs/src/TypeClassWithoutMembers.purs
deleted file mode 100644
--- a/examples/docs/src/TypeClassWithoutMembers.purs
+++ /dev/null
@@ -1,5 +0,0 @@
-module TypeClassWithoutMembers
-  ( module TypeClassWithoutMembersIntermediate )
-  where
-
-import TypeClassWithoutMembersIntermediate
diff --git a/examples/docs/src/TypeClassWithoutMembersIntermediate.purs b/examples/docs/src/TypeClassWithoutMembersIntermediate.purs
deleted file mode 100644
--- a/examples/docs/src/TypeClassWithoutMembersIntermediate.purs
+++ /dev/null
@@ -1,5 +0,0 @@
-module TypeClassWithoutMembersIntermediate
-  ( module SomeTypeClass )
-  where
-
-import SomeTypeClass (class SomeClass)
diff --git a/examples/docs/src/TypeLevelString.purs b/examples/docs/src/TypeLevelString.purs
deleted file mode 100644
--- a/examples/docs/src/TypeLevelString.purs
+++ /dev/null
@@ -1,7 +0,0 @@
-module TypeLevelString where
-
-data Foo
-
-class Bar a
-
-instance fooBar :: Fail "oops" => Bar Foo
diff --git a/examples/docs/src/TypeOpAliases.purs b/examples/docs/src/TypeOpAliases.purs
deleted file mode 100644
--- a/examples/docs/src/TypeOpAliases.purs
+++ /dev/null
@@ -1,44 +0,0 @@
-module TypeOpAliases where
-
-type AltFn a b = a -> b
-
-infixr 6 type AltFn as ~>
-
-foreign import test1 :: forall a b. a ~> b
-foreign import test2 :: forall a b c. a ~> b ~> c
-foreign import test3 :: forall a b c d. a ~> (b ~> c) ~> d
-foreign import test4 :: forall a b c d. ((a ~> b) ~> c) ~> d
-
-data Tuple a b = Tuple a b
-
-infixl 6 Tuple as ×
-infixl 6 type Tuple as ×
-
-data Either a b = Left a | Right b
-
-infixl 5 type Either as ⊕
-
-third ∷ ∀ a b c. a × b × c → c
-third (a × b × c) = c
-
-class Show a where
-  show :: a -> String
-
-instance showTuple :: Show a => Show (a × b) where
-  show (a × _) = show a
-
--- Test that precedence is taken into account while desugaring type operators
-
-class TestL a where
-  testL :: a
-
-class TestR a where
-  testR :: a
-
--- Note: this type is Either Int (Tuple Int String)
-instance testLEither :: TestL (Int ⊕ Int × String) where
-  testL = Right (0 × "hi")
-
--- Note: this type is Either (Tuple Int Int) String
-instance testREither :: TestR (Int × Int ⊕ String) where
-  testR = Left (0 × 1)
diff --git a/examples/docs/src/UTF8.purs b/examples/docs/src/UTF8.purs
deleted file mode 100644
--- a/examples/docs/src/UTF8.purs
+++ /dev/null
@@ -1,7 +0,0 @@
-module UTF8 where
-
-import Prelude (Unit, unit)
-
--- | üÜäÄ 😰
-thing :: Unit
-thing = unit
diff --git a/examples/docs/src/Virtual.purs b/examples/docs/src/Virtual.purs
deleted file mode 100644
--- a/examples/docs/src/Virtual.purs
+++ /dev/null
@@ -1,5 +0,0 @@
-module Virtual
-  ( module VirtualPrelude )
-  where
-
-import Prelude as VirtualPrelude
diff --git a/examples/failing/1071.purs b/examples/failing/1071.purs
deleted file mode 100644
--- a/examples/failing/1071.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- @shouldFailWith KindsDoNotUnify
-module Main where
-
-class Foo a b where
-  foo :: a -> b
-
-bar :: forall a. Foo a => a -> a
-bar a = a
diff --git a/examples/failing/1169.purs b/examples/failing/1169.purs
deleted file mode 100644
--- a/examples/failing/1169.purs
+++ /dev/null
@@ -1,12 +0,0 @@
--- @shouldFailWith IncorrectConstructorArity 
-module Test where
-
-data Outer a = Outer a
-            
-data Inner a b = Inner a b
-
-test1 :: forall a b. Outer (Inner a b) -> Boolean
-test1 (Outer (Inner _)) = true
-
-test2 :: forall a b. Inner a b -> Boolean
-test2 (Inner _) = true
diff --git a/examples/failing/1175.purs b/examples/failing/1175.purs
deleted file mode 100644
--- a/examples/failing/1175.purs
+++ /dev/null
@@ -1,11 +0,0 @@
--- @shouldFailWith TypesDoNotUnify
-module X where
-
-class Foo where
-  foo :: String
-
-instance f :: Foo where
-  foo = "a"
-    where
-    bar :: String
-    bar = 1
diff --git a/examples/failing/1310.purs b/examples/failing/1310.purs
deleted file mode 100644
--- a/examples/failing/1310.purs
+++ /dev/null
@@ -1,18 +0,0 @@
--- @shouldFailWith NoInstanceFound
-
-module Issue1310 where
-
-import Prelude
-import Control.Monad.Eff
-import Control.Monad.Eff.Console
-
-class Inject f g where
-  inj :: forall a. f a -> g a
-
-instance inject :: Inject f f where
-  inj x = x
-
-foreign import data Oops :: Effect
-
-main :: forall eff. Eff (oops :: Oops | eff) Unit
-main = inj (log "Oops")
diff --git a/examples/failing/1570.purs b/examples/failing/1570.purs
deleted file mode 100644
--- a/examples/failing/1570.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith ExpectedType
-module M where
-
-data F a = F a
-
-test = \(x :: F) -> x
diff --git a/examples/failing/1733.purs b/examples/failing/1733.purs
deleted file mode 100644
--- a/examples/failing/1733.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith UnknownName
-module Main where
-
-import Thingy as Thing
-
-main = Thing.doesntExist "hi"
diff --git a/examples/failing/1733/Thingy.purs b/examples/failing/1733/Thingy.purs
deleted file mode 100644
--- a/examples/failing/1733/Thingy.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module Thingy where
-
-foo :: Int
-foo = 1
diff --git a/examples/failing/1825.purs b/examples/failing/1825.purs
deleted file mode 100644
--- a/examples/failing/1825.purs
+++ /dev/null
@@ -1,9 +0,0 @@
--- @shouldFailWith UnknownName
-
-module Main where
-
-data W = X | Y | Z
-
-bad X a = a
-bad Y _ = a
-bad Z a = a
diff --git a/examples/failing/1881.purs b/examples/failing/1881.purs
deleted file mode 100644
--- a/examples/failing/1881.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith ErrorParsingModule
-module Main where
-
-foo =
-bar :: Int
-bar = 3
diff --git a/examples/failing/2128-class.purs b/examples/failing/2128-class.purs
deleted file mode 100644
--- a/examples/failing/2128-class.purs
+++ /dev/null
@@ -1,5 +0,0 @@
--- @shouldFailWith ErrorParsingModule
-module Main where
-
-class Foo a where
-  foo :: a -> !!!
diff --git a/examples/failing/2128-instance.purs b/examples/failing/2128-instance.purs
deleted file mode 100644
--- a/examples/failing/2128-instance.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- @shouldFailWith ErrorParsingModule
-module Main where
-
-class Foo a where
-  foo :: a
-
-instance fooInt :: Foo Int where
-  foo = !!!
diff --git a/examples/failing/2197-shouldFail.purs b/examples/failing/2197-shouldFail.purs
deleted file mode 100644
--- a/examples/failing/2197-shouldFail.purs
+++ /dev/null
@@ -1,10 +0,0 @@
--- @shouldFailWith ScopeConflict
-module Main where
-
-import Prim as P
-import Prim (Number)
-
-type Number = P.Number
-
-z :: Number
-z = 0.0
diff --git a/examples/failing/2197-shouldFail2.purs b/examples/failing/2197-shouldFail2.purs
deleted file mode 100644
--- a/examples/failing/2197-shouldFail2.purs
+++ /dev/null
@@ -1,7 +0,0 @@
--- @shouldFailWith UnknownName
-module Main where
-
-import Prim (Boolean)
-
-z :: Number
-z = 0.0
diff --git a/examples/failing/2378.purs b/examples/failing/2378.purs
deleted file mode 100644
--- a/examples/failing/2378.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith OrphanInstance
-module Main where
-
-import Lib
-
-instance fooX :: Foo "x"
diff --git a/examples/failing/2378/Lib.purs b/examples/failing/2378/Lib.purs
deleted file mode 100644
--- a/examples/failing/2378/Lib.purs
+++ /dev/null
@@ -1,3 +0,0 @@
-module Lib (class Foo) where
-
-class Foo (a :: Symbol)
diff --git a/examples/failing/2379.purs b/examples/failing/2379.purs
deleted file mode 100644
--- a/examples/failing/2379.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith UnknownClass
-module Main where
-
-import Lib
-
-test = x [1, 2, 3]
diff --git a/examples/failing/2379/Lib.purs b/examples/failing/2379/Lib.purs
deleted file mode 100644
--- a/examples/failing/2379/Lib.purs
+++ /dev/null
@@ -1,9 +0,0 @@
-module Lib (class X, x) where
-
-class X a where
-  x :: a -> String
-
-class Y a
-
-instance xArray :: Y a => X (Array a) where
-  x _ = "[]"
diff --git a/examples/failing/2434.purs b/examples/failing/2434.purs
deleted file mode 100644
--- a/examples/failing/2434.purs
+++ /dev/null
@@ -1,5 +0,0 @@
--- @shouldFailWith ErrorParsingModule
-module Main where
-
-x :: Char
-x = '\x10000'
diff --git a/examples/failing/2534.purs b/examples/failing/2534.purs
deleted file mode 100644
--- a/examples/failing/2534.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- @shouldFailWith InfiniteType
-module Main where
-
-foo :: Array Int -> Int
-foo xs = go xs where
-  go :: Array _ -> Int
-  go [] = 0
-  go xs = go [xs]
diff --git a/examples/failing/2542.purs b/examples/failing/2542.purs
deleted file mode 100644
--- a/examples/failing/2542.purs
+++ /dev/null
@@ -1,9 +0,0 @@
--- @shouldFailWith UndefinedTypeVariable
-module Main where
-
-type T = forall a. Array a
-
-foo :: T
-foo = bar where
-  bar :: Array a
-  bar = []
diff --git a/examples/failing/2567.purs b/examples/failing/2567.purs
deleted file mode 100644
--- a/examples/failing/2567.purs
+++ /dev/null
@@ -1,5 +0,0 @@
--- @shouldFailWith NoInstanceFound
-module Main where
-
-foo :: Int
-foo = (0 :: Fail "This constraint should be checked" => Int)
diff --git a/examples/failing/2601.purs b/examples/failing/2601.purs
deleted file mode 100644
--- a/examples/failing/2601.purs
+++ /dev/null
@@ -1,7 +0,0 @@
--- @shouldFailWith KindsDoNotUnify
-module Main where
-
-type Syn (a :: Type -> Type) = String
-
-val :: Syn Int
-val = "bad"
diff --git a/examples/failing/2616.purs b/examples/failing/2616.purs
deleted file mode 100644
--- a/examples/failing/2616.purs
+++ /dev/null
@@ -1,9 +0,0 @@
--- @shouldFailWith NoInstanceFound
-module Main where
-	
-import Prelude
-
-newtype Foo r = Foo { | r }
-
-derive instance eqFoo :: Eq (Foo r)
-derive instance ordFoo :: Ord (Foo r)
diff --git a/examples/failing/2806.purs b/examples/failing/2806.purs
deleted file mode 100644
--- a/examples/failing/2806.purs
+++ /dev/null
@@ -1,7 +0,0 @@
--- @shouldFailWith NoInstanceFound
-module X where
-
-data E a b = L a | R b
-
-g :: forall a b . E a b -> a
-g e | L x <- e = x
diff --git a/examples/failing/2874-forall.purs b/examples/failing/2874-forall.purs
deleted file mode 100644
--- a/examples/failing/2874-forall.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- @shouldFailWith ErrorParsingModule
-module Main where
-
-class T a b | a -> b
-instance tT :: (T Int (forall a. a)) => T Int String
-
-ddd :: Int
-ddd = 0 :: forall t. T Int t => Int
diff --git a/examples/failing/2874-forall2.purs b/examples/failing/2874-forall2.purs
deleted file mode 100644
--- a/examples/failing/2874-forall2.purs
+++ /dev/null
@@ -1,10 +0,0 @@
--- @shouldFailWith ErrorParsingModule
-module Main where
-
-class X a b | a -> b
-class X a (forall t. t) <= Y a b | a -> b
-instance tX :: X Int String
-instance tY :: Y Int Boolean
-
-ggg :: Int
-ggg = 0 :: forall t. Y Int t => Int
diff --git a/examples/failing/2874-wildcard.purs b/examples/failing/2874-wildcard.purs
deleted file mode 100644
--- a/examples/failing/2874-wildcard.purs
+++ /dev/null
@@ -1,11 +0,0 @@
--- @shouldFailWith ErrorParsingModule
-module Main where
-
-class Foo a where
-  foo :: a
-
-class Baz b where
-  baz :: b
-
-instance bazFoo :: (Baz _) => Foo b where
-  foo = baz
diff --git a/examples/failing/365.purs b/examples/failing/365.purs
deleted file mode 100644
--- a/examples/failing/365.purs
+++ /dev/null
@@ -1,14 +0,0 @@
--- @shouldFailWith CycleInDeclaration
-module Main where
-
-import Prelude
-
-class C a where
-  f :: a -> a
-  g :: a -> a
-
-instance cS :: C String where
-  f s = s
-  g = f
-
-main = g "Done"
diff --git a/examples/failing/438.purs b/examples/failing/438.purs
deleted file mode 100644
--- a/examples/failing/438.purs
+++ /dev/null
@@ -1,15 +0,0 @@
--- @shouldFailWith PossiblyInfiniteInstance
-
--- See issue 438 for details: this test is mainly here to test that code like
--- this doesn't cause the compiler to loop.
-
-module Main where
-
-import Prelude
-
-data Fix f = In (f (Fix f))
-
-instance eqFix :: (Eq (f (Fix f))) => Eq (Fix f) where
-  eq (In f) (In g) = f == g
-
-example = In [] == In []
diff --git a/examples/failing/881.purs b/examples/failing/881.purs
deleted file mode 100644
--- a/examples/failing/881.purs
+++ /dev/null
@@ -1,13 +0,0 @@
--- @shouldFailWith DuplicateValueDeclaration
-module Main where
-
-data X = X | Y
-
-class Foo a where
-  foo :: a -> a
-  bar :: a
-
-instance fooX :: Foo X where
-  foo X = X
-  bar = X
-  foo Y = Y
diff --git a/examples/failing/AnonArgument1.purs b/examples/failing/AnonArgument1.purs
deleted file mode 100644
--- a/examples/failing/AnonArgument1.purs
+++ /dev/null
@@ -1,5 +0,0 @@
--- @shouldFailWith IncorrectAnonymousArgument
-module Main where
-
-test :: Int -> Int
-test = _
diff --git a/examples/failing/AnonArgument2.purs b/examples/failing/AnonArgument2.purs
deleted file mode 100644
--- a/examples/failing/AnonArgument2.purs
+++ /dev/null
@@ -1,7 +0,0 @@
--- @shouldFailWith IncorrectAnonymousArgument
-module Main where
-
-import Prelude
-
-test :: Int -> Int
-test = 1 + 2 * _
diff --git a/examples/failing/AnonArgument3.purs b/examples/failing/AnonArgument3.purs
deleted file mode 100644
--- a/examples/failing/AnonArgument3.purs
+++ /dev/null
@@ -1,5 +0,0 @@
--- @shouldFailWith IncorrectAnonymousArgument
-module Main where
-
-test :: Int -> Int
-test = 1 + _
diff --git a/examples/failing/ArgLengthMismatch.purs b/examples/failing/ArgLengthMismatch.purs
deleted file mode 100644
--- a/examples/failing/ArgLengthMismatch.purs
+++ /dev/null
@@ -1,7 +0,0 @@
--- @shouldFailWith ArgListLengthsDiffer
-module ArgLengthMismatch where
-
-import Prelude
-
-f x y = true
-f = false
diff --git a/examples/failing/ArrayType.purs b/examples/failing/ArrayType.purs
deleted file mode 100644
--- a/examples/failing/ArrayType.purs
+++ /dev/null
@@ -1,14 +0,0 @@
--- @shouldFailWith TypesDoNotUnify
-
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console
-
-bar :: Number -> Number -> Number
-bar n m = n + m
-
-foo = x `bar` y
-  where
-  x = 1
-  y = []
diff --git a/examples/failing/Arrays.purs b/examples/failing/Arrays.purs
deleted file mode 100644
--- a/examples/failing/Arrays.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith TypesDoNotUnify
-module Main where
-
-foreign import ix :: forall a. Array a -> Int -> a
-
-test = \arr -> arr `ix` (0 `ix` 0)
diff --git a/examples/failing/BindInDo-2.purs b/examples/failing/BindInDo-2.purs
deleted file mode 100644
--- a/examples/failing/BindInDo-2.purs
+++ /dev/null
@@ -1,9 +0,0 @@
--- @shouldFailWith CannotUseBindWithDo
-module Main where
-
-import Prelude
-
-foo = do
-  let bind = 42
-  x <- [4, 5, 6]
-  pure x
diff --git a/examples/failing/BindInDo.purs b/examples/failing/BindInDo.purs
deleted file mode 100644
--- a/examples/failing/BindInDo.purs
+++ /dev/null
@@ -1,9 +0,0 @@
--- @shouldFailWith CannotUseBindWithDo
-module Main where
-
-import Prelude
-
-foo = do
-  bind <- [1,2,3]
-  x <- [4, 5, 6]
-  pure x
diff --git a/examples/failing/CannotDeriveNewtypeForData.purs b/examples/failing/CannotDeriveNewtypeForData.purs
deleted file mode 100644
--- a/examples/failing/CannotDeriveNewtypeForData.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- @shouldFailWith CannotDeriveNewtypeForData
-module CannotDeriveNewtypeForData where
-
-import Data.Newtype
-
-data Test = Test String
-
-derive instance newtypeTest :: Newtype Test _
diff --git a/examples/failing/CaseBinderLengthsDiffer.purs b/examples/failing/CaseBinderLengthsDiffer.purs
deleted file mode 100644
--- a/examples/failing/CaseBinderLengthsDiffer.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith CaseBinderLengthDiffers
-module Main where
-
-test = case 1, 2 of
-  1, 2, 3 -> 42
-  _, _    -> 43
diff --git a/examples/failing/CaseDoesNotMatchAllConstructorArgs.purs b/examples/failing/CaseDoesNotMatchAllConstructorArgs.purs
deleted file mode 100644
--- a/examples/failing/CaseDoesNotMatchAllConstructorArgs.purs
+++ /dev/null
@@ -1,15 +0,0 @@
--- @shouldFailWith IncorrectConstructorArity
-module Main where
-
-import Prelude
-
-data Person = Person String Int
-
-data TwoPeople = Two Person Person
-
-getName p = case p of
-  (Two (Person n) (Person n2 a2)) -> n
-  _ -> "Unknown"
-
-
-name = getName (Two (Person "Jimmy" 20) (Person "" 1))
diff --git a/examples/failing/ConflictingExports.purs b/examples/failing/ConflictingExports.purs
deleted file mode 100644
--- a/examples/failing/ConflictingExports.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith ScopeConflict
--- Fails here because re-exporting forces any scope conflicts to be resolved
-module Main (module A, module B) where
-
-  import A
-  import B
diff --git a/examples/failing/ConflictingExports/A.purs b/examples/failing/ConflictingExports/A.purs
deleted file mode 100644
--- a/examples/failing/ConflictingExports/A.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module A where
-
-thing :: Int
-thing = 1
diff --git a/examples/failing/ConflictingExports/B.purs b/examples/failing/ConflictingExports/B.purs
deleted file mode 100644
--- a/examples/failing/ConflictingExports/B.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module B where
-
-thing :: Int
-thing = 2
diff --git a/examples/failing/ConflictingImports.purs b/examples/failing/ConflictingImports.purs
deleted file mode 100644
--- a/examples/failing/ConflictingImports.purs
+++ /dev/null
@@ -1,9 +0,0 @@
--- @shouldFailWith ScopeConflict
-module Main where
-
-import A
-import B
-
--- Error due to referencing `thing` which is in scope as A.thing and B.thing
-what :: Int
-what = thing
diff --git a/examples/failing/ConflictingImports/A.purs b/examples/failing/ConflictingImports/A.purs
deleted file mode 100644
--- a/examples/failing/ConflictingImports/A.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module A where
-
-thing :: Int
-thing = 1
diff --git a/examples/failing/ConflictingImports/B.purs b/examples/failing/ConflictingImports/B.purs
deleted file mode 100644
--- a/examples/failing/ConflictingImports/B.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module B where
-
-thing :: Int
-thing = 2
diff --git a/examples/failing/ConflictingImports2.purs b/examples/failing/ConflictingImports2.purs
deleted file mode 100644
--- a/examples/failing/ConflictingImports2.purs
+++ /dev/null
@@ -1,10 +0,0 @@
--- @shouldFailWith ScopeConflict
-module Main where
-
-import A (thing)
-import B (thing)
-
--- Error due to referencing `thing` which is explicitly in scope as A.thing
--- and B.thing
-what :: Int
-what = thing
diff --git a/examples/failing/ConflictingImports2/A.purs b/examples/failing/ConflictingImports2/A.purs
deleted file mode 100644
--- a/examples/failing/ConflictingImports2/A.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module A where
-
-thing :: Int
-thing = 1
diff --git a/examples/failing/ConflictingImports2/B.purs b/examples/failing/ConflictingImports2/B.purs
deleted file mode 100644
--- a/examples/failing/ConflictingImports2/B.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module B where
-
-thing :: Int
-thing = 2
diff --git a/examples/failing/ConflictingQualifiedImports.purs b/examples/failing/ConflictingQualifiedImports.purs
deleted file mode 100644
--- a/examples/failing/ConflictingQualifiedImports.purs
+++ /dev/null
@@ -1,7 +0,0 @@
--- @shouldFailWith ScopeConflict
-module Main where
-
-import A as X
-import B as X
-
-foo = X.thing
diff --git a/examples/failing/ConflictingQualifiedImports/A.purs b/examples/failing/ConflictingQualifiedImports/A.purs
deleted file mode 100644
--- a/examples/failing/ConflictingQualifiedImports/A.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module A where
-
-thing :: Int
-thing = 1
diff --git a/examples/failing/ConflictingQualifiedImports/B.purs b/examples/failing/ConflictingQualifiedImports/B.purs
deleted file mode 100644
--- a/examples/failing/ConflictingQualifiedImports/B.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module B where
-
-thing :: Int
-thing = 2
diff --git a/examples/failing/ConflictingQualifiedImports2.purs b/examples/failing/ConflictingQualifiedImports2.purs
deleted file mode 100644
--- a/examples/failing/ConflictingQualifiedImports2.purs
+++ /dev/null
@@ -1,5 +0,0 @@
--- @shouldFailWith ScopeConflict
-module Main (module X) where
-
-import A as X
-import B as X
diff --git a/examples/failing/ConflictingQualifiedImports2/A.purs b/examples/failing/ConflictingQualifiedImports2/A.purs
deleted file mode 100644
--- a/examples/failing/ConflictingQualifiedImports2/A.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module A where
-
-thing :: Int
-thing = 1
diff --git a/examples/failing/ConflictingQualifiedImports2/B.purs b/examples/failing/ConflictingQualifiedImports2/B.purs
deleted file mode 100644
--- a/examples/failing/ConflictingQualifiedImports2/B.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module B where
-
-thing :: Int
-thing = 2
diff --git a/examples/failing/ConstraintFailure.purs b/examples/failing/ConstraintFailure.purs
deleted file mode 100644
--- a/examples/failing/ConstraintFailure.purs
+++ /dev/null
@@ -1,13 +0,0 @@
--- @shouldFailWith NoInstanceFound
-
-module Main where
-
-import Prelude
-
-data Foo = Bar
-       
-spin :: forall a. a -> Foo
-spin x = Bar
-
-main = show <<< spin
-     
diff --git a/examples/failing/ConstraintInference.purs b/examples/failing/ConstraintInference.purs
deleted file mode 100644
--- a/examples/failing/ConstraintInference.purs
+++ /dev/null
@@ -1,10 +0,0 @@
--- @shouldFailWith AmbiguousTypeVariables
-
-module Main where
-
-import Prelude
-
-spin :: forall a b. a -> b
-spin x = spin x
-
-test = show <<< spin
diff --git a/examples/failing/DctorOperatorAliasExport.purs b/examples/failing/DctorOperatorAliasExport.purs
deleted file mode 100644
--- a/examples/failing/DctorOperatorAliasExport.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith TransitiveDctorExportError
-module Data.List (List, (:)) where
-
-  data List a = Cons a (List a) | Nil
-
-  infixr 6 Cons as :
diff --git a/examples/failing/DeclConflictClassCtor.purs b/examples/failing/DeclConflictClassCtor.purs
deleted file mode 100644
--- a/examples/failing/DeclConflictClassCtor.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith DeclConflict
-module Main where
-
-data T = Fail
-
-class Fail
diff --git a/examples/failing/DeclConflictClassSynonym.purs b/examples/failing/DeclConflictClassSynonym.purs
deleted file mode 100644
--- a/examples/failing/DeclConflictClassSynonym.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- @shouldFailWith DeclConflict
-module Main where
-
-import Prelude
-
-type Fail = Unit
-
-class Fail
diff --git a/examples/failing/DeclConflictClassType.purs b/examples/failing/DeclConflictClassType.purs
deleted file mode 100644
--- a/examples/failing/DeclConflictClassType.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith DeclConflict
-module Main where
-
-class Fail
-
-data Fail
diff --git a/examples/failing/DeclConflictCtorClass.purs b/examples/failing/DeclConflictCtorClass.purs
deleted file mode 100644
--- a/examples/failing/DeclConflictCtorClass.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith DeclConflict
-module Main where
-
-class Fail
-
-data T = Fail
diff --git a/examples/failing/DeclConflictCtorCtor.purs b/examples/failing/DeclConflictCtorCtor.purs
deleted file mode 100644
--- a/examples/failing/DeclConflictCtorCtor.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith DeclConflict
-module Main where
-
-data T1 = Fail
-
-data T2 = Fail
diff --git a/examples/failing/DeclConflictDuplicateCtor.purs b/examples/failing/DeclConflictDuplicateCtor.purs
deleted file mode 100644
--- a/examples/failing/DeclConflictDuplicateCtor.purs
+++ /dev/null
@@ -1,5 +0,0 @@
--- @shouldFailWith DeclConflict
-module Main where
-
-data T = Fail | Fail
-
diff --git a/examples/failing/DeclConflictSynonymClass.purs b/examples/failing/DeclConflictSynonymClass.purs
deleted file mode 100644
--- a/examples/failing/DeclConflictSynonymClass.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- @shouldFailWith DeclConflict
-module Main where
-
-import Prelude
-
-class Fail
-
-type Fail = Unit
diff --git a/examples/failing/DeclConflictSynonymType.purs b/examples/failing/DeclConflictSynonymType.purs
deleted file mode 100644
--- a/examples/failing/DeclConflictSynonymType.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- @shouldFailWith DeclConflict
-module Main where
-
-import Prelude
-
-data Fail
-
-type Fail = Unit
diff --git a/examples/failing/DeclConflictTypeClass.purs b/examples/failing/DeclConflictTypeClass.purs
deleted file mode 100644
--- a/examples/failing/DeclConflictTypeClass.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith DeclConflict
-module Main where
-
-class Fail
-
-data Fail
diff --git a/examples/failing/DeclConflictTypeSynonym.purs b/examples/failing/DeclConflictTypeSynonym.purs
deleted file mode 100644
--- a/examples/failing/DeclConflictTypeSynonym.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- @shouldFailWith DeclConflict
-module Main where
-
-import Prelude
-
-type Fail = Unit
-
-data Fail
diff --git a/examples/failing/DeclConflictTypeType.purs b/examples/failing/DeclConflictTypeType.purs
deleted file mode 100644
--- a/examples/failing/DeclConflictTypeType.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith DeclConflict
-module Main where
-
-data Fail
-
-data Fail
diff --git a/examples/failing/DiffKindsSameName.purs b/examples/failing/DiffKindsSameName.purs
deleted file mode 100644
--- a/examples/failing/DiffKindsSameName.purs
+++ /dev/null
@@ -1,15 +0,0 @@
--- @shouldFailWith KindsDoNotUnify
-module DiffKindsSameName where
-
-import DiffKindsSameName.LibA as LibA
-import DiffKindsSameName.LibB as LibB
-
--- both `LibA` and `LibB` define a kind locally called `DemoKind`
--- `LibB` defines `DemoData :: LibB.DemoKind`
--- if we try to use `DemoData` in a place where `LibA.DemoKind` is expected, it should fail with `KindsDoNotUnify`
-
-data AProxy (m :: LibA.DemoKind) = AProxy
-
-bProxy :: AProxy LibB.DemoData
-bProxy = AProxy
-
diff --git a/examples/failing/DiffKindsSameName/LibA.purs b/examples/failing/DiffKindsSameName/LibA.purs
deleted file mode 100644
--- a/examples/failing/DiffKindsSameName/LibA.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module DiffKindsSameName.LibA where
-
-foreign import kind DemoKind
-
diff --git a/examples/failing/DiffKindsSameName/LibB.purs b/examples/failing/DiffKindsSameName/LibB.purs
deleted file mode 100644
--- a/examples/failing/DiffKindsSameName/LibB.purs
+++ /dev/null
@@ -1,6 +0,0 @@
-module DiffKindsSameName.LibB where
-
-foreign import kind DemoKind
-
-foreign import data DemoData :: DemoKind
-
diff --git a/examples/failing/Do.purs b/examples/failing/Do.purs
deleted file mode 100644
--- a/examples/failing/Do.purs
+++ /dev/null
@@ -1,12 +0,0 @@
--- @shouldFailWith InvalidDoBind
--- @shouldFailWith InvalidDoLet
-module Main where
-
-import Prelude
-
-test1 = do let x = 1
-
-test2 y = do x <- y
-
-test3 = do pure 1
-           pure 2
diff --git a/examples/failing/DoNotSuggestComposition.purs b/examples/failing/DoNotSuggestComposition.purs
deleted file mode 100644
--- a/examples/failing/DoNotSuggestComposition.purs
+++ /dev/null
@@ -1,13 +0,0 @@
--- @shouldFailWith TypesDoNotUnify
--- TODO: Check that this does not produce a "function composition is (<<<)"
--- suggestion.
-module DoNotSuggestComposition where
-
-import Prelude
-
-x = { y: 3 }
-
-foo :: String -> String
-foo y = y
-
-bar = foo x
diff --git a/examples/failing/DoNotSuggestComposition2.purs b/examples/failing/DoNotSuggestComposition2.purs
deleted file mode 100644
--- a/examples/failing/DoNotSuggestComposition2.purs
+++ /dev/null
@@ -1,7 +0,0 @@
--- @shouldFailWith TypesDoNotUnify
--- TODO: Check that this does not produce a "function composition is (<<<)"
--- suggestion.
-
-module DoNotSuggestComposition2 where
-
-foo = let x = { y: 3 } in x 2
diff --git a/examples/failing/DuplicateDeclarationsInLet.purs b/examples/failing/DuplicateDeclarationsInLet.purs
deleted file mode 100644
--- a/examples/failing/DuplicateDeclarationsInLet.purs
+++ /dev/null
@@ -1,12 +0,0 @@
--- @shouldFailWith OverlappingNamesInLet
-module Main where
-
-import Prelude
-
-foo = a
-  where
-  a :: Number
-  a = 1
-
-  a :: Number
-  a = 2
diff --git a/examples/failing/DuplicateInstance.purs b/examples/failing/DuplicateInstance.purs
deleted file mode 100644
--- a/examples/failing/DuplicateInstance.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith DuplicateInstance
-module Main where
-class X
-class Y
-instance i :: X
-instance i :: Y
diff --git a/examples/failing/DuplicateModule.purs b/examples/failing/DuplicateModule.purs
deleted file mode 100644
--- a/examples/failing/DuplicateModule.purs
+++ /dev/null
@@ -1,2 +0,0 @@
--- @shouldFailWith DuplicateModule
-module M1 where
diff --git a/examples/failing/DuplicateModule/M1.purs b/examples/failing/DuplicateModule/M1.purs
deleted file mode 100644
--- a/examples/failing/DuplicateModule/M1.purs
+++ /dev/null
@@ -1,1 +0,0 @@
-module M1 where
diff --git a/examples/failing/DuplicateProperties.purs b/examples/failing/DuplicateProperties.purs
deleted file mode 100644
--- a/examples/failing/DuplicateProperties.purs
+++ /dev/null
@@ -1,12 +0,0 @@
--- @shouldFailWith TypesDoNotUnify
-module DuplicateProperties where
-
-import Prelude
-
-foreign import data Test :: # Type -> Type
-
-foreign import subtractX :: forall r. Test (x :: Unit | r) -> Test r
-
-foreign import hasX :: Test (x :: Unit, y :: Unit)
-
-baz = subtractX (subtractX hasX)
diff --git a/examples/failing/DuplicateTypeClass.purs b/examples/failing/DuplicateTypeClass.purs
deleted file mode 100644
--- a/examples/failing/DuplicateTypeClass.purs
+++ /dev/null
@@ -1,4 +0,0 @@
--- @shouldFailWith DuplicateTypeClass
-module Main where
-class C
-class C
diff --git a/examples/failing/DuplicateTypeVars.purs b/examples/failing/DuplicateTypeVars.purs
deleted file mode 100644
--- a/examples/failing/DuplicateTypeVars.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith DuplicateTypeArgument
-module Main where
-
-import Prelude
-
-type Foo a a = a
diff --git a/examples/failing/Eff.purs b/examples/failing/Eff.purs
deleted file mode 100644
--- a/examples/failing/Eff.purs
+++ /dev/null
@@ -1,13 +0,0 @@
--- @shouldFailWith TypesDoNotUnify
-module Main where
-
-import Prelude
-import Control.Monad.Eff
-import Control.Monad.ST
-import Control.Monad.Eff.Console
-
-test = pureST (do
-         ref <- newSTRef 0
-         log "ST"
-         modifySTRef ref $ \n -> n + 1
-         readSTRef ref)
diff --git a/examples/failing/EmptyCase.purs b/examples/failing/EmptyCase.purs
deleted file mode 100644
--- a/examples/failing/EmptyCase.purs
+++ /dev/null
@@ -1,4 +0,0 @@
--- @shouldFailWith ErrorParsingModule
-module Main where
-
-error err = case err of \_ -> 1
diff --git a/examples/failing/EmptyClass.purs b/examples/failing/EmptyClass.purs
deleted file mode 100644
--- a/examples/failing/EmptyClass.purs
+++ /dev/null
@@ -1,7 +0,0 @@
--- @shouldFailWith ErrorParsingModule
-module Main where
-
-class Foo x where
-
-bar :: String
-bar = "hello"
diff --git a/examples/failing/EmptyDo.purs b/examples/failing/EmptyDo.purs
deleted file mode 100644
--- a/examples/failing/EmptyDo.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith ErrorParsingModule
-
-module Main where
-
-main = do
-
diff --git a/examples/failing/ExportConflictClass.purs b/examples/failing/ExportConflictClass.purs
deleted file mode 100644
--- a/examples/failing/ExportConflictClass.purs
+++ /dev/null
@@ -1,5 +0,0 @@
--- @shouldFailWith ExportConflict
-module C (module A, module B) where
-
-import A as A
-import B as B
diff --git a/examples/failing/ExportConflictClass/A.purs b/examples/failing/ExportConflictClass/A.purs
deleted file mode 100644
--- a/examples/failing/ExportConflictClass/A.purs
+++ /dev/null
@@ -1,3 +0,0 @@
-module A where
-
-class X
diff --git a/examples/failing/ExportConflictClass/B.purs b/examples/failing/ExportConflictClass/B.purs
deleted file mode 100644
--- a/examples/failing/ExportConflictClass/B.purs
+++ /dev/null
@@ -1,3 +0,0 @@
-module B where
-
-class X
diff --git a/examples/failing/ExportConflictCtor.purs b/examples/failing/ExportConflictCtor.purs
deleted file mode 100644
--- a/examples/failing/ExportConflictCtor.purs
+++ /dev/null
@@ -1,5 +0,0 @@
--- @shouldFailWith ExportConflict
-module C (module A, module B) where
-
-import A as A
-import B as B
diff --git a/examples/failing/ExportConflictCtor/A.purs b/examples/failing/ExportConflictCtor/A.purs
deleted file mode 100644
--- a/examples/failing/ExportConflictCtor/A.purs
+++ /dev/null
@@ -1,3 +0,0 @@
-module A where
-
-data T1 = X
diff --git a/examples/failing/ExportConflictCtor/B.purs b/examples/failing/ExportConflictCtor/B.purs
deleted file mode 100644
--- a/examples/failing/ExportConflictCtor/B.purs
+++ /dev/null
@@ -1,3 +0,0 @@
-module B where
-
-data T2 = X
diff --git a/examples/failing/ExportConflictType.purs b/examples/failing/ExportConflictType.purs
deleted file mode 100644
--- a/examples/failing/ExportConflictType.purs
+++ /dev/null
@@ -1,5 +0,0 @@
--- @shouldFailWith ExportConflict
-module C (module A, module B) where
-
-import A as A
-import B as B
diff --git a/examples/failing/ExportConflictType/A.purs b/examples/failing/ExportConflictType/A.purs
deleted file mode 100644
--- a/examples/failing/ExportConflictType/A.purs
+++ /dev/null
@@ -1,3 +0,0 @@
-module A where
-
-data T
diff --git a/examples/failing/ExportConflictType/B.purs b/examples/failing/ExportConflictType/B.purs
deleted file mode 100644
--- a/examples/failing/ExportConflictType/B.purs
+++ /dev/null
@@ -1,3 +0,0 @@
-module B where
-
-data T
diff --git a/examples/failing/ExportConflictTypeOp.purs b/examples/failing/ExportConflictTypeOp.purs
deleted file mode 100644
--- a/examples/failing/ExportConflictTypeOp.purs
+++ /dev/null
@@ -1,5 +0,0 @@
--- @shouldFailWith ExportConflict
-module C (module A, module B) where
-
-import A as A
-import B as B
diff --git a/examples/failing/ExportConflictTypeOp/A.purs b/examples/failing/ExportConflictTypeOp/A.purs
deleted file mode 100644
--- a/examples/failing/ExportConflictTypeOp/A.purs
+++ /dev/null
@@ -1,5 +0,0 @@
-module A where
-
-type T1 a b = a -> b
-
-infixr 4 type T1 as ??
diff --git a/examples/failing/ExportConflictTypeOp/B.purs b/examples/failing/ExportConflictTypeOp/B.purs
deleted file mode 100644
--- a/examples/failing/ExportConflictTypeOp/B.purs
+++ /dev/null
@@ -1,5 +0,0 @@
-module B where
-
-type T2 a b = a -> b
-
-infixr 4 type T2 as ??
diff --git a/examples/failing/ExportConflictValue.purs b/examples/failing/ExportConflictValue.purs
deleted file mode 100644
--- a/examples/failing/ExportConflictValue.purs
+++ /dev/null
@@ -1,5 +0,0 @@
--- @shouldFailWith ExportConflict
-module C (module A, module B) where
-
-import A as A
-import B as B
diff --git a/examples/failing/ExportConflictValue/A.purs b/examples/failing/ExportConflictValue/A.purs
deleted file mode 100644
--- a/examples/failing/ExportConflictValue/A.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module A where
-
-x :: Boolean
-x = true
diff --git a/examples/failing/ExportConflictValue/B.purs b/examples/failing/ExportConflictValue/B.purs
deleted file mode 100644
--- a/examples/failing/ExportConflictValue/B.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module B where
-
-x :: Boolean
-x = false
diff --git a/examples/failing/ExportConflictValueOp.purs b/examples/failing/ExportConflictValueOp.purs
deleted file mode 100644
--- a/examples/failing/ExportConflictValueOp.purs
+++ /dev/null
@@ -1,5 +0,0 @@
--- @shouldFailWith ExportConflict
-module C (module A, module B) where
-
-import A as A
-import B as B
diff --git a/examples/failing/ExportConflictValueOp/A.purs b/examples/failing/ExportConflictValueOp/A.purs
deleted file mode 100644
--- a/examples/failing/ExportConflictValueOp/A.purs
+++ /dev/null
@@ -1,6 +0,0 @@
-module A where
-
-f1 :: forall a b. a -> b -> a
-f1 x _ = x
-
-infix 0 f1 as !!
diff --git a/examples/failing/ExportConflictValueOp/B.purs b/examples/failing/ExportConflictValueOp/B.purs
deleted file mode 100644
--- a/examples/failing/ExportConflictValueOp/B.purs
+++ /dev/null
@@ -1,6 +0,0 @@
-module B where
-
-f2 :: forall a b. a -> b -> a
-f2 x _ = x
-
-infix 0 f2 as !!
diff --git a/examples/failing/ExportExplicit.purs b/examples/failing/ExportExplicit.purs
deleted file mode 100644
--- a/examples/failing/ExportExplicit.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- @shouldFailWith UnknownExport
--- should fail as z does not exist in the module
-module M1 (x, y, z) where
-
-import Prelude
-
-x = 1
-y = 2
diff --git a/examples/failing/ExportExplicit1.purs b/examples/failing/ExportExplicit1.purs
deleted file mode 100644
--- a/examples/failing/ExportExplicit1.purs
+++ /dev/null
@@ -1,12 +0,0 @@
--- @shouldFailWith UnknownName
-module Main where
-
-import M1
-import Control.Monad.Eff.Console (log)
-
-testX = X
-
--- should fail as Y constructor is not exported from M1
-testY = Y
-
-main = log "Done"
diff --git a/examples/failing/ExportExplicit1/M1.purs b/examples/failing/ExportExplicit1/M1.purs
deleted file mode 100644
--- a/examples/failing/ExportExplicit1/M1.purs
+++ /dev/null
@@ -1,3 +0,0 @@
-module M1 (X(X)) where
-
-data X = X | Y
diff --git a/examples/failing/ExportExplicit2.purs b/examples/failing/ExportExplicit2.purs
deleted file mode 100644
--- a/examples/failing/ExportExplicit2.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- @shouldFailWith UnknownExportDataConstructor
--- should fail as Y is not a data constructor for X
-module M1 (X(Y)) where
-
-import Prelude
-
-data X = X
-data Y = Y
diff --git a/examples/failing/ExportExplicit3.purs b/examples/failing/ExportExplicit3.purs
deleted file mode 100644
--- a/examples/failing/ExportExplicit3.purs
+++ /dev/null
@@ -1,10 +0,0 @@
--- @shouldFailWith UnknownName
-module Main where
-
-import M1 as M
-import Control.Monad.Eff.Console (log)
-
--- should fail as Z is not exported from M1
-testZ = M.Z
-
-main = log "Done"
diff --git a/examples/failing/ExportExplicit3/M1.purs b/examples/failing/ExportExplicit3/M1.purs
deleted file mode 100644
--- a/examples/failing/ExportExplicit3/M1.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module M1 (X(..)) where
-
-data X = X | Y
-data Z = Z
diff --git a/examples/failing/ExtraRecordField.purs b/examples/failing/ExtraRecordField.purs
deleted file mode 100644
--- a/examples/failing/ExtraRecordField.purs
+++ /dev/null
@@ -1,9 +0,0 @@
--- @shouldFailWith AdditionalProperty
-module ExtraRecordField where
-
-import Prelude ((<>))
-
-full :: { first :: String, last :: String } -> String
-full p = p.first <> " " <> p.last
-
-oops = full { first: "Jane", last: "Smith", age: 29 }
diff --git a/examples/failing/Foldable.purs b/examples/failing/Foldable.purs
deleted file mode 100644
--- a/examples/failing/Foldable.purs
+++ /dev/null
@@ -1,17 +0,0 @@
--- @shouldFailWith CycleInDeclaration
-module Main where
-
-import Prelude
-
-class Foldable f where
-  fold :: forall a b. (a -> b -> b) -> b -> f a -> b
-  size :: forall a. f a -> Number
-
-data L a = C a (L a) | N
-
-instance foldableL :: Foldable L where
-  fold _ z N = z
-  fold f z (C x xs) = x `f` (fold f z xs)
-  size = fold (const ((+) 1.0)) 0.0
-
-x = size (C 1 (C 2 (C 3 N)))
diff --git a/examples/failing/Generalization1.purs b/examples/failing/Generalization1.purs
deleted file mode 100644
--- a/examples/failing/Generalization1.purs
+++ /dev/null
@@ -1,11 +0,0 @@
--- @shouldFailWith CannotGeneralizeRecursiveFunction
-module Main where
-
-import Prelude
-
-foo 0 x _ = x
-foo n x y = x <> bar (n - 1) x y
-
-bar 0 x _ = x
-bar n x y = y <> foo (n - 1) x y
-
diff --git a/examples/failing/Generalization2.purs b/examples/failing/Generalization2.purs
deleted file mode 100644
--- a/examples/failing/Generalization2.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- @shouldFailWith CannotGeneralizeRecursiveFunction
-module Main where
-
-import Prelude
-
-test n m | n <= 1 = m
-         | otherwise = test (n - 1) (m <> m)
-
diff --git a/examples/failing/ImportExplicit.purs b/examples/failing/ImportExplicit.purs
deleted file mode 100644
--- a/examples/failing/ImportExplicit.purs
+++ /dev/null
@@ -1,4 +0,0 @@
--- @shouldFailWith UnknownImport
-module Main where
-
-import M1 (X(..))
diff --git a/examples/failing/ImportExplicit/M1.purs b/examples/failing/ImportExplicit/M1.purs
deleted file mode 100644
--- a/examples/failing/ImportExplicit/M1.purs
+++ /dev/null
@@ -1,3 +0,0 @@
-module M1 where
-
-foo = "foo"
diff --git a/examples/failing/ImportExplicit2.purs b/examples/failing/ImportExplicit2.purs
deleted file mode 100644
--- a/examples/failing/ImportExplicit2.purs
+++ /dev/null
@@ -1,4 +0,0 @@
--- @shouldFailWith UnknownImportDataConstructor
-module Main where
-
-import M1 (X(Z, Q))
diff --git a/examples/failing/ImportExplicit2/M1.purs b/examples/failing/ImportExplicit2/M1.purs
deleted file mode 100644
--- a/examples/failing/ImportExplicit2/M1.purs
+++ /dev/null
@@ -1,3 +0,0 @@
-module M1 where
-
-data X = Y
diff --git a/examples/failing/ImportHidingModule.purs b/examples/failing/ImportHidingModule.purs
deleted file mode 100644
--- a/examples/failing/ImportHidingModule.purs
+++ /dev/null
@@ -1,4 +0,0 @@
--- @shouldFailWith ImportHidingModule
-module Main where
-
-import B hiding (module A)
diff --git a/examples/failing/ImportHidingModule/A.purs b/examples/failing/ImportHidingModule/A.purs
deleted file mode 100644
--- a/examples/failing/ImportHidingModule/A.purs
+++ /dev/null
@@ -1,2 +0,0 @@
-module A where
-x = 1
diff --git a/examples/failing/ImportHidingModule/B.purs b/examples/failing/ImportHidingModule/B.purs
deleted file mode 100644
--- a/examples/failing/ImportHidingModule/B.purs
+++ /dev/null
@@ -1,3 +0,0 @@
-module B (module B, module A) where
-import A
-y = 1
diff --git a/examples/failing/ImportModule.purs b/examples/failing/ImportModule.purs
deleted file mode 100644
--- a/examples/failing/ImportModule.purs
+++ /dev/null
@@ -1,4 +0,0 @@
--- @shouldFailWith ModuleNotFound
-module Main where
-
-import M1
diff --git a/examples/failing/ImportModule/M2.purs b/examples/failing/ImportModule/M2.purs
deleted file mode 100644
--- a/examples/failing/ImportModule/M2.purs
+++ /dev/null
@@ -1,3 +0,0 @@
-module M2 where
-
-data X = X
diff --git a/examples/failing/InfiniteKind.purs b/examples/failing/InfiniteKind.purs
deleted file mode 100644
--- a/examples/failing/InfiniteKind.purs
+++ /dev/null
@@ -1,5 +0,0 @@
--- @shouldFailWith InfiniteKind 
-
-module Main where
-
-data F a = F (a a)
diff --git a/examples/failing/InfiniteKind2.purs b/examples/failing/InfiniteKind2.purs
deleted file mode 100644
--- a/examples/failing/InfiniteKind2.purs
+++ /dev/null
@@ -1,5 +0,0 @@
--- @shouldFailWith InfiniteKind
-
-module InfiniteKind2 where
-
-data Tree m a = Tree a (m (Tree a))
diff --git a/examples/failing/InfiniteType.purs b/examples/failing/InfiniteType.purs
deleted file mode 100644
--- a/examples/failing/InfiniteType.purs
+++ /dev/null
@@ -1,5 +0,0 @@
--- @shouldFailWith InfiniteType 
-
-module Main where
-
-f a = a a
diff --git a/examples/failing/InstanceExport.purs b/examples/failing/InstanceExport.purs
deleted file mode 100644
--- a/examples/failing/InstanceExport.purs
+++ /dev/null
@@ -1,7 +0,0 @@
--- @shouldFailWith TransitiveExportError
-module Test where
-
-import InstanceExport
-import Prelude
-
-test = f $ S "Test"
diff --git a/examples/failing/InstanceExport/InstanceExport.purs b/examples/failing/InstanceExport/InstanceExport.purs
deleted file mode 100644
--- a/examples/failing/InstanceExport/InstanceExport.purs
+++ /dev/null
@@ -1,11 +0,0 @@
-module InstanceExport (S(..), f) where
-
-import Prelude
-
-newtype S = S String
-
-class F a where
-  f :: a -> String
-
-instance fs :: F S where
-  f (S s) = s
diff --git a/examples/failing/InstanceSigsBodyIncorrect.purs b/examples/failing/InstanceSigsBodyIncorrect.purs
deleted file mode 100644
--- a/examples/failing/InstanceSigsBodyIncorrect.purs
+++ /dev/null
@@ -1,10 +0,0 @@
--- @shouldFailWith TypesDoNotUnify
-
-module Main where
-
-class Foo a where
-  foo :: a
-
-instance fooNumber :: Foo Number where
-  foo :: Number
-  foo = true
diff --git a/examples/failing/InstanceSigsDifferentTypes.purs b/examples/failing/InstanceSigsDifferentTypes.purs
deleted file mode 100644
--- a/examples/failing/InstanceSigsDifferentTypes.purs
+++ /dev/null
@@ -1,10 +0,0 @@
--- @shouldFailWith TypesDoNotUnify
-
-module Main where
-
-class Foo a where
-  foo :: a
-
-instance fooNumber :: Foo Number where
-  foo :: Int
-  foo = 0.0
diff --git a/examples/failing/InstanceSigsIncorrectType.purs b/examples/failing/InstanceSigsIncorrectType.purs
deleted file mode 100644
--- a/examples/failing/InstanceSigsIncorrectType.purs
+++ /dev/null
@@ -1,10 +0,0 @@
--- @shouldFailWith TypesDoNotUnify
-
-module Main where
-
-class Foo a where
-  foo :: a
-
-instance fooNumber :: Foo Number where
-  foo :: Boolean
-  foo = true
diff --git a/examples/failing/InstanceSigsOrphanTypeDeclaration.purs b/examples/failing/InstanceSigsOrphanTypeDeclaration.purs
deleted file mode 100644
--- a/examples/failing/InstanceSigsOrphanTypeDeclaration.purs
+++ /dev/null
@@ -1,10 +0,0 @@
--- @shouldFailWith OrphanTypeDeclaration
-
-module Main where
-
-class Foo a where
-  foo :: a
-
-instance fooNumber :: Foo Number where
-  bar :: Int
-  foo = 0.0
diff --git a/examples/failing/IntOutOfRange.purs b/examples/failing/IntOutOfRange.purs
deleted file mode 100644
--- a/examples/failing/IntOutOfRange.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith IntOutOfRange
-
-module Main where
-
-n :: Int
-n = 2147483648
diff --git a/examples/failing/InvalidDerivedInstance.purs b/examples/failing/InvalidDerivedInstance.purs
deleted file mode 100644
--- a/examples/failing/InvalidDerivedInstance.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- @shouldFailWith InvalidDerivedInstance
-module Main where
-
-import Prelude
-
-data X = X
-
-derive instance eqX :: Eq X X
diff --git a/examples/failing/InvalidDerivedInstance2.purs b/examples/failing/InvalidDerivedInstance2.purs
deleted file mode 100644
--- a/examples/failing/InvalidDerivedInstance2.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith ExpectedTypeConstructor
-module Main where
-
-import Prelude
-
-derive instance eqRecord :: Eq {}
diff --git a/examples/failing/InvalidOperatorInBinder.purs b/examples/failing/InvalidOperatorInBinder.purs
deleted file mode 100644
--- a/examples/failing/InvalidOperatorInBinder.purs
+++ /dev/null
@@ -1,12 +0,0 @@
--- @shouldFailWith InvalidOperatorInBinder
-module Main where
-
-data List a = Cons a (List a) | Nil
-
-cons ∷ ∀ a. a → List a → List a
-cons = Cons
-
-infixl 6 cons as :
-
-get ∷ ∀ a. List a → a
-get (_ : x : _) = x
diff --git a/examples/failing/KindError.purs b/examples/failing/KindError.purs
deleted file mode 100644
--- a/examples/failing/KindError.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith KindsDoNotUnify
-module Main where
-
-import Prelude
-
-data KindError f a = One f | Two (f a)
diff --git a/examples/failing/KindStar.purs b/examples/failing/KindStar.purs
deleted file mode 100644
--- a/examples/failing/KindStar.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- @shouldFailWith ExpectedType
-
-module X where
-
-data List a = Nil | Cons a (List a)
-
-test :: List
-test = Nil
diff --git a/examples/failing/LeadingZeros1.purs b/examples/failing/LeadingZeros1.purs
deleted file mode 100644
--- a/examples/failing/LeadingZeros1.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith ErrorParsingModule
-module Main where
-
-import Prelude
-
-x = 01
diff --git a/examples/failing/LeadingZeros2.purs b/examples/failing/LeadingZeros2.purs
deleted file mode 100644
--- a/examples/failing/LeadingZeros2.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith ErrorParsingModule
-module Main where
-
-import Prelude
-
-x = 00.1
diff --git a/examples/failing/Let.purs b/examples/failing/Let.purs
deleted file mode 100644
--- a/examples/failing/Let.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith CycleInDeclaration
-module Main where
-
-import Prelude
-
-test = let x = x in x
diff --git a/examples/failing/LetPatterns1.purs b/examples/failing/LetPatterns1.purs
deleted file mode 100644
--- a/examples/failing/LetPatterns1.purs
+++ /dev/null
@@ -1,10 +0,0 @@
--- @shouldFailWith ErrorParsingModule
-module Main where
-
-import Prelude
-
--- wrong binders for function, the first one should be VarBinder
-x =
-  let (X a b) x y = hoge
-  in
-   a
diff --git a/examples/failing/LetPatterns2.purs b/examples/failing/LetPatterns2.purs
deleted file mode 100644
--- a/examples/failing/LetPatterns2.purs
+++ /dev/null
@@ -1,14 +0,0 @@
--- @shouldFailWith UnknownName
-module Main where
-
-import Prelude
-
-data X a = X a
-
--- wrong dependency order
-x =
-  let
-    b = a
-    X a = X 10
-  in
-   b
diff --git a/examples/failing/LetPatterns3.purs b/examples/failing/LetPatterns3.purs
deleted file mode 100644
--- a/examples/failing/LetPatterns3.purs
+++ /dev/null
@@ -1,13 +0,0 @@
--- @shouldFailWith IncorrectConstructorArity
-module Main where
-
-import Prelude
-
-data X a = X a
-
--- a parameter binder should be with nullary constructor, or with parens
-x =
-  let
-    a X b = b
-  in
-   a $ X 10
diff --git a/examples/failing/LetPatterns4.purs b/examples/failing/LetPatterns4.purs
deleted file mode 100644
--- a/examples/failing/LetPatterns4.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith ErrorParsingModule
-module Main where
-
-data X a = X a
-
-X a = a
diff --git a/examples/failing/MPTCs.purs b/examples/failing/MPTCs.purs
deleted file mode 100644
--- a/examples/failing/MPTCs.purs
+++ /dev/null
@@ -1,10 +0,0 @@
--- @shouldFailWith ClassInstanceArityMismatch
-module Main where
-
-import Prelude
-
-class Foo a where
-  f :: a -> a
-
-instance fooStringString :: Foo String String where
-  f a = a
diff --git a/examples/failing/MissingClassExport.purs b/examples/failing/MissingClassExport.purs
deleted file mode 100644
--- a/examples/failing/MissingClassExport.purs
+++ /dev/null
@@ -1,7 +0,0 @@
--- @shouldFailWith TransitiveExportError
-module Test (bar) where
-
-import Prelude
-
-class Foo a where
-  bar :: a -> a
diff --git a/examples/failing/MissingClassMemberExport.purs b/examples/failing/MissingClassMemberExport.purs
deleted file mode 100644
--- a/examples/failing/MissingClassMemberExport.purs
+++ /dev/null
@@ -1,7 +0,0 @@
--- @shouldFailWith TransitiveExportError
-module Test (class Foo) where
-
-import Prelude
-
-class Foo a where
-  bar :: a -> a
diff --git a/examples/failing/MissingRecordField.purs b/examples/failing/MissingRecordField.purs
deleted file mode 100644
--- a/examples/failing/MissingRecordField.purs
+++ /dev/null
@@ -1,10 +0,0 @@
--- @shouldFailWith PropertyIsMissing
-module MissingRecordField where
-
-import Prelude ((>))
-
-john = { first: "John", last: "Smith" }
-
-isOver50 p = p.age > 50.0
-
-result = isOver50 john
diff --git a/examples/failing/MultipleErrors.purs b/examples/failing/MultipleErrors.purs
deleted file mode 100644
--- a/examples/failing/MultipleErrors.purs
+++ /dev/null
@@ -1,13 +0,0 @@
--- @shouldFailWith TypesDoNotUnify
--- @shouldFailWith TypesDoNotUnify
-module MultipleErrors where
-
-import Prelude
-
-foo :: Int -> Int
-foo 0 = "Test"
-foo n = bar (n - 1)
-
-bar :: Int -> Int
-bar 0 = "Test"
-bar n = foo (n - 1)
diff --git a/examples/failing/MultipleErrors2.purs b/examples/failing/MultipleErrors2.purs
deleted file mode 100644
--- a/examples/failing/MultipleErrors2.purs
+++ /dev/null
@@ -1,9 +0,0 @@
--- @shouldFailWith UnknownName
--- @shouldFailWith UnknownName
-module MultipleErrors2 where
-
-import Prelude
-
-foo = itDoesntExist
-
-bar = neitherDoesThis
diff --git a/examples/failing/MultipleTypeOpFixities.purs b/examples/failing/MultipleTypeOpFixities.purs
deleted file mode 100644
--- a/examples/failing/MultipleTypeOpFixities.purs
+++ /dev/null
@@ -1,9 +0,0 @@
--- @shouldFailWith MultipleTypeOpFixities
-module MultipleTypeOpFixities where
-
-import Prelude
-
-type Op x y = Op x y
-
-infix 2 type Op as !?
-infix 2 type Op as !?
diff --git a/examples/failing/MultipleValueOpFixities.purs b/examples/failing/MultipleValueOpFixities.purs
deleted file mode 100644
--- a/examples/failing/MultipleValueOpFixities.purs
+++ /dev/null
@@ -1,9 +0,0 @@
--- @shouldFailWith MultipleValueOpFixities
-module MultipleValueOpFixities where
-
-import Prelude
-
-add x y = x + y
-
-infix 2 add as !?
-infix 2 add as !?
diff --git a/examples/failing/MutRec.purs b/examples/failing/MutRec.purs
deleted file mode 100644
--- a/examples/failing/MutRec.purs
+++ /dev/null
@@ -1,9 +0,0 @@
--- @shouldFailWith CycleInDeclaration
--- @shouldFailWith CycleInDeclaration
-module MutRec where
-
-import Prelude
-
-x = y
-
-y = x
diff --git a/examples/failing/MutRec2.purs b/examples/failing/MutRec2.purs
deleted file mode 100644
--- a/examples/failing/MutRec2.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith CycleInDeclaration
-module Main where
-
-import Prelude
-
-x = x
diff --git a/examples/failing/NewtypeInstance.purs b/examples/failing/NewtypeInstance.purs
deleted file mode 100644
--- a/examples/failing/NewtypeInstance.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- @shouldFailWith InvalidNewtypeInstance
-module Main where
-
-import Prelude
-
-data X = X
-
-derive newtype instance showX :: Show X
diff --git a/examples/failing/NewtypeInstance2.purs b/examples/failing/NewtypeInstance2.purs
deleted file mode 100644
--- a/examples/failing/NewtypeInstance2.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- @shouldFailWith InvalidNewtypeInstance
-module Main where
-
-import Prelude
-
-data X a = X a a
-
-derive newtype instance showX :: Show a => Show (X a)
diff --git a/examples/failing/NewtypeInstance3.purs b/examples/failing/NewtypeInstance3.purs
deleted file mode 100644
--- a/examples/failing/NewtypeInstance3.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- @shouldFailWith InvalidNewtypeInstance
-module Main where
-
-import Prelude
-
-class Nullary
-
-derive newtype instance nullary :: Nullary
diff --git a/examples/failing/NewtypeInstance4.purs b/examples/failing/NewtypeInstance4.purs
deleted file mode 100644
--- a/examples/failing/NewtypeInstance4.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- @shouldFailWith InvalidNewtypeInstance
-module Main where
-
-import Prelude
-
-data X = X | Y
-
-derive newtype instance showX :: Show X
diff --git a/examples/failing/NewtypeInstance5.purs b/examples/failing/NewtypeInstance5.purs
deleted file mode 100644
--- a/examples/failing/NewtypeInstance5.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- @shouldFailWith InvalidNewtypeInstance
-module Main where
-
-import Prelude
-
-newtype X a = X a
-
-derive newtype instance functorX :: Functor X
diff --git a/examples/failing/NewtypeInstance6.purs b/examples/failing/NewtypeInstance6.purs
deleted file mode 100644
--- a/examples/failing/NewtypeInstance6.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- @shouldFailWith InvalidNewtypeInstance
-module Main where
-
-import Prelude
-
-newtype X a b = X (Array b)
-
-derive newtype instance functorX :: Functor X
diff --git a/examples/failing/NewtypeMultiArgs.purs b/examples/failing/NewtypeMultiArgs.purs
deleted file mode 100644
--- a/examples/failing/NewtypeMultiArgs.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith InvalidNewtype
-module Main where
-
-import Prelude
-
-newtype Thing = Thing String Boolean
diff --git a/examples/failing/NewtypeMultiCtor.purs b/examples/failing/NewtypeMultiCtor.purs
deleted file mode 100644
--- a/examples/failing/NewtypeMultiCtor.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith InvalidNewtype
-module Main where
-
-import Prelude
-
-newtype Thing = Thing String | Other
diff --git a/examples/failing/NonExhaustivePatGuard.purs b/examples/failing/NonExhaustivePatGuard.purs
deleted file mode 100644
--- a/examples/failing/NonExhaustivePatGuard.purs
+++ /dev/null
@@ -1,5 +0,0 @@
--- @shouldFailWith NoInstanceFound
-module Main where
-
-f :: Int -> Int
-f x | 1 <- x = x
diff --git a/examples/failing/NonWildcardNewtypeInstance.purs b/examples/failing/NonWildcardNewtypeInstance.purs
deleted file mode 100644
--- a/examples/failing/NonWildcardNewtypeInstance.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- @shouldFailWith ExpectedWildcard
-module NonWildcardNewtypeInstance where
-
-import Data.Newtype
-
-data Test = Test String
-
-derive instance newtypeTest :: Newtype Test String
diff --git a/examples/failing/NullaryAbs.purs b/examples/failing/NullaryAbs.purs
deleted file mode 100644
--- a/examples/failing/NullaryAbs.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith ErrorParsingModule
-module Main where
-
-import Prelude
-
-func = \ -> "no"
diff --git a/examples/failing/Object.purs b/examples/failing/Object.purs
deleted file mode 100644
--- a/examples/failing/Object.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- @shouldFailWith PropertyIsMissing
-module Main where
-
-import Prelude
-
-test o = o.foo
-
-test1 = test {}
diff --git a/examples/failing/OperatorAliasNoExport.purs b/examples/failing/OperatorAliasNoExport.purs
deleted file mode 100644
--- a/examples/failing/OperatorAliasNoExport.purs
+++ /dev/null
@@ -1,7 +0,0 @@
--- @shouldFailWith TransitiveExportError
-module Test ((?!)) where
-
-infixl 4 what as ?!
-
-what :: forall a b. a -> b -> a
-what a _ = a
diff --git a/examples/failing/OperatorSections.purs b/examples/failing/OperatorSections.purs
deleted file mode 100644
--- a/examples/failing/OperatorSections.purs
+++ /dev/null
@@ -1,7 +0,0 @@
--- @shouldFailWith TypesDoNotUnify
-module Main where
-
-import Prelude
-
-main = do
-  (true `not` _)
diff --git a/examples/failing/OrphanInstance.purs b/examples/failing/OrphanInstance.purs
deleted file mode 100644
--- a/examples/failing/OrphanInstance.purs
+++ /dev/null
@@ -1,7 +0,0 @@
--- @shouldFailWith OrphanInstance
-module Test where
-
-import Class
-
-instance cBoolean :: C Boolean where
-  op a = a
diff --git a/examples/failing/OrphanInstance/Class.purs b/examples/failing/OrphanInstance/Class.purs
deleted file mode 100644
--- a/examples/failing/OrphanInstance/Class.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module Class where
-
-class C a where
-  op :: a -> a
diff --git a/examples/failing/OrphanInstanceFunDepCycle.purs b/examples/failing/OrphanInstanceFunDepCycle.purs
deleted file mode 100644
--- a/examples/failing/OrphanInstanceFunDepCycle.purs
+++ /dev/null
@@ -1,5 +0,0 @@
--- @shouldFailWith OrphanInstance
-module Main where
-import Lib
-data L
-instance clr :: C L R
diff --git a/examples/failing/OrphanInstanceFunDepCycle/Lib.purs b/examples/failing/OrphanInstanceFunDepCycle/Lib.purs
deleted file mode 100644
--- a/examples/failing/OrphanInstanceFunDepCycle/Lib.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module Lib where
--- covering sets: {{l}, {r}}
-class C l r | l -> r, r -> l
-data R
diff --git a/examples/failing/OrphanInstanceNullary.purs b/examples/failing/OrphanInstanceNullary.purs
deleted file mode 100644
--- a/examples/failing/OrphanInstanceNullary.purs
+++ /dev/null
@@ -1,4 +0,0 @@
--- @shouldFailWith OrphanInstance
-module Test where
-import Lib
-instance c :: C
diff --git a/examples/failing/OrphanInstanceNullary/Lib.purs b/examples/failing/OrphanInstanceNullary/Lib.purs
deleted file mode 100644
--- a/examples/failing/OrphanInstanceNullary/Lib.purs
+++ /dev/null
@@ -1,2 +0,0 @@
-module Lib where
-class C
diff --git a/examples/failing/OrphanInstanceWithDetermined.purs b/examples/failing/OrphanInstanceWithDetermined.purs
deleted file mode 100644
--- a/examples/failing/OrphanInstanceWithDetermined.purs
+++ /dev/null
@@ -1,5 +0,0 @@
--- @shouldFailWith OrphanInstance
-module Main where
-import Lib
-data R
-instance cflr :: C F L R
diff --git a/examples/failing/OrphanInstanceWithDetermined/Lib.purs b/examples/failing/OrphanInstanceWithDetermined/Lib.purs
deleted file mode 100644
--- a/examples/failing/OrphanInstanceWithDetermined/Lib.purs
+++ /dev/null
@@ -1,5 +0,0 @@
-module Lib where
--- covering sets: {{f, l}}
-class C f l r | l -> r
-data F
-data L
diff --git a/examples/failing/OrphanTypeDecl.purs b/examples/failing/OrphanTypeDecl.purs
deleted file mode 100644
--- a/examples/failing/OrphanTypeDecl.purs
+++ /dev/null
@@ -1,4 +0,0 @@
--- @shouldFailWith OrphanTypeDeclaration
-module OrphanTypeDecl where
-
-fn :: Number -> Boolean
diff --git a/examples/failing/OverlappingArguments.purs b/examples/failing/OverlappingArguments.purs
deleted file mode 100644
--- a/examples/failing/OverlappingArguments.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith OverlappingArgNames
-module OverlappingArguments where
-
-import Prelude
-
-f x x = x
diff --git a/examples/failing/OverlappingBinders.purs b/examples/failing/OverlappingBinders.purs
deleted file mode 100644
--- a/examples/failing/OverlappingBinders.purs
+++ /dev/null
@@ -1,9 +0,0 @@
--- @shouldFailWith OverlappingArgNames
-module OverlappingBinders where
-
-import Prelude
-
-data S a = S a (S a)
-
-f x = case x of
-  (S y (S y@(S z zs))) -> y
diff --git a/examples/failing/OverlappingVars.purs b/examples/failing/OverlappingVars.purs
deleted file mode 100644
--- a/examples/failing/OverlappingVars.purs
+++ /dev/null
@@ -1,14 +0,0 @@
--- @shouldFailWith NoInstanceFound
-module Main where
-
-import Prelude
-
-class OverlappingVars a where
-  f :: a -> a
-
-data Foo a b = Foo a b
-
-instance overlappingVarsFoo :: OverlappingVars (Foo a a) where
-  f a = a
-
-test = f (Foo "" 0)
diff --git a/examples/failing/ProgrammableTypeErrors.purs b/examples/failing/ProgrammableTypeErrors.purs
deleted file mode 100644
--- a/examples/failing/ProgrammableTypeErrors.purs
+++ /dev/null
@@ -1,16 +0,0 @@
--- @shouldFailWith NoInstanceFound
-
-module Main where
-
-import Prelude
-import Control.Monad.Eff (Eff)
-import Control.Monad.Eff.Console (log)
-
-class MyShow a where
-  myShow :: a -> String
-
-instance cannotShowFunctions :: Fail "Cannot show functions" => MyShow (a -> b) where
-  myShow _ = "unreachable"
-
-main :: Eff _ _
-main = log (myShow (_ + 1))
diff --git a/examples/failing/ProgrammableTypeErrorsTypeString.purs b/examples/failing/ProgrammableTypeErrorsTypeString.purs
deleted file mode 100644
--- a/examples/failing/ProgrammableTypeErrorsTypeString.purs
+++ /dev/null
@@ -1,18 +0,0 @@
--- @shouldFailWith NoInstanceFound
-
-module Main where
-
-import Prelude
-import Control.Monad.Eff (Eff)
-import Control.Monad.Eff.Console (log)
-
-newtype MyType a = MyType a
-
-instance cannotShowFunctions :: Fail ("Don't want to show " <> TypeString (MyType a) <> " because.") => Show (MyType a) where
-  show _ = "unreachable"
-
-infixl 6 type TypeConcat as <>
-
-main :: Eff _ _
-main = do
-  log $ show (MyType 2)
diff --git a/examples/failing/Rank2Types.purs b/examples/failing/Rank2Types.purs
deleted file mode 100644
--- a/examples/failing/Rank2Types.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- @shouldFailWith TypesDoNotUnify
-module Main where
-
-import Prelude
-
-foreign import test :: (forall a. a -> a) -> Number
-
-test1 = test (\n -> n + 1)
diff --git a/examples/failing/RequiredHiddenType.purs b/examples/failing/RequiredHiddenType.purs
deleted file mode 100644
--- a/examples/failing/RequiredHiddenType.purs
+++ /dev/null
@@ -1,9 +0,0 @@
--- @shouldFailWith TransitiveExportError
--- exporting `a` should fail as `A` is hidden
-module Foo (B(..), a, b) where
-
-data A = A
-data B = B
-
-a = A
-b = B
diff --git a/examples/failing/Reserved.purs b/examples/failing/Reserved.purs
deleted file mode 100644
--- a/examples/failing/Reserved.purs
+++ /dev/null
@@ -1,7 +0,0 @@
--- @shouldFailWith ErrorParsingModule
-module Main where
-
-import Prelude
-
-(<) :: Number -> Number -> Number
-(<) a b = !(a >= b)
diff --git a/examples/failing/RowConstructors1.purs b/examples/failing/RowConstructors1.purs
deleted file mode 100644
--- a/examples/failing/RowConstructors1.purs
+++ /dev/null
@@ -1,9 +0,0 @@
--- @shouldFailWith KindsDoNotUnify
-module Main where
-
-import Control.Monad.Eff.Console (log)
-
-data Foo = Bar
-type Baz = { | Foo }
-
-main = log "Done"
diff --git a/examples/failing/RowConstructors2.purs b/examples/failing/RowConstructors2.purs
deleted file mode 100644
--- a/examples/failing/RowConstructors2.purs
+++ /dev/null
@@ -1,9 +0,0 @@
--- @shouldFailWith KindsDoNotUnify
-module Main where
-
-import Control.Monad.Eff.Console (log)
-
-type Foo r = (x :: Number | r)
-type Bar = { | Foo }
-
-main = log "Done"
diff --git a/examples/failing/RowConstructors3.purs b/examples/failing/RowConstructors3.purs
deleted file mode 100644
--- a/examples/failing/RowConstructors3.purs
+++ /dev/null
@@ -1,9 +0,0 @@
--- @shouldFailWith KindsDoNotUnify
-module Main where
-
-import Control.Monad.Eff.Console (log)
-
-type Foo = { x :: Number }
-type Bar = { | Foo }
-
-main = log "Done"
diff --git a/examples/failing/RowInInstanceNotDetermined0.purs b/examples/failing/RowInInstanceNotDetermined0.purs
deleted file mode 100644
--- a/examples/failing/RowInInstanceNotDetermined0.purs
+++ /dev/null
@@ -1,9 +0,0 @@
--- @shouldFailWith InvalidInstanceHead
-module Main where
-
-import Prelude
-
--- no fundeps
-class C a b
-instance c :: C Unit {}
-
diff --git a/examples/failing/RowInInstanceNotDetermined1.purs b/examples/failing/RowInInstanceNotDetermined1.purs
deleted file mode 100644
--- a/examples/failing/RowInInstanceNotDetermined1.purs
+++ /dev/null
@@ -1,9 +0,0 @@
--- @shouldFailWith InvalidInstanceHead
-module Main where
-
-import Prelude
-
--- `c` not mentioned in any fundeps
-class C a b c | a -> b
-instance c :: C Unit Unit {}
-
diff --git a/examples/failing/RowInInstanceNotDetermined2.purs b/examples/failing/RowInInstanceNotDetermined2.purs
deleted file mode 100644
--- a/examples/failing/RowInInstanceNotDetermined2.purs
+++ /dev/null
@@ -1,9 +0,0 @@
--- @shouldFailWith InvalidInstanceHead
-module Main where
-
-import Prelude
-
--- `b` isn't determined by anything that `b` doesn't determine
-class C a b | a -> b, b -> a
-instance c :: C Unit {}
-
diff --git a/examples/failing/SkolemEscape.purs b/examples/failing/SkolemEscape.purs
deleted file mode 100644
--- a/examples/failing/SkolemEscape.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- @shouldFailWith EscapedSkolem
-module Main where
-
-import Prelude
-
-foreign import foo :: (forall a. a -> a) -> Number
-
-test = \x -> foo x
diff --git a/examples/failing/SkolemEscape2.purs b/examples/failing/SkolemEscape2.purs
deleted file mode 100644
--- a/examples/failing/SkolemEscape2.purs
+++ /dev/null
@@ -1,10 +0,0 @@
--- @shouldFailWith EscapedSkolem
-module Main where
-
-import Prelude
-import Control.Monad.Eff
-import Control.Monad.ST
-
-test _ = do
-  r <- runST (newSTRef 0)
-  pure 0
diff --git a/examples/failing/SuggestComposition.purs b/examples/failing/SuggestComposition.purs
deleted file mode 100644
--- a/examples/failing/SuggestComposition.purs
+++ /dev/null
@@ -1,7 +0,0 @@
--- @shouldFailWith TypesDoNotUnify
--- TODO: Ensure the correct suggestion is produced.
-module SuggestComposition where
-
-import Prelude
-
-f = g . g where g = (_ + 1)
diff --git a/examples/failing/Superclasses1.purs b/examples/failing/Superclasses1.purs
deleted file mode 100644
--- a/examples/failing/Superclasses1.purs
+++ /dev/null
@@ -1,14 +0,0 @@
--- @shouldFailWith NoInstanceFound
-module Main where
-
-import Prelude
-
-class Su a where
-  su :: a -> a
-
-class (Su a) <= Cl a where
-  cl :: a -> a -> a
-
-instance clNumber :: Cl Number where
-  cl n m = n + m
-
diff --git a/examples/failing/Superclasses2.purs b/examples/failing/Superclasses2.purs
deleted file mode 100644
--- a/examples/failing/Superclasses2.purs
+++ /dev/null
@@ -1,13 +0,0 @@
--- @shouldFailWith CycleInTypeSynonym
--- TODO: Should this have its own error, perhaps CycleInTypeClassDeclaration?
-module CycleInSuperclasses where
-
-import Prelude
-
-class (Foo a) <= Bar a
-
-class (Bar a) <= Foo a
-
-instance barString :: Bar String
-
-instance fooString :: Foo String
diff --git a/examples/failing/Superclasses3.purs b/examples/failing/Superclasses3.purs
deleted file mode 100644
--- a/examples/failing/Superclasses3.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- @shouldFailWith UndefinedTypeVariable
-module UnknownSuperclassTypeVar where
-
-import Prelude
-
-class Foo a
-
-class (Foo b) <= Bar a
diff --git a/examples/failing/Superclasses5.purs b/examples/failing/Superclasses5.purs
deleted file mode 100644
--- a/examples/failing/Superclasses5.purs
+++ /dev/null
@@ -1,26 +0,0 @@
--- @shouldFailWith NoInstanceFound
-
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (logShow)
-
-class Su a where
-  su :: a -> a
-
-class Su (Array a) <= Cl a where
-  cl :: a -> a -> a
-
-instance suNumber :: Su Number where
-  su n = n + 1.0
-
-instance suArray :: Su a => Su (Array a) where
-  su [x] = [su x]
-
-instance clNumber :: Cl Number where
-  cl n m = n + m
-
-test :: forall a. Cl a => a -> Array a
-test x = su [cl x x]
-
-main = logShow $ test 10.0
diff --git a/examples/failing/TooFewClassInstanceArgs.purs b/examples/failing/TooFewClassInstanceArgs.purs
deleted file mode 100644
--- a/examples/failing/TooFewClassInstanceArgs.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- @shouldFailWith ClassInstanceArityMismatch
-module Main where
-
-import Prelude
-
-class Foo a b
-
-instance fooString :: Foo String
diff --git a/examples/failing/TopLevelCaseNoArgs.purs b/examples/failing/TopLevelCaseNoArgs.purs
deleted file mode 100644
--- a/examples/failing/TopLevelCaseNoArgs.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- @shouldFailWith DuplicateValueDeclaration
-module Main where
-
-import Prelude
-
-foo :: Number
-foo = 1
-foo = 2
diff --git a/examples/failing/TransitiveDctorExport.purs b/examples/failing/TransitiveDctorExport.purs
deleted file mode 100644
--- a/examples/failing/TransitiveDctorExport.purs
+++ /dev/null
@@ -1,5 +0,0 @@
--- @shouldFailWith TransitiveExportError
-module Main (Y(..)) where
-
-type X = Int
-data Y = Y X
diff --git a/examples/failing/TransitiveSynonymExport.purs b/examples/failing/TransitiveSynonymExport.purs
deleted file mode 100644
--- a/examples/failing/TransitiveSynonymExport.purs
+++ /dev/null
@@ -1,5 +0,0 @@
--- @shouldFailWith TransitiveExportError
-module Main (Y()) where
-
-type X = Int
-type Y = X
diff --git a/examples/failing/TypeClassInstances.purs b/examples/failing/TypeClassInstances.purs
deleted file mode 100644
--- a/examples/failing/TypeClassInstances.purs
+++ /dev/null
@@ -1,11 +0,0 @@
--- @shouldFailWith MissingClassMember
-module Main where
-
-import Prelude
-
-class A a where
-  a :: a -> String
-  b :: a -> Number
-
-instance aString :: A String where
-  a s = s
diff --git a/examples/failing/TypeClasses2.purs b/examples/failing/TypeClasses2.purs
deleted file mode 100644
--- a/examples/failing/TypeClasses2.purs
+++ /dev/null
@@ -1,9 +0,0 @@
--- @shouldFailWith NoInstanceFound
-module Main where
-
-import Prelude ()
-
-class Show a where
-  show :: a -> String
-
-test = show "testing"
diff --git a/examples/failing/TypeError.purs b/examples/failing/TypeError.purs
deleted file mode 100644
--- a/examples/failing/TypeError.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith TypesDoNotUnify
-module Main where
-
-import Prelude
-
-test = 1 <> "A"
diff --git a/examples/failing/TypeOperatorAliasNoExport.purs b/examples/failing/TypeOperatorAliasNoExport.purs
deleted file mode 100644
--- a/examples/failing/TypeOperatorAliasNoExport.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith TransitiveExportError
-module Test (type (×)) where
-
-data Tuple a b = Tuple a b
-
-infixl 6 type Tuple as ×
diff --git a/examples/failing/TypeSynonyms.purs b/examples/failing/TypeSynonyms.purs
deleted file mode 100644
--- a/examples/failing/TypeSynonyms.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- @shouldFailWith CycleInTypeSynonym
-module Main where
-
-import Prelude
-
-type T1 = Array T2
-
-type T2 = T1
diff --git a/examples/failing/TypeSynonyms2.purs b/examples/failing/TypeSynonyms2.purs
deleted file mode 100644
--- a/examples/failing/TypeSynonyms2.purs
+++ /dev/null
@@ -1,12 +0,0 @@
--- @shouldFailWith TypeSynonymInstance
-module Main where
-
-import Prelude
-
-class Foo a where
-  foo :: a -> String
-
-type Bar = String
-
-instance fooBar :: Foo Bar where
-  foo s = s
diff --git a/examples/failing/TypeSynonyms3.purs b/examples/failing/TypeSynonyms3.purs
deleted file mode 100644
--- a/examples/failing/TypeSynonyms3.purs
+++ /dev/null
@@ -1,12 +0,0 @@
--- @shouldFailWith TypeSynonymInstance
-module Main where
-
-import Prelude
-
-class Foo a where
-  foo :: a -> String
-
-type Bar = String
-
-instance fooBar :: Foo Bar where
-  foo s = s
diff --git a/examples/failing/TypeSynonyms4.purs b/examples/failing/TypeSynonyms4.purs
deleted file mode 100644
--- a/examples/failing/TypeSynonyms4.purs
+++ /dev/null
@@ -1,11 +0,0 @@
--- @shouldFailWith PartiallyAppliedSynonym
-module TypeSynonyms4 where
-
-import Prelude
-
-type F x y = x -> y
-
-type G x = F x
-
-f :: G String String -> String
-f k = k "Done"
diff --git a/examples/failing/TypeSynonyms5.purs b/examples/failing/TypeSynonyms5.purs
deleted file mode 100644
--- a/examples/failing/TypeSynonyms5.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith CycleInTypeSynonym
-module Main where
-
-import Prelude
-
-type T = T
diff --git a/examples/failing/TypeWildcards1.purs b/examples/failing/TypeWildcards1.purs
deleted file mode 100644
--- a/examples/failing/TypeWildcards1.purs
+++ /dev/null
@@ -1,7 +0,0 @@
--- @shouldFailWith ErrorParsingModule
-module TypeWildcards where
-
-import Prelude
-
-type Test = _
-
diff --git a/examples/failing/TypeWildcards2.purs b/examples/failing/TypeWildcards2.purs
deleted file mode 100644
--- a/examples/failing/TypeWildcards2.purs
+++ /dev/null
@@ -1,7 +0,0 @@
--- @shouldFailWith ErrorParsingModule
-module TypeWildcards where
-
-import Prelude
-
-data Test = Test _
-
diff --git a/examples/failing/TypeWildcards3.purs b/examples/failing/TypeWildcards3.purs
deleted file mode 100644
--- a/examples/failing/TypeWildcards3.purs
+++ /dev/null
@@ -1,9 +0,0 @@
--- @shouldFailWith InvalidInstanceHead
-module TypeWildcards where
-
-import Prelude
-
-data Foo a = Foo
-
-instance showFoo :: Show (Foo _) where
-  show Foo = "Foo"
diff --git a/examples/failing/TypedBinders.purs b/examples/failing/TypedBinders.purs
deleted file mode 100644
--- a/examples/failing/TypedBinders.purs
+++ /dev/null
@@ -1,10 +0,0 @@
--- @shouldFailWith ErrorParsingModule
-module Main where
-
-import Control.Monad.Eff.Console (log)
-
-test = (\f :: Int -> Int -> f 10) id
-
-main = do
-  let t1 = test
-  log "Done"
diff --git a/examples/failing/TypedBinders2.purs b/examples/failing/TypedBinders2.purs
deleted file mode 100644
--- a/examples/failing/TypedBinders2.purs
+++ /dev/null
@@ -1,9 +0,0 @@
--- @shouldFailWith TypesDoNotUnify
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-main = do
-  s :: String <- log "Foo"
-  log "Done"
diff --git a/examples/failing/TypedBinders3.purs b/examples/failing/TypedBinders3.purs
deleted file mode 100644
--- a/examples/failing/TypedBinders3.purs
+++ /dev/null
@@ -1,13 +0,0 @@
--- @shouldFailWith TypesDoNotUnify
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-test = case 1 of
-  (0 :: String) -> true
-  _ -> false
-
-main = do
-  let t = test
-  log "Done"
diff --git a/examples/failing/TypedHole.purs b/examples/failing/TypedHole.purs
deleted file mode 100644
--- a/examples/failing/TypedHole.purs
+++ /dev/null
@@ -1,9 +0,0 @@
--- @shouldFailWith HoleInferredType
-module Main where
-
-import Prelude
-import Control.Monad.Eff (Eff)
-import Control.Monad.Eff.Console (CONSOLE, log)
-
-main :: forall e. Eff (console :: CONSOLE | e) Unit
-main = ?ummm
diff --git a/examples/failing/UnderscoreModuleName.purs b/examples/failing/UnderscoreModuleName.purs
deleted file mode 100644
--- a/examples/failing/UnderscoreModuleName.purs
+++ /dev/null
@@ -1,6 +0,0 @@
--- @shouldFailWith ErrorParsingModule
-module Bad_Module where
-
-import Control.Monad.Eff.Console (log)
-
-main = log "Done"
diff --git a/examples/failing/UnknownType.purs b/examples/failing/UnknownType.purs
deleted file mode 100644
--- a/examples/failing/UnknownType.purs
+++ /dev/null
@@ -1,7 +0,0 @@
--- @shouldFailWith UnknownName
-module Main where
-
-import Prelude
-
-test :: Number -> Something
-test = {}
diff --git a/examples/failing/UnusableTypeClassMethod.purs b/examples/failing/UnusableTypeClassMethod.purs
deleted file mode 100644
--- a/examples/failing/UnusableTypeClassMethod.purs
+++ /dev/null
@@ -1,7 +0,0 @@
--- @shouldFailWith UnusableDeclaration
-module Main where
-
-class C a b where
-  -- type doesn't contain `a`, which is also required to determine an instance
-  c :: b
-
diff --git a/examples/failing/UnusableTypeClassMethodConflictingIdent.purs b/examples/failing/UnusableTypeClassMethodConflictingIdent.purs
deleted file mode 100644
--- a/examples/failing/UnusableTypeClassMethodConflictingIdent.purs
+++ /dev/null
@@ -1,7 +0,0 @@
--- @shouldFailWith UnusableDeclaration
-module Main where
-
-class C a where
-  -- type doesn't contain the type class var `a`
-  c :: forall a. a
-
diff --git a/examples/failing/UnusableTypeClassMethodSynonym.purs b/examples/failing/UnusableTypeClassMethodSynonym.purs
deleted file mode 100644
--- a/examples/failing/UnusableTypeClassMethodSynonym.purs
+++ /dev/null
@@ -1,9 +0,0 @@
--- @shouldFailWith UnusableDeclaration
-module Main where
-
-type M x = forall a. a
-
-class C a where
-  -- after synonym expansion, the type doesn't actually contain an `a`
-  c :: M a
-
diff --git a/examples/passing/1110.purs b/examples/passing/1110.purs
deleted file mode 100644
--- a/examples/passing/1110.purs
+++ /dev/null
@@ -1,26 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-data X a = X
-
-x :: forall a. X a
-x = X
-	 
-type Y = { x :: X Int }
-
-test :: forall m. Monad m => m Y
-test = pure { x: x }
-
-type Z t = forall x. t x -> (forall a. t a) -> t x
-
-class C t where c :: Z t
-
-instance cA :: C Array where
-  c x _ = x
-
-test2 :: forall m. Monad m => m { ccc :: Z Array }
-test2 = pure { ccc: (c :: Z Array) }
-
-main = log "Done"
diff --git a/examples/passing/1185.purs b/examples/passing/1185.purs
deleted file mode 100644
--- a/examples/passing/1185.purs
+++ /dev/null
@@ -1,15 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console (log)
-
-data Person = Person String Boolean
-
-getName :: Person -> String
-getName p = case p of
-              Person name true -> name
-              _ -> "Unknown"
-
-name :: String
-name = getName (Person "John Smith" true)
-
-main = log "Done"
diff --git a/examples/passing/1335.purs b/examples/passing/1335.purs
deleted file mode 100644
--- a/examples/passing/1335.purs
+++ /dev/null
@@ -1,14 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-x :: forall a. a -> String
-x a = y "Test"
-  where
-  y :: forall a. Show a => a -> String
-  y a = show (a :: a)
-
-main = do
-  log (x 0)
-  log "Done"
diff --git a/examples/passing/1570.purs b/examples/passing/1570.purs
deleted file mode 100644
--- a/examples/passing/1570.purs
+++ /dev/null
@@ -1,8 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console (log)
-
-test :: forall a. a -> a
-test = \(x :: a) -> x
-
-main = log "Done"
diff --git a/examples/passing/1664.purs b/examples/passing/1664.purs
deleted file mode 100644
--- a/examples/passing/1664.purs
+++ /dev/null
@@ -1,16 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff
-import Control.Monad.Eff.Console
-
-data Identity a = Identity a
-
-newtype IdentityEff e a = IdentityEff (Eff e (Identity a))
-
-test :: forall e a. IdentityEff e a -> IdentityEff e Unit
-test (IdentityEff action) = IdentityEff $ do
-  (Identity x :: Identity _) <- action
-  pure $ Identity unit
-
-main = log "Done"
diff --git a/examples/passing/1697.purs b/examples/passing/1697.purs
deleted file mode 100644
--- a/examples/passing/1697.purs
+++ /dev/null
@@ -1,25 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-_2 :: forall a. a -> a
-_2 a = a
-
-x :: forall m. Monad m => m Unit
-x = do
-  _ <- pure unit
-  pure unit
-
-y :: forall m. Monad m => m Unit
-y = do
-  _ <- pure unit
-  pure unit
-
-wtf :: forall m. Monad m => m Unit
-wtf = do
-  _ <- pure unit
-  let tmp = _2 1
-  pure unit
-
-main = log "Done"
diff --git a/examples/passing/1807.purs b/examples/passing/1807.purs
deleted file mode 100644
--- a/examples/passing/1807.purs
+++ /dev/null
@@ -1,14 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-fn = _.b.c.d
-a = {b:{c:{d:2}}}
-
-d :: Int
-d = fn a + a.b.c.d
-
-main = if fn a + a.b.c.d == 4
-  then log "Done"
-  else log "Fail"
diff --git a/examples/passing/1881.purs b/examples/passing/1881.purs
deleted file mode 100644
--- a/examples/passing/1881.purs
+++ /dev/null
@@ -1,19 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console (log)
-
-foo =
- 1
-
-bar
- = 2
-
-baz
- =
- 3
-
-qux
-  =
- 3
-
-main = log "Done"
diff --git a/examples/passing/1991.purs b/examples/passing/1991.purs
deleted file mode 100644
--- a/examples/passing/1991.purs
+++ /dev/null
@@ -1,22 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-singleton :: forall a. a -> Array a
-singleton x = [x]
-
-empty :: forall a. Array a
-empty = []
-
-foldMap :: forall a m. Semigroup m => (a -> m) -> Array a -> m
-foldMap f [a, b, c, d, e] = f a <> f b <> f c <> f d <> f e
-foldMap f xs = foldMap f xs -- spin, not used
-
-regression :: Array Int
-regression =
-  let as = [1,2,3,4,5]
-      as' = foldMap (\x -> if 1 < x && x < 4 then singleton x else empty) as
-  in as'
-
-main = log "Done"
diff --git a/examples/passing/2018.purs b/examples/passing/2018.purs
deleted file mode 100644
--- a/examples/passing/2018.purs
+++ /dev/null
@@ -1,12 +0,0 @@
-module Main where
-
-import Prelude
-import A (foo)
-import B (Foo(..))
-import Control.Monad.Eff (Eff)
-import Control.Monad.Eff.Console (CONSOLE, log)
-
-main :: forall e. Eff (console :: CONSOLE | e) Unit
-main = do
-  let tmp = foo X
-  log "Done"
diff --git a/examples/passing/2018/A.purs b/examples/passing/2018/A.purs
deleted file mode 100644
--- a/examples/passing/2018/A.purs
+++ /dev/null
@@ -1,7 +0,0 @@
-module A where
-
-import B as Main
-
--- Prior to the 2018 fix this would be detected as a cycle between A and Main.
-foo ∷ Main.Foo → Main.Foo
-foo x = x
diff --git a/examples/passing/2018/B.purs b/examples/passing/2018/B.purs
deleted file mode 100644
--- a/examples/passing/2018/B.purs
+++ /dev/null
@@ -1,3 +0,0 @@
-module B where
-
-data Foo = X | Y
diff --git a/examples/passing/2049.purs b/examples/passing/2049.purs
deleted file mode 100644
--- a/examples/passing/2049.purs
+++ /dev/null
@@ -1,14 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-data List a = Cons a (List a) | Nil
-
-infixr 6 Cons as :
-
-f :: List { x :: Int, y :: Int } -> Int
-f ( r@{ x } : _) = x + r.y
-f _ = 0
-
-main = log "Done"
diff --git a/examples/passing/2136.purs b/examples/passing/2136.purs
deleted file mode 100644
--- a/examples/passing/2136.purs
+++ /dev/null
@@ -1,9 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-main = 
-  if (negate (bottom :: Int) > top)
-    then log "Fail"
-    else log "Done"
diff --git a/examples/passing/2138.purs b/examples/passing/2138.purs
deleted file mode 100644
--- a/examples/passing/2138.purs
+++ /dev/null
@@ -1,7 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console (log)
-
-import Lib (A(B,C))
-
-main = log "Done"
diff --git a/examples/passing/2138/Lib.purs b/examples/passing/2138/Lib.purs
deleted file mode 100644
--- a/examples/passing/2138/Lib.purs
+++ /dev/null
@@ -1,3 +0,0 @@
-module Lib (A(..), A) where
-
-data A = B | C
diff --git a/examples/passing/2172.js b/examples/passing/2172.js
deleted file mode 100644
--- a/examples/passing/2172.js
+++ /dev/null
@@ -1,5 +0,0 @@
-exports['a\''] = 0;
-exports["\x62\x27"] = 1;
-// NOTE: I wanted to use "\c'" here, but langauge-javascript doesn't support it...
-exports["c'"] = 2;
-exports["\u0064\u0027"] = 3;
diff --git a/examples/passing/2172.purs b/examples/passing/2172.purs
deleted file mode 100644
--- a/examples/passing/2172.purs
+++ /dev/null
@@ -1,10 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console (log)
-
-foreign import a' :: Number
-foreign import b' :: Number
-foreign import c' :: Number
-foreign import d' :: Number
-
-main = log "Done"
diff --git a/examples/passing/2197-1.purs b/examples/passing/2197-1.purs
deleted file mode 100644
--- a/examples/passing/2197-1.purs
+++ /dev/null
@@ -1,12 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console
-import Prim as P
-
-type Number = P.Number
-type Test = {}
-
-z :: Number
-z = 0.0
-
-main = log "Done"
diff --git a/examples/passing/2197-2.purs b/examples/passing/2197-2.purs
deleted file mode 100644
--- a/examples/passing/2197-2.purs
+++ /dev/null
@@ -1,11 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console
-import Prim (Int)
-
-type Number = Int
-
-z :: Number
-z = 0
-
-main = log "Done"
diff --git a/examples/passing/2252.purs b/examples/passing/2252.purs
deleted file mode 100644
--- a/examples/passing/2252.purs
+++ /dev/null
@@ -1,15 +0,0 @@
-module Main where
-	
-import Control.Monad.Eff.Console (log)
-
-data T a = T
-	 
-ti :: T Int
-ti = T
-
-t :: forall a. T a
-t = T
-
-xs = [ti, t, t]
-
-main = log "Done"
diff --git a/examples/passing/2288.purs b/examples/passing/2288.purs
deleted file mode 100644
--- a/examples/passing/2288.purs
+++ /dev/null
@@ -1,19 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff
-import Control.Monad.Eff.Console
-import Data.Array
-import Data.Array.Partial as P
-import Partial.Unsafe
-
-length :: forall a. Array a -> Int
-length = go 0 where
-  go acc arr =
-    if null arr
-    then acc
-    else go (acc + 1) (unsafePartial P.tail arr)
-
-main = do
-  logShow (length (1 .. 10000))
-  log "Done"
diff --git a/examples/passing/2378.purs b/examples/passing/2378.purs
deleted file mode 100644
--- a/examples/passing/2378.purs
+++ /dev/null
@@ -1,9 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console (log)
-
-class Foo (a :: Symbol)
-
-instance fooX :: Foo "x"
-
-main = log "Done"
diff --git a/examples/passing/2438.purs b/examples/passing/2438.purs
deleted file mode 100644
--- a/examples/passing/2438.purs
+++ /dev/null
@@ -1,8 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console (log)
-
-done :: String
-done = {"𝌆": "Done"}."𝌆"
-
-main = log done
diff --git a/examples/passing/2609.purs b/examples/passing/2609.purs
deleted file mode 100644
--- a/examples/passing/2609.purs
+++ /dev/null
@@ -1,12 +0,0 @@
-module Main where
-
-import Prelude
-import Eg (Foo'(Bar'), (:->))
-import Control.Monad.Eff (Eff)
-import Control.Monad.Eff.Console (CONSOLE, log)
-
-bar' :: Foo'
-bar' = 4 :-> 5
-
-main :: forall e. Eff (console :: CONSOLE | e) Unit
-main = case bar' of Bar' l r -> log "Done"
diff --git a/examples/passing/2609/Eg.purs b/examples/passing/2609/Eg.purs
deleted file mode 100644
--- a/examples/passing/2609/Eg.purs
+++ /dev/null
@@ -1,6 +0,0 @@
-module Eg (Foo'(Bar'), (:->)) where
-
-data Foo' = Bar' Int Int
-
-infix 4 Bar' as :->
-
diff --git a/examples/passing/2616.purs b/examples/passing/2616.purs
deleted file mode 100644
--- a/examples/passing/2616.purs
+++ /dev/null
@@ -1,13 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-newtype F r a = F { x :: a | r }
-
-unF :: forall r a. F r a -> { x :: a | r }
-unF (F x) = x
-
-derive instance functorF :: Functor (F r)
-
-main = log (unF (map id (F { x: "Done", y: 42 }))).x
diff --git a/examples/passing/2626.purs b/examples/passing/2626.purs
deleted file mode 100644
--- a/examples/passing/2626.purs
+++ /dev/null
@@ -1,13 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console (log)
-
-f = \(x :: forall a. a -> a) -> x x
-
-test1 = (f \x -> x) 1
-
-g = \(x :: (forall a. a -> a) -> Int) -> x (\y -> y)
-
-test2 = g \f -> if f true then f 0 else f 1
-
-main = log "Done"
diff --git a/examples/passing/2663.purs b/examples/passing/2663.purs
deleted file mode 100644
--- a/examples/passing/2663.purs
+++ /dev/null
@@ -1,9 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-foo :: forall t. Warn "Example" => t -> t
-foo x = x
-
-main = when (foo 42 == 42) $ log "Done"
diff --git a/examples/passing/2689.purs b/examples/passing/2689.purs
deleted file mode 100644
--- a/examples/passing/2689.purs
+++ /dev/null
@@ -1,36 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console
-import Data.Array.Partial
-import Partial.Unsafe
-
-sumTCObug = go id where 
-  go f 0 = f 
-  go f n =
-    let
-      f' a = n + a
-    in
-      go f' 0
-
-sumTCObug' = go id where 
-  go f 0 = f
-  go f n = go (\a -> n + a) 0
-
-count :: forall a. (a -> Boolean) -> Array a -> Int
-count p = count' 0 where
-  count' acc [] = acc
-  count' acc xs =
-    let h = unsafePartial head xs
-    in count' (acc + if p h then 1 else 0) (unsafePartial tail xs)
-
-main = do
-  let x = sumTCObug 7 3
-      y = sumTCObug' 7 3
-      z = count (_ > 0) [-1, 0, 1]
-  logShow x
-  logShow y 
-  logShow z
-  if x == 10 && y == 10 && z == 1
-    then log "Done"
-    else log "Fail"
diff --git a/examples/passing/2695.purs b/examples/passing/2695.purs
deleted file mode 100644
--- a/examples/passing/2695.purs
+++ /dev/null
@@ -1,13 +0,0 @@
-module Main where
-
-import Prelude
-import Data.Generic
-import Control.Monad.Eff.Console (log)
-
-type Foo = { foo :: Int }
-
-newtype Foo' = Foo' Foo
-
-derive instance genericFoo :: Generic Foo'
-
-main = log "Done"
diff --git a/examples/passing/2756.purs b/examples/passing/2756.purs
deleted file mode 100644
--- a/examples/passing/2756.purs
+++ /dev/null
@@ -1,20 +0,0 @@
-module Main where
-
-import Control.Monad.Eff (Eff)
-import Control.Monad.Eff.Console (log)
-import Prelude
-
-pu :: forall eff. Eff eff Unit
-pu = pure unit
-
-type C eff = { pu :: Eff eff Unit }
-
-sampleC :: C ()
-sampleC = { pu: pu }
-
-newtype Identity a = Id a
-
-sampleIdC :: Identity (C ())
-sampleIdC = Id { pu : pu }
-
-main = log "Done"
diff --git a/examples/passing/2787.purs b/examples/passing/2787.purs
deleted file mode 100644
--- a/examples/passing/2787.purs
+++ /dev/null
@@ -1,8 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console
-
-main
-  | between 0 1 2 = log "Fail"
-  | otherwise = log "Done"
diff --git a/examples/passing/2795.purs b/examples/passing/2795.purs
deleted file mode 100644
--- a/examples/passing/2795.purs
+++ /dev/null
@@ -1,14 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-data X = X Int | Y
-
-x :: X -> Int
-x = case _ of
-      Y -> 0
-      X n | 1 <- n -> 1
-          | otherwise -> 2
-
-main = log "Done"
diff --git a/examples/passing/2806.purs b/examples/passing/2806.purs
deleted file mode 100644
--- a/examples/passing/2806.purs
+++ /dev/null
@@ -1,14 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-data Stream a = Cons a (Stream a)
-
-step :: forall a. Stream a -> Stream a
-step (Cons _ xs) = xs
-
-head :: forall a. Stream a -> a
-head xs | Cons x _ <- step xs = x
-
-main = log "Done"
diff --git a/examples/passing/2958.purs b/examples/passing/2958.purs
deleted file mode 100644
--- a/examples/passing/2958.purs
+++ /dev/null
@@ -1,14 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console
-
-data Nil
-data Snoc xs x
-
-infixl 1 type Snoc as :>
-
-type One = Nil :> Int
-type Two = Nil :> Int :> Int
-type Three = Nil :> Int :> Int :> Int
-
-main = log "Done"
diff --git a/examples/passing/2972.purs b/examples/passing/2972.purs
deleted file mode 100644
--- a/examples/passing/2972.purs
+++ /dev/null
@@ -1,13 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console (log)
-import Prelude (class Show, show)
-
-type I t = t
-
-newtype Id t = Id t
-
-instance foo :: Show (I t) => Show (Id t) where
-  show (Id t) = "Done"
-
-main = log (show (Id "other"))
diff --git a/examples/passing/3125.purs b/examples/passing/3125.purs
deleted file mode 100644
--- a/examples/passing/3125.purs
+++ /dev/null
@@ -1,16 +0,0 @@
-module Main where
-
-import Prelude
-import Data.Monoid (class Monoid, mempty)
-import Control.Monad.Eff.Console (log, logShow)
-
-data B a = B a a
-
-memptyB :: forall a b. Monoid b => B (a -> b)
-memptyB = B l r where
-  l _ = mempty
-  r _ = mempty
-
-main = do
-  logShow $ case (memptyB :: B (Int -> Array Unit)) of B l r -> l 0 == r 0
-  log "Done"
diff --git a/examples/passing/652.purs b/examples/passing/652.purs
deleted file mode 100644
--- a/examples/passing/652.purs
+++ /dev/null
@@ -1,18 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-class Foo a b
-
-class Bar a c
-
-class (Foo a b, Bar a c) <= Baz a b c
-
-instance foo :: Foo (a -> b) a
-
-instance bar :: Bar (a -> b) b
-
-instance baz :: (Eq a) => Baz (a -> b) a b
-
-main = log "Done"
diff --git a/examples/passing/810.purs b/examples/passing/810.purs
deleted file mode 100644
--- a/examples/passing/810.purs
+++ /dev/null
@@ -1,14 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-data Maybe a = Nothing | Just a
-
-test :: forall a. Maybe a -> Maybe a
-test m = o.x
-  where
-    o = case m of Nothing -> { x : Nothing }
-                  Just a  -> { x : Just a }
-
-main = log "Done"
diff --git a/examples/passing/862.purs b/examples/passing/862.purs
deleted file mode 100644
--- a/examples/passing/862.purs
+++ /dev/null
@@ -1,8 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console
-
-id' = (\x -> x) <$> \y -> y
-
-main = log (id' "Done")
diff --git a/examples/passing/922.purs b/examples/passing/922.purs
deleted file mode 100644
--- a/examples/passing/922.purs
+++ /dev/null
@@ -1,20 +0,0 @@
-module Main where
-
-import Prelude
-
-import Control.Monad.Eff.Console
-
-class Default a where
-  def :: a
-
-instance defaultString :: Default String where
-  def = "Done"
-
-data I a = I a
-
-instance defaultI :: (Default a) => Default (I a) where
-  def = I def
-
-main = do
-  case def of
-    I s -> log s
diff --git a/examples/passing/Applicative.purs b/examples/passing/Applicative.purs
deleted file mode 100644
--- a/examples/passing/Applicative.purs
+++ /dev/null
@@ -1,16 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console (log)
-
-class Applicative f where
-  pure :: forall a. a -> f a
-  apply :: forall a b. f (a -> b) -> f a -> f b
-
-data Maybe a = Nothing | Just a
-
-instance applicativeMaybe :: Applicative Maybe where
-  pure = Just
-  apply (Just f) (Just a) = Just (f a)
-  apply _ _ = Nothing
-
-main = log "Done"
diff --git a/examples/passing/ArrayType.purs b/examples/passing/ArrayType.purs
deleted file mode 100644
--- a/examples/passing/ArrayType.purs
+++ /dev/null
@@ -1,12 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-class Pointed p where
-  point :: forall a. a -> p a
-
-instance pointedArray :: Pointed Array where
-  point a = [a]
-
-main = log "Done"
diff --git a/examples/passing/Auto.purs b/examples/passing/Auto.purs
deleted file mode 100644
--- a/examples/passing/Auto.purs
+++ /dev/null
@@ -1,16 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-data Auto s i o = Auto { state :: s, step :: s -> i -> o }
-
-type SomeAuto i o = forall r. (forall s. Auto s i o -> r) -> r
-
-exists :: forall s i o. s -> (s -> i -> o) -> SomeAuto i o
-exists = \state step f -> f (Auto { state: state, step: step })
-
-run :: forall i o. SomeAuto i o -> i -> o
-run = \s i -> s (\a -> case a of Auto a -> a.step a.state i)
-
-main = log "Done"
diff --git a/examples/passing/AutoPrelude.purs b/examples/passing/AutoPrelude.purs
deleted file mode 100644
--- a/examples/passing/AutoPrelude.purs
+++ /dev/null
@@ -1,11 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-f x = x * 10.0
-g y = y - 10.0
-
-main = do
-  log $ show $ (f <<< g) 100.0
-  log "Done"
diff --git a/examples/passing/AutoPrelude2.purs b/examples/passing/AutoPrelude2.purs
deleted file mode 100644
--- a/examples/passing/AutoPrelude2.purs
+++ /dev/null
@@ -1,10 +0,0 @@
-module Main where
-
-import Prelude
-import Prelude as P
-import Control.Monad.Eff.Console
-
-f :: forall a. a -> a
-f = P.id
-
-main = P.($) log ((f P.<<< f) "Done")
diff --git a/examples/passing/BindersInFunctions.purs b/examples/passing/BindersInFunctions.purs
deleted file mode 100644
--- a/examples/passing/BindersInFunctions.purs
+++ /dev/null
@@ -1,16 +0,0 @@
-module Main where
-
-import Prelude
-import Partial.Unsafe (unsafePartial)
-import Test.Assert (assert')
-import Control.Monad.Eff (Eff)
-import Control.Monad.Eff.Console (log)
-
-snd :: forall a. Partial => Array a -> a
-snd = \[_, y] -> y
-
-main :: Eff _ _
-main = do
-  let ts = unsafePartial (snd [1.0, 2.0])
-  assert' "Incorrect result from 'snd'." (ts == 2.0)
-  log "Done"
diff --git a/examples/passing/BindingGroups.purs b/examples/passing/BindingGroups.purs
deleted file mode 100644
--- a/examples/passing/BindingGroups.purs
+++ /dev/null
@@ -1,11 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-foo = bar
-  where bar r = r + 1.0
-
-r = foo 2.0
-
-main = log "Done"
diff --git a/examples/passing/BlockString.purs b/examples/passing/BlockString.purs
deleted file mode 100644
--- a/examples/passing/BlockString.purs
+++ /dev/null
@@ -1,9 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-foo :: String
-foo = """foo"""
-
-main = log "Done"
diff --git a/examples/passing/CaseInDo.purs b/examples/passing/CaseInDo.purs
deleted file mode 100644
--- a/examples/passing/CaseInDo.purs
+++ /dev/null
@@ -1,21 +0,0 @@
-module Main where
-
-import Prelude
-import Partial.Unsafe (unsafeCrashWith)
-import Control.Monad.Eff.Console
-import Control.Monad.Eff
-
-doIt :: forall eff. Eff eff Boolean
-doIt = pure true
-
-set = do
-  log "Testing..."
-  case 0 of
-    0 -> doIt
-    _ -> pure false
-
-main = do
-  b <- set
-  case b of
-    true -> log "Done"
-    false -> unsafeCrashWith "Failed"
diff --git a/examples/passing/CaseInputWildcard.purs b/examples/passing/CaseInputWildcard.purs
deleted file mode 100644
--- a/examples/passing/CaseInputWildcard.purs
+++ /dev/null
@@ -1,18 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff (Eff)
-import Control.Monad.Eff.Console (log, CONSOLE)
-
-data Foo = X | Y
-
-what ∷ Foo → Int → Boolean → Foo
-what x = case _, x, _ of
-  0, X, true → X
-  0, Y, true → X
-  _, _, _ → Y
-
-main :: forall e. Eff (console :: CONSOLE | e) Unit
-main = do
-  let tmp = what Y 0 true
-  log "Done"
diff --git a/examples/passing/CaseMultipleExpressions.purs b/examples/passing/CaseMultipleExpressions.purs
deleted file mode 100644
--- a/examples/passing/CaseMultipleExpressions.purs
+++ /dev/null
@@ -1,21 +0,0 @@
-module Main where
-
-import Prelude
-import Partial.Unsafe (unsafeCrashWith)
-import Control.Monad.Eff.Console
-import Control.Monad.Eff
-
-doIt :: forall eff. Eff eff Boolean
-doIt = pure true
-
-set = do
-  log "Testing..."
-  case 42, 10 of
-    42, 10 -> doIt
-    _ , _  -> pure false
-
-main = do
-  b <- set
-  case b of
-    true -> log "Done"
-    false -> unsafeCrashWith "Failed"
diff --git a/examples/passing/CaseStatement.purs b/examples/passing/CaseStatement.purs
deleted file mode 100644
--- a/examples/passing/CaseStatement.purs
+++ /dev/null
@@ -1,22 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-data A = A | B | C
-
-f a _ A = a
-f _ a B = a
-f _ _ C = "Done"
-
-g a _ A = a
-g _ b B = b
-g _ _ C = C
-
-data M a = N | J a
-
-h f N a = a
-h f a N = a
-h f (J a) (J b) = J (f a b)
-
-main = log $ f "Done" "Failed" A
diff --git a/examples/passing/CheckFunction.purs b/examples/passing/CheckFunction.purs
deleted file mode 100644
--- a/examples/passing/CheckFunction.purs
+++ /dev/null
@@ -1,8 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-test = ((\x -> x+1.0) >>> (\x -> x*2.0)) 4.0
-
-main = log "Done"
diff --git a/examples/passing/CheckSynonymBug.purs b/examples/passing/CheckSynonymBug.purs
deleted file mode 100644
--- a/examples/passing/CheckSynonymBug.purs
+++ /dev/null
@@ -1,13 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-length :: forall a. Array a -> Int
-length _ = 0
-
-type Foo a = Array a
-
-foo _ = length ([] :: Foo Number)
-
-main = log "Done"
diff --git a/examples/passing/CheckTypeClass.purs b/examples/passing/CheckTypeClass.purs
deleted file mode 100644
--- a/examples/passing/CheckTypeClass.purs
+++ /dev/null
@@ -1,18 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-data Bar a = Bar
-data Baz
-
-class Foo a where
-  foo :: Bar a -> Baz
-
-foo_ :: forall a. Foo a => a -> Baz
-foo_ x = foo ((mkBar :: forall a. Foo a => a -> Bar a) x)
-
-mkBar :: forall a. a -> Bar a
-mkBar _ = Bar
-
-main = log "Done"
diff --git a/examples/passing/Church.purs b/examples/passing/Church.purs
deleted file mode 100644
--- a/examples/passing/Church.purs
+++ /dev/null
@@ -1,18 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console (log)
-
-type List a = forall r. r -> (a -> r -> r) -> r
-
-empty :: forall a. List a
-empty = \r f -> r
-
-cons :: forall a. a -> List a -> List a
-cons = \a l r f -> f a (l r f)
-
-append :: forall a. List a -> List a -> List a
-append = \l1 l2 r f -> l2 (l1 r f) f
-
-test = append (cons 1 empty) (cons 2 empty)
-
-main = log "Done"
diff --git a/examples/passing/ClassRefSyntax.purs b/examples/passing/ClassRefSyntax.purs
deleted file mode 100644
--- a/examples/passing/ClassRefSyntax.purs
+++ /dev/null
@@ -1,9 +0,0 @@
-module Main where
-
-import Lib (class X, go)
-import Control.Monad.Eff.Console (log)
-
-go' :: forall a. X a => a -> a
-go' = go
-
-main = log "Done"
diff --git a/examples/passing/ClassRefSyntax/Lib.purs b/examples/passing/ClassRefSyntax/Lib.purs
deleted file mode 100644
--- a/examples/passing/ClassRefSyntax/Lib.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module Lib (class X, go) where
-
-class X a where
-  go :: a -> a
diff --git a/examples/passing/Collatz.purs b/examples/passing/Collatz.purs
deleted file mode 100644
--- a/examples/passing/Collatz.purs
+++ /dev/null
@@ -1,21 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff
-import Control.Monad.ST
-import Control.Monad.Eff.Console (log, logShow)
-
-collatz :: Int -> Int
-collatz n = runPure (runST (do
-  r <- newSTRef n
-  count <- newSTRef 0
-  untilE $ do
-    _ <- modifySTRef count $ (+) 1
-    m <- readSTRef r
-    _ <- writeSTRef r $ if m `mod` 2 == 0 then m / 2 else 3 * m + 1
-    pure $ m == 1
-  readSTRef count))
-
-main = do
-  logShow $ collatz 1000
-  log "Done"
diff --git a/examples/passing/Comparisons.purs b/examples/passing/Comparisons.purs
deleted file mode 100644
--- a/examples/passing/Comparisons.purs
+++ /dev/null
@@ -1,15 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff
-import Control.Monad.Eff.Console
-import Test.Assert
-
-main = do
-  assert (1.0 < 2.0)
-  assert (2.0 == 2.0)
-  assert (3.0 > 1.0)
-  assert ("a" < "b")
-  assert ("a" == "a")
-  assert ("z" > "a")
-  log "Done"
diff --git a/examples/passing/Conditional.purs b/examples/passing/Conditional.purs
deleted file mode 100644
--- a/examples/passing/Conditional.purs
+++ /dev/null
@@ -1,9 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console (log)
-
-fns = \f -> if f true then f else \x -> x
-
-not = \x -> if x then false else true
-
-main = log "Done"
diff --git a/examples/passing/Console.purs b/examples/passing/Console.purs
deleted file mode 100644
--- a/examples/passing/Console.purs
+++ /dev/null
@@ -1,15 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff
-import Control.Monad.Eff.Console
-
-replicateM_ :: forall m a. Monad m => Number -> m a -> m Unit
-replicateM_ 0.0 _ = pure unit
-replicateM_ n act = do
-  _ <- act
-  replicateM_ (n - 1.0) act
-
-main = do
-  replicateM_ 10.0 (log "Hello World!")
-  log "Done"
diff --git a/examples/passing/ConstraintInference.purs b/examples/passing/ConstraintInference.purs
deleted file mode 100644
--- a/examples/passing/ConstraintInference.purs
+++ /dev/null
@@ -1,10 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-shout = log <<< (_ <> "!") <<< show
-
-main = do
-  shout "Test"
-  log "Done"
diff --git a/examples/passing/ConstraintParens.purs b/examples/passing/ConstraintParens.purs
deleted file mode 100644
--- a/examples/passing/ConstraintParens.purs
+++ /dev/null
@@ -1,12 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-class Foo a where
-  foo ∷ a → a
-
-test ∷ ∀ a. (Foo a) ⇒ a → a
-test = foo
-
-main = log "Done"
diff --git a/examples/passing/ConstraintParsingIssue.purs b/examples/passing/ConstraintParsingIssue.purs
deleted file mode 100644
--- a/examples/passing/ConstraintParsingIssue.purs
+++ /dev/null
@@ -1,9 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console
-
-class X a
-
-instance x :: X (Array (Array a)) => X (Array a)
-
-main = log "Done"
diff --git a/examples/passing/ContextSimplification.purs b/examples/passing/ContextSimplification.purs
deleted file mode 100644
--- a/examples/passing/ContextSimplification.purs
+++ /dev/null
@@ -1,15 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console
-
-shout = log <<< (_ <> "!") <<< show
-
--- Here, we should simplify the context so that only one Show
--- constraint is added.
-usesShowTwice true = shout
-usesShowTwice false = logShow
-
-main = do
-  usesShowTwice true "Test"
-  log "Done"
diff --git a/examples/passing/DataAndType.purs b/examples/passing/DataAndType.purs
deleted file mode 100644
--- a/examples/passing/DataAndType.purs
+++ /dev/null
@@ -1,10 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-data A = A B
-
-type B = A
-
-main = log "Done"
diff --git a/examples/passing/DctorName.purs b/examples/passing/DctorName.purs
deleted file mode 100644
--- a/examples/passing/DctorName.purs
+++ /dev/null
@@ -1,33 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-newtype Bar' = Bar' Int
-
-data Foo' = Foo' Bar'
-
-data Baz'' = Baz'' | Baz'
-
-f ∷ Foo' → Boolean
-f a = case a of Foo' b → true
-
-f' ∷ Boolean
-f' = f $ Foo' $ Bar' 0
-
-g ∷ Baz'' → Int
-g Baz'' = 0
-g Baz' = 1
-
-g' ∷ Int
-g' = g Baz''
-
-h ∷ Bar' → Int
-h (Bar' x)
- | x <= 10 = x * 2 
- | otherwise = 10
-
-h' ∷ Int
-h' = h $ Bar' 4
-
-main = log "Done"
diff --git a/examples/passing/DctorOperatorAlias.purs b/examples/passing/DctorOperatorAlias.purs
deleted file mode 100644
--- a/examples/passing/DctorOperatorAlias.purs
+++ /dev/null
@@ -1,34 +0,0 @@
-module Main where
-
-  import Prelude (Unit, bind, discard, (==))
-  import Control.Monad.Eff (Eff)
-  import Control.Monad.Eff.Console (CONSOLE, log)
-  import Test.Assert (ASSERT, assert')
-  import List (List(..), (:))
-  import List as L
-
-  -- unqualified
-  infixl 6 Cons as !
-
-  -- qualified
-  infixl 6 L.Cons as !!
-
-  get1 ∷ ∀ a. a → List a → a
-  get1 y xs = case xs of
-    _ : x : _ → x
-    _ → y
-
-  get2 ∷ ∀ a. a → List a → a
-  get2 _ (_ : x : _) = x
-  get2 y _ = y
-
-  get3 ∷ ∀ a. a → List a → a
-  get3 _ (_ ! (x ! _)) = x
-  get3 y _ = y
-
-  main ∷ Eff (assert ∷ ASSERT, console ∷ CONSOLE) Unit
-  main = do
-    assert' "Incorrect result!" (get1 0 (1 : 2 : 3 : Nil) == 2)
-    assert' "Incorrect result!" (get2 0 (1 ! (2 ! (3 ! Nil))) == 2)
-    assert' "Incorrect result!" (get3 0.0 (1.0 : 2.0 : (3.0 ! Nil)) == 2.0)
-    log "Done"
diff --git a/examples/passing/DctorOperatorAlias/List.purs b/examples/passing/DctorOperatorAlias/List.purs
deleted file mode 100644
--- a/examples/passing/DctorOperatorAlias/List.purs
+++ /dev/null
@@ -1,5 +0,0 @@
-module List where
-
-data List a = Cons a (List a) | Nil
-
-infixr 6 Cons as :
diff --git a/examples/passing/DeepArrayBinder.purs b/examples/passing/DeepArrayBinder.purs
deleted file mode 100644
--- a/examples/passing/DeepArrayBinder.purs
+++ /dev/null
@@ -1,17 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff
-import Control.Monad.Eff.Console (log)
-import Test.Assert
-
-data List a = Cons a (List a) | Nil
-
-match2 :: List Number -> Number
-match2 (Cons x (Cons y xs)) = x * y + match2 xs
-match2 _ = 0.0
-
-main = do
-  let result = match2 (Cons 1.0 (Cons 2.0 (Cons 3.0 (Cons 4.0 (Cons 5.0 (Cons 6.0 (Cons 7.0 (Cons 8.0 (Cons 9.0 Nil)))))))))
-  assert' "Incorrect result!" (result == 100.0)
-  log "Done"
diff --git a/examples/passing/DeepCase.purs b/examples/passing/DeepCase.purs
deleted file mode 100644
--- a/examples/passing/DeepCase.purs
+++ /dev/null
@@ -1,15 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log, logShow)
-
-f x y =
-  let
-    g = case y of
-	  0.0 -> x
-          x -> 1.0 + x * x
-  in g + x + y
-
-main = do
-  logShow $ f 1.0 10.0
-  log "Done"
diff --git a/examples/passing/DeriveNewtype.purs b/examples/passing/DeriveNewtype.purs
deleted file mode 100644
--- a/examples/passing/DeriveNewtype.purs
+++ /dev/null
@@ -1,29 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console (log)
-
-import Data.Newtype
-
-type MyString = String
-
-newtype Test = Test MyString
-
-derive instance newtypeTest :: Newtype Test _
-
-t :: Test
-t = wrap "hello"
-
-a :: String
-a = unwrap t
-
-newtype First a = First a
-
-derive instance newtypeFirst :: Newtype (First b) _
-
-f :: First Int
-f = wrap 1
-
-i :: Int
-i = unwrap f
-
-main = log "Done"
diff --git a/examples/passing/DeriveWithNestedSynonyms.purs b/examples/passing/DeriveWithNestedSynonyms.purs
deleted file mode 100644
--- a/examples/passing/DeriveWithNestedSynonyms.purs
+++ /dev/null
@@ -1,29 +0,0 @@
-module Main where
-	
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-type L = {}
-data X = X L
-derive instance eqX :: Eq X
-
-type M = {}
-data Y = Y {foo :: M}
-derive instance eqY :: Eq Y
-
-type N = {}
-data Z = Z N
-derive instance eqZ :: Eq Z
-
-type Foo = String
-
-type Bar = { foo :: Foo }
-
-type Baz = { baz :: Bar }
-
-newtype T = T Baz
-
-derive instance eqT :: Eq T
-derive instance ordT :: Ord T
-
-main = log "Done"
diff --git a/examples/passing/Deriving.purs b/examples/passing/Deriving.purs
deleted file mode 100644
--- a/examples/passing/Deriving.purs
+++ /dev/null
@@ -1,36 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-import Test.Assert
-
-data V
-
-derive instance eqV :: Eq V
-
-derive instance ordV :: Ord V
-
-type MyString = String
-
-data X = X Int | Y MyString
-
-derive instance eqX :: Eq X
-
-derive instance ordX :: Ord X
-
-newtype Z = Z { left :: X, right :: X }
-
-derive instance eqZ :: Eq Z
-
-main = do
-  assert $ X 0 == X 0
-  assert $ X 0 /= X 1
-  assert $ Y "Foo" == Y "Foo"
-  assert $ Y "Foo" /= Y "Bar"
-  assert $ X 0 < X 1
-  assert $ X 0 < Y "Foo"
-  assert $ Y "Bar" < Y "Baz"
-  assert $ z == z
-  log "Done"
-  where
-  z = Z { left: X 0, right: Y "Foo" }
diff --git a/examples/passing/DerivingFunctor.purs b/examples/passing/DerivingFunctor.purs
deleted file mode 100644
--- a/examples/passing/DerivingFunctor.purs
+++ /dev/null
@@ -1,28 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-import Test.Assert
-
-type MyRecord a = { myField :: a }
-
-data M f a
-  = M0 a (Array a)
-  | M1 Int
-  | M2 (f a)
-  | M3 { foo :: Int, bar :: a, baz :: f a }
-  | M4 (MyRecord a)
-
-derive instance eqM :: (Eq (f a), Eq a) => Eq (M f a)
-
-derive instance functorM :: Functor f => Functor (M f)
-
-type MA = M Array
-
-main = do
-  assert $ map show (M0 0 [1, 2] :: MA Int) == M0 "0" ["1", "2"]
-  assert $ map show (M1 0 :: MA Int) == M1 0
-  assert $ map show (M2 [0, 1] :: MA Int) == M2 ["0", "1"]
-  assert $ map show (M3 {foo: 0, bar: 1, baz: [2, 3]} :: MA Int) == M3 {foo: 0, bar: "1", baz: ["2", "3"]}
-  assert $ map show (M4 { myField: 42 }) == M4 { myField: "42" } :: MA String 
-  log "Done"
diff --git a/examples/passing/Do.purs b/examples/passing/Do.purs
deleted file mode 100644
--- a/examples/passing/Do.purs
+++ /dev/null
@@ -1,68 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-data Maybe a = Nothing | Just a
-
-instance functorMaybe :: Functor Maybe where
-  map f Nothing = Nothing
-  map f (Just x) = Just (f x)
-
-instance applyMaybe :: Apply Maybe where
-  apply (Just f) (Just x) = Just (f x)
-  apply _ _ = Nothing
-
-instance applicativeMaybe :: Applicative Maybe where
-  pure = Just
-
-instance bindMaybe :: Bind Maybe where
-  bind Nothing _ = Nothing
-  bind (Just a) f = f a
-
-instance monadMaybe :: Monad Maybe
-
-test1 = \_ -> do
-  Just "abc"
-
-test2 = \_ -> do
-  x <- Just 1.0
-  y <- Just 2.0
-  Just (x + y)
-
-test3 = \_ -> do
-  _ <- Just 1.0
-  _ <- Nothing :: Maybe Number
-  Just 2.0
-
-test4 mx my = do
-  x <- mx
-  y <- my
-  Just (x + y + 1.0)
-
-test5 mx my mz = do
-  x <- mx
-  y <- my
-  let sum = x + y
-  z <- mz
-  Just (z + sum + 1.0)
-
-test6 mx = \_ -> do
-  let
-    f :: forall a. Maybe a -> a
-    f (Just x) = x
-  Just (f mx)
-
-test8 = \_ -> do
-  Just (do
-    Just 1.0)
-
-test9 = \_ -> (+) <$> Just 1.0 <*> Just 2.0
-
-test10 _ = do
-  let
-    f x = g x * 3.0
-    g x = f x / 2.0
-  Just (f 10.0)
-
-main = log "Done"
diff --git a/examples/passing/Dollar.purs b/examples/passing/Dollar.purs
deleted file mode 100644
--- a/examples/passing/Dollar.purs
+++ /dev/null
@@ -1,16 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console (log)
-
-applyFn :: forall a b. (a -> b) -> a -> b
-applyFn f x = f x
-
-infixr 1000 applyFn as $
-
-id x = x
-
-test1 x = id $ id $ id $ id $ x
-
-test2 x = id id $ id x
-
-main = log "Done"
diff --git a/examples/passing/DuplicateProperties.purs b/examples/passing/DuplicateProperties.purs
deleted file mode 100644
--- a/examples/passing/DuplicateProperties.purs
+++ /dev/null
@@ -1,27 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-data RProxy (r :: # Type) = RProxy
-
-data Proxy (a :: Type) = Proxy
-
-subtractX :: forall r a. RProxy (x :: a | r) -> RProxy r
-subtractX RProxy = RProxy
-
-extractX :: forall r a. RProxy (x :: a | r) -> Proxy a
-extractX RProxy = Proxy
-
-hasX :: forall r a b. RProxy (x :: a, y :: b | r)
-hasX = RProxy
-
-test1 = subtractX (subtractX hasX)
-
-test2
-  :: forall r a b
-   . RProxy (x :: a, x :: b, x :: Int | r)
-  -> Proxy Int
-test2 x = extractX (subtractX (subtractX x))
-
-main = log "Done"
diff --git a/examples/passing/Eff.purs b/examples/passing/Eff.purs
deleted file mode 100644
--- a/examples/passing/Eff.purs
+++ /dev/null
@@ -1,26 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff
-import Control.Monad.ST
-import Control.Monad.Eff.Console (log, logShow)
-
-test1 = do
-  log "Line 1"
-  log "Line 2"
-
-test2 = runPure (runST (do
-          ref <- newSTRef 0.0
-          _ <- modifySTRef ref $ \n -> n + 1.0
-          readSTRef ref))
-
-test3 = pureST (do
-          ref <- newSTRef 0.0
-          _ <- modifySTRef ref $ \n -> n + 1.0
-          readSTRef ref)
-
-main = do
-  test1
-  logShow test2
-  logShow test3
-  log "Done"
diff --git a/examples/passing/EmptyDataDecls.purs b/examples/passing/EmptyDataDecls.purs
deleted file mode 100644
--- a/examples/passing/EmptyDataDecls.purs
+++ /dev/null
@@ -1,20 +0,0 @@
-module Main where
-
-import Prelude
-import Test.Assert
-import Control.Monad.Eff.Console (log)
-
-data Z
-data S n
-
-data ArrayBox n a = ArrayBox (Array a)
-
-nil :: forall a. ArrayBox Z a
-nil = ArrayBox []
-
-cons' :: forall a n. a -> ArrayBox n a -> ArrayBox (S n) a
-cons' x (ArrayBox xs) = ArrayBox $ append [x] xs
-
-main = case cons' 1 $ cons' 2 $ cons' 3 nil of
-         ArrayBox [1, 2, 3] -> log "Done"
-         _ -> assert' "Failed" false
diff --git a/examples/passing/EmptyRow.purs b/examples/passing/EmptyRow.purs
deleted file mode 100644
--- a/examples/passing/EmptyRow.purs
+++ /dev/null
@@ -1,11 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-data Foo r = Foo { | r }
-
-test :: Foo ()
-test = Foo {}
-
-main = log "Done"
diff --git a/examples/passing/EmptyTypeClass.purs b/examples/passing/EmptyTypeClass.purs
deleted file mode 100644
--- a/examples/passing/EmptyTypeClass.purs
+++ /dev/null
@@ -1,11 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff
-import Control.Monad.Eff.Console
-
-head :: forall a. Partial => Array a -> a
-head [x] = x
-
-main :: Eff _ _
-main = log "Done"
diff --git a/examples/passing/EntailsKindedType.purs b/examples/passing/EntailsKindedType.purs
deleted file mode 100644
--- a/examples/passing/EntailsKindedType.purs
+++ /dev/null
@@ -1,11 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff
-import Control.Monad.Eff.Console
-
-test x = show (x :: _ :: Type)
-
-main = do
-  when (show (unit :: Unit :: Type) == "unit") (log "Done")
-  when (test unit == "unit") (log "Done")
diff --git a/examples/passing/EqOrd.purs b/examples/passing/EqOrd.purs
deleted file mode 100644
--- a/examples/passing/EqOrd.purs
+++ /dev/null
@@ -1,18 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log, logShow)
-
-data Pair a b = Pair a b
-
-instance ordPair :: (Ord a, Ord b) => Ord (Pair a b) where
-  compare (Pair a1 b1) (Pair a2 b2) = case compare a1 a2 of
-    EQ -> compare b1 b2
-    r -> r
-
-instance eqPair :: (Eq a, Eq b) => Eq (Pair a b) where
-  eq (Pair a1 b1) (Pair a2 b2) = a1 == a2 && b1 == b2
-
-main = do
-  logShow $ Pair 1.0 2.0 == Pair 1.0 2.0
-  log "Done"
diff --git a/examples/passing/ExplicitImportReExport.purs b/examples/passing/ExplicitImportReExport.purs
deleted file mode 100644
--- a/examples/passing/ExplicitImportReExport.purs
+++ /dev/null
@@ -1,11 +0,0 @@
--- from #1244
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-import Bar (foo)
-
-baz :: Int
-baz = foo
-
-main = log "Done"
diff --git a/examples/passing/ExplicitImportReExport/Bar.purs b/examples/passing/ExplicitImportReExport/Bar.purs
deleted file mode 100644
--- a/examples/passing/ExplicitImportReExport/Bar.purs
+++ /dev/null
@@ -1,3 +0,0 @@
-module Bar (module Foo) where
-
-import Foo
diff --git a/examples/passing/ExplicitImportReExport/Foo.purs b/examples/passing/ExplicitImportReExport/Foo.purs
deleted file mode 100644
--- a/examples/passing/ExplicitImportReExport/Foo.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module Foo where
-
-foo :: Int
-foo = 3
diff --git a/examples/passing/ExplicitOperatorSections.purs b/examples/passing/ExplicitOperatorSections.purs
deleted file mode 100644
--- a/examples/passing/ExplicitOperatorSections.purs
+++ /dev/null
@@ -1,15 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-subtractOne :: Int -> Int
-subtractOne = (_ - 1)
-
-addOne :: Int -> Int
-addOne = (1 + _)
-
-named :: Int -> Int
-named = (_ `sub` 1)
-
-main = log "Done"
diff --git a/examples/passing/ExportExplicit.purs b/examples/passing/ExportExplicit.purs
deleted file mode 100644
--- a/examples/passing/ExportExplicit.purs
+++ /dev/null
@@ -1,10 +0,0 @@
-module Main where
-
-import M1
-import Control.Monad.Eff.Console (log)
-
-testX = X
-testZ = Z
-testFoo = foo
-
-main = log "Done"
diff --git a/examples/passing/ExportExplicit/M1.purs b/examples/passing/ExportExplicit/M1.purs
deleted file mode 100644
--- a/examples/passing/ExportExplicit/M1.purs
+++ /dev/null
@@ -1,10 +0,0 @@
-module M1 (X(X), Z(..), foo) where
-
-data X = X | Y
-data Z = Z
-
-foo :: Int
-foo = 0
-
-bar :: Int
-bar = 1
diff --git a/examples/passing/ExportExplicit2.purs b/examples/passing/ExportExplicit2.purs
deleted file mode 100644
--- a/examples/passing/ExportExplicit2.purs
+++ /dev/null
@@ -1,8 +0,0 @@
-module Main where
-
-import M1
-import Control.Monad.Eff.Console (log)
-
-testBar = bar
-
-main = log "Done"
diff --git a/examples/passing/ExportExplicit2/M1.purs b/examples/passing/ExportExplicit2/M1.purs
deleted file mode 100644
--- a/examples/passing/ExportExplicit2/M1.purs
+++ /dev/null
@@ -1,7 +0,0 @@
-module M1 (bar) where
-
-foo :: Int
-foo = 0
-
-bar :: Int
-bar = foo
diff --git a/examples/passing/ExportedInstanceDeclarations.purs b/examples/passing/ExportedInstanceDeclarations.purs
deleted file mode 100644
--- a/examples/passing/ExportedInstanceDeclarations.purs
+++ /dev/null
@@ -1,45 +0,0 @@
--- Tests that instances for non-exported classes / types do not appear in the
--- result of `exportedDeclarations`.
-module Main
-  ( Const(..)
-  , class Foo
-  , foo
-  , main
-  ) where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-data Const a b = Const a
-
-class Foo a where
-  foo :: a
-
-data NonexportedType = NonexportedType
-
-class NonexportedClass a where
-  notExported :: a
-
--- There are three places that a nonexported type or type class can occur,
--- leading an instance to count as non-exported:
---  * Constraints
---  * The type class itself
---  * The instance types
-
--- Case 1: constraints
-instance nonExportedFoo :: (NonexportedClass a) => Foo a where
-  foo = notExported
-
--- Another instance of case 1:
-instance nonExportedFoo2 :: (Foo NonexportedType) => Foo (a -> a) where
-  foo = id
-
--- Case 2: type class
-instance nonExportedNonexportedType :: NonexportedClass (Const Int a) where
-  notExported = Const 0
-
--- Case 3: instance types
-instance constFoo :: Foo (Const NonexportedType b) where
-  foo = Const NonexportedType
-
-main = log "Done"
diff --git a/examples/passing/ExtendedInfixOperators.purs b/examples/passing/ExtendedInfixOperators.purs
deleted file mode 100644
--- a/examples/passing/ExtendedInfixOperators.purs
+++ /dev/null
@@ -1,17 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log, logShow)
-import Data.Function (on)
-
-comparing :: forall a b. Ord b => (a -> b) -> a -> a -> Ordering
-comparing f = compare `on` f
-
-null [] = true
-null _ = false
-
-test = [1.0, 2.0, 3.0] `comparing null` [4.0, 5.0, 6.0]
-
-main = do
-  logShow test
-  log "Done"
diff --git a/examples/passing/Fib.purs b/examples/passing/Fib.purs
deleted file mode 100644
--- a/examples/passing/Fib.purs
+++ /dev/null
@@ -1,18 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff (whileE)
-import Control.Monad.Eff.Console (log, logShow)
-import Control.Monad.ST (runST, newSTRef, readSTRef, writeSTRef)
-
-main = do
-  runST do
-    n1 <- newSTRef 1.0
-    n2 <- newSTRef 1.0
-    whileE ((>) 1000.0 <$> readSTRef n1) $ do
-      n1' <- readSTRef n1
-      n2' <- readSTRef n2
-      _ <- writeSTRef n2 $ n1' + n2'
-      _ <- writeSTRef n1 n2'
-      logShow n2'
-  log "Done"
diff --git a/examples/passing/FieldConsPuns.purs b/examples/passing/FieldConsPuns.purs
deleted file mode 100644
--- a/examples/passing/FieldConsPuns.purs
+++ /dev/null
@@ -1,13 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log, logShow)
-
-greet { greeting, name } = log $ greeting <> ", " <> name <> "."
-
-main = do
-  greet { greeting, name }
-  log "Done"
-  where
-  greeting = "Hello"
-  name = "World"
diff --git a/examples/passing/FieldPuns.purs b/examples/passing/FieldPuns.purs
deleted file mode 100644
--- a/examples/passing/FieldPuns.purs
+++ /dev/null
@@ -1,10 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console
-
-greet { greeting, name } = log $ greeting <> ", " <> name <> "."
-
-main = do
-  greet { greeting: "Hello", name: "World" }
-  log "Done"
diff --git a/examples/passing/FinalTagless.purs b/examples/passing/FinalTagless.purs
deleted file mode 100644
--- a/examples/passing/FinalTagless.purs
+++ /dev/null
@@ -1,25 +0,0 @@
-module Main where
-
-import Prelude hiding (add)
-import Control.Monad.Eff.Console (log, logShow)
-
-class E e where
-  num :: Number -> e Number
-  add :: e Number -> e Number -> e Number
-
-type Expr a = forall e. E e => e a
-
-data Id a = Id a
-
-instance exprId :: E Id where
-  num = Id
-  add (Id n) (Id m) = Id (n + m)
-
-runId (Id a) = a
-
-three :: Expr Number
-three = add (num 1.0) (num 2.0)
-
-main = do
-  logShow $ runId three
-  log "Done"
diff --git a/examples/passing/ForeignKind.purs b/examples/passing/ForeignKind.purs
deleted file mode 100644
--- a/examples/passing/ForeignKind.purs
+++ /dev/null
@@ -1,10 +0,0 @@
-module Main where
-
-import Prelude
-import ForeignKinds.Lib (kind Nat, Zero, Succ, N3, NatProxy, class AddNat, addNat, proxy1, proxy2)
-import Control.Monad.Eff.Console (log)
-
-proxy1Add2Is3 :: NatProxy N3
-proxy1Add2Is3 = addNat proxy1 proxy2
-
-main = log "Done"
diff --git a/examples/passing/ForeignKind/Lib.purs b/examples/passing/ForeignKind/Lib.purs
deleted file mode 100644
--- a/examples/passing/ForeignKind/Lib.purs
+++ /dev/null
@@ -1,60 +0,0 @@
-module ForeignKinds.Lib (kind Nat, Kinded, Zero, Succ, N0, N1, N2, N3, NatProxy(..), class AddNat, addNat, proxy1, proxy2) where
-
--- declaration
-
-foreign import kind Nat
-
--- use in foreign data
-
-foreign import data Zero :: Nat
-foreign import data Succ :: Nat -> Nat
-
--- use in data
-
-data NatProxy (t :: Nat) = NatProxy
-
--- use in type sig
-
-succProxy :: forall n. NatProxy n -> NatProxy (Succ n)
-succProxy _ = NatProxy
-
--- use in alias
-
-type Kinded f = f :: Nat
-
-type KindedZero = Kinded Zero
-
-type N0 = Zero
-type N1 = Succ N0
-type N2 = Succ N1
-type N3 = Succ N2
-
--- use of alias
-
-proxy0 :: NatProxy N0
-proxy0 = NatProxy
-
-proxy1 :: NatProxy N1
-proxy1 = NatProxy
-
-proxy2 :: NatProxy N2
-proxy2 = NatProxy
-
-proxy3 :: NatProxy N3
-proxy3 = NatProxy
-
--- use in class
-
-class AddNat (l :: Nat) (r :: Nat) (o :: Nat) | l -> r o
-
-instance addNatZero
-  :: AddNat Zero r r
-
-instance addNatSucc
-  :: AddNat l r o
-  => AddNat (Succ l) r (Succ o)
-
--- use of class
-
-addNat :: forall l r o. AddNat l r o => NatProxy l -> NatProxy r -> NatProxy o
-addNat _ _ = NatProxy
diff --git a/examples/passing/FunWithFunDeps.js b/examples/passing/FunWithFunDeps.js
deleted file mode 100644
--- a/examples/passing/FunWithFunDeps.js
+++ /dev/null
@@ -1,32 +0,0 @@
-
-//: forall e. FVect Z e
-exports.fnil = [];
-
-//: forall n e. e -> FVect n e -> FVect (S n) e
-exports.fcons = function (hd) {
-  return function (tl) {
-    return [hd].concat(tl);
-  };
-};
-
-exports.fappend = function (dict) {
-  return function (left) {
-    return function (right) {
-      return left.concat(right);
-    };
-  };
-};
-
-exports.fflatten = function (dict) {
-  return function (v) {
-    var accRef = [];
-    for (var indexRef = 0; indexRef < v.length; indexRef += 1) {
-      accRef = accRef.concat(v[indexRef]);
-    }
-    return accRef;
-  };
-};
-
-exports.ftoArray = function (vect) {
-  return vect;
-};
diff --git a/examples/passing/FunWithFunDeps.purs b/examples/passing/FunWithFunDeps.purs
deleted file mode 100644
--- a/examples/passing/FunWithFunDeps.purs
+++ /dev/null
@@ -1,41 +0,0 @@
--- Taken from https://github.com/LiamGoodacre/purescript-fun-with-fundeps
-
-module Main where
-
-import Control.Monad.Eff.Console (log)
-
--- Nat : Type
-data Z
-data S n
-
-type S2 n = S (S n)
-type S3 n = S (S2 n)
-type S4 n = S (S3 n)
-type S5 n = S (S4 n)
-type S15 n = S5 (S5 (S5 n))
-
-class NatPlus l r o | l r -> o
-instance natPlusZ :: NatPlus Z r r
-instance natPlusS :: (NatPlus l r o) => NatPlus (S l) r (S o)
-
-class NatMult l r o | l r -> o
-instance natMultZ :: NatMult Z n Z
-instance natMultS :: (NatMult m n r, NatPlus n r s) => NatMult (S m) n s
-
--- Foreign Vect
-foreign import data FVect :: Type -> Type -> Type
-foreign import fnil :: forall e. FVect Z e
-foreign import fcons :: forall n e. e -> FVect n e -> FVect (S n) e
-foreign import fappend :: forall l r o e. NatPlus l r o => FVect l e -> FVect r e -> FVect o e
-foreign import fflatten :: forall f s t o. NatMult f s o => FVect f (FVect s t) -> FVect o t
-foreign import ftoArray :: forall n e. FVect n e -> Array e
-
--- should be able to figure these out
-fsingleton x = fcons x fnil
-fexample = fcons 1 (fsingleton 2) `fappend` fsingleton 3 `fappend` fcons 4 (fsingleton 5)
-fexample2 = fexample `fappend` fexample `fappend` fexample
-fexample3 = fsingleton fexample `fappend` fsingleton fexample `fappend` fsingleton fexample
-
-fexample4 = fflatten fexample3
-
-main = log "Done"
diff --git a/examples/passing/FunctionScope.purs b/examples/passing/FunctionScope.purs
deleted file mode 100644
--- a/examples/passing/FunctionScope.purs
+++ /dev/null
@@ -1,13 +0,0 @@
-module Main where
-
-import Prelude
-import Test.Assert
-import Control.Monad.Eff.Console (log)
-
-mkValue :: Number -> Number
-mkValue id = id
-
-main = do
-  let value = mkValue 1.0
-  assert $ value == 1.0
-  log "Done"
diff --git a/examples/passing/FunctionalDependencies.purs b/examples/passing/FunctionalDependencies.purs
deleted file mode 100644
--- a/examples/passing/FunctionalDependencies.purs
+++ /dev/null
@@ -1,21 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console (log)
-
-data Nil
-data Cons x xs
-
-class Append a b c | a b -> c
-
-instance appendNil :: Append Nil b b
-
-instance appendCons :: Append xs b c => Append (Cons x xs) b (Cons x c)
-
-data Proxy a = Proxy
-
-appendProxy :: forall a b c. Append a b c => Proxy a -> Proxy b -> Proxy c
-appendProxy Proxy Proxy = Proxy
-
-test = appendProxy (Proxy :: Proxy (Cons Int Nil)) (Proxy :: Proxy (Cons String Nil))
-
-main = log "Done"
diff --git a/examples/passing/Functions.purs b/examples/passing/Functions.purs
deleted file mode 100644
--- a/examples/passing/Functions.purs
+++ /dev/null
@@ -1,12 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-test1 = \_ -> 0.0
-
-test2 = \a b -> a + b + 1.0
-
-test3 = \a -> a
-
-main = log "Done"
diff --git a/examples/passing/Functions2.purs b/examples/passing/Functions2.purs
deleted file mode 100644
--- a/examples/passing/Functions2.purs
+++ /dev/null
@@ -1,13 +0,0 @@
-module Main where
-
-import Prelude
-import Test.Assert
-import Control.Monad.Eff.Console (log)
-
-test :: forall a b. a -> b -> a
-test = \const _ -> const
-
-main = do
-  let value = test "Done" {}
-  assert' "Not done" $ value == "Done"
-  log "Done"
diff --git a/examples/passing/Generalization1.purs b/examples/passing/Generalization1.purs
deleted file mode 100644
--- a/examples/passing/Generalization1.purs
+++ /dev/null
@@ -1,11 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (logShow, log)
-
-main = do
-  logShow (sum 1.0 2.0)
-  logShow (sum 1 2)
-  log "Done"
-
-sum x y = x + y
diff --git a/examples/passing/GenericsRep.purs b/examples/passing/GenericsRep.purs
deleted file mode 100644
--- a/examples/passing/GenericsRep.purs
+++ /dev/null
@@ -1,63 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff (Eff)
-import Control.Monad.Eff.Console (CONSOLE, log, logShow)
-import Data.Generic.Rep (class Generic)
-import Data.Generic.Rep.Eq (genericEq)
-
-data X a = X a 
-	 
-derive instance genericX :: Generic (X a) _
-
-instance eqX :: Eq a => Eq (X a) where
-  eq xs ys = genericEq xs ys
-
-data Y a = Y | Z a (Y a)
-
-derive instance genericY :: Generic (Y a) _
-
-instance eqY :: Eq a => Eq (Y a) where
-  eq xs ys = genericEq xs ys
-
-data Z
-
-derive instance genericZ :: Generic Z _
-
-instance eqZ :: Eq Z where
-  eq x y = genericEq x y
-
-type MyString = String
-
-newtype W = W { x :: Int, y :: MyString }
-
-derive instance genericW :: Generic W _
-
-instance eqW :: Eq W where
-  eq x y = genericEq x y
-
-data V = V { x :: Int } { x :: Int }
- 
-derive instance genericV :: Generic V _
-
-instance eqV :: Eq V where
-  eq x y = genericEq x y
-
-newtype U = U {}
-
-derive instance genericU :: Generic U _
-
-instance eqU :: Eq U where
-  eq x y = genericEq x y
-
-main :: Eff (console :: CONSOLE) Unit
-main = do
-  logShow (X 0 == X 1)
-  logShow (X 1 == X 1)
-  logShow (Z 1 Y == Z 1 Y)
-  logShow (Z 1 Y == Y)
-  logShow (Y == Y :: Y Z)
-  logShow (W { x: 0, y: "A" } == W { x: 0, y: "A" })
-  logShow (V { x: 0 } { x: 0 } == V { x: 0 } { x: 0 })
-  logShow (U {} == U {})
-  log "Done"
diff --git a/examples/passing/Guards.purs b/examples/passing/Guards.purs
deleted file mode 100644
--- a/examples/passing/Guards.purs
+++ /dev/null
@@ -1,64 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-collatz = \x -> case x of
-  y | y `mod` 2.0 == 0.0 -> y / 2.0
-  y -> y * 3.0 + 1.0
-
--- Guards have access to current scope
-collatz2 = \x y -> case x of
-  z | y > 0.0 -> z / 2.0
-  z -> z * 3.0 + 1.0
-
-min :: forall a. Ord a => a -> a -> a
-min n m | n < m     = n
-        | otherwise = m
-
-max :: forall a. Ord a => a -> a -> a
-max n m = case unit of
-  _ | m < n     -> n
-    | otherwise -> m
-
-testIndentation :: Number -> Number -> Number
-testIndentation x y | x > 0.0
-  = x + y
-                    | otherwise
-  = y - x
-
--- pattern guard example with two clauses
-clunky1 :: Int -> Int -> Int
-clunky1 a b | x <- max a b
-            , x > 5
-            = x
-clunky1 a _ = a
-
-clunky2 :: Int -> Int -> Int
-clunky2 a b | x <- max a b
-            , x > 5
-            = x
-            | otherwise
-            = a + b
-
--- pattern guards on case epxressions
-clunky_case1 :: Int -> Int -> Int
-clunky_case1 a b =
-  case unit of
-    unit | x <- max a b
-         , x > 5
-         -> x
-         | otherwise -> a + b
-
--- test indentation
-clunky_case2 :: Int -> Int -> Int
-clunky_case2 a b =
-  case unit of
-    unit
-      | x <- max a b
-      , x > 5
-      -> x
-      | otherwise
-      -> a + b
-
-main = log $ min "Done" "ZZZZ"
diff --git a/examples/passing/HasOwnProperty.purs b/examples/passing/HasOwnProperty.purs
deleted file mode 100644
--- a/examples/passing/HasOwnProperty.purs
+++ /dev/null
@@ -1,5 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console (log)
-
-main = log ({hasOwnProperty: "Hi"} {hasOwnProperty = "Done"}).hasOwnProperty
diff --git a/examples/passing/HoistError.purs b/examples/passing/HoistError.purs
deleted file mode 100644
--- a/examples/passing/HoistError.purs
+++ /dev/null
@@ -1,12 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff
-import Control.Monad.Eff.Console
-import Test.Assert
-
-main = do
-  let x = 0.0
-  assert $ x == 0.0
-  let x = 1.0 + 1.0
-  log "Done"
diff --git a/examples/passing/IfThenElseMaybe.purs b/examples/passing/IfThenElseMaybe.purs
deleted file mode 100644
--- a/examples/passing/IfThenElseMaybe.purs
+++ /dev/null
@@ -1,12 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-data Maybe a = Nothing | Just a
-
-test1 = if true then Just 10 else Nothing
-
-test2 = if true then Nothing else Just 10
-
-main = log "Done"
diff --git a/examples/passing/IfWildcard.purs b/examples/passing/IfWildcard.purs
deleted file mode 100644
--- a/examples/passing/IfWildcard.purs
+++ /dev/null
@@ -1,19 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff (Eff)
-import Control.Monad.Eff.Console (log, CONSOLE)
-
-data Foo = X | Y
-
-cond ∷ ∀ a. Boolean → a → a → a
-cond = if _ then _ else _
-
-what ∷ Boolean → Foo
-what = if _ then X else Y
-
-main :: forall e. Eff (console :: CONSOLE | e) Unit
-main = do
-  let tmp1 = what true
-      tmp2 = cond true 0 1
-  log "Done"
diff --git a/examples/passing/ImplicitEmptyImport.purs b/examples/passing/ImplicitEmptyImport.purs
deleted file mode 100644
--- a/examples/passing/ImplicitEmptyImport.purs
+++ /dev/null
@@ -1,9 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-main = do
-  log "Hello"
-  log "Goodbye"
-  log "Done"
diff --git a/examples/passing/Import.purs b/examples/passing/Import.purs
deleted file mode 100644
--- a/examples/passing/Import.purs
+++ /dev/null
@@ -1,6 +0,0 @@
-module Main where
-
-import M2
-import Control.Monad.Eff.Console (log)
-
-main = log "Done"
diff --git a/examples/passing/Import/M1.purs b/examples/passing/Import/M1.purs
deleted file mode 100644
--- a/examples/passing/Import/M1.purs
+++ /dev/null
@@ -1,8 +0,0 @@
-module M1 where
-
-import Prelude ()
-
-id :: forall a. a -> a
-id = \x -> x
-
-foo = id
diff --git a/examples/passing/Import/M2.purs b/examples/passing/Import/M2.purs
deleted file mode 100644
--- a/examples/passing/Import/M2.purs
+++ /dev/null
@@ -1,6 +0,0 @@
-module M2 where
-
-import Prelude ()
-import M1
-
-main = \_ -> foo 42
diff --git a/examples/passing/ImportExplicit.purs b/examples/passing/ImportExplicit.purs
deleted file mode 100644
--- a/examples/passing/ImportExplicit.purs
+++ /dev/null
@@ -1,10 +0,0 @@
-module Main where
-
-import M1 (X(..))
-import Control.Monad.Eff.Console (log)
-
-testX :: X
-testX = X
-testY = Y
-
-main = log "Done"
diff --git a/examples/passing/ImportExplicit/M1.purs b/examples/passing/ImportExplicit/M1.purs
deleted file mode 100644
--- a/examples/passing/ImportExplicit/M1.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module M1 where
-
-data X = X | Y
-data Z = Z
diff --git a/examples/passing/ImportHiding.purs b/examples/passing/ImportHiding.purs
deleted file mode 100644
--- a/examples/passing/ImportHiding.purs
+++ /dev/null
@@ -1,19 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console
-import Prelude hiding (
-  show, -- a value
-  class Show, -- a type class
-  Unit(..)  -- a constructor
-  )
-
-show = 1.0
-
-class Show a where
-  noshow :: a -> a
-
-data Unit = X | Y
-
-main = do
-  logShow show
-  log "Done"
diff --git a/examples/passing/ImportQualified.purs b/examples/passing/ImportQualified.purs
deleted file mode 100644
--- a/examples/passing/ImportQualified.purs
+++ /dev/null
@@ -1,8 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff
-import M1
-import Control.Monad.Eff.Console as C
-
-main = C.log (log "Done")
diff --git a/examples/passing/ImportQualified/M1.purs b/examples/passing/ImportQualified/M1.purs
deleted file mode 100644
--- a/examples/passing/ImportQualified/M1.purs
+++ /dev/null
@@ -1,3 +0,0 @@
-module M1 where
-
-log x = x
diff --git a/examples/passing/InferRecFunWithConstrainedArgument.purs b/examples/passing/InferRecFunWithConstrainedArgument.purs
deleted file mode 100644
--- a/examples/passing/InferRecFunWithConstrainedArgument.purs
+++ /dev/null
@@ -1,11 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log, logShow)
-
-test 100 = 100
-test n = test(1 + n)
-
-main = do
-  logShow (test 0)
-  log "Done"
diff --git a/examples/passing/InstanceBeforeClass.purs b/examples/passing/InstanceBeforeClass.purs
deleted file mode 100644
--- a/examples/passing/InstanceBeforeClass.purs
+++ /dev/null
@@ -1,12 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-instance fooNumber :: Foo Number where
-  foo = 0.0
-
-class Foo a where
-  foo :: a
-
-main = log "Done"
diff --git a/examples/passing/InstanceSigs.purs b/examples/passing/InstanceSigs.purs
deleted file mode 100644
--- a/examples/passing/InstanceSigs.purs
+++ /dev/null
@@ -1,12 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console (log)
-
-class Foo a where
-  foo :: a
-
-instance fooNumber :: Foo Number where
-  foo :: Number
-  foo = 0.0
-
-main = log "Done"
diff --git a/examples/passing/InstanceSigsGeneral.purs b/examples/passing/InstanceSigsGeneral.purs
deleted file mode 100644
--- a/examples/passing/InstanceSigsGeneral.purs
+++ /dev/null
@@ -1,12 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console (log)
-
-class Eq a where
-  eq :: a -> a -> Boolean
-
-instance eqNumber :: Eq Number where
-  eq :: forall x y. x -> y -> Boolean
-  eq _ _ = true
-
-main = log "Done"
diff --git a/examples/passing/IntAndChar.purs b/examples/passing/IntAndChar.purs
deleted file mode 100644
--- a/examples/passing/IntAndChar.purs
+++ /dev/null
@@ -1,19 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff
-import Control.Monad.Eff.Console (log)
-import Test.Assert
-
-f 1 = 1
-f _ = 0
-
-g 'a' = 'a'
-g _ = 'b'
-
-main = do
-  assert $ f 1 == 1
-  assert $ f 0 == 0
-  assert $ g 'a' == 'a'
-  assert $ g 'b' == 'b'
-  log "Done"
diff --git a/examples/passing/JSReserved.purs b/examples/passing/JSReserved.purs
deleted file mode 100644
--- a/examples/passing/JSReserved.purs
+++ /dev/null
@@ -1,13 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-yield = 0
-member = 1
-
-public = \return -> return
-
-this catch = catch
-
-main = log "Done"
diff --git a/examples/passing/KindedType.purs b/examples/passing/KindedType.purs
deleted file mode 100644
--- a/examples/passing/KindedType.purs
+++ /dev/null
@@ -1,34 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-type Star2Star f = f :: Type -> Type
-
-type Star t = t :: Type
-
-test1 :: Star2Star Array String
-test1 = ["test"]
-
-f :: Star (String -> String)
-f s = s
-
-test2 = f "test"
-
-data Proxy (f :: Type -> Type) = Proxy
-
-test3 :: Proxy Array
-test3 = Proxy
-
-type Test (f :: Type -> Type) = f String
-
-test4 :: Test Array
-test4 = ["test"]
-
-class Clazz (a :: Type) where
-  def :: a
-
-instance clazzString :: Clazz String where
-  def = "test"
-
-main = log "Done"
diff --git a/examples/passing/LargeSumType.purs b/examples/passing/LargeSumType.purs
deleted file mode 100644
--- a/examples/passing/LargeSumType.purs
+++ /dev/null
@@ -1,35 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console (log)
-
-data Large = A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z
-
-explode A A = "A"
-explode B B = "B"
-explode C C = "C"
-explode D D = "D"
-explode E E = "E"
-explode F F = "F"
-explode G G = "G"
-explode H H = "H"
-explode I I = "I"
-explode J J = "J"
-explode K K = "K"
-explode L L = "L"
-explode M M = "M"
-explode N N = "N"
-explode O O = "O"
-explode P P = "P"
-explode Q Q = "Q"
-explode R R = "R"
-explode S S = "S"
-explode T T = "T"
-explode U U = "U"
-explode V V = "V"
-explode W W = "W"
-explode X X = "X"
-explode Y Y = "Y"
-explode Z Z = "Z"
-explode _ _ = ""
-
-main = log "Done"
diff --git a/examples/passing/Let.purs b/examples/passing/Let.purs
deleted file mode 100644
--- a/examples/passing/Let.purs
+++ /dev/null
@@ -1,58 +0,0 @@
-module Main where
-
-import Prelude
-import Partial.Unsafe (unsafePartial)
-import Control.Monad.Eff
-import Control.Monad.Eff.Console (log, logShow)
-import Control.Monad.ST
-
-test1 x = let
-            y :: Number
-            y = x + 1.0
-          in y
-
-test2 x y =
-  let x' = x + 1.0 in
-  let y' = y + 1.0 in
-  x' + y'
-
-test3 = let f x y z = x + y + z in
-        f 1.0 2.0 3.0
-
-test4 = let
-          f x [y, z] = x y z
-        in f (+) [1.0, 2.0]
-
-test5 = let
-          f x | x > 0.0 = g (x / 2.0) + 1.0
-          f x = 0.0
-          g x = f (x - 1.0) + 1.0
-        in f 10.0
-
-test7 = let
-          f :: forall a. a -> a
-          f x = x
-        in if f true then f 1.0 else f 2.0
-
-test8 :: Number -> Number
-test8 x = let
-            go y | (x - 0.1 < y * y) && (y * y < x + 0.1) = y
-            go y = go $ (y + x / y) / 2.0
-          in go x
-
-test10 _ =
-  let
-    f x = g x * 3.0
-    g x = f x / 2.0
-  in f 10.0
-
-main :: Eff _ _
-main = do
-  logShow (test1 1.0)
-  logShow (test2 1.0 2.0)
-  logShow test3
-  unsafePartial (logShow test4)
-  logShow test5
-  logShow test7
-  logShow (test8 100.0)
-  log "Done"
diff --git a/examples/passing/Let2.purs b/examples/passing/Let2.purs
deleted file mode 100644
--- a/examples/passing/Let2.purs
+++ /dev/null
@@ -1,20 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log, logShow)
-
-test =
-  let f :: Number -> Boolean
-      f 0.0 = false
-      f n = g (n - 1.0)
-
-      g :: Number -> Boolean
-      g 0.0 = true
-      g n = f (n - 1.0)
-
-      x = f 1.0
-  in not x
-
-main = do
-  logShow test
-  log "Done"
diff --git a/examples/passing/LetInInstance.purs b/examples/passing/LetInInstance.purs
deleted file mode 100644
--- a/examples/passing/LetInInstance.purs
+++ /dev/null
@@ -1,15 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-class Foo a where
-  foo :: a -> String
-
-instance fooString :: Foo String where
-  foo = go
-    where
-    go :: String -> String
-    go s = s
-
-main = log "Done"
diff --git a/examples/passing/LetPattern.purs b/examples/passing/LetPattern.purs
deleted file mode 100644
--- a/examples/passing/LetPattern.purs
+++ /dev/null
@@ -1,196 +0,0 @@
-module Main where
-
-import Prelude
-import Partial.Unsafe (unsafePartial)
-import Control.Monad.Eff (Eff)
-import Control.Monad.Eff.Console (CONSOLE, log)
-import Test.Assert (ASSERT, assert')
-
-patternSimple :: Boolean
-patternSimple =
-  let x = 25252
-  in
-   x == 25252
-
-patternDoSimple :: forall e. Eff e Boolean
-patternDoSimple = do
-  let x = 25252
-  pure $ x == 25252
-
-newtype X = X Int
-
-patternNewtype :: Boolean
-patternNewtype =
-  let X a = X 123
-  in
-   a == 123
-
-patternDoNewtype :: forall e. Eff e Boolean
-patternDoNewtype = do
-  let X a = X 123
-  pure $ a == 123
-
-data Y = Y Int String Boolean
-
-patternData :: Boolean
-patternData =
-  let Y a b c = Y 456 "hello, world" false
-  in
-   a == 456 && b == "hello, world" && not c
-
-patternDataIgnored :: Boolean
-patternDataIgnored =
-  let Y _ x _ = Y 789 "world, hello" true
-  in
-   x == "world, hello"
-
-patternDoData :: forall e. Eff e Boolean
-patternDoData = do
-  let Y a b c = Y 456 "hello, world" false
-  pure $ a == 456 && b == "hello, world" && not c
-
-patternDoDataIgnored :: forall e. Eff e Boolean
-patternDoDataIgnored = do
-  let Y _ x _ = Y 789 "world, hello" true
-  pure $ x == "world, hello"
-
-patternArray :: Boolean
-patternArray = unsafePartial $
-  let [a, b] = [1, 2]
-  in
-   a == 1 && b == 2
-
-patternDoArray :: forall e. Eff e Boolean
-patternDoArray = unsafePartial do
-  let [a, b] = [1, 2]
-  pure $ a == 1 && b == 2
-
-patternMultiple :: Boolean
-patternMultiple = unsafePartial $
-  let
-    x = 25252
-    X a = X x
-    Y b c d = Y x "hello, world" false
-    Y _ e _ = Y 789 "world, hello" true
-    [f, g] = [1, 2]
-  in
-   x == 25252 && a == 25252 && b == 25252 && c == "hello, world" &&
-     not d && e == "world, hello" && f == 1 && g == 2
-
-patternDoMultiple :: forall e. Eff e Boolean
-patternDoMultiple = unsafePartial do
-  let
-    x = 25252
-    X a = X x
-    Y b c d = Y x "hello, world" false
-    Y _ e _ = Y 789 "world, hello" true
-    [f, g] = [1, 2]
-  pure $ x == 25252 && a == 25252 && b == 25252 && c == "hello, world" &&
-     not d && e == "world, hello" && f == 1 && g == 2
-
-patternMultipleWithNormal :: Boolean
-patternMultipleWithNormal = unsafePartial $
-  let
-    x = 25252
-    X a = X x
-    y = 2525
-    Y b c d = Y y "hello, world" false
-  in
-   x == 25252 && y == 2525 &&
-     a == 25252 && b == 2525 && c == "hello, world" && not d
-
-patternDoMultipleWithNormal :: forall e. Eff e Boolean
-patternDoMultipleWithNormal = unsafePartial do
-  let
-    x = 25252
-    X a = X x
-    y = 2525
-    Y b c d = Y y "hello, world" false
-  pure $ x == 25252 && y == 2525 &&
-    a == 25252 && b == 2525 && c == "hello, world" && not d
-
-patternWithParens :: Boolean
-patternWithParens = unsafePartial $
-  let
-    (x) = 25252
-    (X a) = X x
-    (Y b c d) = Y x "hello, world" false
-    (Y _ e _) = Y 789 "world, hello" true
-    ([f, g]) = [1, 2]
-  in
-   x == 25252 && a == 25252 && b == 25252 && c == "hello, world" &&
-     not d && e == "world, hello" && f == 1 && g == 2
-
-patternDoWithParens :: forall e. Eff e Boolean
-patternDoWithParens = unsafePartial do
-  let
-    (x) = 25252
-    (X a) = X x
-    (Y b c d) = Y x "hello, world" false
-    (Y _ e _) = Y 789 "world, hello" true
-    ([f, g]) = [1, 2]
-  pure $ x == 25252 && a == 25252 && b == 25252 && c == "hello, world" &&
-     not d && e == "world, hello" && f == 1 && g == 2
-
-patternWithNamedBinder :: Boolean
-patternWithNamedBinder = unsafePartial $
-  let
-    a@{x, y} = {x: 10, y: 20}
-  in
-   a.x == 10 && x == 10 && a.y == 20 && y == 20
-
-patternDoWithNamedBinder :: forall e. Eff e Boolean
-patternDoWithNamedBinder = unsafePartial do
-  let
-    a@{x, y} = {x: 10, y: 20}
-  pure $
-    a.x == 10 && x == 10 && a.y == 20 && y == 20
-
-data List a = Nil | Cons a (List a)
-infixr 6 Cons as :
-
-instance eqList :: Eq a => Eq (List a) where
-  eq xs ys = go xs ys true
-    where
-      go _ _ false = false
-      go Nil Nil acc = acc
-      go (x : xs') (y : ys') acc = go xs' ys' $ acc && (y == x)
-      go _ _ _ = false
-
-patternWithInfixOp :: Boolean
-patternWithInfixOp = unsafePartial $
-  let
-    x : xs = 1 : 2 : 3 : 4 : Nil
-  in
-   x == 1 && xs == 2 : 3 : 4 : Nil
-
-patternDoWithInfixOp :: forall e. Eff e Boolean
-patternDoWithInfixOp = unsafePartial do
-  let
-    x : xs = 1 : 2 : 3 : 4 : Nil
-  pure $
-    x == 1 && xs == 2 : 3 : 4 : Nil
-
-main :: Eff (assert :: ASSERT, console :: CONSOLE) Unit
-main = do
-  assert' "simple variable pattern" patternSimple
-  assert' "simple variable pattern with do" =<< patternDoSimple
-  assert' "constructor pattern (newtype)" patternNewtype
-  assert' "constructor pattern (newtype) with do" =<< patternDoNewtype
-  assert' "constructor pattern (data)" patternData
-  assert' "constructor pattern with ignorances" patternDataIgnored
-  assert' "constructor pattern (data) with do" =<< patternDoData
-  assert' "constructor pattern with ignorances and do" =<< patternDoDataIgnored
-  assert' "array pattern" patternArray
-  assert' "array pattern with do" =<< patternDoArray
-  assert' "multiple patterns" patternMultiple
-  assert' "multiple patterns with do" =<< patternDoMultiple
-  assert' "multiple patterns with normal let's" patternMultipleWithNormal
-  assert' "multiple patterns with normal let's and do" =<< patternDoMultipleWithNormal
-  assert' "multiple patterns with parens" patternWithParens
-  assert' "multiple patterns with parens and do" =<< patternDoWithParens
-  assert' "multiple patterns with named binder" patternWithNamedBinder
-  assert' "multiple patterns with named binder and do" =<< patternDoWithNamedBinder
-  assert' "pattern with infix operator" patternWithInfixOp
-  assert' "pattern with infix operator and do" =<< patternDoWithInfixOp
-  log "Done"
diff --git a/examples/passing/LiberalTypeSynonyms.purs b/examples/passing/LiberalTypeSynonyms.purs
deleted file mode 100644
--- a/examples/passing/LiberalTypeSynonyms.purs
+++ /dev/null
@@ -1,22 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-type Reader = (->) String
-
-foo :: Reader String
-foo s = s
-
-type AndFoo r = (foo :: String | r)
-
-getFoo :: forall r. Prim.Record (AndFoo r) -> String
-getFoo o = o.foo
-
-type F r = { | r } -> { | r }
-
-f :: (forall r. F r) -> String
-f g = case g { x: "Hello" } of
-        { x: x } -> x
-
-main = log "Done"
diff --git a/examples/passing/MPTCs.purs b/examples/passing/MPTCs.purs
deleted file mode 100644
--- a/examples/passing/MPTCs.purs
+++ /dev/null
@@ -1,21 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-class NullaryTypeClass where
-  greeting :: String
-
-instance nullaryTypeClass :: NullaryTypeClass where
-  greeting = "Hello, World!"
-
-class Coerce a b where
-  coerce :: a -> b
-
-instance coerceRefl :: Coerce a a where
-  coerce a = a
-
-instance coerceShow :: Show a => Coerce a String where
-  coerce = show
-
-main = log "Done"
diff --git a/examples/passing/Match.purs b/examples/passing/Match.purs
deleted file mode 100644
--- a/examples/passing/Match.purs
+++ /dev/null
@@ -1,10 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-data Foo a = Foo
-
-foo = \f -> case f of Foo -> "foo"
-
-main = log "Done"
diff --git a/examples/passing/Module.purs b/examples/passing/Module.purs
deleted file mode 100644
--- a/examples/passing/Module.purs
+++ /dev/null
@@ -1,7 +0,0 @@
-module Main where
-
-import M1
-import M2
-import Control.Monad.Eff.Console (log)
-
-main = log "Done"
diff --git a/examples/passing/Module/M1.purs b/examples/passing/Module/M1.purs
deleted file mode 100644
--- a/examples/passing/Module/M1.purs
+++ /dev/null
@@ -1,14 +0,0 @@
-module M1 where
-
-import Prelude
-
-data Foo = Foo String
-
-foo :: Foo -> String
-foo = \f -> case f of Foo s -> s <> "foo"
-
-bar :: Foo -> String
-bar = foo
-
-incr :: Int -> Int
-incr x = x + 1
diff --git a/examples/passing/Module/M2.purs b/examples/passing/Module/M2.purs
deleted file mode 100644
--- a/examples/passing/Module/M2.purs
+++ /dev/null
@@ -1,10 +0,0 @@
-module M2 where
-
-import Prelude
-import M1 as M1
-
-baz :: M1.Foo -> String
-baz = M1.foo
-
-match :: M1.Foo -> String
-match = \f -> case f of M1.Foo s -> s <> "foo"
diff --git a/examples/passing/ModuleDeps.purs b/examples/passing/ModuleDeps.purs
deleted file mode 100644
--- a/examples/passing/ModuleDeps.purs
+++ /dev/null
@@ -1,6 +0,0 @@
-module Main where
-
-import M1
-import Control.Monad.Eff.Console (log)
-
-main = log "Done"
diff --git a/examples/passing/ModuleDeps/M1.purs b/examples/passing/ModuleDeps/M1.purs
deleted file mode 100644
--- a/examples/passing/ModuleDeps/M1.purs
+++ /dev/null
@@ -1,5 +0,0 @@
-module M1 where
-
-import M2 as M2
-
-foo = M2.bar
diff --git a/examples/passing/ModuleDeps/M2.purs b/examples/passing/ModuleDeps/M2.purs
deleted file mode 100644
--- a/examples/passing/ModuleDeps/M2.purs
+++ /dev/null
@@ -1,5 +0,0 @@
-module M2 where
-
-import M3 as M3
-
-bar = M3.baz
diff --git a/examples/passing/ModuleDeps/M3.purs b/examples/passing/ModuleDeps/M3.purs
deleted file mode 100644
--- a/examples/passing/ModuleDeps/M3.purs
+++ /dev/null
@@ -1,3 +0,0 @@
-module M3 where
-
-baz = 1
diff --git a/examples/passing/ModuleExport.purs b/examples/passing/ModuleExport.purs
deleted file mode 100644
--- a/examples/passing/ModuleExport.purs
+++ /dev/null
@@ -1,8 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console (log, logShow)
-import A
-
-main = do
-  logShow (show 1.0)
-  log "Done"
diff --git a/examples/passing/ModuleExport/A.purs b/examples/passing/ModuleExport/A.purs
deleted file mode 100644
--- a/examples/passing/ModuleExport/A.purs
+++ /dev/null
@@ -1,3 +0,0 @@
-module A (module Prelude) where
-
-import Prelude
diff --git a/examples/passing/ModuleExportDupes.purs b/examples/passing/ModuleExportDupes.purs
deleted file mode 100644
--- a/examples/passing/ModuleExportDupes.purs
+++ /dev/null
@@ -1,11 +0,0 @@
-module Main where
-
-  import Control.Monad.Eff.Console
-  import A
-  import B
-  import C
-  import Prelude
-
-  main = do
-    logShow (show 1.0)
-    log "Done"
diff --git a/examples/passing/ModuleExportDupes/A.purs b/examples/passing/ModuleExportDupes/A.purs
deleted file mode 100644
--- a/examples/passing/ModuleExportDupes/A.purs
+++ /dev/null
@@ -1,3 +0,0 @@
-module A (module Prelude) where
-
-import Prelude
diff --git a/examples/passing/ModuleExportDupes/B.purs b/examples/passing/ModuleExportDupes/B.purs
deleted file mode 100644
--- a/examples/passing/ModuleExportDupes/B.purs
+++ /dev/null
@@ -1,3 +0,0 @@
-module B (module Prelude) where
-
-import Prelude
diff --git a/examples/passing/ModuleExportDupes/C.purs b/examples/passing/ModuleExportDupes/C.purs
deleted file mode 100644
--- a/examples/passing/ModuleExportDupes/C.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module C (module Prelude, module A) where
-
-import Prelude
-import A
diff --git a/examples/passing/ModuleExportExcluded.purs b/examples/passing/ModuleExportExcluded.purs
deleted file mode 100644
--- a/examples/passing/ModuleExportExcluded.purs
+++ /dev/null
@@ -1,11 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log, logShow)
-import A (foo)
-
-otherwise = false
-
-main = do
-  logShow "1.0"
-  log "Done"
diff --git a/examples/passing/ModuleExportExcluded/A.purs b/examples/passing/ModuleExportExcluded/A.purs
deleted file mode 100644
--- a/examples/passing/ModuleExportExcluded/A.purs
+++ /dev/null
@@ -1,6 +0,0 @@
-module A (module Prelude, foo) where
-
-import Prelude
-
-foo :: Number -> Number
-foo _ = 0.0
diff --git a/examples/passing/ModuleExportQualified.purs b/examples/passing/ModuleExportQualified.purs
deleted file mode 100644
--- a/examples/passing/ModuleExportQualified.purs
+++ /dev/null
@@ -1,9 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log, logShow)
-import A as B
-
-main = do
-  logShow (B.show 1.0)
-  log "Done"
diff --git a/examples/passing/ModuleExportQualified/A.purs b/examples/passing/ModuleExportQualified/A.purs
deleted file mode 100644
--- a/examples/passing/ModuleExportQualified/A.purs
+++ /dev/null
@@ -1,3 +0,0 @@
-module A (module Prelude) where
-
-import Prelude
diff --git a/examples/passing/ModuleExportSelf.purs b/examples/passing/ModuleExportSelf.purs
deleted file mode 100644
--- a/examples/passing/ModuleExportSelf.purs
+++ /dev/null
@@ -1,11 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console
-import A
-
-bar :: Foo
-bar = true
-
-main = do
-  logShow (show bar)
-  log "Done"
diff --git a/examples/passing/ModuleExportSelf/A.purs b/examples/passing/ModuleExportSelf/A.purs
deleted file mode 100644
--- a/examples/passing/ModuleExportSelf/A.purs
+++ /dev/null
@@ -1,5 +0,0 @@
-module A (module A, module Prelude) where
-
-import Prelude
-
-type Foo = Boolean
diff --git a/examples/passing/Monad.purs b/examples/passing/Monad.purs
deleted file mode 100644
--- a/examples/passing/Monad.purs
+++ /dev/null
@@ -1,32 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console (log)
-
-type Monad m = { return :: forall a. a -> m a
-	 , bind :: forall a b. m a -> (a -> m b) -> m b }
-
-data Id a = Id a
-
-id :: Monad Id
-id = { return : Id
-     , bind : \ma f -> case ma of Id a -> f a }
-
-data Maybe a = Nothing | Just a
-
-maybe :: Monad Maybe
-maybe = { return : Just
-  , bind : \ma f -> case ma of
-      Nothing -> Nothing
-      Just a -> f a
-  }
-
-test :: forall m. Monad m -> m Number
-test = \m -> m.bind (m.return 1.0) (\n1 ->
-	 m.bind (m.return "Test") (\n2 ->
-	   m.return n1))
-
-test1 = test id
-
-test2 = test maybe
-
-main = log "Done"
diff --git a/examples/passing/MonadState.purs b/examples/passing/MonadState.purs
deleted file mode 100644
--- a/examples/passing/MonadState.purs
+++ /dev/null
@@ -1,63 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console
-
-data Tuple a b = Tuple a b
-
-instance showTuple :: (Show a, Show b) => Show (Tuple a b) where
-  show (Tuple a b) = "(" <> show a <> ", " <> show b <> ")"
-
-class Monad m <= MonadState s m where
-  get :: m s
-  put :: s -> m Unit
-
-data State s a = State (s -> Tuple s a)
-
-runState s (State f) = f s
-
-instance functorState :: Functor (State s) where
-  map = liftM1
-
-instance applyState :: Apply (State s) where
-  apply = ap
-
-instance applicativeState :: Applicative (State s) where
-  pure a = State $ \s -> Tuple s a
-
-instance bindState :: Bind (State s) where
-  bind f g = State $ \s -> case runState s f of
-                              Tuple s1 a -> runState s1 (g a)
-
-instance monadState :: Monad (State s)
-
-instance monadStateState :: MonadState s (State s) where
-  get = State (\s -> Tuple s s)
-  put s = State (\_ -> Tuple s unit)
-
--- Without the call to same, the following strange (but correct, in the absence of
--- functional dependencies) type:
---
--- forall m t1 t2.
--- ( Bind m
--- , MonadState t1 m
--- , MonadState t2 m
--- ) => (t1 -> t2) -> m Unit
---
--- With the type hint, the inferred type is more sensible:
---
--- forall m t.
--- ( Bind m
--- , MonadState t m
--- ) => (t -> t) -> m Unit
-modify f =
-  do
-    s <- get
-    put (same f s)
-  where
-    same :: forall a. (a -> a) -> (a -> a)
-    same = id
-
-main = do
-  logShow $ runState 0 (modify (_ + 1))
-  log "Done"
diff --git a/examples/passing/MultiArgFunctions.purs b/examples/passing/MultiArgFunctions.purs
deleted file mode 100644
--- a/examples/passing/MultiArgFunctions.purs
+++ /dev/null
@@ -1,27 +0,0 @@
-module Main where
-
-import Prelude
-import Data.Function.Uncurried
-import Control.Monad.Eff
-import Control.Monad.Eff.Console
-
-f = mkFn2 $ \a b -> runFn2 g a b + runFn2 g b a
-
-g = mkFn2 $ \a b -> case {} of
-  _ | a <= 0.0 || b <= 0.0 -> b
-  _ -> runFn2 f (a - 0.0) (b - 0.0)
-
-main = do
-  runFn0 (mkFn0 $ \_ -> log $ show 0.0)
-  runFn1 (mkFn1 $ \a -> log $ show a) 0.0
-  runFn2 (mkFn2 $ \a b -> log $ show [a, b]) 0.0 0.0
-  runFn3 (mkFn3 $ \a b c -> log $ show [a, b, c]) 0.0 0.0 0.0
-  runFn4 (mkFn4 $ \a b c d -> log $ show [a, b, c, d]) 0.0 0.0 0.0 0.0
-  runFn5 (mkFn5 $ \a b c d e -> log $ show [a, b, c, d, e]) 0.0 0.0 0.0 0.0 0.0
-  runFn6 (mkFn6 $ \a b c d e f -> log $ show [a, b, c, d, e, f]) 0.0 0.0 0.0 0.0 0.0 0.0
-  runFn7 (mkFn7 $ \a b c d e f g -> log $ show [a, b, c, d, e, f, g]) 0.0 0.0 0.0 0.0 0.0 0.0 0.0
-  runFn8 (mkFn8 $ \a b c d e f g h -> log $ show [a, b, c, d, e, f, g, h]) 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
-  runFn9 (mkFn9 $ \a b c d e f g h i -> log $ show [a, b, c, d, e, f, g, h, i]) 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
-  runFn10 (mkFn10 $ \a b c d e f g h i j-> log $ show [a, b, c, d, e, f, g, h, i, j]) 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
-  logShow $ runFn2 g 0.0 0.0
-  log "Done"
diff --git a/examples/passing/MutRec.purs b/examples/passing/MutRec.purs
deleted file mode 100644
--- a/examples/passing/MutRec.purs
+++ /dev/null
@@ -1,20 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-f 0.0 = 0.0
-f x = g x + 0.0
-
-g x = f (x / 0.0)
-
-data Even = Zero | Even Odd
-
-data Odd = Odd Even
-
-evenToNumber Zero = 0.0
-evenToNumber (Even n) = oddToNumber n + 0.0
-
-oddToNumber (Odd n) = evenToNumber n + 0.0
-
-main = log "Done"
diff --git a/examples/passing/MutRec2.purs b/examples/passing/MutRec2.purs
deleted file mode 100644
--- a/examples/passing/MutRec2.purs
+++ /dev/null
@@ -1,20 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-data A = A B
-
-data B = B A
-
-foreign import data S :: Type
-
-f :: A -> S
-f a = case a of A b -> g b
-
-g b = case b of B a -> f a
-
-showN :: A -> S
-showN a = f a
-
-main = log "Done"
diff --git a/examples/passing/MutRec3.purs b/examples/passing/MutRec3.purs
deleted file mode 100644
--- a/examples/passing/MutRec3.purs
+++ /dev/null
@@ -1,20 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-data A = A B
-
-data B = B A
-
-foreign import data S :: Type
-
-f a = case a of A b -> g b
-
-g :: B -> S
-g b = case b of B a -> f a
-
-showN :: A -> S
-showN a = f a
-
-main = log "Done"
diff --git a/examples/passing/NakedConstraint.purs b/examples/passing/NakedConstraint.purs
deleted file mode 100644
--- a/examples/passing/NakedConstraint.purs
+++ /dev/null
@@ -1,10 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console
-
-data List a = Nil | Cons a (List a)
-
-head :: Partial => List Int -> Int
-head (Cons x _) = x
-
-main = log "Done"
diff --git a/examples/passing/NamedPatterns.purs b/examples/passing/NamedPatterns.purs
deleted file mode 100644
--- a/examples/passing/NamedPatterns.purs
+++ /dev/null
@@ -1,10 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-foo = \x -> case x of
-  y@{ foo: "Foo" } -> y
-  y -> y
-
-main = log "Done"
diff --git a/examples/passing/NegativeBinder.purs b/examples/passing/NegativeBinder.purs
deleted file mode 100644
--- a/examples/passing/NegativeBinder.purs
+++ /dev/null
@@ -1,10 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-test :: Number -> Boolean
-test -1.0 = false
-test _  = true
-
-main = log "Done"
diff --git a/examples/passing/NegativeIntInRange.purs b/examples/passing/NegativeIntInRange.purs
deleted file mode 100644
--- a/examples/passing/NegativeIntInRange.purs
+++ /dev/null
@@ -1,9 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-n :: Int
-n = -2147483648
-
-main = log "Done"
diff --git a/examples/passing/Nested.purs b/examples/passing/Nested.purs
deleted file mode 100644
--- a/examples/passing/Nested.purs
+++ /dev/null
@@ -1,10 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-data Extend r a = Extend { prev :: r a, next :: a }
-
-data Matrix r a = Square (r (r a)) | Bigger (Matrix (Extend r) a)
-
-main = log "Done"
diff --git a/examples/passing/NestedRecordUpdate.purs b/examples/passing/NestedRecordUpdate.purs
deleted file mode 100644
--- a/examples/passing/NestedRecordUpdate.purs
+++ /dev/null
@@ -1,24 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console
-
-type T = { foo :: Int, bar :: { baz :: Int, qux :: { lhs :: Int, rhs :: Int } } }
-
-init :: T
-init = { foo: 1, bar: { baz: 2, qux: { lhs: 3, rhs: 4 } } }
-
-updated :: T
-updated = init { foo = 10, bar { baz = 20, qux { lhs = 30, rhs = 40 } } }
-
-expected :: T
-expected = { foo: 10, bar: { baz: 20, qux: { lhs: 30, rhs: 40 } } }
-
-check l r =
-  l.foo == r.foo &&
-  l.bar.baz == r.bar.baz &&
-  l.bar.qux.lhs == r.bar.qux.lhs &&
-  l.bar.qux.rhs == r.bar.qux.rhs
-
-main = do
-  when (check updated expected) $ log "Done"
diff --git a/examples/passing/NestedRecordUpdateWildcards.purs b/examples/passing/NestedRecordUpdateWildcards.purs
deleted file mode 100644
--- a/examples/passing/NestedRecordUpdateWildcards.purs
+++ /dev/null
@@ -1,20 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console
-
-update = _ { foo = _, bar { baz = _, qux = _ } }
-
-init = { foo: 1, bar: { baz: 2, qux: 3 } }
-
-after = update init 10 20 30
-
-expected = { foo: 10, bar: { baz: 20, qux: 30 } }
-
-check l r =
-  l.foo == r.foo &&
-  l.bar.baz == r.bar.baz &&
-  l.bar.qux == r.bar.qux
-
-main = do
-  when (check after expected) $ log "Done"
diff --git a/examples/passing/NestedTypeSynonyms.purs b/examples/passing/NestedTypeSynonyms.purs
deleted file mode 100644
--- a/examples/passing/NestedTypeSynonyms.purs
+++ /dev/null
@@ -1,12 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-type X = String
-type Y = X -> X
-
-fn :: Y
-fn a = a
-
-main = log (fn "Done")
diff --git a/examples/passing/NestedWhere.purs b/examples/passing/NestedWhere.purs
deleted file mode 100644
--- a/examples/passing/NestedWhere.purs
+++ /dev/null
@@ -1,13 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-f x = g x
-  where
-  g x = go x
-    where
-    go x = go1 (x - 1.0)
-    go1 x = go x
-
-main = log "Done"
diff --git a/examples/passing/Newtype.purs b/examples/passing/Newtype.purs
deleted file mode 100644
--- a/examples/passing/Newtype.purs
+++ /dev/null
@@ -1,23 +0,0 @@
-module Main where
-
-import Prelude hiding (apply)
-import Control.Monad.Eff
-import Control.Monad.Eff.Console
-
-newtype Thing = Thing String
-
-instance showThing :: Show Thing where
-  show (Thing x) = "Thing " <> show x
-
-newtype Box a = Box a
-
-instance showBox :: (Show a) => Show (Box a) where
-  show (Box x) = "Box " <> show x
-
-apply f x = f x
-
-main = do
-  logShow $ Thing "hello"
-  logShow $ Box 42.0
-  logShow $ apply Box 9000.0
-  log "Done"
diff --git a/examples/passing/NewtypeClass.purs b/examples/passing/NewtypeClass.purs
deleted file mode 100644
--- a/examples/passing/NewtypeClass.purs
+++ /dev/null
@@ -1,40 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff
-import Control.Monad.Eff.Console
-
-class Newtype t a | t -> a where
-  wrap :: a -> t
-  unwrap :: t -> a
-
-instance newtypeMultiplicative :: Newtype (Multiplicative a) a where
-  wrap = Multiplicative
-  unwrap (Multiplicative a) = a
-
-data Multiplicative a = Multiplicative a
-
-instance semiringMultiplicative :: Semiring a => Semigroup (Multiplicative a) where
-  append (Multiplicative a) (Multiplicative b) = Multiplicative (a * b)
-
-data Pair a = Pair a a
-
-foldPair :: forall a s. Semigroup s => (a -> s) -> Pair a -> s
-foldPair f (Pair a b) = f a <> f b
-
-ala
-  :: forall f t a
-   . Functor f
-  => Newtype t a
-  => (a -> t)
-  -> ((a -> t) -> f t)
-  -> f a
-ala _ f = map unwrap (f wrap)
-
-test = ala Multiplicative foldPair
-
-test1 = ala Multiplicative foldPair (Pair 2 3)
-
-main = do
-  logShow (test (Pair 2 3))
-  log "Done"
diff --git a/examples/passing/NewtypeEff.purs b/examples/passing/NewtypeEff.purs
deleted file mode 100644
--- a/examples/passing/NewtypeEff.purs
+++ /dev/null
@@ -1,29 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console
-import Control.Monad.Eff
-
-newtype T a = T (Eff (console :: CONSOLE) a)
-
-runT :: forall a. T a -> Eff (console :: CONSOLE) a
-runT (T t) = t
-
-instance functorT :: Functor T where
-  map f (T t) = T (f <$> t)
-
-instance applyT :: Apply T where
-  apply (T f) (T x) = T (f <*> x)
-
-instance applicativeT :: Applicative T where
-  pure t = T (pure t)
-
-instance bindT :: Bind T where
-  bind (T t) f = T (t >>= \x -> runT (f x))
-
-instance monadT :: Monad T
-
-main = runT do
-  T $ log "Done"
-  T $ log "Done"
-  T $ log "Done"
diff --git a/examples/passing/NewtypeInstance.purs b/examples/passing/NewtypeInstance.purs
deleted file mode 100644
--- a/examples/passing/NewtypeInstance.purs
+++ /dev/null
@@ -1,57 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff
-import Control.Monad.Eff.Console
-import Data.Monoid
-import Data.Tuple
-
-type MyString = String 
-
-newtype X = X MyString
-
-derive newtype instance showX :: Show X
-derive newtype instance eqX :: Eq X
-derive newtype instance ordX :: Ord X
-
-newtype Y a = Y (Array a)
-
-derive newtype instance showY :: Show (Y String)
-
-class Singleton a b where
-  singleton :: a -> b
-
-instance singletonArray :: Singleton a (Array a) where
-  singleton x = [x]
-
-derive newtype instance singletonY :: Singleton a (Y a)
-
-newtype MyArray a = MyArray (Array a)
-
-derive newtype instance showMyArray :: Show a => Show (MyArray a)
-derive newtype instance functorMyArray :: Functor MyArray
-
-newtype ProxyArray x a = ProxyArray (Array a)
-
-derive newtype instance functorProxyArray :: Functor (ProxyArray x)
-
-class (Monad m, Monoid w) <= MonadWriter w m | m -> w where
-  tell :: w -> m Unit
-
-instance monadWriterTuple :: Monoid w => MonadWriter w (Tuple w) where
-  tell w = Tuple w unit
-
-newtype MyWriter w a = MyWriter (Tuple w a)
-
-derive newtype instance functorMyWriter :: Functor (MyWriter w)
-derive newtype instance applyMyWriter :: Semigroup w => Apply (MyWriter w)
-derive newtype instance applicativeMyWriter :: Monoid w => Applicative (MyWriter w)
-derive newtype instance bindMyWriter :: Semigroup w => Bind (MyWriter w)
-derive newtype instance monadMyWriter :: Monoid w => Monad (MyWriter w)
-derive newtype instance monadWriterMyWriter :: Monoid w => MonadWriter w (MyWriter w)
-
-main = do
-  logShow (X "test")
-  logShow (singleton "test" :: Y String)
-  logShow (map show (MyArray [1, 2, 3]))
-  log "Done"
diff --git a/examples/passing/NewtypeWithRecordUpdate.purs b/examples/passing/NewtypeWithRecordUpdate.purs
deleted file mode 100644
--- a/examples/passing/NewtypeWithRecordUpdate.purs
+++ /dev/null
@@ -1,16 +0,0 @@
--- https://github.com/purescript/purescript/issues/812.0
-
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console
-
-newtype NewType a = NewType (Record a)
-
-rec1 :: Record (a :: Number, b :: Number, c:: Number)
-rec1 = { a: 0.0, b: 0.0, c: 0.0 }
-
-rec2 :: NewType (a :: Number, b :: Number, c :: Number)
-rec2 = NewType (rec1 { a = 1.0 })
-
-main = log "Done"
diff --git a/examples/passing/NonConflictingExports.purs b/examples/passing/NonConflictingExports.purs
deleted file mode 100644
--- a/examples/passing/NonConflictingExports.purs
+++ /dev/null
@@ -1,10 +0,0 @@
--- No failure here as the export `thing` only refers to Main.thing
-module Main (thing, main) where
-
-import A
-import Control.Monad.Eff.Console (log)
-
-thing :: Int
-thing = 2
-
-main = log "Done"
diff --git a/examples/passing/NonConflictingExports/A.purs b/examples/passing/NonConflictingExports/A.purs
deleted file mode 100644
--- a/examples/passing/NonConflictingExports/A.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module A where
-
-thing :: Int
-thing = 1
diff --git a/examples/passing/NonOrphanInstanceFunDepExtra.purs b/examples/passing/NonOrphanInstanceFunDepExtra.purs
deleted file mode 100644
--- a/examples/passing/NonOrphanInstanceFunDepExtra.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- Both f and l must be known, thus can be in separate modules
-module Main where
-import Control.Monad.Eff.Console (log)
-import Lib
-data F
-data R
-instance cflr :: C F L R
-main = log "Done"
diff --git a/examples/passing/NonOrphanInstanceFunDepExtra/Lib.purs b/examples/passing/NonOrphanInstanceFunDepExtra/Lib.purs
deleted file mode 100644
--- a/examples/passing/NonOrphanInstanceFunDepExtra/Lib.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module Lib where
--- covering sets: {{f, l}}
-class C f l r | l -> r
-data L
diff --git a/examples/passing/NonOrphanInstanceMulti.purs b/examples/passing/NonOrphanInstanceMulti.purs
deleted file mode 100644
--- a/examples/passing/NonOrphanInstanceMulti.purs
+++ /dev/null
@@ -1,7 +0,0 @@
--- Both l and r must be known, thus can be in separate modules
-module Main where
-import Control.Monad.Eff.Console (log)
-import Lib
-data L
-instance clr :: C L R
-main = log "Done"
diff --git a/examples/passing/NonOrphanInstanceMulti/Lib.purs b/examples/passing/NonOrphanInstanceMulti/Lib.purs
deleted file mode 100644
--- a/examples/passing/NonOrphanInstanceMulti/Lib.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module Lib where
--- covering sets: {{l, r}}
-class C l r
-data R
diff --git a/examples/passing/NumberLiterals.purs b/examples/passing/NumberLiterals.purs
deleted file mode 100644
--- a/examples/passing/NumberLiterals.purs
+++ /dev/null
@@ -1,39 +0,0 @@
-module Main where
-
--- See issue #2115.
-
-import Prelude
-import Test.Assert (assert')
-import Control.Monad.Eff.Console (log)
-
-main = do
-  test "0.17" 0.17
-  test "0.25996181067141905" 0.25996181067141905
-  test "0.3572019862807257" 0.3572019862807257
-  test "0.46817723004874223" 0.46817723004874223
-  test "0.9640035681058178" 0.9640035681058178
-  test "4.23808622486133" 4.23808622486133
-  test "4.540362294799751" 4.540362294799751
-  test "5.212384849884261" 5.212384849884261
-  test "13.958257048123212" 13.958257048123212
-  test "32.96176575630599" 32.96176575630599
-  test "38.47735512322269" 38.47735512322269
-
-  test "10000000000.0" 1e10
-  test "10000000000.0" 1.0e10
-  test "0.00001" 1e-5
-  test "0.00001" 1.0e-5
-  test "1.5339794352098402e-118" 1.5339794352098402e-118
-  test "2.108934760892056e-59" 2.108934760892056e-59
-  test "2.250634744599241e-19" 2.250634744599241e-19
-  test "5.960464477539063e-8" 5.960464477539063e-8
-  test "5e-324" 5e-324
-  test "5e-324" 5.0e-324
-
-  log "Done"
-
-test str num =
-  if (show num == str)
-    then pure unit
-    else flip assert' false $
-      "Expected " <> show str <> ", got " <> show (show num) <> "."
diff --git a/examples/passing/ObjectGetter.purs b/examples/passing/ObjectGetter.purs
deleted file mode 100644
--- a/examples/passing/ObjectGetter.purs
+++ /dev/null
@@ -1,14 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log, logShow)
-
-getX = _.x
-
-point = { x: 1.0, y: 0.0 }
-
-main = do
-  logShow $ getX point
-  log $ _." 123 string Prop Name " { " 123 string Prop Name ": "OK" }
-  log $ (_.x >>> _.y) { x: { y: "Nested" } }
-  log $ _.value { value: "Done" }
diff --git a/examples/passing/ObjectSynonym.purs b/examples/passing/ObjectSynonym.purs
deleted file mode 100644
--- a/examples/passing/ObjectSynonym.purs
+++ /dev/null
@@ -1,16 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-type Inner = Number
-
-inner :: Inner
-inner = 0.0
-
-type Outer = { inner :: Inner }
-
-outer :: Outer
-outer = { inner: inner }
-
-main = log "Done"
diff --git a/examples/passing/ObjectUpdate.purs b/examples/passing/ObjectUpdate.purs
deleted file mode 100644
--- a/examples/passing/ObjectUpdate.purs
+++ /dev/null
@@ -1,23 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-update1 = \o -> o { foo = "Foo" }
-
-update2 :: forall r. { foo :: String | r } -> { foo :: String | r }
-update2 = \o -> o { foo = "Foo" }
-
-replace = \o -> case o of
-  { foo: "Foo" } -> o { foo = "Bar" }
-  { foo: "Bar" } -> o { bar = "Baz" }
-  o -> o
-
-polyUpdate :: forall a r. { foo :: a | r } -> { foo :: String | r }
-polyUpdate = \o -> o { foo = "Foo" }
-
-inferPolyUpdate = \o -> o { foo = "Foo" }
-
-main = do
-  log ((update1 {foo: ""}).foo)
-  log "Done"
diff --git a/examples/passing/ObjectUpdate2.purs b/examples/passing/ObjectUpdate2.purs
deleted file mode 100644
--- a/examples/passing/ObjectUpdate2.purs
+++ /dev/null
@@ -1,18 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-type X r = { | r }
-
-x :: X (baz :: String)
-x = { baz: "baz" }
-
-blah :: forall r. X r -> X r
-blah x = x
-
-test = blah x
-  { baz = "blah"
-  }
-
-main = log "Done"
diff --git a/examples/passing/ObjectUpdater.purs b/examples/passing/ObjectUpdater.purs
deleted file mode 100644
--- a/examples/passing/ObjectUpdater.purs
+++ /dev/null
@@ -1,26 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff
-import Control.Monad.Eff.Console
-import Test.Assert
-
-getValue :: forall e. Eff (| e) Boolean
-getValue = pure true
-
-main = do
-  let record = { value: false }
-  record' <- record { value = _ } <$> getValue
-  assert $ record'.value == true
-
-  let point = { x: 1.0, y: 1.0 }
-      x = 10.0
-      point' = (point { x = _, y = x }) 100.0
-
-  assert $ point'.x == 100.0
-  assert $ point'.y == 10.0
-
-  let record2 = (_ { x = _ }) { x: 0.0 } 10.0
-  assert $ record2.x == 10.0
-
-  log "Done"
diff --git a/examples/passing/ObjectWildcards.purs b/examples/passing/ObjectWildcards.purs
deleted file mode 100644
--- a/examples/passing/ObjectWildcards.purs
+++ /dev/null
@@ -1,20 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff
-import Control.Monad.Eff.Console
-import Test.Assert
-
-mkRecord = { foo: _, bar: _, baz: "baz" }
-
-getValue :: forall e. Eff (| e) Boolean
-getValue = pure true
-
-main = do
-  obj <- { value: _ } <$> getValue
-  logShow obj.value
-  let x = 1.0
-  point <- { x: _, y: x } <$> pure 2.0
-  assert $ point.x == 2.0
-  assert $ point.y == 1.0
-  log (mkRecord 1.0 "Done").bar
diff --git a/examples/passing/Objects.purs b/examples/passing/Objects.purs
deleted file mode 100644
--- a/examples/passing/Objects.purs
+++ /dev/null
@@ -1,36 +0,0 @@
-module Main where
-
-import Prelude hiding (append)
-import Control.Monad.Eff.Console (log)
-
-test = \x -> x.foo + x.bar + 1.0
-
-append = \o -> { foo: o.foo, bar: 1.0 }
-
-apTest = append({foo : "Foo", baz: "Baz"})
-
-f = (\a -> a.b.c) { b: { c: 1.0, d: "Hello" }, e: "World" }
-
-g = (\a -> a.f { x: 1.0, y: "y" }) { f: \o -> o.x + 1.0 }
-
-typed :: { foo :: Number }
-typed = { foo: 0.0 }
-
-test2 = \x -> x."!@#"
-
-test3 = typed."foo"
-
-test4 = test2 weirdObj
-  where
-  weirdObj :: { "!@#" :: Number }
-  weirdObj = { "!@#": 1.0 }
-
-test5 = case { "***": 1.0 } of
-  { "***": n } -> n
-
-test6 = case { "***": 1.0 } of
-             { "***": n } -> n
-
-test7 {a:    snoog , b     : blah } = blah
-
-main = log "Done"
diff --git a/examples/passing/OneConstructor.purs b/examples/passing/OneConstructor.purs
deleted file mode 100644
--- a/examples/passing/OneConstructor.purs
+++ /dev/null
@@ -1,10 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-data One a = One a
-
-one' (One a) = a
-
-main = log "Done"
diff --git a/examples/passing/OperatorAlias.purs b/examples/passing/OperatorAlias.purs
deleted file mode 100644
--- a/examples/passing/OperatorAlias.purs
+++ /dev/null
@@ -1,11 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console
-
-infixl 4 what as ?!
-
-what :: forall a b. a -> b -> a
-what a _ = a
-
-main = log $ "Done" ?! true
diff --git a/examples/passing/OperatorAliasElsewhere.purs b/examples/passing/OperatorAliasElsewhere.purs
deleted file mode 100644
--- a/examples/passing/OperatorAliasElsewhere.purs
+++ /dev/null
@@ -1,9 +0,0 @@
-module Main where
-
-import Prelude
-import Def (what)
-import Control.Monad.Eff.Console
-
-infixl 4 what as ?!
-
-main = log $ "Done" ?! true
diff --git a/examples/passing/OperatorAliasElsewhere/Def.purs b/examples/passing/OperatorAliasElsewhere/Def.purs
deleted file mode 100644
--- a/examples/passing/OperatorAliasElsewhere/Def.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module Def where
-
-what :: forall a b. a -> b -> a
-what a _ = a
diff --git a/examples/passing/OperatorAssociativity.purs b/examples/passing/OperatorAssociativity.purs
deleted file mode 100644
--- a/examples/passing/OperatorAssociativity.purs
+++ /dev/null
@@ -1,25 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff
-import Control.Monad.Eff.Console
-import Test.Assert
-
-bug :: Number -> Number -> Number
-bug a b = 0.0 - (a - b)
-
-main = do
-  assert (bug 0.0 2.0 == 2.0)
-  assert (0.0 - (0.0 - 2.0) == 2.0)
-  assert (0.0 - (0.0 + 2.0) == -2.0)
-  assert (6.0 / (3.0 * 2.0) == 1.0)
-  assert ((6.0 / 3.0) * 2.0 == 4.0)
-  assert (not (1.0 < 0.0) == true)
-  assert (not ((negate 1.0) < 0.0) == false)
-  assert (negate (1.0 + 10.0) == -11.0)
-  assert (2.0 * 3.0 / 4.0 == 1.5)
-  assert (1.0 * 2.0 * 3.0 * 4.0 * 5.0 / 6.0 == 20.0)
-  assert (1.0 + 10.0 - 5.0 == 6.0)
-  assert (1.0 + 10.0 * 5.0 == 51.0)
-  assert (10.0 * 5.0 - 1.0 == 49.0)
-  log "Done"
diff --git a/examples/passing/OperatorInlining.purs b/examples/passing/OperatorInlining.purs
deleted file mode 100644
--- a/examples/passing/OperatorInlining.purs
+++ /dev/null
@@ -1,48 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (logShow, log)
-
-main = do
-
-  -- semiringNumber
-  logShow (1.0 + 2.0)
-  logShow (1.0 * 2.0)
-
-  -- ringNumber
-  logShow (1.0 - 2.0)
-  logShow (negate 1.0)
-
-  -- moduleSemiringNumber
-  logShow (1.0 / 2.0)
-
-  -- ordNumber
-  logShow (1.0 > 2.0)
-  logShow (1.0 < 2.0)
-  logShow (1.0 <= 2.0)
-  logShow (1.0 >= 2.0)
-  logShow (1.0 == 2.0)
-
-  -- eqNumber
-  logShow (1.0 == 2.0)
-  logShow (1.0 /= 2.0)
-
-  -- eqString
-  logShow ("foo" == "bar")
-  logShow ("foo" /= "bar")
-
-  -- eqBoolean
-  logShow (true == false)
-  logShow (true /= false)
-
-  -- semigroupString
-  logShow ("foo" <> "bar")
-
-  -- latticeBoolean
-  logShow (top && true)
-  logShow (bottom || false)
-
-  -- complementedLatticeBoolean
-  logShow (not true)
-
-  log "Done"
diff --git a/examples/passing/OperatorSections.purs b/examples/passing/OperatorSections.purs
deleted file mode 100644
--- a/examples/passing/OperatorSections.purs
+++ /dev/null
@@ -1,18 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-import Test.Assert
-
-main = do
-  assert $ (_ / 2.0) 4.0 == 2.0
-  assert $ (2.0 / _) 4.0 == 0.5
-  assert $ (_ `const` 1.0) 2.0 == 2.0
-  assert $ (1.0 `const` _) 2.0 == 1.0
-  let foo = { x: 2.0 }
-  assert $ (_ / foo.x) 4.0 == 2.0
-  assert $ (foo.x / _) 4.0 == 0.5
-  let div x y = x.x / y.x
-  assert $ (_ `div` foo { x = 4.0 }) { x: 4.0 } == 1.0
-  assert $ (foo { x = 4.0 } `div` _) { x: 4.0 } == 1.0
-  log "Done"
diff --git a/examples/passing/Operators.purs b/examples/passing/Operators.purs
deleted file mode 100644
--- a/examples/passing/Operators.purs
+++ /dev/null
@@ -1,91 +0,0 @@
-module Main where
-
-import Prelude
-import Other (foo)
-import Other as Other
-import Control.Monad.Eff
-import Control.Monad.Eff.Console
-
-op1 :: forall a. a -> a -> a
-op1 x _ = x
-
-infix 4 op1 as ?!
-
-test1 :: forall n. Semiring n => n -> n -> (n -> n -> n) -> n
-test1 x y z = x * y + z x y
-
-test2 = (\x -> x.foo false) { foo : \_ -> 1.0 }
-
-test3 = (\x y -> x)(1.0 + 2.0 * (1.0 + 2.0)) (true && (false || false))
-
-k = \x -> \y -> x
-
-test4 = 1 `k` 2
-
-op2 :: Number -> Number -> Number
-op2 x y = x * y + y
-
-infixl 5 op2 as %%
-
-test5 = 1.0 %% 2.0 %% 3.0
-
-test6 = ((\x -> x) `k` 2.0) 3.0
-
-op3 :: String -> String -> String
-op3 = \s1 s2 -> s1 <> s2
-
-infix 4 op3 as <+>
-
-test7 = "Hello" <+> "World!"
-
-op4 :: forall a b. (a -> b) -> a -> b
-op4 = \f x -> f x
-
-infix 4 op4 as @@
-
-test8 = foo @@ "Hello World"
-
-test9 = Other.foo @@ "Hello World"
-
-test10 = "Hello" `Other.baz` "World"
-
-op5 :: forall a. Array a -> Array a -> Array a
-op5 = \as -> \bs -> as
-
-infix 4 op5 as ...
-
-test11 = [1.0, 2.0, 0.0] ... [4.0, 5.0, 6.0]
-
-test14 :: Number -> Number -> Boolean
-test14 a b = a < b
-
-test15 :: Number -> Number -> Boolean
-test15 a b = const false $ a `test14` b
-
-test17 :: Number
-test17 = negate (-1.0)
-
-test18 :: Number
-test18 = negate $ negate 1.0
-
-test19 :: Number
-test19 = negate $ negate (-1.0)
-
-main = do
-  let t1 = test1 1.0 2.0 (\x y -> x + y)
-  let t2 = test2
-  let t3 = test3
-  let t4 = test4
-  let t5 = test5
-  let t6 = test6
-  let t7 = test7
-  let t8 = test8
-  let t9 = test9
-  let t10 = test10
-  let t11 = test11
-  let t14 = test14 1.0 2.0
-  let t15 = test15 1.0 2.0
-  let t17 = test17
-  let t18 = test18
-  let t19 = test19
-  log "Done"
diff --git a/examples/passing/Operators/Other.purs b/examples/passing/Operators/Other.purs
deleted file mode 100644
--- a/examples/passing/Operators/Other.purs
+++ /dev/null
@@ -1,7 +0,0 @@
-module Other where
-
-foo :: String -> String
-foo s = s
-
-baz :: String -> String -> String
-baz s _ = s
diff --git a/examples/passing/OptimizerBug.purs b/examples/passing/OptimizerBug.purs
deleted file mode 100644
--- a/examples/passing/OptimizerBug.purs
+++ /dev/null
@@ -1,10 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-x a = 1.0 + y a
-
-y a = x a
-
-main = log "Done"
diff --git a/examples/passing/OptionalQualified.purs b/examples/passing/OptionalQualified.purs
deleted file mode 100644
--- a/examples/passing/OptionalQualified.purs
+++ /dev/null
@@ -1,12 +0,0 @@
-module Main where
-
-import Prelude as P
-
--- qualified import without the "qualified" keyword
-import Control.Monad.Eff.Console as Console
-
-bind = P.bind
-
-main = do
-  message <- P.pure "Done"
-  Console.log message
diff --git a/examples/passing/OverlappingInstances.purs b/examples/passing/OverlappingInstances.purs
deleted file mode 100644
--- a/examples/passing/OverlappingInstances.purs
+++ /dev/null
@@ -1,17 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-import Test.Assert (assert)
-
-data A = A
-
-instance showA1 :: Show A where
-  show A = "Instance 1"
-
-instance showA2 :: Show A where
-  show A = "Instance 2"
-
-main = do
-  assert $ show A == "Instance 1"
-  log "Done"
diff --git a/examples/passing/OverlappingInstances2.purs b/examples/passing/OverlappingInstances2.purs
deleted file mode 100644
--- a/examples/passing/OverlappingInstances2.purs
+++ /dev/null
@@ -1,27 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-import Test.Assert (assert)
-
-data A = A | B
-
-instance eqA1 :: Eq A where
-  eq A A = true
-  eq B B = true
-  eq _ _ = false
-
-instance eqA2 :: Eq A where
-  eq _ _ = true
-
-instance ordA :: Ord A where
-  compare A B = LT
-  compare B A = GT
-  compare _ _ = EQ
-
-test :: forall a. Ord a => a -> a -> String
-test x y = show $ x == y
-
-main = do
-  assert $ test A B == "false"
-  log "Done"
diff --git a/examples/passing/OverlappingInstances3.purs b/examples/passing/OverlappingInstances3.purs
deleted file mode 100644
--- a/examples/passing/OverlappingInstances3.purs
+++ /dev/null
@@ -1,20 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-import Test.Assert (assert)
-
-class Foo a
-
-instance foo1 :: Foo Number
-
-instance foo2 :: Foo Number
-
-test :: forall a. Foo a => a -> a
-test a = a
-
-test1 = test 0.0
-
-main = do
-  assert (test1 == 0.0)
-  log "Done"
diff --git a/examples/passing/ParensInType.purs b/examples/passing/ParensInType.purs
deleted file mode 100644
--- a/examples/passing/ParensInType.purs
+++ /dev/null
@@ -1,20 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff (Eff)
-import Control.Monad.Eff.Console (CONSOLE, log)
-
-class Foo a where
-  foo :: forall eff. (String -> a (( console :: CONSOLE | eff)) ((Unit)))
-
-instance fooLogEff :: Foo Eff where
-  foo = log
-
-main :: 
-    forall eff.
-      Eff
-        ( console :: CONSOLE
-        | eff
-        )
-        Unit
-main = foo "Done"
diff --git a/examples/passing/ParensInTypedBinder.purs b/examples/passing/ParensInTypedBinder.purs
deleted file mode 100644
--- a/examples/passing/ParensInTypedBinder.purs
+++ /dev/null
@@ -1,20 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff (Eff)
-import Control.Monad.Eff.Console (CONSOLE, log)
-
-foo :: Array Int
-foo = do
-  xss :: Array (Array Int) <- [[[1,2,3], [4, 5]], [[6]]]
-  xs :: Array Int <- xss
-  xs
-
-main :: 
-    forall eff.
-      Eff
-        ( console :: CONSOLE
-        | eff
-        )
-        Unit
-main = log "Done"
diff --git a/examples/passing/PartialFunction.purs b/examples/passing/PartialFunction.purs
deleted file mode 100644
--- a/examples/passing/PartialFunction.purs
+++ /dev/null
@@ -1,11 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff
-import Control.Monad.Eff.Console
-
-fn :: Partial => Number -> Number
-fn 0.0 = 0.0
-fn 1.0 = 2.0
-
-main = log "Done"
diff --git a/examples/passing/Patterns.purs b/examples/passing/Patterns.purs
deleted file mode 100644
--- a/examples/passing/Patterns.purs
+++ /dev/null
@@ -1,23 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-test = \x -> case x of
-  { str: "Foo", bool: true } -> true
-  { str: "Bar", bool: b } -> b
-  _ -> false
-
-f = \o -> case o of
-  { foo: "Foo" } -> o.bar
-  _ -> 0
-
-h = \o -> case o of
-  a@[_,_,_] -> a
-  _ -> []
-
-isDesc :: Array Number -> Boolean
-isDesc [x, y] | x > y = true
-isDesc _ = false
-
-main = log "Done"
diff --git a/examples/passing/PendingConflictingImports.purs b/examples/passing/PendingConflictingImports.purs
deleted file mode 100644
--- a/examples/passing/PendingConflictingImports.purs
+++ /dev/null
@@ -1,8 +0,0 @@
-module Main where
-
--- No error as we never force `thing` to be resolved in `Main`
-import A
-import B
-import Control.Monad.Eff.Console (log)
-
-main = log "Done"
diff --git a/examples/passing/PendingConflictingImports/A.purs b/examples/passing/PendingConflictingImports/A.purs
deleted file mode 100644
--- a/examples/passing/PendingConflictingImports/A.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module A where
-
-thing :: Int
-thing = 1
diff --git a/examples/passing/PendingConflictingImports/B.purs b/examples/passing/PendingConflictingImports/B.purs
deleted file mode 100644
--- a/examples/passing/PendingConflictingImports/B.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module B where
-
-thing :: Int
-thing = 2
diff --git a/examples/passing/PendingConflictingImports2.purs b/examples/passing/PendingConflictingImports2.purs
deleted file mode 100644
--- a/examples/passing/PendingConflictingImports2.purs
+++ /dev/null
@@ -1,10 +0,0 @@
-module Main where
-
-import A
-import Control.Monad.Eff.Console (log)
-
--- No error as we never force `thing` to be resolved in `Main`
-thing :: Int
-thing = 2
-
-main = log "Done"
diff --git a/examples/passing/PendingConflictingImports2/A.purs b/examples/passing/PendingConflictingImports2/A.purs
deleted file mode 100644
--- a/examples/passing/PendingConflictingImports2/A.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module A where
-
-thing :: Int
-thing = 1
diff --git a/examples/passing/Person.purs b/examples/passing/Person.purs
deleted file mode 100644
--- a/examples/passing/Person.purs
+++ /dev/null
@@ -1,12 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-data Person = Person { name :: String, age :: Number }
-
-showPerson :: Person -> String
-showPerson = \p -> case p of
-  Person o -> o.name <> ", aged " <> show o.age
-
-main = log "Done"
diff --git a/examples/passing/PolyLabels.js b/examples/passing/PolyLabels.js
deleted file mode 100644
--- a/examples/passing/PolyLabels.js
+++ /dev/null
@@ -1,17 +0,0 @@
-"use strict";
-
-exports.unsafeGet = function (s) {
-  return function (o) {
-    return o[s];
-  };
-};
-
-exports.unsafeSet = function(s) {
-  return function(a) {
-    return function (o) {
-      var o1 = {};
-      o1[s] = a;
-      return Object.assign({}, o, o1);
-    };
-  };
-};
diff --git a/examples/passing/PolyLabels.purs b/examples/passing/PolyLabels.purs
deleted file mode 100644
--- a/examples/passing/PolyLabels.purs
+++ /dev/null
@@ -1,65 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff
-import Control.Monad.Eff.Console
-import Data.Symbol (class IsSymbol, SProxy(..), reflectSymbol)
-
-foreign import unsafeGet
-  :: forall r a
-   . String
-  -> Record r
-  -> a
-
-foreign import unsafeSet
-  :: forall r1 r2 a
-   . String
-  -> a
-  -> Record r1
-  -> Record r2
-
-get
-  :: forall r r' l a
-   . IsSymbol l
-  => RowCons l a r' r
-  => SProxy l
-  -> Record r
-  -> a
-get l = unsafeGet (reflectSymbol l)
-
-set
-  :: forall r1 r2 r l a b
-   . IsSymbol l
-  => RowCons l a r r1
-  => RowCons l b r r2
-  => SProxy l
-  -> b
-  -> Record r1
-  -> Record r2
-set l = unsafeSet (reflectSymbol l)
-
-lens 
-  :: forall l f r1 r2 r a b
-   . IsSymbol l
-  => RowCons l a r r1
-  => RowCons l b r r2
-  => Functor f
-  => SProxy l
-  -> (a -> f b)
-  -> Record r1
-  -> f (Record r2)
-lens l f r = flip (set l) r <$> f (get l r)
-
-getFoo :: forall a r. { foo :: a | r } -> a
-getFoo = get (SProxy :: SProxy "foo")
-
-setFoo :: forall a b r. b -> { foo :: a | r } -> { foo :: b | r }
-setFoo = set (SProxy :: SProxy "foo")
-
-fooLens :: forall f a b r. Functor f => (a -> f b) -> { foo :: a | r } -> f { foo :: b | r } 
-fooLens = lens (SProxy :: SProxy "foo")
-
-main :: Eff (console :: CONSOLE) Unit
-main = do
-  _ <- fooLens logShow { foo: 1 }
-  log (getFoo (setFoo "Done" { foo: 1 }))
diff --git a/examples/passing/PrimedTypeName.purs b/examples/passing/PrimedTypeName.purs
deleted file mode 100644
--- a/examples/passing/PrimedTypeName.purs
+++ /dev/null
@@ -1,20 +0,0 @@
-module Main (T, T', T'', T''', main) where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-data T a = T
-type T' = T Unit
-
-data T'' = TP
-
-foreign import data T''' ∷ Type
-
-instance eqT ∷ Eq T'' where
-  eq _ _ = true
-
-type A' a b = b → a
-
-infixr 4 type A' as ↫
-
-main = log "Done"
diff --git a/examples/passing/QualifiedNames.purs b/examples/passing/QualifiedNames.purs
deleted file mode 100644
--- a/examples/passing/QualifiedNames.purs
+++ /dev/null
@@ -1,11 +0,0 @@
-module Main where
-
-import Prelude
-import Either as Either
-import Control.Monad.Eff.Console (log)
-
-either :: forall a b c. (a -> c) -> (b -> c) -> Either.Either a b -> c
-either f _ (Either.Left x) = f x
-either _ g (Either.Right y) = g y
-
-main = log (either id id (Either.Left "Done"))
diff --git a/examples/passing/QualifiedNames/Either.purs b/examples/passing/QualifiedNames/Either.purs
deleted file mode 100644
--- a/examples/passing/QualifiedNames/Either.purs
+++ /dev/null
@@ -1,5 +0,0 @@
-module Either where
-
-import Prelude
-
-data Either a b = Left a | Right b
diff --git a/examples/passing/QualifiedQualifiedImports.purs b/examples/passing/QualifiedQualifiedImports.purs
deleted file mode 100644
--- a/examples/passing/QualifiedQualifiedImports.purs
+++ /dev/null
@@ -1,6 +0,0 @@
-module Main where
-
--- qualified import with qualified imported names
-import Control.Monad.Eff.Console (log) as Console
-
-main = Console.log "Done"
diff --git a/examples/passing/Rank2Data.purs b/examples/passing/Rank2Data.purs
deleted file mode 100644
--- a/examples/passing/Rank2Data.purs
+++ /dev/null
@@ -1,30 +0,0 @@
-module Main where
-
-import Prelude hiding (add)
-import Control.Monad.Eff.Console (log)
-
-data Id = Id forall a. a -> a
-
-runId = \id a -> case id of
-  Id f -> f a
-
-data Nat = Nat forall r. r -> (r -> r) -> r
-
-runNat = \nat -> case nat of
-  Nat f -> f 0.0 (\n -> n + 1.0)
-
-zero' = Nat (\zero' _ -> zero')
-
-succ = \n -> case n of
-  Nat f -> Nat (\zero' succ -> succ (f zero' succ))
-
-add = \n m -> case n of
-  Nat f -> case m of
-    Nat g -> Nat (\zero' succ -> g (f zero' succ) succ)
-
-one' = succ zero'
-two = succ zero'
-four = add two two
-fourNumber = runNat four
-
-main = log "Done"
diff --git a/examples/passing/Rank2Object.purs b/examples/passing/Rank2Object.purs
deleted file mode 100644
--- a/examples/passing/Rank2Object.purs
+++ /dev/null
@@ -1,11 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console
-
-data Foo = Foo { id :: forall a. a -> a }
-
-foo :: Foo -> Number
-foo (Foo { id: f }) = f 0.0
-
-main = log "Done"
diff --git a/examples/passing/Rank2TypeSynonym.purs b/examples/passing/Rank2TypeSynonym.purs
deleted file mode 100644
--- a/examples/passing/Rank2TypeSynonym.purs
+++ /dev/null
@@ -1,17 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log, logShow)
-
-type Foo a = forall f. Monad f => f a
-
-foo :: forall a. a -> Foo a
-foo x = pure x
-
-bar :: Foo Number
-bar = foo 3.0
-
-main = do
-  x <- bar
-  logShow x
-  log "Done"
diff --git a/examples/passing/Rank2Types.purs b/examples/passing/Rank2Types.purs
deleted file mode 100644
--- a/examples/passing/Rank2Types.purs
+++ /dev/null
@@ -1,12 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-test1 :: (forall a. (a -> a)) -> Number
-test1 = \f -> f 0.0
-
-forever :: forall m a b. (forall a b. m a -> (a -> m b) -> m b) -> m a -> m b
-forever = \bind action -> bind action $ \_ -> forever bind action
-
-main = log "Done"
diff --git a/examples/passing/ReExportQualified.purs b/examples/passing/ReExportQualified.purs
deleted file mode 100644
--- a/examples/passing/ReExportQualified.purs
+++ /dev/null
@@ -1,7 +0,0 @@
-module Main where
-
-import Prelude
-import C
-import Control.Monad.Eff.Console (log)
-
-main = log (x <> y)
diff --git a/examples/passing/ReExportQualified/A.purs b/examples/passing/ReExportQualified/A.purs
deleted file mode 100644
--- a/examples/passing/ReExportQualified/A.purs
+++ /dev/null
@@ -1,3 +0,0 @@
-module A where
-
-x = "Do"
diff --git a/examples/passing/ReExportQualified/B.purs b/examples/passing/ReExportQualified/B.purs
deleted file mode 100644
--- a/examples/passing/ReExportQualified/B.purs
+++ /dev/null
@@ -1,3 +0,0 @@
-module B where
-
-y = "ne"
diff --git a/examples/passing/ReExportQualified/C.purs b/examples/passing/ReExportQualified/C.purs
deleted file mode 100644
--- a/examples/passing/ReExportQualified/C.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module C (module A, module M2) where
-
-import A
-import B as M2
diff --git a/examples/passing/RebindableSyntax.purs b/examples/passing/RebindableSyntax.purs
deleted file mode 100644
--- a/examples/passing/RebindableSyntax.purs
+++ /dev/null
@@ -1,43 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-example1 :: String
-example1 = do
-  "Do"
-  " notation"
-  " for"
-  " Semigroup"
-  where
-  discard x f = x <> f unit
-
-applySecond :: forall f a b. Apply f => f a -> f b -> f b
-applySecond fa fb = const id <$> fa <*> fb
-
-infixl 4 applySecond as *>
-
-newtype Const a b = Const a
-
-runConst :: forall a b. Const a b -> a
-runConst (Const a) = a
-
-instance functorConst :: Functor (Const a) where
-  map _ (Const a) = Const a
-
-instance applyConst :: Semigroup a => Apply (Const a) where
-  apply (Const a1) (Const a2) = Const (a1 <> a2)
-
-example2 :: Const String Unit
-example2 = do
-  Const "Do"
-  Const " notation"
-  Const " for"
-  Const " Apply"
-  where
-  discard x f = x *> f unit
-
-main = do
-  log example1
-  log $ runConst example2
-  log "Done"
diff --git a/examples/passing/Recursion.purs b/examples/passing/Recursion.purs
deleted file mode 100644
--- a/examples/passing/Recursion.purs
+++ /dev/null
@@ -1,11 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-fib = \n -> case n of
-  0.0 -> 1.0
-  1.0 -> 1.0
-  n -> fib (n - 1.0) + fib (n - 2.0)
-
-main = log "Done"
diff --git a/examples/passing/RedefinedFixity.purs b/examples/passing/RedefinedFixity.purs
deleted file mode 100644
--- a/examples/passing/RedefinedFixity.purs
+++ /dev/null
@@ -1,6 +0,0 @@
-module Main where
-
-import M3
-import Control.Monad.Eff.Console (log)
-
-main = log "Done"
diff --git a/examples/passing/RedefinedFixity/M1.purs b/examples/passing/RedefinedFixity/M1.purs
deleted file mode 100644
--- a/examples/passing/RedefinedFixity/M1.purs
+++ /dev/null
@@ -1,6 +0,0 @@
-module M1 where
-
-applyFn :: forall a b. (forall c d. c -> d) -> a -> b
-applyFn f a = f a
-
-infixr 1000 applyFn as $
diff --git a/examples/passing/RedefinedFixity/M2.purs b/examples/passing/RedefinedFixity/M2.purs
deleted file mode 100644
--- a/examples/passing/RedefinedFixity/M2.purs
+++ /dev/null
@@ -1,5 +0,0 @@
-module M2 where
-
-import Prelude ()
-
-import M1
diff --git a/examples/passing/RedefinedFixity/M3.purs b/examples/passing/RedefinedFixity/M3.purs
deleted file mode 100644
--- a/examples/passing/RedefinedFixity/M3.purs
+++ /dev/null
@@ -1,6 +0,0 @@
-module M3 where
-
-import Prelude ()
-
-import M1
-import M2
diff --git a/examples/passing/ReservedWords.purs b/examples/passing/ReservedWords.purs
deleted file mode 100644
--- a/examples/passing/ReservedWords.purs
+++ /dev/null
@@ -1,19 +0,0 @@
--- See https://github.com/purescript/purescript/issues/606
-module Main where
-
-import Prelude
-import Control.Monad.Eff
-import Control.Monad.Eff.Console (log)
-
-o :: { type :: String }
-o = { type: "o" }
-
-p :: { type :: String }
-p = o { type = "p" }
-
-f :: forall r. { type :: String | r } -> String
-f { type: "p" } = "Done"
-f _ = "Fail"
-
-main :: Eff _ _
-main = log $ f { type: p.type, foo: "bar" }
diff --git a/examples/passing/ResolvableScopeConflict.purs b/examples/passing/ResolvableScopeConflict.purs
deleted file mode 100644
--- a/examples/passing/ResolvableScopeConflict.purs
+++ /dev/null
@@ -1,13 +0,0 @@
-module Main where
-
-import A (thing)
-import B
-import Control.Monad.Eff.Console (log)
-
--- Not an error as although we have `thing` in scope from both A and B, it is
--- imported explicitly from A, giving it a resolvable solution.
-what :: Boolean -> Int
-what true = thing
-what false = zing
-
-main = log "Done"
diff --git a/examples/passing/ResolvableScopeConflict/A.purs b/examples/passing/ResolvableScopeConflict/A.purs
deleted file mode 100644
--- a/examples/passing/ResolvableScopeConflict/A.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module A where
-
-thing :: Int
-thing = 1
diff --git a/examples/passing/ResolvableScopeConflict/B.purs b/examples/passing/ResolvableScopeConflict/B.purs
deleted file mode 100644
--- a/examples/passing/ResolvableScopeConflict/B.purs
+++ /dev/null
@@ -1,7 +0,0 @@
-module B where
-
-thing :: Int
-thing = 2
-
-zing :: Int
-zing = 3
diff --git a/examples/passing/ResolvableScopeConflict2.purs b/examples/passing/ResolvableScopeConflict2.purs
deleted file mode 100644
--- a/examples/passing/ResolvableScopeConflict2.purs
+++ /dev/null
@@ -1,15 +0,0 @@
-module Main where
-
-import A
-import Control.Monad.Eff.Console (log)
-
-thing :: Int
-thing = 1
-
--- Not an error as although we have `thing` in scope from both Main and A,
--- as the local declaration takes precedence over the implicit import
-what :: Boolean -> Int
-what true = thing
-what false = zing
-
-main = log "Done"
diff --git a/examples/passing/ResolvableScopeConflict2/A.purs b/examples/passing/ResolvableScopeConflict2/A.purs
deleted file mode 100644
--- a/examples/passing/ResolvableScopeConflict2/A.purs
+++ /dev/null
@@ -1,7 +0,0 @@
-module A where
-
-thing :: Int
-thing = 2
-
-zing :: Int
-zing = 3
diff --git a/examples/passing/ResolvableScopeConflict3.purs b/examples/passing/ResolvableScopeConflict3.purs
deleted file mode 100644
--- a/examples/passing/ResolvableScopeConflict3.purs
+++ /dev/null
@@ -1,9 +0,0 @@
-module Main (thing, main, module A) where
-
-import A
-import Control.Monad.Eff.Console (log)
-
-thing :: Int
-thing = 2
-
-main = log "Done"
diff --git a/examples/passing/ResolvableScopeConflict3/A.purs b/examples/passing/ResolvableScopeConflict3/A.purs
deleted file mode 100644
--- a/examples/passing/ResolvableScopeConflict3/A.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module A where
-
-thing :: Int
-thing = 1
diff --git a/examples/passing/RowConstructors.purs b/examples/passing/RowConstructors.purs
deleted file mode 100644
--- a/examples/passing/RowConstructors.purs
+++ /dev/null
@@ -1,43 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-type Foo = (x :: Number | (y :: Number | (z :: Number)))
-type Bar = (x :: Number, y :: Number, z :: Number)
-type Baz = { w :: Number | Bar }
-
-foo :: { | Foo }
-foo = { x: 0.0, y: 0.0, z: 0.0 }
-
-bar :: { | Bar }
-bar = { x: 0.0, y: 0.0, z: 0.0 }
-
-id' :: Record Foo -> Record Bar
-id' = id
-
-foo' :: { | Foo }
-foo' = id' foo
-
-bar' :: { | Bar }
-bar' = id' bar
-
-baz :: Baz
-baz = { x: 0.0, y: 0.0, z: 0.0, w: 0.0 }
-
-type Quux r = (q :: Number | r)
-type Norf r = (q' :: Number | Quux r)
-
-quux :: { f :: { | Foo } | Quux Bar }
-quux = { f: foo', x: 0.0, y: 0.0, z: 0.0, q: 0.0 }
-
-quux' :: { | Norf Bar }
-quux' = { x: 0.0, y: 0.0, z: 0.0, q: 0.0, q': 0.0 }
-
-wildcard :: { w :: Number | _ } -> Baz
-wildcard { w: w } = { x: w, y: w, z: w, w: w }
-
-wildcard' :: { | Quux _ } -> Number
-wildcard' { q: q } = q
-
-main = log "Done"
diff --git a/examples/passing/RowInInstanceHeadDetermined.purs b/examples/passing/RowInInstanceHeadDetermined.purs
deleted file mode 100644
--- a/examples/passing/RowInInstanceHeadDetermined.purs
+++ /dev/null
@@ -1,40 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-data Empty = Empty
-data Cons = Cons
-
-
--- simple case
-class Simple a b | a -> b where c :: a -> b
-instance simple0 :: Simple Empty {} where c _ = {}
-instance simple1 :: Simple Cons {foo :: Cons} where c cons = {foo: cons}
-
-
--- simple transitive example
-class Transitive a b c | a -> b, b -> c where d :: a -> c
-instance transitive :: Transitive Empty {} {} where d _ = {}
-
-
--- transitive example with cycles
-class Cyclic a b c d | a -> b, b -> a
-                     , a -> c
-                     , c -> d, d -> c
-instance cyclic :: Cyclic Empty Empty {} {}
-
-
--- Determined cycle
-class DeterminedCycle a b c | a -> b
-                            , b -> c, c -> b
-instance determinedCycle :: DeterminedCycle Empty {} {}
-
-
--- multiple determiners
-class MultipleDeterminers a b c d | a b -> c d
-instance multipleDeterminers :: MultipleDeterminers Empty Empty {} {}
-
-
-main = log "Done"
-
diff --git a/examples/passing/RowPolyInstanceContext.purs b/examples/passing/RowPolyInstanceContext.purs
deleted file mode 100644
--- a/examples/passing/RowPolyInstanceContext.purs
+++ /dev/null
@@ -1,23 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-class T s m | m -> s where
-  state :: (s -> s) -> m Unit
-
-data S s a = S (s -> { new :: s, ret :: a })
-
-instance st :: T s (S s) where
-  state f = S $ \s -> { new: f s, ret: unit }
-
-test1 :: forall r . S { foo :: String | r } Unit
-test1 = state $ \o -> o { foo = o.foo <> "!" }
-
-test2 :: forall m r . T { foo :: String | r } m => m Unit
-test2 = state $ \o -> o { foo = o.foo <> "!" }
-
-main = do
-  let t1 = test1
-  let t2 = test2
-  log "Done"
diff --git a/examples/passing/RowUnion.js b/examples/passing/RowUnion.js
deleted file mode 100644
--- a/examples/passing/RowUnion.js
+++ /dev/null
@@ -1,10 +0,0 @@
-"use strict";
-
-exports.merge = function (dict) {
-  return function (l) {
-    return function (r) {
-      var o = {};
-      return Object.assign(o, r, l);
-    };
-  };
-};
diff --git a/examples/passing/RowUnion.purs b/examples/passing/RowUnion.purs
deleted file mode 100644
--- a/examples/passing/RowUnion.purs
+++ /dev/null
@@ -1,68 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff
-import Control.Monad.Eff.Console
-
-foreign import merge
-  :: forall r1 r2 r3
-   . Union r1 r2 r3
-  => Record r1
-  -> Record r2
-  -> Record r3
-
-test1 = merge { x: 1 } { y: true }
-
-test2 = merge { x: 1 } { x: true }
-
-mergeWithExtras
- :: forall r1 r2 r3
-  . Union r1 (y :: Boolean | r2) (y :: Boolean | r3)
- => { x :: Int | r1 }
- -> { y :: Boolean | r2 }
- -> { x :: Int, y :: Boolean | r3}
-mergeWithExtras = merge
-
-test3 x = merge { x: 1 } x
-test3' x = merge x { x: 1 }
-
-type Mandatory r = (x :: Int | r)
-type Optional r = (x :: Int, y :: Int, z :: Int | r)
-
-withDefaults
-  :: forall r s
-   . Union r (y :: Int, z :: Int) (y :: Int, z :: Int | s)
-  => Record (Mandatory r)
-  -> Record (Optional s)
-withDefaults p = merge p { y: 1, z: 1 }
-
-withDefaultsClosed
-  :: forall r s
-   . Union r (y :: Int, z :: Int) (y :: Int, z :: Int | s)
-  => Subrow s (y :: Int, z :: Int)
-  => Record (Mandatory r)
-  -> Record (Optional s)
-withDefaultsClosed p = merge p { y: 1, z: 1 }
-
-test4 = withDefaults { x: 1, y: 2 }
-
--- r is a subrow of s if Union r t s for some t.
-class Subrow (r :: # Type) (s :: # Type)
-instance subrow :: Union r t s => Subrow r s
-
-main :: Eff (console :: CONSOLE) Unit
-main = do
-  logShow test1.x
-  logShow test1.y
-  logShow (test1.x == 1)
-  logShow (mergeWithExtras { x: 1 } { x: 0, y: true, z: 42.0 }).x
-  logShow (withDefaults { x: 1 }).x
-  logShow (withDefaults { x: 1 }).y
-  logShow (withDefaults { x: 1 }).z
-  logShow (withDefaults { x: 1, y: 2 }).x
-  logShow (withDefaults { x: 1, y: 2 }).y
-  logShow (withDefaults { x: 1, y: 2 }).z
-  logShow (withDefaultsClosed { x: 1, y: 2 }).x
-  logShow (withDefaultsClosed { x: 1, y: 2 }).y
-  logShow (withDefaultsClosed { x: 1, y: 2 }).z
-  log "Done"
diff --git a/examples/passing/RowsInInstanceContext.purs b/examples/passing/RowsInInstanceContext.purs
deleted file mode 100644
--- a/examples/passing/RowsInInstanceContext.purs
+++ /dev/null
@@ -1,25 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff (Eff)
-import Control.Monad.Eff.Console (CONSOLE, log)
-import Data.Newtype (class Newtype, unwrap)
-
-class TypeEquals a b | a -> b, b -> a where
-  coerce :: a -> b
-  coerceBack :: b -> a
-
-instance refl :: TypeEquals a a where
-  coerce = id
-  coerceBack = id
-
-newtype RecordNewtype = RecordNewtype { x :: String }
-
-instance newtypeRecordNewtype ::
-  TypeEquals inner { x :: String }
-    => Newtype RecordNewtype inner where
-  wrap = RecordNewtype <<< coerce
-  unwrap (RecordNewtype rec) = coerceBack rec
-
-main :: Eff (console :: CONSOLE) Unit
-main = log (unwrap (RecordNewtype { x: "Done" })).x
diff --git a/examples/passing/RuntimeScopeIssue.purs b/examples/passing/RuntimeScopeIssue.purs
deleted file mode 100644
--- a/examples/passing/RuntimeScopeIssue.purs
+++ /dev/null
@@ -1,22 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log, logShow)
-
-class A a where
-  a :: a -> Boolean
-
-class B a where
-  b :: a -> Boolean
-
-instance aNumber :: A Number where
-  a 0.0 = true
-  a n = b (n - 1.0)
-
-instance bNumber :: B Number where
-  b 0.0 = false
-  b n = a (n - 1.0)
-
-main = do
-  logShow $ a 10.0
-  log "Done"
diff --git a/examples/passing/ScopedTypeVariables.purs b/examples/passing/ScopedTypeVariables.purs
deleted file mode 100644
--- a/examples/passing/ScopedTypeVariables.purs
+++ /dev/null
@@ -1,37 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-test1 :: forall a. (a -> a) -> a -> a
-test1 f x = g (g x)
-  where
-  g :: a -> a
-  g y = f (f y)
-
-test2 :: forall a. (a -> a) -> a -> a
-test2 = h
-  where
-  h :: forall b. (b -> b) -> b -> b
-  h f x = g (g x)
-    where
-    g :: b -> b
-    g y = f (f y)
-
-test3 :: Number
-test3 = ((\b -> b :: b) :: forall b. b -> b) 0.0
-
-test4 :: forall a. (a -> a) -> a -> a
-test4 = h
-  where
-  h :: forall b. (b -> b) -> b -> b
-  h f x = g (g x)
-    where
-    g :: b -> b
-    g y = j (f (f y))
-      where
-      j :: forall b. b -> b
-      j x = x
-
-
-main = log "Done"
diff --git a/examples/passing/Sequence.purs b/examples/passing/Sequence.purs
deleted file mode 100644
--- a/examples/passing/Sequence.purs
+++ /dev/null
@@ -1,16 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff
-import Control.Monad.Eff.Console (log)
-
-data List a = Cons a (List a) | Nil
-
-class Sequence t where
-  sequence :: forall m a. Monad m => t (m a) -> m (t a)
-
-instance sequenceList :: Sequence List where
-  sequence Nil = pure Nil
-  sequence (Cons x xs) = Cons <$> x <*> sequence xs
-
-main = sequence $ Cons (log "Done") Nil
diff --git a/examples/passing/SequenceDesugared.purs b/examples/passing/SequenceDesugared.purs
deleted file mode 100644
--- a/examples/passing/SequenceDesugared.purs
+++ /dev/null
@@ -1,38 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff
-import Control.Monad.Eff.Console (log)
-
-data List a = Cons a (List a) | Nil
-
-data Sequence t = Sequence (forall m a. Monad m => t (m a) -> m (t a))
-
-sequence :: forall t. Sequence t -> (forall m a. Monad m => t (m a) -> m (t a))
-sequence (Sequence s) = s
-
-sequenceListSeq :: forall m a. Monad m => List (m a) -> m (List a)
-sequenceListSeq Nil = pure Nil
-sequenceListSeq (Cons x xs) = Cons <$> x <*> sequenceListSeq xs
-
-sequenceList :: Sequence List
-sequenceList = Sequence (sequenceListSeq)
-
-sequenceList' :: Sequence List
-sequenceList' = Sequence ((\val -> case val of
-  Nil -> pure Nil
-  Cons x xs -> Cons <$> x <*> sequence sequenceList' xs))
-
-sequenceList'' :: Sequence List
-sequenceList'' = Sequence (sequenceListSeq :: forall m a. Monad m => List (m a) -> m (List a))
-
-sequenceList''' :: Sequence List
-sequenceList''' = Sequence ((\val -> case val of
-  Nil -> pure Nil
-  Cons x xs -> Cons <$> x <*> sequence sequenceList''' xs) :: forall m a. Monad m => List (m a) -> m (List a))
-
-main = do
-  void $ sequence sequenceList $ Cons (log "Done") Nil
-  void $ sequence sequenceList' $ Cons (log "Done") Nil
-  void $ sequence sequenceList'' $ Cons (log "Done") Nil
-  void $ sequence sequenceList''' $ Cons (log "Done") Nil
diff --git a/examples/passing/ShadowedModuleName.purs b/examples/passing/ShadowedModuleName.purs
deleted file mode 100644
--- a/examples/passing/ShadowedModuleName.purs
+++ /dev/null
@@ -1,8 +0,0 @@
-module Main where
-
-import Test
-import Control.Monad.Eff.Console
-
-data Test = Test
-
-main = log (runZ (Z "Done"))
diff --git a/examples/passing/ShadowedModuleName/Test.purs b/examples/passing/ShadowedModuleName/Test.purs
deleted file mode 100644
--- a/examples/passing/ShadowedModuleName/Test.purs
+++ /dev/null
@@ -1,6 +0,0 @@
-module Test where
-
-data Z = Z String
-
-runZ :: Z -> String
-runZ (Z s) = s
diff --git a/examples/passing/ShadowedName.purs b/examples/passing/ShadowedName.purs
deleted file mode 100644
--- a/examples/passing/ShadowedName.purs
+++ /dev/null
@@ -1,11 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console
-import Control.Monad.Eff.Console (log)
-
-done :: String
-done = let str = "Not yet done" in
-        let str = "Done" in str
-
-main = log done
diff --git a/examples/passing/ShadowedRename.purs b/examples/passing/ShadowedRename.purs
deleted file mode 100644
--- a/examples/passing/ShadowedRename.purs
+++ /dev/null
@@ -1,14 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff
-import Control.Monad.Eff.Console
-import Test.Assert
-
-foo foo = let foo_1 = \_ -> foo
-              foo_2 = foo_1 unit + 1.0
-          in foo_2
-
-main = do
-  assert $ foo 1.0 == 2.0
-  log "Done"
diff --git a/examples/passing/ShadowedTCO.purs b/examples/passing/ShadowedTCO.purs
deleted file mode 100644
--- a/examples/passing/ShadowedTCO.purs
+++ /dev/null
@@ -1,21 +0,0 @@
-module Main where
-
-import Prelude hiding (add)
-import Control.Monad.Eff.Console (log)
-
-runNat f = f 0.0 (\n -> n + 1.0)
-
-zero' z _ = z
-
-succ f zero' succ = succ (f zero' succ)
-
-add f g zero' succ = g (f zero' succ) succ
-
-one' = succ zero'
-two = succ one'
-four = add two two
-fourNumber = runNat four
-
-main = do
-  log $ show fourNumber
-  log "Done"
diff --git a/examples/passing/ShadowedTCOLet.purs b/examples/passing/ShadowedTCOLet.purs
deleted file mode 100644
--- a/examples/passing/ShadowedTCOLet.purs
+++ /dev/null
@@ -1,15 +0,0 @@
-module Main where
-
-import Prelude
-import Partial.Unsafe (unsafePartial)
-import Control.Monad.Eff
-import Control.Monad.Eff.Console (log)
-
-f x y z =
-  let f 1.0 2.0 3.0 = 1.0
-  in f x z y
-
-main :: Eff _ _
-main = do
-  log $ show $ unsafePartial f 1.0 3.0 2.0
-  log "Done"
diff --git a/examples/passing/SignedNumericLiterals.purs b/examples/passing/SignedNumericLiterals.purs
deleted file mode 100644
--- a/examples/passing/SignedNumericLiterals.purs
+++ /dev/null
@@ -1,18 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-p = 0.5
-q = 1.0
-x = -1.0
-y = -0.5
-z = 0.5
-w = 1.0
-
-f :: Number -> Number
-f x = -x
-
-test1 = 2.0 - 1.0
-
-main = log "Done"
diff --git a/examples/passing/SolvingAppendSymbol.purs b/examples/passing/SolvingAppendSymbol.purs
deleted file mode 100644
--- a/examples/passing/SolvingAppendSymbol.purs
+++ /dev/null
@@ -1,32 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-import Type.Data.Symbol (SProxy(..), class AppendSymbol, appendSymbol, reflectSymbol)
-
-sym :: SProxy ""
-sym = SProxy
-
-symA :: SProxy "A"
-symA = SProxy
-
-symB :: SProxy "B"
-symB = SProxy
-
-egAB :: SProxy "AB"
-egAB = appendSymbol symA symB
-
-egBA :: SProxy "BA"
-egBA = appendSymbol symB symA
-
-egA' :: SProxy "A"
-egA' = appendSymbol sym (appendSymbol symA sym)
-
-main = do
-  let gotAB = reflectSymbol egAB == "AB"
-      gotBA = reflectSymbol egBA == "BA"
-      gotA' = reflectSymbol egA' == "A"
-  when (not gotAB) $ log "Did not get AB"
-  when (not gotBA) $ log "Did not get BA"
-  when (not gotA') $ log "Did not get A"
-  when (gotAB && gotBA && gotA') $ log "Done"
diff --git a/examples/passing/SolvingCompareSymbol.purs b/examples/passing/SolvingCompareSymbol.purs
deleted file mode 100644
--- a/examples/passing/SolvingCompareSymbol.purs
+++ /dev/null
@@ -1,30 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-import Type.Data.Symbol (SProxy(..), class CompareSymbol, compareSymbol)
-import Type.Data.Ordering (OProxy(..), kind Ordering, LT, EQ, GT, reflectOrdering)
-
-symA :: SProxy "A"
-symA = SProxy
-
-symB :: SProxy "B"
-symB = SProxy
-
-egLT :: OProxy LT
-egLT = compareSymbol symA symB
-
-egEQ :: OProxy EQ
-egEQ = compareSymbol symA symA
-
-egGT :: OProxy GT
-egGT = compareSymbol symB symA
-
-main = do
-  let gotLT = reflectOrdering egLT == LT
-      gotEQ = reflectOrdering egEQ == EQ
-      gotGT = reflectOrdering egGT == GT
-  when (not gotLT) $ log "Did not get LT"
-  when (not gotEQ) $ log "Did not get EQ"
-  when (not gotGT) $ log "Did not get GT"
-  when (gotLT && gotEQ && gotGT) $ log "Done"
diff --git a/examples/passing/SolvingIsSymbol.purs b/examples/passing/SolvingIsSymbol.purs
deleted file mode 100644
--- a/examples/passing/SolvingIsSymbol.purs
+++ /dev/null
@@ -1,13 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff
-import Control.Monad.Eff.Console
-
--- Here we import as alias of reflectSymbol without importing Data.Symbol. However,
--- Data.Symbol should be implicitly imported as we have an instance of IsSymbol solved.
-import SolvingIsSymbol.Lib (literalSymbol, libReflectSymbol)
-
-main = do
-  let lit = libReflectSymbol literalSymbol
-  when (lit == "literal") (log "Done")
diff --git a/examples/passing/SolvingIsSymbol/Lib.purs b/examples/passing/SolvingIsSymbol/Lib.purs
deleted file mode 100644
--- a/examples/passing/SolvingIsSymbol/Lib.purs
+++ /dev/null
@@ -1,10 +0,0 @@
-module SolvingIsSymbol.Lib where
-
-import Data.Symbol
-
-literalSymbol :: SProxy "literal"
-literalSymbol = SProxy
-
-libReflectSymbol :: forall s. IsSymbol s => SProxy s -> String
-libReflectSymbol = reflectSymbol
-
diff --git a/examples/passing/Stream.purs b/examples/passing/Stream.purs
deleted file mode 100644
--- a/examples/passing/Stream.purs
+++ /dev/null
@@ -1,26 +0,0 @@
-module Main where
-
-import Prelude
-
-import Control.Monad.Eff (Eff)
-import Control.Monad.Eff.Console (CONSOLE, log)
-
-class IsStream el s | s -> el where
-  cons :: el -> (Unit -> s) -> s
-  uncons :: s -> { head :: el, tail :: s }
-
-data Stream a = Stream a (Unit -> Stream a)
-
-instance streamIsStream :: IsStream a (Stream a) where
-  cons x xs = Stream x xs
-  uncons (Stream x f) = { head: x, tail: f unit }
-
-test :: forall el s. IsStream el s => s -> s
-test s = case uncons s of
-           { head, tail } -> cons head \_ -> tail
-
-main :: Eff (console :: CONSOLE) Unit
-main = do
-  let dones :: Stream String
-      dones = cons "Done" \_ -> dones
-  log (uncons (test dones)).head
diff --git a/examples/passing/StringEdgeCases.purs b/examples/passing/StringEdgeCases.purs
deleted file mode 100644
--- a/examples/passing/StringEdgeCases.purs
+++ /dev/null
@@ -1,9 +0,0 @@
-module Main where
-
-import Prelude
-import Records as Records
-import Symbols as Symbols
-
-main = do
-  Records.main
-  Symbols.main
diff --git a/examples/passing/StringEdgeCases/Records.purs b/examples/passing/StringEdgeCases/Records.purs
deleted file mode 100644
--- a/examples/passing/StringEdgeCases/Records.purs
+++ /dev/null
@@ -1,66 +0,0 @@
-module Records where
-
-import Prelude
-import Data.Generic (class Generic, toSpine, GenericSpine(..))
-import Control.Monad.Eff.Console (log)
-import Test.Assert (assert')
-
-newtype AstralKeys = AstralKeys { "💡" :: Int, "💢" :: Int }
-newtype LoneSurrogateKeys = LoneSurrogateKeys { "\xdf06" :: Int, "\xd834" :: Int }
-
-derive instance genericAstralKeys :: Generic AstralKeys
-derive instance genericLoneSurrogateKeys :: Generic LoneSurrogateKeys
-
-spineOf :: forall a. Generic a => a -> Unit -> GenericSpine
-spineOf x _ = toSpine x
-
-testLoneSurrogateKeys =
-  let
-    expected = 5
-    actual = (_."\xd801" <<< helper) { "\xd800": 5 }
-  in
-    assert' ("lone surrogate keys: " <> show actual) (expected == actual)
-
-  where
-  helper :: { "\xd800" :: Int } -> { "\xd801" :: Int }
-  helper o =
-    case o."\xd800" of
-      x -> { "\xd801": x }
-
-testAstralKeys =
-  let
-    expected = 5
-    actual = (_."💢" <<< helper) { "💡": 5 }
-  in
-    assert' ("astral keys: " <> show actual) (expected == actual)
-
-  where
-  helper :: { "💡" :: Int } -> { "💢" :: Int }
-  helper o =
-    case o."💡" of
-      x -> { "💢": x }
-
-testGenericLoneSurrogateKeys = do
-  let expected = SProd "Records.LoneSurrogateKeys"
-                  [ \_ -> SRecord [ {recLabel: "\xd834", recValue: spineOf 1}
-                                  , {recLabel: "\xdf06", recValue: spineOf 0}
-                                  ]
-                  ]
-      actual = toSpine (LoneSurrogateKeys { "\xdf06": 0, "\xd834": 1 })
-  assert' ("generic lone surrogate keys: " <> show actual) (expected == actual)
-
-testGenericAstralKeys = do
-  let expected = SProd "Records.AstralKeys"
-                  [ \_ -> SRecord [ {recLabel: "💡", recValue: spineOf 0}
-                                  , {recLabel: "💢", recValue: spineOf 1}
-                                  ]
-                  ]
-      actual = toSpine (AstralKeys { "💡": 0, "💢": 1 })
-  assert' ("generic astral keys: " <> show actual) (expected == actual)
-
-main = do
-  testLoneSurrogateKeys
-  testAstralKeys
-  testGenericLoneSurrogateKeys
-  testGenericAstralKeys
-  log "Done"
diff --git a/examples/passing/StringEdgeCases/Symbols.purs b/examples/passing/StringEdgeCases/Symbols.purs
deleted file mode 100644
--- a/examples/passing/StringEdgeCases/Symbols.purs
+++ /dev/null
@@ -1,30 +0,0 @@
--- This is similar to StringEscapes except we are performing the same tests
--- with Symbols (at the type level).
-
-module Symbols where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-import Type.Data.Symbol (SProxy(..), class AppendSymbol, appendSymbol, reflectSymbol)
-import Test.Assert (assert')
-
-highS :: SProxy "\xd834"
-highS = SProxy
-
-lowS :: SProxy "\xdf06"
-lowS = SProxy
-
-loneSurrogates :: Boolean
-loneSurrogates = reflectSymbol (appendSymbol highS lowS) == "\x1d306"
-
-outOfOrderSurrogates :: Boolean
-outOfOrderSurrogates = reflectSymbol (appendSymbol lowS highS) == "\xdf06\xd834"
-
-notReplacing :: Boolean
-notReplacing = reflectSymbol lowS /= "\xfffd"
-
-main = do
-  assert' "lone surrogates may be combined into a surrogate pair" loneSurrogates
-  assert' "lone surrogates may be combined out of order to remain lone surrogates" outOfOrderSurrogates
-  assert' "lone surrogates are not replaced with the Unicode replacement character U+FFFD" notReplacing
-  log "Done"
diff --git a/examples/passing/StringEscapes.purs b/examples/passing/StringEscapes.purs
deleted file mode 100644
--- a/examples/passing/StringEscapes.purs
+++ /dev/null
@@ -1,26 +0,0 @@
-module Main where
-
-import Prelude ((==), (/=), (<>), discard)
-import Test.Assert (assert, assert')
-import Control.Monad.Eff.Console (log)
-
-singleCharacter = "\0\b\t\n\v\f\r\"\\" == "\x0\x8\x9\xA\xB\xC\xD\x22\x5C"
-hex = "\x1D306\x2603\x3C6\xE0\x0" == "𝌆☃φà\0"
-decimal  = "\119558\9731\966\224\0" == "𝌆☃φà\0"
-surrogatePair = "\xD834\xDF06" == "\x1D306"
-highSurrogate = "\xD834"
-lowSurrogate = "\xDF06"
-loneSurrogates = (highSurrogate <> lowSurrogate) == "\x1D306"
-outOfOrderSurrogates = (lowSurrogate <> highSurrogate) == "\xDF06\xD834"
-replacement = "\xFFFD"
-notReplacing = replacement /= highSurrogate
-
-main = do
-  assert' "single-character escape sequences" singleCharacter
-  assert' "hex escape sequences" hex
-  assert' "decimal escape sequences" decimal
-  assert' "astral code points are represented as a UTF-16 surrogate pair" surrogatePair
-  assert' "lone surrogates may be combined into a surrogate pair" loneSurrogates
-  assert' "lone surrogates may be combined out of order to remain lone surrogates" outOfOrderSurrogates
-  assert' "lone surrogates are not replaced with the Unicode replacement character U+FFFD" notReplacing
-  log "Done"
diff --git a/examples/passing/Superclasses1.purs b/examples/passing/Superclasses1.purs
deleted file mode 100644
--- a/examples/passing/Superclasses1.purs
+++ /dev/null
@@ -1,23 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log, logShow)
-
-class Su a where
-  su :: a -> a
-
-class (Su a) <= Cl a where
-  cl :: a -> a -> a
-
-instance suNumber :: Su Number where
-  su n = n + 1.0
-
-instance clNumber :: Cl Number where
-  cl n m = n + m
-
-test :: forall a. Cl a => a -> a
-test a = su (cl a a)
-
-main = do
-  logShow $ test 10.0
-  log "Done"
diff --git a/examples/passing/Superclasses3.purs b/examples/passing/Superclasses3.purs
deleted file mode 100644
--- a/examples/passing/Superclasses3.purs
+++ /dev/null
@@ -1,41 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console
-import Control.Monad.Eff
-
-class Monad m <= MonadWriter w m where
-  tell :: w -> m Unit
-
-testFunctor :: forall m. Monad m => m Number -> m Number
-testFunctor n = (+) 1.0 <$> n
-
-test :: forall w m. Monad m => MonadWriter w m => w -> m Unit
-test w = do
-  tell w
-  tell w
-  tell w
-
-data MTrace a = MTrace (Eff (console :: CONSOLE) a)
-
-runMTrace :: forall a. MTrace a -> Eff (console :: CONSOLE) a
-runMTrace (MTrace a) = a
-
-instance functorMTrace :: Functor MTrace where
-  map = liftM1
-
-instance applyMTrace :: Apply MTrace where
-  apply = ap
-
-instance applicativeMTrace :: Applicative MTrace where
-  pure = MTrace <<< pure
-
-instance bindMTrace :: Bind MTrace where
-  bind m f = MTrace (runMTrace m >>= (runMTrace <<< f))
-
-instance monadMTrace :: Monad MTrace
-
-instance writerMTrace :: MonadWriter String MTrace where
-  tell s = MTrace (log s)
-
-main = runMTrace $ test "Done"
diff --git a/examples/passing/TCO.purs b/examples/passing/TCO.purs
deleted file mode 100644
--- a/examples/passing/TCO.purs
+++ /dev/null
@@ -1,28 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log, logShow)
-import Control.Monad.Rec.Class
-import Data.Array ((..), span, length)
-
-main = do
-  let f x = x + 1
-  let v = 0
-  logShow (applyN 0 f v)
-  logShow (applyN 1 f v)
-  logShow (applyN 2 f v)
-  logShow (applyN 3 f v)
-  logShow (applyN 4 f v)
-
-  let largeArray = 1..10000
-  logShow (length (span (\_ -> true) largeArray).init)
-
-  logShow (tailRec (\n -> if n < 10000 then Loop (n + 1) else Done 42) 0)
-
-  log "Done"
-
-applyN :: forall a. Int -> (a -> a) -> a -> a
-applyN = go id
-  where
-  go f n _ | n <= 0 = f
-  go f n g = go (f >>> g) (n - 1) g
diff --git a/examples/passing/TCOCase.purs b/examples/passing/TCOCase.purs
deleted file mode 100644
--- a/examples/passing/TCOCase.purs
+++ /dev/null
@@ -1,13 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-data Data = One | More Data
-
-main = log (from (to 10000.0 One))
-  where
-  to 0.0 a = a
-  to n a = to (n - 1.0) (More a)
-  from One = "Done"
-  from (More d) = from d
diff --git a/examples/passing/TailCall.purs b/examples/passing/TailCall.purs
deleted file mode 100644
--- a/examples/passing/TailCall.purs
+++ /dev/null
@@ -1,20 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log, logShow)
-
-data L a = C a (L a) | N
-
-test :: Number -> L Number -> Number
-test n N = n
-test n (C x xs) = test (n + x) xs
-
-loop :: forall a. Number -> a
-loop x = loop (x + 1.0)
-
-notATailCall = \x ->
-  (\notATailCall -> notATailCall x) (\x -> x)
-
-main = do
-  logShow (test 0.0 (1.0 `C` (2.0 `C` (3.0 `C` N))))
-  log "Done"
diff --git a/examples/passing/Tick.purs b/examples/passing/Tick.purs
deleted file mode 100644
--- a/examples/passing/Tick.purs
+++ /dev/null
@@ -1,8 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-test' x = x
-
-main = log "Done"
diff --git a/examples/passing/TopLevelCase.purs b/examples/passing/TopLevelCase.purs
deleted file mode 100644
--- a/examples/passing/TopLevelCase.purs
+++ /dev/null
@@ -1,19 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-gcd :: Number -> Number -> Number
-gcd 0.0 x = x
-gcd x 0.0 = x
-gcd x y | x > y = gcd (x `mod` y) y
-gcd x y = gcd (y `mod` x) x
-
-guardsTest [x] | x > 0.0 = []
-guardsTest xs = xs
-
-data A = A
-
-parseTest A 0.0 = 0.0
-
-main = log "Done"
diff --git a/examples/passing/TransitiveImport.purs b/examples/passing/TransitiveImport.purs
deleted file mode 100644
--- a/examples/passing/TransitiveImport.purs
+++ /dev/null
@@ -1,9 +0,0 @@
-module Main where
-
-  import Prelude
-  import Middle
-  import Control.Monad.Eff.Console
-
-  main = do
-    logShow (middle unit)
-    log "Done"
diff --git a/examples/passing/TransitiveImport/Middle.purs b/examples/passing/TransitiveImport/Middle.purs
deleted file mode 100644
--- a/examples/passing/TransitiveImport/Middle.purs
+++ /dev/null
@@ -1,5 +0,0 @@
-module Middle where
-
-import Test (test)
-
-middle = test
diff --git a/examples/passing/TransitiveImport/Test.purs b/examples/passing/TransitiveImport/Test.purs
deleted file mode 100644
--- a/examples/passing/TransitiveImport/Test.purs
+++ /dev/null
@@ -1,9 +0,0 @@
-module Test where
-
-import Prelude
-
-class TestCls a where
-  test :: a -> a
-
-instance unitTestCls :: TestCls Unit where
-  test _ = unit
diff --git a/examples/passing/TypeClassMemberOrderChange.purs b/examples/passing/TypeClassMemberOrderChange.purs
deleted file mode 100644
--- a/examples/passing/TypeClassMemberOrderChange.purs
+++ /dev/null
@@ -1,16 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-class Test a where
-  fn :: a -> a -> a
-  val :: a
-
-instance testBoolean :: Test Boolean where
-  val = true
-  fn x y = y
-
-main = do
-  log (show (fn true val))
-  log "Done"
diff --git a/examples/passing/TypeClasses.purs b/examples/passing/TypeClasses.purs
deleted file mode 100644
--- a/examples/passing/TypeClasses.purs
+++ /dev/null
@@ -1,71 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-test1 = \_ -> show "testing"
-
-f :: forall a. Show a => a -> String
-f x = show x
-
-test2 = \_ -> f "testing"
-
-test7 :: forall a. Show a => a -> String
-test7 = show
-
-test8 = \_ -> show $ "testing"
-
-data Data a = Data a
-
-instance showData :: Show a => Show (Data a) where
-  show (Data a) = "Data (" <> show a <> ")"
-
-test3 = \_ -> show (Data "testing")
-
-instance functorData :: Functor Data where
-  map = liftM1
-
-instance applyData :: Apply Data where
-  apply = ap
-
-instance applicativeData :: Applicative Data where
-  pure = Data
-
-instance bindData :: Bind Data where
-  bind (Data a) f = f a
-
-instance monadData :: Monad Data
-
-data Maybe a = Nothing | Just a
-
-instance functorMaybe :: Functor Maybe where
-  map = liftM1
-
-instance applyMaybe :: Apply Maybe where
-  apply = ap
-
-instance applicativeMaybe :: Applicative Maybe where
-  pure = Just
-
-instance bindMaybe :: Bind Maybe where
-  bind Nothing _ = Nothing
-  bind (Just a) f = f a
-
-instance monadMaybe :: Monad Maybe
-
-test4 :: forall a m. Monad m => a -> m Number
-test4 = \_ -> pure 1.0
-
-test5 = \_ -> Just 1.0 >>= \n -> pure (n + 1.0)
-
-ask r = r
-
-runReader r f = f r
-
-test9 _ = runReader 0.0 $ do
-  n <- ask
-  pure $ n + 1.0
-
-main = do
-  log (test7 "Hello")
-  log "Done"
diff --git a/examples/passing/TypeClassesInOrder.purs b/examples/passing/TypeClassesInOrder.purs
deleted file mode 100644
--- a/examples/passing/TypeClassesInOrder.purs
+++ /dev/null
@@ -1,12 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-class Foo a where
-  foo :: a -> String
-
-instance fooString :: Foo String where
-  foo s = s
-
-main = log $ foo "Done"
diff --git a/examples/passing/TypeClassesWithOverlappingTypeVariables.purs b/examples/passing/TypeClassesWithOverlappingTypeVariables.purs
deleted file mode 100644
--- a/examples/passing/TypeClassesWithOverlappingTypeVariables.purs
+++ /dev/null
@@ -1,12 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-data Either a b = Left a | Right b
-
-instance functorEither :: Functor (Either a) where
-  map _ (Left x) = Left x
-  map f (Right y) = Right (f y)
-
-main = log "Done"
diff --git a/examples/passing/TypeDecl.purs b/examples/passing/TypeDecl.purs
deleted file mode 100644
--- a/examples/passing/TypeDecl.purs
+++ /dev/null
@@ -1,13 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-k :: String -> Number -> String
-k x y = x
-
-iterate :: forall a. Number -> (a -> a) -> a -> a
-iterate 0.0 f a = a
-iterate n f a = iterate (n - 1.0) f (f a)
-
-main = log "Done"
diff --git a/examples/passing/TypeOperators.purs b/examples/passing/TypeOperators.purs
deleted file mode 100644
--- a/examples/passing/TypeOperators.purs
+++ /dev/null
@@ -1,20 +0,0 @@
-module Main where
-
-import A (type (~>), type (/\), (/\))
-import Control.Monad.Eff.Console (log)
-
-natty ∷ ∀ f. f ~> f
-natty x = x
-
-data Compose f g a = Compose (f (g a))
-
-testPrecedence1 ∷ ∀ f g. Compose f g ~> Compose f g
-testPrecedence1 x = x
-
-testPrecedence2 ∷ ∀ f g. f ~> g → f ~> g
-testPrecedence2 nat fx = nat fx
-
-swap ∷ ∀ a b. a /\ b → b /\ a
-swap (a /\ b) = b /\ a
-
-main = log "Done"
diff --git a/examples/passing/TypeOperators/A.purs b/examples/passing/TypeOperators/A.purs
deleted file mode 100644
--- a/examples/passing/TypeOperators/A.purs
+++ /dev/null
@@ -1,22 +0,0 @@
-module A
-( Tuple(..)
-, type (/\)
-, (/\)
-, Natural
-, type (~>)
-) where
-
-data Tuple a b = Tuple a b
-
-infixl 6 Tuple as /\
-infixl 6 type Tuple as /\
-
-type Natural f g = ∀ a. f a → g a
-
-infixr 0 type Natural as ~>
-
-tup ∷ ∀ a b. a → b → b /\ a
-tup a b = b /\ a
-
-tupX ∷ ∀ a b c. a /\ b /\ c → c
-tupX (a /\ b /\ c) = c
diff --git a/examples/passing/TypeSynonymInData.purs b/examples/passing/TypeSynonymInData.purs
deleted file mode 100644
--- a/examples/passing/TypeSynonymInData.purs
+++ /dev/null
@@ -1,12 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-type A a = Array a
-
-data Foo a = Foo (A a) | Bar
-
-foo (Foo []) = Bar
-
-main = log "Done"
diff --git a/examples/passing/TypeSynonyms.purs b/examples/passing/TypeSynonyms.purs
deleted file mode 100644
--- a/examples/passing/TypeSynonyms.purs
+++ /dev/null
@@ -1,28 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-type Lens a b =
-  { get :: a -> b
-  , set :: a -> b -> a
-  }
-
-composeLenses :: forall a b c. Lens a b -> Lens b c -> Lens a c
-composeLenses = \l1 -> \l2 ->
-  { get: \a -> l2.get (l1.get a)
-  , set: \a c -> l1.set a (l2.set (l1.get a) c)
-  }
-
-type Pair a b = { fst :: a, snd :: b }
-
-fst :: forall a b. Lens (Pair a b) a
-fst =
-  { get: \p -> p.fst
-  , set: \p a -> { fst: a, snd: p.snd }
-  }
-
-test1 :: forall a b c. Lens (Pair (Pair a b) c) a
-test1 = composeLenses fst fst
-
-main = log "Done"
diff --git a/examples/passing/TypeWildcards.purs b/examples/passing/TypeWildcards.purs
deleted file mode 100644
--- a/examples/passing/TypeWildcards.purs
+++ /dev/null
@@ -1,16 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-testTopLevel :: _ -> _
-testTopLevel n = n + 1.0
-
-test :: forall a. Eq a => (a -> a) -> a -> a
-test f a = go (f a) a
-  where
-  go :: _ -> _ -> _
-  go a1 a2 | a1 == a2 = a1
-  go a1 _ = go (f a1) a1
-
-main = log "Done"
diff --git a/examples/passing/TypeWildcardsRecordExtension.purs b/examples/passing/TypeWildcardsRecordExtension.purs
deleted file mode 100644
--- a/examples/passing/TypeWildcardsRecordExtension.purs
+++ /dev/null
@@ -1,9 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-foo :: forall a. {b :: Number | a} -> {b :: Number | _}
-foo f = f
-
-main = log "Done"
diff --git a/examples/passing/TypeWithoutParens.purs b/examples/passing/TypeWithoutParens.purs
deleted file mode 100644
--- a/examples/passing/TypeWithoutParens.purs
+++ /dev/null
@@ -1,12 +0,0 @@
-module Main where
-
-import Lib (X, Y)
-import Control.Monad.Eff.Console (log)
-
-idX :: X -> X
-idX x = x
-
-idY :: Y -> Y
-idY y = y
-
-main = log "Done"
diff --git a/examples/passing/TypeWithoutParens/Lib.purs b/examples/passing/TypeWithoutParens/Lib.purs
deleted file mode 100644
--- a/examples/passing/TypeWithoutParens/Lib.purs
+++ /dev/null
@@ -1,4 +0,0 @@
-module Lib (X, Y) where
-
-data X = X
-type Y = X
diff --git a/examples/passing/TypedBinders.purs b/examples/passing/TypedBinders.purs
deleted file mode 100644
--- a/examples/passing/TypedBinders.purs
+++ /dev/null
@@ -1,68 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-data Tuple a b = Tuple a b
-
-class MonadState s m where
-  get :: m s
-  put :: s -> m Unit
-
-data State s a = State (s -> Tuple s a)
-
-runState s (State f) = f s
-
-instance functorState :: Functor (State s) where
-  map = liftM1
-
-instance applyState :: Apply (State s) where
-  apply = ap
-
-instance applicativeState :: Applicative (State s) where
-  pure a = State $ \s -> Tuple s a
-
-instance bindState :: Bind (State s) where
-  bind f g = State $ \s -> case runState s f of
-                              Tuple s1 a -> runState s1 (g a)
-
-instance monadState :: Monad (State s)
-
-instance monadStateState :: MonadState s (State s) where
-  get = State (\s -> Tuple s s)
-  put s = State (\_ -> Tuple s unit)
-
-modify :: forall m s. Monad m => MonadState s m => (s -> s) -> m Unit
-modify f = do
-  s <- get
-  put (f s)
-
-test :: Tuple String String
-test = runState "" $ do
-  modify $ (<>) "World!"
-  modify $ (<>) "Hello, "
-  str :: String <- get
-  pure str
-
-test2 :: (Int -> Int) -> Int
-test2 = (\(f :: Int -> Int) -> f 10)
-
-test3 :: Int -> Boolean
-test3 n = case n of
-  (0 :: Int) -> true
-  _ -> false
-
-test4 :: Tuple Int Int -> Tuple Int Int
-test4 = (\(Tuple a b :: Tuple Int Int) -> Tuple b a)
-
-type Int1 = Int
-
-test5 :: Int1 -> Int1
-test5 = \(x :: Int1) -> x
-
-main = do
-  let t1 = test
-      t2 = test2 id
-      t3 = test3 1
-      t4 = test4 (Tuple 1 0)
-  log "Done"
diff --git a/examples/passing/TypedWhere.purs b/examples/passing/TypedWhere.purs
deleted file mode 100644
--- a/examples/passing/TypedWhere.purs
+++ /dev/null
@@ -1,18 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-data E a b = L a | R b
-
-data L a = C a (L a) | N
-
-lefts :: forall a b. L (E a b) -> L a
-lefts = go N
-  where
-  go :: forall a b. L a -> L (E a b) -> L a
-  go ls N = ls
-  go ls (C (L a) rest) = go (C a ls) rest
-  go ls (C _ rest) = go ls rest
-
-main = log "Done"
diff --git a/examples/passing/UTF8Sourcefile.purs b/examples/passing/UTF8Sourcefile.purs
deleted file mode 100644
--- a/examples/passing/UTF8Sourcefile.purs
+++ /dev/null
@@ -1,8 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console
-
--- '→' is multibyte sequence \u2192.
-utf8multibyte = "Hello λ→ world!!"
-
-main = log "Done"
diff --git a/examples/passing/UnderscoreIdent.purs b/examples/passing/UnderscoreIdent.purs
deleted file mode 100644
--- a/examples/passing/UnderscoreIdent.purs
+++ /dev/null
@@ -1,13 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-data Data_type = Con_Structor | Con_2 String
-
-type Type_name = Data_type
-
-done (Con_2 s) = s
-done _ = "Failed"
-
-main = log (done (Con_2 "Done"))
diff --git a/examples/passing/UnicodeIdentifier.purs b/examples/passing/UnicodeIdentifier.purs
deleted file mode 100644
--- a/examples/passing/UnicodeIdentifier.purs
+++ /dev/null
@@ -1,7 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console (log)
-
-f asgård = asgård
-
-main = log (f "Done")
diff --git a/examples/passing/UnicodeOperators.purs b/examples/passing/UnicodeOperators.purs
deleted file mode 100644
--- a/examples/passing/UnicodeOperators.purs
+++ /dev/null
@@ -1,22 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console (log)
-
-compose :: forall a b c. (b -> c) -> (a -> b) -> a -> c
-compose f g a = f (g a)
-
-infixr 9 compose as ∘
-
-test1 = (\x -> x) ∘ \y -> y
-
-elem :: forall a b. a -> (a -> Boolean) -> Boolean
-elem x f = f x
-
-infixl 1 elem as ∈
-
-emptySet :: forall a. a -> Boolean
-emptySet _ = true
-
-test2 = 1 ∈ emptySet
-
-main = log "Done"
diff --git a/examples/passing/UnicodeType.purs b/examples/passing/UnicodeType.purs
deleted file mode 100644
--- a/examples/passing/UnicodeType.purs
+++ /dev/null
@@ -1,22 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-class Monad m ⇐ Monad1 m where
-  f1 :: m Int
-
-class Monad m <= Monad2 m where
-  f2 :: m Int
-
-f ∷ ∀ m. Monad m ⇒ Int → m Int
-f n = do
-  n' ← pure n
-  pure n'
-
-f' :: forall m. Monad m => Int -> m Int
-f' n = do
-  n' <- pure n
-  pure n'
-
-main = log "Done"
diff --git a/examples/passing/UnifyInTypeInstanceLookup.purs b/examples/passing/UnifyInTypeInstanceLookup.purs
deleted file mode 100644
--- a/examples/passing/UnifyInTypeInstanceLookup.purs
+++ /dev/null
@@ -1,25 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console (log)
-
-data Z = Z
-data S n = S n
-
-data T
-data F
-
-class EQ x y b
-instance eqT :: EQ x x T
-instance eqF :: EQ x y F
-
-test :: forall a b. EQ a b T => a -> b -> a
-test a _ = a
-
-spin :: forall a b. a -> b
-spin a = spin a
-
--- Expected type:
--- forall t. (EQ t (S Z) T) => t
-test1 = test (spin 1) (S Z)
-
-main = log "Done"
diff --git a/examples/passing/Unit.purs b/examples/passing/Unit.purs
deleted file mode 100644
--- a/examples/passing/Unit.purs
+++ /dev/null
@@ -1,8 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (logShow, log)
-
-main = do
-  logShow (const unit $ "Hello world")
-  log "Done"
diff --git a/examples/passing/UnknownInTypeClassLookup.purs b/examples/passing/UnknownInTypeClassLookup.purs
deleted file mode 100644
--- a/examples/passing/UnknownInTypeClassLookup.purs
+++ /dev/null
@@ -1,15 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-class EQ a b
-
-instance eqAA :: EQ a a
-
-test :: forall a b. EQ a b => a -> b -> String
-test _ _ = "Done"
-
-runTest a = test a a
-
-main = log $ runTest 0.0
diff --git a/examples/passing/UnsafeCoerce.purs b/examples/passing/UnsafeCoerce.purs
deleted file mode 100644
--- a/examples/passing/UnsafeCoerce.purs
+++ /dev/null
@@ -1,16 +0,0 @@
-module Main where
-
-import Prelude (Unit)
-import Unsafe.Coerce (unsafeCoerce)
-import Control.Monad.Eff (Eff)
-import Control.Monad.Eff.Console (CONSOLE, log)
-
-x :: Number
-x = unsafeCoerce 1
-
-y :: Number
-y = case unsafeCoerce 1 of
-  z -> unsafeCoerce z
-
-main :: Eff (console :: CONSOLE) Unit
-main = log "Done"
diff --git a/examples/passing/UntupledConstraints.purs b/examples/passing/UntupledConstraints.purs
deleted file mode 100644
--- a/examples/passing/UntupledConstraints.purs
+++ /dev/null
@@ -1,17 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-class Show a <= Nonsense a where
-  method :: a -> a
-
-data Box a = Box a
-
-instance showBox :: Show a => Show (Box a) where
-  show (Box a) = "Box " <> show a
-
-strangeThing :: forall m. Semigroup (m Unit) => m Unit -> m Unit -> m Unit
-strangeThing x y = x <> y
-
-main = log "Done"
diff --git a/examples/passing/UsableTypeClassMethods.purs b/examples/passing/UsableTypeClassMethods.purs
deleted file mode 100644
--- a/examples/passing/UsableTypeClassMethods.purs
+++ /dev/null
@@ -1,35 +0,0 @@
--- this is testing that we don't see an `UnusableDeclaration` error for type
--- class methods that should be valid based on various configurations of fundeps
-module Main where
-
-import Control.Monad.Eff.Console (log)
-
--- no fundeps
-class C0 a b where
-  c0 :: a -> b
-
--- simple fundep
-class C1 a b | a -> b where
-  c1 :: a
-  c1' :: a -> b
-
--- transitive
-class C2 a b c | a -> b, b -> c where
-  c2 :: a
-  c2' :: a -> b
-  c2'' :: a -> c
-  c2''' :: a -> b -> c
-
--- with cycles
-class C3 a b c | a -> b, b -> a, b -> c where
-  c3 :: a
-  c3' :: b
-  c3'' :: a -> c
-  c3''' :: b -> c
-  c3'''' :: a -> b -> c
-
--- nullary class
-class C4 where
-  c4 :: forall a. a
-
-main = log "Done"
diff --git a/examples/passing/Where.purs b/examples/passing/Where.purs
deleted file mode 100644
--- a/examples/passing/Where.purs
+++ /dev/null
@@ -1,49 +0,0 @@
-module Main where
-
-import Prelude
-import Partial.Unsafe (unsafePartial)
-import Control.Monad.Eff
-import Control.Monad.Eff.Console (logShow, log)
-
-test1 x = y
-  where
-  y :: Number
-  y = x + 1.0
-
-test2 x y = x' + y'
-  where
-  x' = x + 1.0
-  y' = y + 1.0
-
-test3 = f 1.0 2.0 3.0
-  where f x y z = x + y + z
-
-test4 = f (+) [1.0, 2.0]
-  where f x [y, z] = x y z
-
-test5 = g 10.0
-  where
-  f x | x > 0.0 = g (x / 2.0) + 1.0
-  f x = 0.0
-  g x = f (x - 1.0) + 1.0
-
-test6 = if f true then f 1.0 else f 2.0
-  where f :: forall a. a -> a
-        f x = x
-
-test7 :: Number -> Number
-test7 x = go x
-  where
-  go y | (x - 0.1 < y * y) && (y * y < x + 0.1) = y
-  go y = go $ (y + x / y) / 2.0
-
-main :: Eff _ _
-main = do
-  logShow (test1 1.0)
-  logShow (test2 1.0 2.0)
-  logShow test3
-  unsafePartial (logShow test4)
-  logShow test5
-  logShow test6
-  logShow (test7 100.0)
-  log "Done"
diff --git a/examples/passing/WildcardInInstance.purs b/examples/passing/WildcardInInstance.purs
deleted file mode 100644
--- a/examples/passing/WildcardInInstance.purs
+++ /dev/null
@@ -1,23 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff
-import Control.Monad.Eff.Console
-
--- Until the functional dependency gets added to purescript-eff, 
--- we need this here.
-class Monad m <= MonadEff eff m | m -> eff where
-  liftEff :: forall a. Eff eff a -> m a
-
-instance monadEffEff :: MonadEff eff (Eff eff) where
-  liftEff = id
-
--- This should generate a warning with the correct inferred type.
-test :: forall m. MonadEff _ m => m Unit
-test = liftEff $ log "Done"
-
-test1 :: Eff _ Unit
-test1 = liftEff $ log "Done"
-
-main :: forall eff. Eff (console :: CONSOLE | eff) Unit
-main = test
diff --git a/examples/passing/WildcardType.purs b/examples/passing/WildcardType.purs
deleted file mode 100644
--- a/examples/passing/WildcardType.purs
+++ /dev/null
@@ -1,12 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-f1 :: (_ -> _) -> _
-f1 g = g 1
-
-f2 :: _ -> _
-f2 _ = "Done"
-
-main = log $ f1 f2
diff --git a/examples/passing/iota.purs b/examples/passing/iota.purs
deleted file mode 100644
--- a/examples/passing/iota.purs
+++ /dev/null
@@ -1,11 +0,0 @@
-module Main where
-
-import Control.Monad.Eff.Console (log)
-
-s = \x -> \y -> \z -> x z (y z)
-
-k = \x -> \y -> x
-
-iota = \x -> x s k
-
-main = log "Done"
diff --git a/examples/passing/s.purs b/examples/passing/s.purs
deleted file mode 100644
--- a/examples/passing/s.purs
+++ /dev/null
@@ -1,8 +0,0 @@
-module Main where
-
-import Prelude
-import Control.Monad.Eff.Console (log)
-
-s = \x y z -> x z (y z)
-
-main = log "Done"
diff --git a/examples/psci/BasicEval.purs b/examples/psci/BasicEval.purs
deleted file mode 100644
--- a/examples/psci/BasicEval.purs
+++ /dev/null
@@ -1,10 +0,0 @@
-import Prelude
-import Data.Array
-
--- @shouldEvaluateTo 3628800
-let fac n = foldl mul 1 (1..n) in fac 10
-
-fac n = foldl mul 1 (1..n)
-
--- @shouldEvaluateTo 3628800
-fac 10
diff --git a/examples/psci/Multiline.purs b/examples/psci/Multiline.purs
deleted file mode 100644
--- a/examples/psci/Multiline.purs
+++ /dev/null
@@ -1,10 +0,0 @@
-import Prelude
-import Data.Array
-
--- @paste
-fac :: Int -> Int
-fac n = foldl mul 1 (1..n)
--- @paste
-
--- @shouldEvaluateTo 3628800
-fac 10
diff --git a/examples/warning/2140.purs b/examples/warning/2140.purs
deleted file mode 100644
--- a/examples/warning/2140.purs
+++ /dev/null
@@ -1,5 +0,0 @@
--- @shouldWarnWith ShadowedTypeVar
-module Main where
-
-class Test a where
-  f :: (forall a. a -> a) -> a -> a
diff --git a/examples/warning/2383.purs b/examples/warning/2383.purs
deleted file mode 100644
--- a/examples/warning/2383.purs
+++ /dev/null
@@ -1,12 +0,0 @@
--- | This specifically shouldn't warn about `x` being shadowed in `main`
--- | See https://github.com/purescript/purescript/issues/2383
-module Main where
-
-import Prelude
-
-import Control.Monad.Eff (Eff)
-
-main :: Eff () Unit
-main = do
-  x <- let x = pure unit in x
-  pure unit
diff --git a/examples/warning/2411.purs b/examples/warning/2411.purs
deleted file mode 100644
--- a/examples/warning/2411.purs
+++ /dev/null
@@ -1,15 +0,0 @@
--- @shouldWarnWith ShadowedName
-module Main where
-
-import Prelude
-
-import Control.Monad.Eff (Eff)
-
-test :: forall m. Monad m => Int -> m Unit
-test x =
-  let x = unit
-  in pure x
-
-main :: Eff () Unit
-main = test 42
-
diff --git a/examples/warning/2542.purs b/examples/warning/2542.purs
deleted file mode 100644
--- a/examples/warning/2542.purs
+++ /dev/null
@@ -1,16 +0,0 @@
--- @shouldWarnWith MissingTypeDeclaration
-module Main where
-
-import Control.Monad.Eff.Console
-
-type T = forall a. Array a
-
--- | Note: This should not raise a `ShadowedTypeVar` warning as the 
--- | type `a` introduced in `T` should not be in scope 
--- | in the definition of `bar`.
-foo :: T
-foo = bar where
-  bar :: forall a. Array a
-  bar = []
-
-main = log "Done"
diff --git a/examples/warning/CustomWarning.purs b/examples/warning/CustomWarning.purs
deleted file mode 100644
--- a/examples/warning/CustomWarning.purs
+++ /dev/null
@@ -1,9 +0,0 @@
--- @shouldWarnWith UserDefinedWarning
-module Main where
-
-foo :: forall t. Warn (TypeConcat "Custom warning " (TypeString t)) => t -> t
-foo x = x
-
-bar :: Int
-bar = foo 42
-
diff --git a/examples/warning/CustomWarning2.purs b/examples/warning/CustomWarning2.purs
deleted file mode 100644
--- a/examples/warning/CustomWarning2.purs
+++ /dev/null
@@ -1,11 +0,0 @@
--- @shouldWarnWith UserDefinedWarning
-module Main where
-
-foo :: Warn "foo" => Int -> Int
-foo x = x
-
-bar :: Warn "foo" => Int
-bar = foo 42
-
-baz :: Int
-baz = bar
diff --git a/examples/warning/CustomWarning3.purs b/examples/warning/CustomWarning3.purs
deleted file mode 100644
--- a/examples/warning/CustomWarning3.purs
+++ /dev/null
@@ -1,13 +0,0 @@
--- @shouldWarnWith UserDefinedWarning
--- @shouldWarnWith UserDefinedWarning
-module Main where
-
-foo :: Warn "foo" => Int -> Int
-foo x = x
-
--- Defer the "foo" warning and warn with "bar" as well
-bar :: Warn "foo" => Warn "bar" => Int
-bar = foo 42
-
-baz :: Int
-baz = bar
diff --git a/examples/warning/DuplicateExportRef.purs b/examples/warning/DuplicateExportRef.purs
deleted file mode 100644
--- a/examples/warning/DuplicateExportRef.purs
+++ /dev/null
@@ -1,30 +0,0 @@
--- @shouldWarnWith DuplicateExportRef
--- @shouldWarnWith DuplicateExportRef
--- @shouldWarnWith DuplicateExportRef
--- @shouldWarnWith DuplicateExportRef
--- @shouldWarnWith DuplicateExportRef
--- @shouldWarnWith DuplicateExportRef
--- @shouldWarnWith DuplicateExportRef
-module Main
-  ( X(X, X), X
-  , fn, fn
-  , (!), (!)
-  , class Y, class Y
-  , Natural, type (~>), type (~>)
-  , module Prelude, module Prelude
-  ) where
-
-import Prelude (Unit)
-
-data X = X
-
-fn :: X -> X -> X
-fn _ _ = X
-
-infix 2 fn as !
-
-class Y a
-
-type Natural f g = forall a. f a -> g a
-
-infixl 1 type Natural as ~>
diff --git a/examples/warning/DuplicateImport.purs b/examples/warning/DuplicateImport.purs
deleted file mode 100644
--- a/examples/warning/DuplicateImport.purs
+++ /dev/null
@@ -1,10 +0,0 @@
--- @shouldWarnWith DuplicateImport
-module Main where
-
-import Prelude (Unit, unit, pure)
-import Prelude (Unit, unit, pure)
-
-import Control.Monad.Eff (Eff)
-
-main :: Eff () Unit
-main = pure unit
diff --git a/examples/warning/DuplicateImportRef.purs b/examples/warning/DuplicateImportRef.purs
deleted file mode 100644
--- a/examples/warning/DuplicateImportRef.purs
+++ /dev/null
@@ -1,18 +0,0 @@
--- @shouldWarnWith DuplicateImportRef
--- @shouldWarnWith DuplicateImportRef
--- @shouldWarnWith DuplicateImportRef
--- @shouldWarnWith DuplicateImportRef
-module Main where
-
-import Prelude
-  ( Unit, Unit
-  , unit, unit
-  , class Functor, class Functor
-  , (<>), (<>)
-  )
-
-u :: Unit
-u = unit <> unit
-
-fid :: forall f a. Functor f => f a -> f a
-fid fa = fa
diff --git a/examples/warning/DuplicateSelectiveImport.purs b/examples/warning/DuplicateSelectiveImport.purs
deleted file mode 100644
--- a/examples/warning/DuplicateSelectiveImport.purs
+++ /dev/null
@@ -1,10 +0,0 @@
--- @shouldWarnWith DuplicateSelectiveImport
-module Main where
-
-import Prelude (Unit, unit)
-import Prelude (pure)
-
-import Control.Monad.Eff (Eff)
-
-main :: Eff () Unit
-main = pure unit
diff --git a/examples/warning/HidingImport.purs b/examples/warning/HidingImport.purs
deleted file mode 100644
--- a/examples/warning/HidingImport.purs
+++ /dev/null
@@ -1,9 +0,0 @@
--- @shouldWarnWith HidingImport
--- @shouldWarnWith HidingImport
-module Main where
-
-import Prelude hiding (one)
-import Control.Monad.Eff hiding (runPure)
-
-main :: Eff () Unit
-main = pure unit
diff --git a/examples/warning/ImplicitImport.purs b/examples/warning/ImplicitImport.purs
deleted file mode 100644
--- a/examples/warning/ImplicitImport.purs
+++ /dev/null
@@ -1,9 +0,0 @@
--- @shouldWarnWith ImplicitImport
--- @shouldWarnWith ImplicitImport
-module Main where
-
-import Prelude
-import Control.Monad.Eff
-
-main :: Eff () Unit
-main = pure unit
diff --git a/examples/warning/ImplicitQualifiedImport.purs b/examples/warning/ImplicitQualifiedImport.purs
deleted file mode 100644
--- a/examples/warning/ImplicitQualifiedImport.purs
+++ /dev/null
@@ -1,11 +0,0 @@
--- @shouldWarnWith ImplicitQualifiedImport
--- @shouldWarnWith ImplicitQualifiedImport
-module Main where
-
-import Data.Unit
-
-import Control.Monad.Eff as E
-import Control.Monad.Eff.Console as E
-
-main :: E.Eff (console :: E.CONSOLE) Unit
-main = E.log "test"
diff --git a/examples/warning/MissingTypeDeclaration.purs b/examples/warning/MissingTypeDeclaration.purs
deleted file mode 100644
--- a/examples/warning/MissingTypeDeclaration.purs
+++ /dev/null
@@ -1,4 +0,0 @@
--- @shouldWarnWith MissingTypeDeclaration
-module Main where
-
-x = 0
diff --git a/examples/warning/NewtypeInstance.purs b/examples/warning/NewtypeInstance.purs
deleted file mode 100644
--- a/examples/warning/NewtypeInstance.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- @shouldWarnWith MissingNewtypeSuperclassInstance
-module Main where
-
-import Prelude
-
-newtype X = X String
-
-derive newtype instance ordX :: Ord X
diff --git a/examples/warning/NewtypeInstance2.purs b/examples/warning/NewtypeInstance2.purs
deleted file mode 100644
--- a/examples/warning/NewtypeInstance2.purs
+++ /dev/null
@@ -1,16 +0,0 @@
--- @shouldWarnWith MissingNewtypeSuperclassInstance
-module Main where
-
-import Prelude
-import Data.Monoid (class Monoid)
-import Data.Tuple (Tuple(..))
-
-class (Monad m, Monoid w) <= MonadWriter w m | m -> w where
-  tell :: w -> m Unit
-
-instance monadWriterTuple :: Monoid w => MonadWriter w (Tuple w) where
-  tell w = Tuple w unit
-
-newtype MyWriter w a = MyWriter (Tuple w a)
-
-derive newtype instance monadWriterMyWriter :: Monoid w => MonadWriter w (MyWriter w)
diff --git a/examples/warning/NewtypeInstance3.purs b/examples/warning/NewtypeInstance3.purs
deleted file mode 100644
--- a/examples/warning/NewtypeInstance3.purs
+++ /dev/null
@@ -1,22 +0,0 @@
--- @shouldWarnWith MissingNewtypeSuperclassInstance
-module Main where
-
-import Prelude
-import Data.Monoid (class Monoid)
-import Data.Tuple (Tuple(..))
-
-class (Monad m, Monoid w) <= MonadTell w m | m -> w where
-  tell :: w -> m Unit
-
-class (MonadTell w m) <= MonadWriter w m | m -> w where
-  listen :: forall a. m a -> m (Tuple w a)
-
-instance monadTellTuple :: Monoid w => MonadTell w (Tuple w) where
-  tell w = Tuple w unit
-
-instance monadWriterTuple :: Monoid w => MonadWriter w (Tuple w) where
-  listen (Tuple w a) = Tuple w (Tuple w a)
-
-newtype MyWriter w a = MyWriter (Tuple w a)
-
-derive newtype instance monadWriterMyWriter :: Monoid w => MonadWriter w (MyWriter w)
diff --git a/examples/warning/NewtypeInstance4.purs b/examples/warning/NewtypeInstance4.purs
deleted file mode 100644
--- a/examples/warning/NewtypeInstance4.purs
+++ /dev/null
@@ -1,24 +0,0 @@
--- @shouldWarnWith UnverifiableSuperclassInstance
-module Main where
-
-import Prelude
-import Data.Monoid (class Monoid)
-import Data.Tuple (Tuple(..))
-
-class Monoid w <= MonadTell w m where
-  tell :: w -> m Unit
-
-class (MonadTell w m) <= MonadWriter w m where
-  listen :: forall a. m a -> m (Tuple w a)
-
-instance monadTellTuple :: Monoid w => MonadTell w (Tuple w) where
-  tell w = Tuple w unit
-
-instance monadWriterTuple :: Monoid w => MonadWriter w (Tuple w) where
-  listen (Tuple w a) = Tuple w (Tuple w a)
-
-newtype MyWriter w a = MyWriter (Tuple w a)
-
--- No fundep means this is unverifiable
-derive newtype instance monadTellMyWriter :: Monoid w => MonadTell w (MyWriter w)
-derive newtype instance monadWriterMyWriter :: Monoid w => MonadWriter w (MyWriter w)
diff --git a/examples/warning/OverlappingInstances.purs b/examples/warning/OverlappingInstances.purs
deleted file mode 100644
--- a/examples/warning/OverlappingInstances.purs
+++ /dev/null
@@ -1,17 +0,0 @@
--- @shouldWarnWith OverlappingInstances
-module Main where
-
-class Test a where
-  test :: a -> a
-
-instance testRefl :: Test a where
-  test x = x
-
-instance testInt :: Test Int where
-  test _ = 0
-
--- The OverlappingInstances instances warning only arises when there are two
--- choices for a dictionary, not when the instances are defined. So without
--- `value` this module would not raise a warning.
-value :: Int
-value = test 1
diff --git a/examples/warning/OverlappingPattern.purs b/examples/warning/OverlappingPattern.purs
deleted file mode 100644
--- a/examples/warning/OverlappingPattern.purs
+++ /dev/null
@@ -1,15 +0,0 @@
--- @shouldWarnWith OverlappingPattern
--- @shouldWarnWith OverlappingPattern
-module Main where
-
-data X = A | B
-
-pat1 :: X -> Boolean
-pat1 A = true
-pat1 A = true
-pat1 B = false
-
-pat2 :: X -> Boolean
-pat2 A = true
-pat2 _ = false
-pat2 B = false
diff --git a/examples/warning/ScopeShadowing.purs b/examples/warning/ScopeShadowing.purs
deleted file mode 100644
--- a/examples/warning/ScopeShadowing.purs
+++ /dev/null
@@ -1,13 +0,0 @@
--- @shouldWarnWith ScopeShadowing
-module Main where
-
-import Prelude
-
--- No warning at the definition, only when the name is later resolved
-data Unit = Unit
-
--- This is only a warning as the `Prelude` import is implicit. If `Unit` was
--- named explicitly in an import list, then this refernce to `Unit`
--- would be a `ScopeConflict` error instead.
-test :: Unit
-test = const Unit unit
diff --git a/examples/warning/ShadowedBinderPatternGuard.purs b/examples/warning/ShadowedBinderPatternGuard.purs
deleted file mode 100644
--- a/examples/warning/ShadowedBinderPatternGuard.purs
+++ /dev/null
@@ -1,7 +0,0 @@
--- @shouldWarnWith ShadowedName
-module Main where
-
-f :: Int -> Int
-f n | i <- true -- this i is shadowed
-	, i <- 1234
-	= i
diff --git a/examples/warning/ShadowedNameParens.purs b/examples/warning/ShadowedNameParens.purs
deleted file mode 100644
--- a/examples/warning/ShadowedNameParens.purs
+++ /dev/null
@@ -1,5 +0,0 @@
--- @shouldWarnWith ShadowedName
-module Main where
-
-f :: Int -> Int -> Int
-f n = \(n) -> 1
diff --git a/examples/warning/ShadowedTypeVar.purs b/examples/warning/ShadowedTypeVar.purs
deleted file mode 100644
--- a/examples/warning/ShadowedTypeVar.purs
+++ /dev/null
@@ -1,5 +0,0 @@
--- @shouldWarnWith ShadowedTypeVar
-module Main where
-
-f :: forall a. (forall a. a -> a) -> a -> a
-f g x = g x
diff --git a/examples/warning/UnnecessaryFFIModule.js b/examples/warning/UnnecessaryFFIModule.js
deleted file mode 100644
--- a/examples/warning/UnnecessaryFFIModule.js
+++ /dev/null
@@ -1,1 +0,0 @@
-exports.out = null;
diff --git a/examples/warning/UnnecessaryFFIModule.purs b/examples/warning/UnnecessaryFFIModule.purs
deleted file mode 100644
--- a/examples/warning/UnnecessaryFFIModule.purs
+++ /dev/null
@@ -1,5 +0,0 @@
--- @shouldWarnWith UnnecessaryFFIModule
-module Main where
-
-t :: Boolean
-t = true
diff --git a/examples/warning/UnusedDctorExplicitImport.purs b/examples/warning/UnusedDctorExplicitImport.purs
deleted file mode 100644
--- a/examples/warning/UnusedDctorExplicitImport.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- @shouldWarnWith UnusedDctorExplicitImport
-module Main where
-
-import Data.Ordering (Ordering(EQ, LT))
-
-f :: Ordering -> Ordering
-f EQ = EQ
-f x = x
diff --git a/examples/warning/UnusedDctorImportAll.purs b/examples/warning/UnusedDctorImportAll.purs
deleted file mode 100644
--- a/examples/warning/UnusedDctorImportAll.purs
+++ /dev/null
@@ -1,7 +0,0 @@
--- @shouldWarnWith UnusedDctorImport
-module Main where
-
-import Data.Ordering (Ordering(..))
-
-f :: Ordering -> Ordering
-f x = x
diff --git a/examples/warning/UnusedDctorImportExplicit.purs b/examples/warning/UnusedDctorImportExplicit.purs
deleted file mode 100644
--- a/examples/warning/UnusedDctorImportExplicit.purs
+++ /dev/null
@@ -1,7 +0,0 @@
--- @shouldWarnWith UnusedDctorImport
-module Main where
-
-import Data.Ordering (Ordering(EQ))
-
-f :: Ordering -> Ordering
-f x = x
diff --git a/examples/warning/UnusedExplicitImport.purs b/examples/warning/UnusedExplicitImport.purs
deleted file mode 100644
--- a/examples/warning/UnusedExplicitImport.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- @shouldWarnWith UnusedExplicitImport
-module Main where
-
-import Prelude (Unit, unit, pure, bind)
-import Control.Monad.Eff (Eff)
-
-main :: Eff () Unit
-main = pure unit
diff --git a/examples/warning/UnusedExplicitImportTypeOp.purs b/examples/warning/UnusedExplicitImportTypeOp.purs
deleted file mode 100644
--- a/examples/warning/UnusedExplicitImportTypeOp.purs
+++ /dev/null
@@ -1,9 +0,0 @@
--- @shouldWarnWith UnusedExplicitImport
-module Main where
-
-import Prelude (Unit, unit, pure)
-import Control.Monad.Eff (Eff)
-import Lib (type (~>), natId)
-
-main :: Eff () Unit
-main = natId (pure unit)
diff --git a/examples/warning/UnusedExplicitImportTypeOp/Lib.purs b/examples/warning/UnusedExplicitImportTypeOp/Lib.purs
deleted file mode 100644
--- a/examples/warning/UnusedExplicitImportTypeOp/Lib.purs
+++ /dev/null
@@ -1,8 +0,0 @@
-module Lib where
-
-type Nat f g = ∀ x. f x → g x
-
-infixr 4 type Nat as ~>
-
-natId ∷ ∀ f. f ~> f
-natId x = x
diff --git a/examples/warning/UnusedExplicitImportValOp.purs b/examples/warning/UnusedExplicitImportValOp.purs
deleted file mode 100644
--- a/examples/warning/UnusedExplicitImportValOp.purs
+++ /dev/null
@@ -1,8 +0,0 @@
--- @shouldWarnWith UnusedExplicitImport
-module Main where
-
-import Prelude (Unit, unit, pure, (+))
-import Control.Monad.Eff (Eff)
-
-main :: Eff () Unit
-main = pure unit
diff --git a/examples/warning/UnusedFFIImplementations.js b/examples/warning/UnusedFFIImplementations.js
deleted file mode 100644
--- a/examples/warning/UnusedFFIImplementations.js
+++ /dev/null
@@ -1,2 +0,0 @@
-exports.yes = true;
-exports.no = false;
diff --git a/examples/warning/UnusedFFIImplementations.purs b/examples/warning/UnusedFFIImplementations.purs
deleted file mode 100644
--- a/examples/warning/UnusedFFIImplementations.purs
+++ /dev/null
@@ -1,4 +0,0 @@
--- @shouldWarnWith UnusedFFIImplementations
-module Main where
-
-foreign import yes :: Boolean
diff --git a/examples/warning/UnusedImport.purs b/examples/warning/UnusedImport.purs
deleted file mode 100644
--- a/examples/warning/UnusedImport.purs
+++ /dev/null
@@ -1,14 +0,0 @@
--- @shouldWarnWith UnusedImport
--- @shouldWarnWith UnusedImport
--- @shouldWarnWith UnusedImport
-module Main where
-
-import Data.Unit (Unit, unit)
-
--- All of the below are unused
-import Control.Monad.Eff
-import Control.Monad.Eff.Console as Console
-import Test.Assert ()
-
-main :: Unit
-main = unit
diff --git a/examples/warning/UnusedTypeVar.purs b/examples/warning/UnusedTypeVar.purs
deleted file mode 100644
--- a/examples/warning/UnusedTypeVar.purs
+++ /dev/null
@@ -1,5 +0,0 @@
--- @shouldWarnWith UnusedTypeVar
-module Main where
-
-f :: forall a b. a -> a
-f x = x
diff --git a/examples/warning/WildcardInferredType.purs b/examples/warning/WildcardInferredType.purs
deleted file mode 100644
--- a/examples/warning/WildcardInferredType.purs
+++ /dev/null
@@ -1,23 +0,0 @@
--- @shouldWarnWith WildcardInferredType
--- @shouldWarnWith WildcardInferredType
--- @shouldWarnWith WildcardInferredType
--- @shouldWarnWith WildcardInferredType
-module Main where
-
-x :: Int
-x = 0 :: _
-
-y :: _
-y = 0
-
-z :: Int
-z =
-  let n :: _
-      n = 0
-  in n
-
-w :: Int
-w = n
-  where
-  n :: _
-  n = 0
diff --git a/purescript.cabal b/purescript.cabal
--- a/purescript.cabal
+++ b/purescript.cabal
@@ -1,1075 +1,1121 @@
--- This file has been generated from package.yaml by hpack version 0.17.1.
---
--- see: https://github.com/sol/hpack
-
-name:           purescript
-version:        0.11.7
-synopsis:       PureScript Programming Language Compiler
-description:    A small strongly, statically typed programming language with expressive types, inspired by Haskell and compiling to JavaScript.
-category:       Language
-stability:      experimental
-homepage:       http://www.purescript.org/
-bug-reports:    https://github.com/purescript/purescript/issues
-author:         Phil Freeman <paf31@cantab.net>, Gary Burgess <gary.burgess@gmail.com>, Hardy Jones <jones3.hardy@gmail.com>, Harry Garrood <harry@garrood.me>, Christoph Hegemann <christoph.hegemann1337@gmail.com>
-
-maintainer:     Phil Freeman <paf31@cantab.net>
-copyright:      (c) 2013-17 Phil Freeman, (c) 2014-17 Gary Burgess
-license:        BSD3
-license-file:   LICENSE
-build-type:     Simple
-cabal-version:  >= 1.10
-
-extra-source-files:
-    app/static/index.html
-    app/static/index.js
-    app/static/normalize.css
-    app/static/pursuit.css
-    app/static/pursuit.less
-    CONTRIBUTING.md
-    CONTRIBUTORS.md
-    examples/docs/bower.json
-    examples/docs/bower_components/purescript-prelude/src/Prelude.purs
-    examples/docs/resolutions.json
-    examples/docs/src/ChildDeclOrder.purs
-    examples/docs/src/Clash.purs
-    examples/docs/src/Clash1.purs
-    examples/docs/src/Clash1a.purs
-    examples/docs/src/Clash2.purs
-    examples/docs/src/Clash2a.purs
-    examples/docs/src/ConstrainedArgument.purs
-    examples/docs/src/DeclOrder.purs
-    examples/docs/src/DeclOrderNoExportList.purs
-    examples/docs/src/Desugar.purs
-    examples/docs/src/DocComments.purs
-    examples/docs/src/DuplicateNames.purs
-    examples/docs/src/Example.purs
-    examples/docs/src/Example2.purs
-    examples/docs/src/ExplicitTypeSignatures.purs
-    examples/docs/src/ImportedTwice.purs
-    examples/docs/src/ImportedTwiceA.purs
-    examples/docs/src/ImportedTwiceB.purs
-    examples/docs/src/MultiVirtual.purs
-    examples/docs/src/MultiVirtual1.purs
-    examples/docs/src/MultiVirtual2.purs
-    examples/docs/src/MultiVirtual3.purs
-    examples/docs/src/NewOperators.purs
-    examples/docs/src/NewOperators2.purs
-    examples/docs/src/NotAllCtors.purs
-    examples/docs/src/ReExportedTypeClass.purs
-    examples/docs/src/SolitaryTypeClassMember.purs
-    examples/docs/src/SomeTypeClass.purs
-    examples/docs/src/Transitive1.purs
-    examples/docs/src/Transitive2.purs
-    examples/docs/src/Transitive3.purs
-    examples/docs/src/TypeClassWithFunDeps.purs
-    examples/docs/src/TypeClassWithoutMembers.purs
-    examples/docs/src/TypeClassWithoutMembersIntermediate.purs
-    examples/docs/src/TypeLevelString.purs
-    examples/docs/src/TypeOpAliases.purs
-    examples/docs/src/UTF8.purs
-    examples/docs/src/Virtual.purs
-    examples/failing/1071.purs
-    examples/failing/1169.purs
-    examples/failing/1175.purs
-    examples/failing/1310.purs
-    examples/failing/1570.purs
-    examples/failing/1733.purs
-    examples/failing/1733/Thingy.purs
-    examples/failing/1825.purs
-    examples/failing/1881.purs
-    examples/failing/2128-class.purs
-    examples/failing/2128-instance.purs
-    examples/failing/2197-shouldFail.purs
-    examples/failing/2197-shouldFail2.purs
-    examples/failing/2378.purs
-    examples/failing/2378/Lib.purs
-    examples/failing/2379.purs
-    examples/failing/2379/Lib.purs
-    examples/failing/2434.purs
-    examples/failing/2534.purs
-    examples/failing/2542.purs
-    examples/failing/2567.purs
-    examples/failing/2601.purs
-    examples/failing/2616.purs
-    examples/failing/2806.purs
-    examples/failing/2874-forall.purs
-    examples/failing/2874-forall2.purs
-    examples/failing/2874-wildcard.purs
-    examples/failing/365.purs
-    examples/failing/438.purs
-    examples/failing/881.purs
-    examples/failing/AnonArgument1.purs
-    examples/failing/AnonArgument2.purs
-    examples/failing/AnonArgument3.purs
-    examples/failing/ArgLengthMismatch.purs
-    examples/failing/Arrays.purs
-    examples/failing/ArrayType.purs
-    examples/failing/BindInDo-2.purs
-    examples/failing/BindInDo.purs
-    examples/failing/CannotDeriveNewtypeForData.purs
-    examples/failing/CaseBinderLengthsDiffer.purs
-    examples/failing/CaseDoesNotMatchAllConstructorArgs.purs
-    examples/failing/ConflictingExports.purs
-    examples/failing/ConflictingExports/A.purs
-    examples/failing/ConflictingExports/B.purs
-    examples/failing/ConflictingImports.purs
-    examples/failing/ConflictingImports/A.purs
-    examples/failing/ConflictingImports/B.purs
-    examples/failing/ConflictingImports2.purs
-    examples/failing/ConflictingImports2/A.purs
-    examples/failing/ConflictingImports2/B.purs
-    examples/failing/ConflictingQualifiedImports.purs
-    examples/failing/ConflictingQualifiedImports/A.purs
-    examples/failing/ConflictingQualifiedImports/B.purs
-    examples/failing/ConflictingQualifiedImports2.purs
-    examples/failing/ConflictingQualifiedImports2/A.purs
-    examples/failing/ConflictingQualifiedImports2/B.purs
-    examples/failing/ConstraintFailure.purs
-    examples/failing/ConstraintInference.purs
-    examples/failing/DctorOperatorAliasExport.purs
-    examples/failing/DeclConflictClassCtor.purs
-    examples/failing/DeclConflictClassSynonym.purs
-    examples/failing/DeclConflictClassType.purs
-    examples/failing/DeclConflictCtorClass.purs
-    examples/failing/DeclConflictCtorCtor.purs
-    examples/failing/DeclConflictDuplicateCtor.purs
-    examples/failing/DeclConflictSynonymClass.purs
-    examples/failing/DeclConflictSynonymType.purs
-    examples/failing/DeclConflictTypeClass.purs
-    examples/failing/DeclConflictTypeSynonym.purs
-    examples/failing/DeclConflictTypeType.purs
-    examples/failing/DiffKindsSameName.purs
-    examples/failing/DiffKindsSameName/LibA.purs
-    examples/failing/DiffKindsSameName/LibB.purs
-    examples/failing/Do.purs
-    examples/failing/DoNotSuggestComposition.purs
-    examples/failing/DoNotSuggestComposition2.purs
-    examples/failing/DuplicateDeclarationsInLet.purs
-    examples/failing/DuplicateInstance.purs
-    examples/failing/DuplicateModule.purs
-    examples/failing/DuplicateModule/M1.purs
-    examples/failing/DuplicateProperties.purs
-    examples/failing/DuplicateTypeClass.purs
-    examples/failing/DuplicateTypeVars.purs
-    examples/failing/Eff.purs
-    examples/failing/EmptyCase.purs
-    examples/failing/EmptyClass.purs
-    examples/failing/EmptyDo.purs
-    examples/failing/ExportConflictClass.purs
-    examples/failing/ExportConflictClass/A.purs
-    examples/failing/ExportConflictClass/B.purs
-    examples/failing/ExportConflictCtor.purs
-    examples/failing/ExportConflictCtor/A.purs
-    examples/failing/ExportConflictCtor/B.purs
-    examples/failing/ExportConflictType.purs
-    examples/failing/ExportConflictType/A.purs
-    examples/failing/ExportConflictType/B.purs
-    examples/failing/ExportConflictTypeOp.purs
-    examples/failing/ExportConflictTypeOp/A.purs
-    examples/failing/ExportConflictTypeOp/B.purs
-    examples/failing/ExportConflictValue.purs
-    examples/failing/ExportConflictValue/A.purs
-    examples/failing/ExportConflictValue/B.purs
-    examples/failing/ExportConflictValueOp.purs
-    examples/failing/ExportConflictValueOp/A.purs
-    examples/failing/ExportConflictValueOp/B.purs
-    examples/failing/ExportExplicit.purs
-    examples/failing/ExportExplicit1.purs
-    examples/failing/ExportExplicit1/M1.purs
-    examples/failing/ExportExplicit2.purs
-    examples/failing/ExportExplicit3.purs
-    examples/failing/ExportExplicit3/M1.purs
-    examples/failing/ExtraRecordField.purs
-    examples/failing/Foldable.purs
-    examples/failing/Generalization1.purs
-    examples/failing/Generalization2.purs
-    examples/failing/ImportExplicit.purs
-    examples/failing/ImportExplicit/M1.purs
-    examples/failing/ImportExplicit2.purs
-    examples/failing/ImportExplicit2/M1.purs
-    examples/failing/ImportHidingModule.purs
-    examples/failing/ImportHidingModule/A.purs
-    examples/failing/ImportHidingModule/B.purs
-    examples/failing/ImportModule.purs
-    examples/failing/ImportModule/M2.purs
-    examples/failing/InfiniteKind.purs
-    examples/failing/InfiniteKind2.purs
-    examples/failing/InfiniteType.purs
-    examples/failing/InstanceExport.purs
-    examples/failing/InstanceExport/InstanceExport.purs
-    examples/failing/InstanceSigsBodyIncorrect.purs
-    examples/failing/InstanceSigsDifferentTypes.purs
-    examples/failing/InstanceSigsIncorrectType.purs
-    examples/failing/InstanceSigsOrphanTypeDeclaration.purs
-    examples/failing/IntOutOfRange.purs
-    examples/failing/InvalidDerivedInstance.purs
-    examples/failing/InvalidDerivedInstance2.purs
-    examples/failing/InvalidOperatorInBinder.purs
-    examples/failing/KindError.purs
-    examples/failing/KindStar.purs
-    examples/failing/LeadingZeros1.purs
-    examples/failing/LeadingZeros2.purs
-    examples/failing/Let.purs
-    examples/failing/LetPatterns1.purs
-    examples/failing/LetPatterns2.purs
-    examples/failing/LetPatterns3.purs
-    examples/failing/LetPatterns4.purs
-    examples/failing/MissingClassExport.purs
-    examples/failing/MissingClassMemberExport.purs
-    examples/failing/MissingRecordField.purs
-    examples/failing/MPTCs.purs
-    examples/failing/MultipleErrors.purs
-    examples/failing/MultipleErrors2.purs
-    examples/failing/MultipleTypeOpFixities.purs
-    examples/failing/MultipleValueOpFixities.purs
-    examples/failing/MutRec.purs
-    examples/failing/MutRec2.purs
-    examples/failing/NewtypeInstance.purs
-    examples/failing/NewtypeInstance2.purs
-    examples/failing/NewtypeInstance3.purs
-    examples/failing/NewtypeInstance4.purs
-    examples/failing/NewtypeInstance5.purs
-    examples/failing/NewtypeInstance6.purs
-    examples/failing/NewtypeMultiArgs.purs
-    examples/failing/NewtypeMultiCtor.purs
-    examples/failing/NonExhaustivePatGuard.purs
-    examples/failing/NonWildcardNewtypeInstance.purs
-    examples/failing/NullaryAbs.purs
-    examples/failing/Object.purs
-    examples/failing/OperatorAliasNoExport.purs
-    examples/failing/OperatorSections.purs
-    examples/failing/OrphanInstance.purs
-    examples/failing/OrphanInstance/Class.purs
-    examples/failing/OrphanInstanceFunDepCycle.purs
-    examples/failing/OrphanInstanceFunDepCycle/Lib.purs
-    examples/failing/OrphanInstanceNullary.purs
-    examples/failing/OrphanInstanceNullary/Lib.purs
-    examples/failing/OrphanInstanceWithDetermined.purs
-    examples/failing/OrphanInstanceWithDetermined/Lib.purs
-    examples/failing/OrphanTypeDecl.purs
-    examples/failing/OverlappingArguments.purs
-    examples/failing/OverlappingBinders.purs
-    examples/failing/OverlappingVars.purs
-    examples/failing/ProgrammableTypeErrors.purs
-    examples/failing/ProgrammableTypeErrorsTypeString.purs
-    examples/failing/Rank2Types.purs
-    examples/failing/RequiredHiddenType.purs
-    examples/failing/Reserved.purs
-    examples/failing/RowConstructors1.purs
-    examples/failing/RowConstructors2.purs
-    examples/failing/RowConstructors3.purs
-    examples/failing/RowInInstanceNotDetermined0.purs
-    examples/failing/RowInInstanceNotDetermined1.purs
-    examples/failing/RowInInstanceNotDetermined2.purs
-    examples/failing/SkolemEscape.purs
-    examples/failing/SkolemEscape2.purs
-    examples/failing/SuggestComposition.purs
-    examples/failing/Superclasses1.purs
-    examples/failing/Superclasses2.purs
-    examples/failing/Superclasses3.purs
-    examples/failing/Superclasses5.purs
-    examples/failing/TooFewClassInstanceArgs.purs
-    examples/failing/TopLevelCaseNoArgs.purs
-    examples/failing/TransitiveDctorExport.purs
-    examples/failing/TransitiveSynonymExport.purs
-    examples/failing/TypeClasses2.purs
-    examples/failing/TypeClassInstances.purs
-    examples/failing/TypedBinders.purs
-    examples/failing/TypedBinders2.purs
-    examples/failing/TypedBinders3.purs
-    examples/failing/TypedHole.purs
-    examples/failing/TypeError.purs
-    examples/failing/TypeOperatorAliasNoExport.purs
-    examples/failing/TypeSynonyms.purs
-    examples/failing/TypeSynonyms2.purs
-    examples/failing/TypeSynonyms3.purs
-    examples/failing/TypeSynonyms4.purs
-    examples/failing/TypeSynonyms5.purs
-    examples/failing/TypeWildcards1.purs
-    examples/failing/TypeWildcards2.purs
-    examples/failing/TypeWildcards3.purs
-    examples/failing/UnderscoreModuleName.purs
-    examples/failing/UnknownType.purs
-    examples/failing/UnusableTypeClassMethod.purs
-    examples/failing/UnusableTypeClassMethodConflictingIdent.purs
-    examples/failing/UnusableTypeClassMethodSynonym.purs
-    examples/passing/1110.purs
-    examples/passing/1185.purs
-    examples/passing/1335.purs
-    examples/passing/1570.purs
-    examples/passing/1664.purs
-    examples/passing/1697.purs
-    examples/passing/1807.purs
-    examples/passing/1881.purs
-    examples/passing/1991.purs
-    examples/passing/2018.purs
-    examples/passing/2018/A.purs
-    examples/passing/2018/B.purs
-    examples/passing/2049.purs
-    examples/passing/2136.purs
-    examples/passing/2138.purs
-    examples/passing/2138/Lib.purs
-    examples/passing/2172.js
-    examples/passing/2172.purs
-    examples/passing/2197-1.purs
-    examples/passing/2197-2.purs
-    examples/passing/2252.purs
-    examples/passing/2288.purs
-    examples/passing/2378.purs
-    examples/passing/2438.purs
-    examples/passing/2609.purs
-    examples/passing/2609/Eg.purs
-    examples/passing/2616.purs
-    examples/passing/2626.purs
-    examples/passing/2663.purs
-    examples/passing/2689.purs
-    examples/passing/2695.purs
-    examples/passing/2756.purs
-    examples/passing/2787.purs
-    examples/passing/2795.purs
-    examples/passing/2806.purs
-    examples/passing/2958.purs
-    examples/passing/2972.purs
-    examples/passing/3125.purs
-    examples/passing/652.purs
-    examples/passing/810.purs
-    examples/passing/862.purs
-    examples/passing/922.purs
-    examples/passing/Applicative.purs
-    examples/passing/ArrayType.purs
-    examples/passing/Auto.purs
-    examples/passing/AutoPrelude.purs
-    examples/passing/AutoPrelude2.purs
-    examples/passing/BindersInFunctions.purs
-    examples/passing/BindingGroups.purs
-    examples/passing/BlockString.purs
-    examples/passing/CaseInDo.purs
-    examples/passing/CaseInputWildcard.purs
-    examples/passing/CaseMultipleExpressions.purs
-    examples/passing/CaseStatement.purs
-    examples/passing/CheckFunction.purs
-    examples/passing/CheckSynonymBug.purs
-    examples/passing/CheckTypeClass.purs
-    examples/passing/Church.purs
-    examples/passing/ClassRefSyntax.purs
-    examples/passing/ClassRefSyntax/Lib.purs
-    examples/passing/Collatz.purs
-    examples/passing/Comparisons.purs
-    examples/passing/Conditional.purs
-    examples/passing/Console.purs
-    examples/passing/ConstraintInference.purs
-    examples/passing/ConstraintParens.purs
-    examples/passing/ConstraintParsingIssue.purs
-    examples/passing/ContextSimplification.purs
-    examples/passing/DataAndType.purs
-    examples/passing/DctorName.purs
-    examples/passing/DctorOperatorAlias.purs
-    examples/passing/DctorOperatorAlias/List.purs
-    examples/passing/DeepArrayBinder.purs
-    examples/passing/DeepCase.purs
-    examples/passing/DeriveNewtype.purs
-    examples/passing/DeriveWithNestedSynonyms.purs
-    examples/passing/Deriving.purs
-    examples/passing/DerivingFunctor.purs
-    examples/passing/Do.purs
-    examples/passing/Dollar.purs
-    examples/passing/DuplicateProperties.purs
-    examples/passing/Eff.purs
-    examples/passing/EmptyDataDecls.purs
-    examples/passing/EmptyRow.purs
-    examples/passing/EmptyTypeClass.purs
-    examples/passing/EntailsKindedType.purs
-    examples/passing/EqOrd.purs
-    examples/passing/ExplicitImportReExport.purs
-    examples/passing/ExplicitImportReExport/Bar.purs
-    examples/passing/ExplicitImportReExport/Foo.purs
-    examples/passing/ExplicitOperatorSections.purs
-    examples/passing/ExportedInstanceDeclarations.purs
-    examples/passing/ExportExplicit.purs
-    examples/passing/ExportExplicit/M1.purs
-    examples/passing/ExportExplicit2.purs
-    examples/passing/ExportExplicit2/M1.purs
-    examples/passing/ExtendedInfixOperators.purs
-    examples/passing/Fib.purs
-    examples/passing/FieldConsPuns.purs
-    examples/passing/FieldPuns.purs
-    examples/passing/FinalTagless.purs
-    examples/passing/ForeignKind.purs
-    examples/passing/ForeignKind/Lib.purs
-    examples/passing/FunctionalDependencies.purs
-    examples/passing/Functions.purs
-    examples/passing/Functions2.purs
-    examples/passing/FunctionScope.purs
-    examples/passing/FunWithFunDeps.js
-    examples/passing/FunWithFunDeps.purs
-    examples/passing/Generalization1.purs
-    examples/passing/GenericsRep.purs
-    examples/passing/Guards.purs
-    examples/passing/HasOwnProperty.purs
-    examples/passing/HoistError.purs
-    examples/passing/IfThenElseMaybe.purs
-    examples/passing/IfWildcard.purs
-    examples/passing/ImplicitEmptyImport.purs
-    examples/passing/Import.purs
-    examples/passing/Import/M1.purs
-    examples/passing/Import/M2.purs
-    examples/passing/ImportExplicit.purs
-    examples/passing/ImportExplicit/M1.purs
-    examples/passing/ImportHiding.purs
-    examples/passing/ImportQualified.purs
-    examples/passing/ImportQualified/M1.purs
-    examples/passing/InferRecFunWithConstrainedArgument.purs
-    examples/passing/InstanceBeforeClass.purs
-    examples/passing/InstanceSigs.purs
-    examples/passing/InstanceSigsGeneral.purs
-    examples/passing/IntAndChar.purs
-    examples/passing/iota.purs
-    examples/passing/JSReserved.purs
-    examples/passing/KindedType.purs
-    examples/passing/LargeSumType.purs
-    examples/passing/Let.purs
-    examples/passing/Let2.purs
-    examples/passing/LetInInstance.purs
-    examples/passing/LetPattern.purs
-    examples/passing/LiberalTypeSynonyms.purs
-    examples/passing/Match.purs
-    examples/passing/Module.purs
-    examples/passing/Module/M1.purs
-    examples/passing/Module/M2.purs
-    examples/passing/ModuleDeps.purs
-    examples/passing/ModuleDeps/M1.purs
-    examples/passing/ModuleDeps/M2.purs
-    examples/passing/ModuleDeps/M3.purs
-    examples/passing/ModuleExport.purs
-    examples/passing/ModuleExport/A.purs
-    examples/passing/ModuleExportDupes.purs
-    examples/passing/ModuleExportDupes/A.purs
-    examples/passing/ModuleExportDupes/B.purs
-    examples/passing/ModuleExportDupes/C.purs
-    examples/passing/ModuleExportExcluded.purs
-    examples/passing/ModuleExportExcluded/A.purs
-    examples/passing/ModuleExportQualified.purs
-    examples/passing/ModuleExportQualified/A.purs
-    examples/passing/ModuleExportSelf.purs
-    examples/passing/ModuleExportSelf/A.purs
-    examples/passing/Monad.purs
-    examples/passing/MonadState.purs
-    examples/passing/MPTCs.purs
-    examples/passing/MultiArgFunctions.purs
-    examples/passing/MutRec.purs
-    examples/passing/MutRec2.purs
-    examples/passing/MutRec3.purs
-    examples/passing/NakedConstraint.purs
-    examples/passing/NamedPatterns.purs
-    examples/passing/NegativeBinder.purs
-    examples/passing/NegativeIntInRange.purs
-    examples/passing/Nested.purs
-    examples/passing/NestedRecordUpdate.purs
-    examples/passing/NestedRecordUpdateWildcards.purs
-    examples/passing/NestedTypeSynonyms.purs
-    examples/passing/NestedWhere.purs
-    examples/passing/Newtype.purs
-    examples/passing/NewtypeClass.purs
-    examples/passing/NewtypeEff.purs
-    examples/passing/NewtypeInstance.purs
-    examples/passing/NewtypeWithRecordUpdate.purs
-    examples/passing/NonConflictingExports.purs
-    examples/passing/NonConflictingExports/A.purs
-    examples/passing/NonOrphanInstanceFunDepExtra.purs
-    examples/passing/NonOrphanInstanceFunDepExtra/Lib.purs
-    examples/passing/NonOrphanInstanceMulti.purs
-    examples/passing/NonOrphanInstanceMulti/Lib.purs
-    examples/passing/NumberLiterals.purs
-    examples/passing/ObjectGetter.purs
-    examples/passing/Objects.purs
-    examples/passing/ObjectSynonym.purs
-    examples/passing/ObjectUpdate.purs
-    examples/passing/ObjectUpdate2.purs
-    examples/passing/ObjectUpdater.purs
-    examples/passing/ObjectWildcards.purs
-    examples/passing/OneConstructor.purs
-    examples/passing/OperatorAlias.purs
-    examples/passing/OperatorAliasElsewhere.purs
-    examples/passing/OperatorAliasElsewhere/Def.purs
-    examples/passing/OperatorAssociativity.purs
-    examples/passing/OperatorInlining.purs
-    examples/passing/Operators.purs
-    examples/passing/Operators/Other.purs
-    examples/passing/OperatorSections.purs
-    examples/passing/OptimizerBug.purs
-    examples/passing/OptionalQualified.purs
-    examples/passing/OverlappingInstances.purs
-    examples/passing/OverlappingInstances2.purs
-    examples/passing/OverlappingInstances3.purs
-    examples/passing/ParensInType.purs
-    examples/passing/ParensInTypedBinder.purs
-    examples/passing/PartialFunction.purs
-    examples/passing/Patterns.purs
-    examples/passing/PendingConflictingImports.purs
-    examples/passing/PendingConflictingImports/A.purs
-    examples/passing/PendingConflictingImports/B.purs
-    examples/passing/PendingConflictingImports2.purs
-    examples/passing/PendingConflictingImports2/A.purs
-    examples/passing/Person.purs
-    examples/passing/PolyLabels.js
-    examples/passing/PolyLabels.purs
-    examples/passing/PrimedTypeName.purs
-    examples/passing/QualifiedNames.purs
-    examples/passing/QualifiedNames/Either.purs
-    examples/passing/QualifiedQualifiedImports.purs
-    examples/passing/Rank2Data.purs
-    examples/passing/Rank2Object.purs
-    examples/passing/Rank2Types.purs
-    examples/passing/Rank2TypeSynonym.purs
-    examples/passing/RebindableSyntax.purs
-    examples/passing/Recursion.purs
-    examples/passing/RedefinedFixity.purs
-    examples/passing/RedefinedFixity/M1.purs
-    examples/passing/RedefinedFixity/M2.purs
-    examples/passing/RedefinedFixity/M3.purs
-    examples/passing/ReExportQualified.purs
-    examples/passing/ReExportQualified/A.purs
-    examples/passing/ReExportQualified/B.purs
-    examples/passing/ReExportQualified/C.purs
-    examples/passing/ReservedWords.purs
-    examples/passing/ResolvableScopeConflict.purs
-    examples/passing/ResolvableScopeConflict/A.purs
-    examples/passing/ResolvableScopeConflict/B.purs
-    examples/passing/ResolvableScopeConflict2.purs
-    examples/passing/ResolvableScopeConflict2/A.purs
-    examples/passing/ResolvableScopeConflict3.purs
-    examples/passing/ResolvableScopeConflict3/A.purs
-    examples/passing/RowConstructors.purs
-    examples/passing/RowInInstanceHeadDetermined.purs
-    examples/passing/RowPolyInstanceContext.purs
-    examples/passing/RowsInInstanceContext.purs
-    examples/passing/RowUnion.js
-    examples/passing/RowUnion.purs
-    examples/passing/RuntimeScopeIssue.purs
-    examples/passing/s.purs
-    examples/passing/ScopedTypeVariables.purs
-    examples/passing/Sequence.purs
-    examples/passing/SequenceDesugared.purs
-    examples/passing/ShadowedModuleName.purs
-    examples/passing/ShadowedModuleName/Test.purs
-    examples/passing/ShadowedName.purs
-    examples/passing/ShadowedRename.purs
-    examples/passing/ShadowedTCO.purs
-    examples/passing/ShadowedTCOLet.purs
-    examples/passing/SignedNumericLiterals.purs
-    examples/passing/SolvingAppendSymbol.purs
-    examples/passing/SolvingCompareSymbol.purs
-    examples/passing/SolvingIsSymbol.purs
-    examples/passing/SolvingIsSymbol/Lib.purs
-    examples/passing/Stream.purs
-    examples/passing/StringEdgeCases.purs
-    examples/passing/StringEdgeCases/Records.purs
-    examples/passing/StringEdgeCases/Symbols.purs
-    examples/passing/StringEscapes.purs
-    examples/passing/Superclasses1.purs
-    examples/passing/Superclasses3.purs
-    examples/passing/TailCall.purs
-    examples/passing/TCO.purs
-    examples/passing/TCOCase.purs
-    examples/passing/Tick.purs
-    examples/passing/TopLevelCase.purs
-    examples/passing/TransitiveImport.purs
-    examples/passing/TransitiveImport/Middle.purs
-    examples/passing/TransitiveImport/Test.purs
-    examples/passing/TypeClasses.purs
-    examples/passing/TypeClassesInOrder.purs
-    examples/passing/TypeClassesWithOverlappingTypeVariables.purs
-    examples/passing/TypeClassMemberOrderChange.purs
-    examples/passing/TypedBinders.purs
-    examples/passing/TypeDecl.purs
-    examples/passing/TypedWhere.purs
-    examples/passing/TypeOperators.purs
-    examples/passing/TypeOperators/A.purs
-    examples/passing/TypeSynonymInData.purs
-    examples/passing/TypeSynonyms.purs
-    examples/passing/TypeWildcards.purs
-    examples/passing/TypeWildcardsRecordExtension.purs
-    examples/passing/TypeWithoutParens.purs
-    examples/passing/TypeWithoutParens/Lib.purs
-    examples/passing/UnderscoreIdent.purs
-    examples/passing/UnicodeIdentifier.purs
-    examples/passing/UnicodeOperators.purs
-    examples/passing/UnicodeType.purs
-    examples/passing/UnifyInTypeInstanceLookup.purs
-    examples/passing/Unit.purs
-    examples/passing/UnknownInTypeClassLookup.purs
-    examples/passing/UnsafeCoerce.purs
-    examples/passing/UntupledConstraints.purs
-    examples/passing/UsableTypeClassMethods.purs
-    examples/passing/UTF8Sourcefile.purs
-    examples/passing/Where.purs
-    examples/passing/WildcardInInstance.purs
-    examples/passing/WildcardType.purs
-    examples/psci/BasicEval.purs
-    examples/psci/Multiline.purs
-    examples/warning/2140.purs
-    examples/warning/2383.purs
-    examples/warning/2411.purs
-    examples/warning/2542.purs
-    examples/warning/CustomWarning.purs
-    examples/warning/CustomWarning2.purs
-    examples/warning/CustomWarning3.purs
-    examples/warning/DuplicateExportRef.purs
-    examples/warning/DuplicateImport.purs
-    examples/warning/DuplicateImportRef.purs
-    examples/warning/DuplicateSelectiveImport.purs
-    examples/warning/HidingImport.purs
-    examples/warning/ImplicitImport.purs
-    examples/warning/ImplicitQualifiedImport.purs
-    examples/warning/MissingTypeDeclaration.purs
-    examples/warning/NewtypeInstance.purs
-    examples/warning/NewtypeInstance2.purs
-    examples/warning/NewtypeInstance3.purs
-    examples/warning/NewtypeInstance4.purs
-    examples/warning/OverlappingInstances.purs
-    examples/warning/OverlappingPattern.purs
-    examples/warning/ScopeShadowing.purs
-    examples/warning/ShadowedBinderPatternGuard.purs
-    examples/warning/ShadowedNameParens.purs
-    examples/warning/ShadowedTypeVar.purs
-    examples/warning/UnnecessaryFFIModule.js
-    examples/warning/UnnecessaryFFIModule.purs
-    examples/warning/UnusedDctorExplicitImport.purs
-    examples/warning/UnusedDctorImportAll.purs
-    examples/warning/UnusedDctorImportExplicit.purs
-    examples/warning/UnusedExplicitImport.purs
-    examples/warning/UnusedExplicitImportTypeOp.purs
-    examples/warning/UnusedExplicitImportTypeOp/Lib.purs
-    examples/warning/UnusedExplicitImportValOp.purs
-    examples/warning/UnusedFFIImplementations.js
-    examples/warning/UnusedFFIImplementations.purs
-    examples/warning/UnusedImport.purs
-    examples/warning/UnusedTypeVar.purs
-    examples/warning/WildcardInferredType.purs
-    INSTALL.md
-    README.md
-    stack.yaml
-    tests/support/bower.json
-    tests/support/package.json
-    tests/support/prelude-resolutions.json
-    tests/support/psci/Sample.purs
-    tests/support/pscide/src/CompletionSpecDocs.purs
-    tests/support/pscide/src/ImportsSpec.purs
-    tests/support/pscide/src/ImportsSpec1.purs
-    tests/support/pscide/src/MatcherSpec.purs
-    tests/support/pscide/src/RebuildSpecDep.purs
-    tests/support/pscide/src/RebuildSpecSingleModule.fail
-    tests/support/pscide/src/RebuildSpecSingleModule.purs
-    tests/support/pscide/src/RebuildSpecWithDeps.purs
-    tests/support/pscide/src/RebuildSpecWithForeign.js
-    tests/support/pscide/src/RebuildSpecWithForeign.purs
-    tests/support/pscide/src/RebuildSpecWithHiddenIdent.purs
-    tests/support/pscide/src/RebuildSpecWithMissingForeign.fail
-    tests/support/setup-win.cmd
-
-source-repository head
-  type: git
-  location: https://github.com/purescript/purescript
-
-flag release
-  description: Mark this build as a release build: prevents inclusion of extra info e.g. commit SHA in --version output)
-
-  manual: False
-  default: False
-
-library
-  hs-source-dirs:
-      src
-  default-extensions: ConstraintKinds DataKinds DeriveFunctor EmptyDataDecls FlexibleContexts KindSignatures LambdaCase MultiParamTypeClasses NoImplicitPrelude PatternGuards PatternSynonyms RankNTypes RecordWildCards OverloadedStrings ScopedTypeVariables TupleSections ViewPatterns
-  ghc-options: -Wall -O2
-  build-depends:
-      aeson >=1.0 && <1.3
-    , aeson-better-errors >=0.8
-    , ansi-terminal >=0.6.2 && <0.7
-    , base >=4.8 && <5
-    , base-compat >=0.6.0
-    , blaze-html >=0.8.1 && <0.10
-    , bower-json >=1.0.0.1 && <1.1
-    , boxes >=0.1.4 && <0.2.0
-    , bytestring
-    , cheapskate >=0.1 && <0.2
-    , clock
-    , containers
-    , data-ordlist >=0.4.7.0
-    , deepseq
-    , directory >=1.2.3
-    , dlist
-    , edit-distance
-    , file-embed
-    , filepath
-    , fsnotify >=0.2.1
-    , Glob >=0.7 && <0.9
-    , haskeline >=0.7.0.0
-    , http-client >=0.4.30 && <0.6.0
-    , http-types
-    , language-javascript >=0.6.0.9 && <0.7
-    , lens ==4.*
-    , lifted-base >=0.2.3 && <0.2.4
-    , monad-control >=1.0.0.0 && <1.1
-    , monad-logger >=0.3 && <0.4
-    , mtl >=2.1.0 && <2.3.0
-    , parallel >=3.2 && <3.3
-    , parsec >=3.1.10
-    , pattern-arrows >=0.0.2 && <0.1
-    , pipes >=4.0.0 && <4.4.0
-    , pipes-http
-    , process >=1.2.0 && <1.7
-    , protolude >=0.1.6
-    , regex-tdfa
-    , safe >=0.3.9 && <0.4
-    , scientific >=0.3.4.9 && <0.4
-    , semigroups >=0.16.2 && <0.19
-    , sourcemap >=0.1.6
-    , spdx ==0.2.*
-    , split
-    , stm >=0.2.4.0
-    , stringsearch
-    , syb
-    , text
-    , time
-    , transformers >=0.3.0 && <0.6
-    , transformers-base >=0.4.0 && <0.5
-    , transformers-compat >=0.3.0
-    , unordered-containers
-    , utf8-string >=1 && <2
-    , vector
-  exposed-modules:
-      Control.Monad.Logger
-      Control.Monad.Supply
-      Control.Monad.Supply.Class
-      Language.PureScript
-      Language.PureScript.AST
-      Language.PureScript.AST.Binders
-      Language.PureScript.AST.Declarations
-      Language.PureScript.AST.Exported
-      Language.PureScript.AST.Literals
-      Language.PureScript.AST.Operators
-      Language.PureScript.AST.SourcePos
-      Language.PureScript.AST.Traversals
-      Language.PureScript.Bundle
-      Language.PureScript.CodeGen
-      Language.PureScript.CodeGen.JS
-      Language.PureScript.CodeGen.JS.Common
-      Language.PureScript.CodeGen.JS.Printer
-      Language.PureScript.Comments
-      Language.PureScript.Constants
-      Language.PureScript.CoreFn
-      Language.PureScript.CoreFn.Ann
-      Language.PureScript.CoreFn.Binders
-      Language.PureScript.CoreFn.Desugar
-      Language.PureScript.CoreFn.Expr
-      Language.PureScript.CoreFn.Meta
-      Language.PureScript.CoreFn.Module
-      Language.PureScript.CoreFn.ToJSON
-      Language.PureScript.CoreFn.Traversals
-      Language.PureScript.CoreImp
-      Language.PureScript.CoreImp.AST
-      Language.PureScript.CoreImp.Optimizer
-      Language.PureScript.CoreImp.Optimizer.Blocks
-      Language.PureScript.CoreImp.Optimizer.Common
-      Language.PureScript.CoreImp.Optimizer.Inliner
-      Language.PureScript.CoreImp.Optimizer.MagicDo
-      Language.PureScript.CoreImp.Optimizer.TCO
-      Language.PureScript.CoreImp.Optimizer.Unused
-      Language.PureScript.Crash
-      Language.PureScript.Docs
-      Language.PureScript.Docs.AsHtml
-      Language.PureScript.Docs.AsMarkdown
-      Language.PureScript.Docs.Convert
-      Language.PureScript.Docs.Convert.ReExports
-      Language.PureScript.Docs.Convert.Single
-      Language.PureScript.Docs.Css
-      Language.PureScript.Docs.ParseInPackage
-      Language.PureScript.Docs.Prim
-      Language.PureScript.Docs.Render
-      Language.PureScript.Docs.RenderedCode
-      Language.PureScript.Docs.RenderedCode.RenderKind
-      Language.PureScript.Docs.RenderedCode.RenderType
-      Language.PureScript.Docs.RenderedCode.Types
-      Language.PureScript.Docs.Types
-      Language.PureScript.Docs.Utils.MonoidExtras
-      Language.PureScript.Environment
-      Language.PureScript.Errors
-      Language.PureScript.Errors.JSON
-      Language.PureScript.Externs
-      Language.PureScript.Hierarchy
-      Language.PureScript.Ide
-      Language.PureScript.Ide.CaseSplit
-      Language.PureScript.Ide.Command
-      Language.PureScript.Ide.Completion
-      Language.PureScript.Ide.Error
-      Language.PureScript.Ide.Externs
-      Language.PureScript.Ide.Filter
-      Language.PureScript.Ide.Filter.Declaration
-      Language.PureScript.Ide.Imports
-      Language.PureScript.Ide.Logging
-      Language.PureScript.Ide.Matcher
-      Language.PureScript.Ide.Prim
-      Language.PureScript.Ide.Pursuit
-      Language.PureScript.Ide.Rebuild
-      Language.PureScript.Ide.Reexports
-      Language.PureScript.Ide.SourceFile
-      Language.PureScript.Ide.State
-      Language.PureScript.Ide.Types
-      Language.PureScript.Ide.Util
-      Language.PureScript.Ide.Watcher
-      Language.PureScript.Interactive
-      Language.PureScript.Interactive.Completion
-      Language.PureScript.Interactive.Directive
-      Language.PureScript.Interactive.IO
-      Language.PureScript.Interactive.Message
-      Language.PureScript.Interactive.Module
-      Language.PureScript.Interactive.Parser
-      Language.PureScript.Interactive.Printer
-      Language.PureScript.Interactive.Types
-      Language.PureScript.Kinds
-      Language.PureScript.Label
-      Language.PureScript.Linter
-      Language.PureScript.Linter.Exhaustive
-      Language.PureScript.Linter.Imports
-      Language.PureScript.Make
-      Language.PureScript.ModuleDependencies
-      Language.PureScript.Names
-      Language.PureScript.Options
-      Language.PureScript.Parser
-      Language.PureScript.Parser.Common
-      Language.PureScript.Parser.Declarations
-      Language.PureScript.Parser.Kinds
-      Language.PureScript.Parser.Lexer
-      Language.PureScript.Parser.State
-      Language.PureScript.Parser.Types
-      Language.PureScript.Pretty
-      Language.PureScript.Pretty.Common
-      Language.PureScript.Pretty.Kinds
-      Language.PureScript.Pretty.Types
-      Language.PureScript.Pretty.Values
-      Language.PureScript.PSString
-      Language.PureScript.Publish
-      Language.PureScript.Publish.BoxesHelpers
-      Language.PureScript.Publish.ErrorsWarnings
-      Language.PureScript.Publish.Utils
-      Language.PureScript.Renamer
-      Language.PureScript.Sugar
-      Language.PureScript.Sugar.BindingGroups
-      Language.PureScript.Sugar.CaseDeclarations
-      Language.PureScript.Sugar.DoNotation
-      Language.PureScript.Sugar.LetPattern
-      Language.PureScript.Sugar.Names
-      Language.PureScript.Sugar.Names.Common
-      Language.PureScript.Sugar.Names.Env
-      Language.PureScript.Sugar.Names.Exports
-      Language.PureScript.Sugar.Names.Imports
-      Language.PureScript.Sugar.ObjectWildcards
-      Language.PureScript.Sugar.Operators
-      Language.PureScript.Sugar.Operators.Binders
-      Language.PureScript.Sugar.Operators.Common
-      Language.PureScript.Sugar.Operators.Expr
-      Language.PureScript.Sugar.Operators.Types
-      Language.PureScript.Sugar.TypeClasses
-      Language.PureScript.Sugar.TypeClasses.Deriving
-      Language.PureScript.Sugar.TypeDeclarations
-      Language.PureScript.Traversals
-      Language.PureScript.TypeChecker
-      Language.PureScript.TypeChecker.Entailment
-      Language.PureScript.TypeChecker.Kinds
-      Language.PureScript.TypeChecker.Monad
-      Language.PureScript.TypeChecker.Skolems
-      Language.PureScript.TypeChecker.Subsumption
-      Language.PureScript.TypeChecker.Synonyms
-      Language.PureScript.TypeChecker.Types
-      Language.PureScript.TypeChecker.TypeSearch
-      Language.PureScript.TypeChecker.Unify
-      Language.PureScript.TypeClassDictionaries
-      Language.PureScript.Types
-      System.IO.UTF8
-  other-modules:
-      Paths_purescript
-  default-language: Haskell2010
-
-executable purs
-  main-is: Main.hs
-  hs-source-dirs:
-      app
-  ghc-options: -Wall -O2 -fno-warn-unused-do-bind -threaded -rtsopts -with-rtsopts=-N
-  build-depends:
-      aeson >=1.0 && <1.3
-    , aeson-better-errors >=0.8
-    , ansi-terminal >=0.6.2 && <0.7
-    , base >=4.8 && <5
-    , base-compat >=0.6.0
-    , blaze-html >=0.8.1 && <0.10
-    , bower-json >=1.0.0.1 && <1.1
-    , boxes >=0.1.4 && <0.2.0
-    , bytestring
-    , cheapskate >=0.1 && <0.2
-    , clock
-    , containers
-    , data-ordlist >=0.4.7.0
-    , deepseq
-    , directory >=1.2.3
-    , dlist
-    , edit-distance
-    , file-embed
-    , filepath
-    , fsnotify >=0.2.1
-    , Glob >=0.7 && <0.9
-    , haskeline >=0.7.0.0
-    , http-client >=0.4.30 && <0.6.0
-    , http-types
-    , language-javascript >=0.6.0.9 && <0.7
-    , lens ==4.*
-    , lifted-base >=0.2.3 && <0.2.4
-    , monad-control >=1.0.0.0 && <1.1
-    , monad-logger >=0.3 && <0.4
-    , mtl >=2.1.0 && <2.3.0
-    , parallel >=3.2 && <3.3
-    , parsec >=3.1.10
-    , pattern-arrows >=0.0.2 && <0.1
-    , pipes >=4.0.0 && <4.4.0
-    , pipes-http
-    , process >=1.2.0 && <1.7
-    , protolude >=0.1.6
-    , regex-tdfa
-    , safe >=0.3.9 && <0.4
-    , scientific >=0.3.4.9 && <0.4
-    , semigroups >=0.16.2 && <0.19
-    , sourcemap >=0.1.6
-    , spdx ==0.2.*
-    , split
-    , stm >=0.2.4.0
-    , stringsearch
-    , syb
-    , text
-    , time
-    , transformers >=0.3.0 && <0.6
-    , transformers-base >=0.4.0 && <0.5
-    , transformers-compat >=0.3.0
-    , unordered-containers
-    , utf8-string >=1 && <2
-    , vector
-    , ansi-wl-pprint
-    , file-embed
-    , network
-    , optparse-applicative >=0.13.0
-    , purescript
-    , wai ==3.*
-    , wai-websockets ==3.*
-    , warp ==3.*
-    , websockets >=0.9 && <0.13
-  if flag(release)
-    cpp-options: -DRELEASE
-  else
-    build-depends:
-        gitrev >=1.2.0 && <1.4
-  other-modules:
-      Command.Bundle
-      Command.Compile
-      Command.Docs
-      Command.Docs.Ctags
-      Command.Docs.Etags
-      Command.Docs.Html
-      Command.Docs.Tags
-      Command.Hierarchy
-      Command.Ide
-      Command.Publish
-      Command.REPL
-      Paths_purescript
-      Version
-  default-language: Haskell2010
-
-test-suite tests
-  type: exitcode-stdio-1.0
-  main-is: Main.hs
-  hs-source-dirs:
-      tests
-  ghc-options: -Wall
-  build-depends:
-      aeson >=1.0 && <1.3
-    , aeson-better-errors >=0.8
-    , ansi-terminal >=0.6.2 && <0.7
-    , base >=4.8 && <5
-    , base-compat >=0.6.0
-    , blaze-html >=0.8.1 && <0.10
-    , bower-json >=1.0.0.1 && <1.1
-    , boxes >=0.1.4 && <0.2.0
-    , bytestring
-    , cheapskate >=0.1 && <0.2
-    , clock
-    , containers
-    , data-ordlist >=0.4.7.0
-    , deepseq
-    , directory >=1.2.3
-    , dlist
-    , edit-distance
-    , file-embed
-    , filepath
-    , fsnotify >=0.2.1
-    , Glob >=0.7 && <0.9
-    , haskeline >=0.7.0.0
-    , http-client >=0.4.30 && <0.6.0
-    , http-types
-    , language-javascript >=0.6.0.9 && <0.7
-    , lens ==4.*
-    , lifted-base >=0.2.3 && <0.2.4
-    , monad-control >=1.0.0.0 && <1.1
-    , monad-logger >=0.3 && <0.4
-    , mtl >=2.1.0 && <2.3.0
-    , parallel >=3.2 && <3.3
-    , parsec >=3.1.10
-    , pattern-arrows >=0.0.2 && <0.1
-    , pipes >=4.0.0 && <4.4.0
-    , pipes-http
-    , process >=1.2.0 && <1.7
-    , protolude >=0.1.6
-    , regex-tdfa
-    , safe >=0.3.9 && <0.4
-    , scientific >=0.3.4.9 && <0.4
-    , semigroups >=0.16.2 && <0.19
-    , sourcemap >=0.1.6
-    , spdx ==0.2.*
-    , split
-    , stm >=0.2.4.0
-    , stringsearch
-    , syb
-    , text
-    , time
-    , transformers >=0.3.0 && <0.6
-    , transformers-base >=0.4.0 && <0.5
-    , transformers-compat >=0.3.0
-    , unordered-containers
-    , utf8-string >=1 && <2
-    , vector
-    , purescript
-    , hspec
-    , hspec-discover
-    , HUnit
-    , silently
-  other-modules:
-      Language.PureScript.Ide.CompletionSpec
-      Language.PureScript.Ide.FilterSpec
-      Language.PureScript.Ide.ImportsSpec
-      Language.PureScript.Ide.MatcherSpec
-      Language.PureScript.Ide.RebuildSpec
-      Language.PureScript.Ide.ReexportsSpec
-      Language.PureScript.Ide.SourceFileSpec
-      Language.PureScript.Ide.StateSpec
-      Language.PureScript.Ide.Test
-      PscIdeSpec
-      TestCompiler
-      TestDocs
-      TestHierarchy
-      TestPrimDocs
-      TestPsci
-      TestPsci.CommandTest
-      TestPsci.CompletionTest
-      TestPsci.EvalTest
-      TestPsci.TestEnv
-      TestPscIde
-      TestPscPublish
-      TestUtils
+-- This file has been generated from package.yaml by hpack version 0.28.2.
+--
+-- see: https://github.com/sol/hpack
+--
+-- hash: ed9acbb7111e989600e6d412bddce7d96a240dabdfa42338b1d3a2434ac6c976
+
+name:           purescript
+version:        0.12.0
+synopsis:       PureScript Programming Language Compiler
+description:    A small strongly, statically typed programming language with expressive types, inspired by Haskell and compiling to JavaScript.
+category:       Language
+stability:      experimental
+homepage:       http://www.purescript.org/
+bug-reports:    https://github.com/purescript/purescript/issues
+author:         Phil Freeman <paf31@cantab.net>, Gary Burgess <gary.burgess@gmail.com>, Hardy Jones <jones3.hardy@gmail.com>, Harry Garrood <harry@garrood.me>, Christoph Hegemann <christoph.hegemann1337@gmail.com>
+
+maintainer:     Phil Freeman <paf31@cantab.net>
+copyright:      (c) 2013-17 Phil Freeman, (c) 2014-17 Gary Burgess
+license:        BSD3
+license-file:   LICENSE
+build-type:     Simple
+cabal-version:  >= 1.10
+extra-source-files:
+    app/static/index.html
+    app/static/index.js
+    app/static/normalize.css
+    app/static/pursuit.css
+    app/static/pursuit.less
+    CONTRIBUTING.md
+    CONTRIBUTORS.md
+    INSTALL.md
+    README.md
+    stack.yaml
+    tests/purs/docs/bower.json
+    tests/purs/docs/bower_components/purescript-prelude/src/Prelude.purs
+    tests/purs/docs/output/ConstrainedArgument/externs.json
+    tests/purs/docs/output/ConstrainedArgument/index.js
+    tests/purs/docs/resolutions.json
+    tests/purs/docs/src/ChildDeclOrder.purs
+    tests/purs/docs/src/Clash.purs
+    tests/purs/docs/src/Clash1.purs
+    tests/purs/docs/src/Clash1a.purs
+    tests/purs/docs/src/Clash2.purs
+    tests/purs/docs/src/Clash2a.purs
+    tests/purs/docs/src/ConstrainedArgument.purs
+    tests/purs/docs/src/DeclOrder.purs
+    tests/purs/docs/src/DeclOrderNoExportList.purs
+    tests/purs/docs/src/Desugar.purs
+    tests/purs/docs/src/DocComments.purs
+    tests/purs/docs/src/DuplicateNames.purs
+    tests/purs/docs/src/Example.purs
+    tests/purs/docs/src/Example2.purs
+    tests/purs/docs/src/ExplicitExport.purs
+    tests/purs/docs/src/ExplicitTypeSignatures.purs
+    tests/purs/docs/src/ImportedTwice.purs
+    tests/purs/docs/src/ImportedTwiceA.purs
+    tests/purs/docs/src/ImportedTwiceB.purs
+    tests/purs/docs/src/MultiVirtual.purs
+    tests/purs/docs/src/MultiVirtual1.purs
+    tests/purs/docs/src/MultiVirtual2.purs
+    tests/purs/docs/src/MultiVirtual3.purs
+    tests/purs/docs/src/NewOperators.purs
+    tests/purs/docs/src/NewOperators2.purs
+    tests/purs/docs/src/NotAllCtors.purs
+    tests/purs/docs/src/PrimSubmodules.purs
+    tests/purs/docs/src/ReExportedTypeClass.purs
+    tests/purs/docs/src/SolitaryTypeClassMember.purs
+    tests/purs/docs/src/SomeTypeClass.purs
+    tests/purs/docs/src/Transitive1.purs
+    tests/purs/docs/src/Transitive2.purs
+    tests/purs/docs/src/Transitive3.purs
+    tests/purs/docs/src/TypeClassWithFunDeps.purs
+    tests/purs/docs/src/TypeClassWithoutMembers.purs
+    tests/purs/docs/src/TypeClassWithoutMembersIntermediate.purs
+    tests/purs/docs/src/TypeLevelString.purs
+    tests/purs/docs/src/TypeOpAliases.purs
+    tests/purs/docs/src/UTF8.purs
+    tests/purs/docs/src/Virtual.purs
+    tests/purs/failing/1071.purs
+    tests/purs/failing/1169.purs
+    tests/purs/failing/1175.purs
+    tests/purs/failing/1310.purs
+    tests/purs/failing/1570.purs
+    tests/purs/failing/1733.purs
+    tests/purs/failing/1733/Thingy.purs
+    tests/purs/failing/1825.purs
+    tests/purs/failing/1881.purs
+    tests/purs/failing/2128-class.purs
+    tests/purs/failing/2128-instance.purs
+    tests/purs/failing/2197-shouldFail.purs
+    tests/purs/failing/2197-shouldFail2.purs
+    tests/purs/failing/2378.purs
+    tests/purs/failing/2378/Lib.purs
+    tests/purs/failing/2379.purs
+    tests/purs/failing/2379/Lib.purs
+    tests/purs/failing/2434.purs
+    tests/purs/failing/2534.purs
+    tests/purs/failing/2542.purs
+    tests/purs/failing/2567.purs
+    tests/purs/failing/2601.purs
+    tests/purs/failing/2616.purs
+    tests/purs/failing/2806.purs
+    tests/purs/failing/2874-forall.purs
+    tests/purs/failing/2874-forall2.purs
+    tests/purs/failing/2874-wildcard.purs
+    tests/purs/failing/2947.purs
+    tests/purs/failing/3132.purs
+    tests/purs/failing/3275-BindingGroupErrorPos.purs
+    tests/purs/failing/3275-DataBindingGroupErrorPos.purs
+    tests/purs/failing/3335-TypeOpAssociativityError.purs
+    tests/purs/failing/365.purs
+    tests/purs/failing/438.purs
+    tests/purs/failing/881.purs
+    tests/purs/failing/AnonArgument1.purs
+    tests/purs/failing/AnonArgument2.purs
+    tests/purs/failing/AnonArgument3.purs
+    tests/purs/failing/ArgLengthMismatch.purs
+    tests/purs/failing/Arrays.purs
+    tests/purs/failing/ArrayType.purs
+    tests/purs/failing/BindInDo-2.purs
+    tests/purs/failing/BindInDo.purs
+    tests/purs/failing/CannotDeriveNewtypeForData.purs
+    tests/purs/failing/CaseBinderLengthsDiffer.purs
+    tests/purs/failing/CaseDoesNotMatchAllConstructorArgs.purs
+    tests/purs/failing/ConflictingExports.purs
+    tests/purs/failing/ConflictingExports/A.purs
+    tests/purs/failing/ConflictingExports/B.purs
+    tests/purs/failing/ConflictingImports.purs
+    tests/purs/failing/ConflictingImports/A.purs
+    tests/purs/failing/ConflictingImports/B.purs
+    tests/purs/failing/ConflictingImports2.purs
+    tests/purs/failing/ConflictingImports2/A.purs
+    tests/purs/failing/ConflictingImports2/B.purs
+    tests/purs/failing/ConflictingQualifiedImports.purs
+    tests/purs/failing/ConflictingQualifiedImports/A.purs
+    tests/purs/failing/ConflictingQualifiedImports/B.purs
+    tests/purs/failing/ConflictingQualifiedImports2.purs
+    tests/purs/failing/ConflictingQualifiedImports2/A.purs
+    tests/purs/failing/ConflictingQualifiedImports2/B.purs
+    tests/purs/failing/ConstraintFailure.purs
+    tests/purs/failing/ConstraintInference.purs
+    tests/purs/failing/DctorOperatorAliasExport.purs
+    tests/purs/failing/DeclConflictClassCtor.purs
+    tests/purs/failing/DeclConflictClassSynonym.purs
+    tests/purs/failing/DeclConflictClassType.purs
+    tests/purs/failing/DeclConflictCtorClass.purs
+    tests/purs/failing/DeclConflictCtorCtor.purs
+    tests/purs/failing/DeclConflictDuplicateCtor.purs
+    tests/purs/failing/DeclConflictSynonymClass.purs
+    tests/purs/failing/DeclConflictSynonymType.purs
+    tests/purs/failing/DeclConflictTypeClass.purs
+    tests/purs/failing/DeclConflictTypeSynonym.purs
+    tests/purs/failing/DeclConflictTypeType.purs
+    tests/purs/failing/DiffKindsSameName.purs
+    tests/purs/failing/DiffKindsSameName/LibA.purs
+    tests/purs/failing/DiffKindsSameName/LibB.purs
+    tests/purs/failing/Do.purs
+    tests/purs/failing/DoNotSuggestComposition.purs
+    tests/purs/failing/DoNotSuggestComposition2.purs
+    tests/purs/failing/DuplicateDeclarationsInLet.purs
+    tests/purs/failing/DuplicateInstance.purs
+    tests/purs/failing/DuplicateModule.purs
+    tests/purs/failing/DuplicateModule/M1.purs
+    tests/purs/failing/DuplicateProperties.purs
+    tests/purs/failing/DuplicateTypeClass.purs
+    tests/purs/failing/DuplicateTypeVars.purs
+    tests/purs/failing/EmptyCase.purs
+    tests/purs/failing/EmptyClass.purs
+    tests/purs/failing/EmptyDo.purs
+    tests/purs/failing/ExpectedWildcard.purs
+    tests/purs/failing/ExportConflictClass.purs
+    tests/purs/failing/ExportConflictClass/A.purs
+    tests/purs/failing/ExportConflictClass/B.purs
+    tests/purs/failing/ExportConflictCtor.purs
+    tests/purs/failing/ExportConflictCtor/A.purs
+    tests/purs/failing/ExportConflictCtor/B.purs
+    tests/purs/failing/ExportConflictType.purs
+    tests/purs/failing/ExportConflictType/A.purs
+    tests/purs/failing/ExportConflictType/B.purs
+    tests/purs/failing/ExportConflictTypeOp.purs
+    tests/purs/failing/ExportConflictTypeOp/A.purs
+    tests/purs/failing/ExportConflictTypeOp/B.purs
+    tests/purs/failing/ExportConflictValue.purs
+    tests/purs/failing/ExportConflictValue/A.purs
+    tests/purs/failing/ExportConflictValue/B.purs
+    tests/purs/failing/ExportConflictValueOp.purs
+    tests/purs/failing/ExportConflictValueOp/A.purs
+    tests/purs/failing/ExportConflictValueOp/B.purs
+    tests/purs/failing/ExportExplicit.purs
+    tests/purs/failing/ExportExplicit1.purs
+    tests/purs/failing/ExportExplicit1/M1.purs
+    tests/purs/failing/ExportExplicit2.purs
+    tests/purs/failing/ExportExplicit3.purs
+    tests/purs/failing/ExportExplicit3/M1.purs
+    tests/purs/failing/ExtraneousClassMember.purs
+    tests/purs/failing/ExtraRecordField.purs
+    tests/purs/failing/Foldable.purs
+    tests/purs/failing/Generalization1.purs
+    tests/purs/failing/Generalization2.purs
+    tests/purs/failing/ImportExplicit.purs
+    tests/purs/failing/ImportExplicit/M1.purs
+    tests/purs/failing/ImportExplicit2.purs
+    tests/purs/failing/ImportExplicit2/M1.purs
+    tests/purs/failing/ImportHidingModule.purs
+    tests/purs/failing/ImportHidingModule/A.purs
+    tests/purs/failing/ImportHidingModule/B.purs
+    tests/purs/failing/ImportModule.purs
+    tests/purs/failing/ImportModule/M2.purs
+    tests/purs/failing/InfiniteKind.purs
+    tests/purs/failing/InfiniteKind2.purs
+    tests/purs/failing/InfiniteType.purs
+    tests/purs/failing/InstanceChainBothUnknownAndMatch.purs
+    tests/purs/failing/InstanceChainSkolemUnknownMatch.purs
+    tests/purs/failing/InstanceExport.purs
+    tests/purs/failing/InstanceExport/InstanceExport.purs
+    tests/purs/failing/InstanceSigsBodyIncorrect.purs
+    tests/purs/failing/InstanceSigsDifferentTypes.purs
+    tests/purs/failing/InstanceSigsIncorrectType.purs
+    tests/purs/failing/InstanceSigsOrphanTypeDeclaration.purs
+    tests/purs/failing/IntOutOfRange.purs
+    tests/purs/failing/InvalidDerivedInstance.purs
+    tests/purs/failing/InvalidDerivedInstance2.purs
+    tests/purs/failing/InvalidOperatorInBinder.purs
+    tests/purs/failing/KindError.purs
+    tests/purs/failing/KindStar.purs
+    tests/purs/failing/LacksWithSubGoal.purs
+    tests/purs/failing/LeadingZeros1.purs
+    tests/purs/failing/LeadingZeros2.purs
+    tests/purs/failing/Let.purs
+    tests/purs/failing/LetPatterns1.purs
+    tests/purs/failing/LetPatterns2.purs
+    tests/purs/failing/LetPatterns3.purs
+    tests/purs/failing/LetPatterns4.purs
+    tests/purs/failing/MissingClassExport.purs
+    tests/purs/failing/MissingClassMember.purs
+    tests/purs/failing/MissingClassMemberExport.purs
+    tests/purs/failing/MissingFFIImplementations.js
+    tests/purs/failing/MissingFFIImplementations.purs
+    tests/purs/failing/MissingRecordField.purs
+    tests/purs/failing/MixedAssociativityError.purs
+    tests/purs/failing/MPTCs.purs
+    tests/purs/failing/MultipleErrors.purs
+    tests/purs/failing/MultipleErrors2.purs
+    tests/purs/failing/MultipleTypeOpFixities.purs
+    tests/purs/failing/MultipleValueOpFixities.purs
+    tests/purs/failing/MutRec.purs
+    tests/purs/failing/MutRec2.purs
+    tests/purs/failing/NewtypeInstance.purs
+    tests/purs/failing/NewtypeInstance2.purs
+    tests/purs/failing/NewtypeInstance3.purs
+    tests/purs/failing/NewtypeInstance4.purs
+    tests/purs/failing/NewtypeInstance5.purs
+    tests/purs/failing/NewtypeInstance6.purs
+    tests/purs/failing/NewtypeMultiArgs.purs
+    tests/purs/failing/NewtypeMultiCtor.purs
+    tests/purs/failing/NonAssociativeError.purs
+    tests/purs/failing/NonExhaustivePatGuard.purs
+    tests/purs/failing/NullaryAbs.purs
+    tests/purs/failing/Object.purs
+    tests/purs/failing/OperatorAliasNoExport.purs
+    tests/purs/failing/OperatorSections.purs
+    tests/purs/failing/OrphanInstance.purs
+    tests/purs/failing/OrphanInstance/Class.purs
+    tests/purs/failing/OrphanInstanceFunDepCycle.purs
+    tests/purs/failing/OrphanInstanceFunDepCycle/Lib.purs
+    tests/purs/failing/OrphanInstanceNullary.purs
+    tests/purs/failing/OrphanInstanceNullary/Lib.purs
+    tests/purs/failing/OrphanInstanceWithDetermined.purs
+    tests/purs/failing/OrphanInstanceWithDetermined/Lib.purs
+    tests/purs/failing/OrphanTypeDecl.purs
+    tests/purs/failing/OverlapAcrossModules.purs
+    tests/purs/failing/OverlapAcrossModules/Class.purs
+    tests/purs/failing/OverlapAcrossModules/X.purs
+    tests/purs/failing/OverlappingArguments.purs
+    tests/purs/failing/OverlappingBinders.purs
+    tests/purs/failing/OverlappingInstances.purs
+    tests/purs/failing/OverlappingVars.purs
+    tests/purs/failing/PrimModuleReserved.purs
+    tests/purs/failing/PrimModuleReserved/Prim.purs
+    tests/purs/failing/PrimRow.purs
+    tests/purs/failing/PrimSubModuleReserved.purs
+    tests/purs/failing/PrimSubModuleReserved/Prim_Foobar.purs
+    tests/purs/failing/ProgrammableTypeErrors.purs
+    tests/purs/failing/ProgrammableTypeErrorsTypeString.purs
+    tests/purs/failing/Rank2Types.purs
+    tests/purs/failing/RequiredHiddenType.purs
+    tests/purs/failing/Reserved.purs
+    tests/purs/failing/RowConstructors1.purs
+    tests/purs/failing/RowConstructors2.purs
+    tests/purs/failing/RowConstructors3.purs
+    tests/purs/failing/RowInInstanceNotDetermined0.purs
+    tests/purs/failing/RowInInstanceNotDetermined1.purs
+    tests/purs/failing/RowInInstanceNotDetermined2.purs
+    tests/purs/failing/RowLacks.purs
+    tests/purs/failing/SkolemEscape.purs
+    tests/purs/failing/SkolemEscape2.purs
+    tests/purs/failing/SuggestComposition.purs
+    tests/purs/failing/Superclasses1.purs
+    tests/purs/failing/Superclasses2.purs
+    tests/purs/failing/Superclasses3.purs
+    tests/purs/failing/Superclasses5.purs
+    tests/purs/failing/TooFewClassInstanceArgs.purs
+    tests/purs/failing/TopLevelCaseNoArgs.purs
+    tests/purs/failing/TransitiveDctorExport.purs
+    tests/purs/failing/TransitiveKindExport.purs
+    tests/purs/failing/TransitiveSynonymExport.purs
+    tests/purs/failing/TypeClasses2.purs
+    tests/purs/failing/TypedBinders.purs
+    tests/purs/failing/TypedBinders2.purs
+    tests/purs/failing/TypedBinders3.purs
+    tests/purs/failing/TypedHole.purs
+    tests/purs/failing/TypeError.purs
+    tests/purs/failing/TypeOperatorAliasNoExport.purs
+    tests/purs/failing/TypeSynonyms.purs
+    tests/purs/failing/TypeSynonyms2.purs
+    tests/purs/failing/TypeSynonyms3.purs
+    tests/purs/failing/TypeSynonyms4.purs
+    tests/purs/failing/TypeSynonyms5.purs
+    tests/purs/failing/TypeWildcards1.purs
+    tests/purs/failing/TypeWildcards2.purs
+    tests/purs/failing/TypeWildcards3.purs
+    tests/purs/failing/UnderscoreModuleName.purs
+    tests/purs/failing/UnknownType.purs
+    tests/purs/failing/UnusableTypeClassMethod.purs
+    tests/purs/failing/UnusableTypeClassMethodConflictingIdent.purs
+    tests/purs/failing/UnusableTypeClassMethodSynonym.purs
+    tests/purs/passing/1110.purs
+    tests/purs/passing/1185.purs
+    tests/purs/passing/1335.purs
+    tests/purs/passing/1570.purs
+    tests/purs/passing/1664.purs
+    tests/purs/passing/1697.purs
+    tests/purs/passing/1807.purs
+    tests/purs/passing/1881.purs
+    tests/purs/passing/1991.purs
+    tests/purs/passing/2018.purs
+    tests/purs/passing/2018/A.purs
+    tests/purs/passing/2018/B.purs
+    tests/purs/passing/2049.purs
+    tests/purs/passing/2136.purs
+    tests/purs/passing/2138.purs
+    tests/purs/passing/2138/Lib.purs
+    tests/purs/passing/2172.js
+    tests/purs/passing/2172.purs
+    tests/purs/passing/2197-1.purs
+    tests/purs/passing/2197-2.purs
+    tests/purs/passing/2252.purs
+    tests/purs/passing/2288.purs
+    tests/purs/passing/2378.purs
+    tests/purs/passing/2438.purs
+    tests/purs/passing/2609.purs
+    tests/purs/passing/2609/Eg.purs
+    tests/purs/passing/2616.purs
+    tests/purs/passing/2626.purs
+    tests/purs/passing/2663.purs
+    tests/purs/passing/2689.purs
+    tests/purs/passing/2756.purs
+    tests/purs/passing/2787.purs
+    tests/purs/passing/2795.purs
+    tests/purs/passing/2803.purs
+    tests/purs/passing/2806.purs
+    tests/purs/passing/2947.purs
+    tests/purs/passing/2958.purs
+    tests/purs/passing/2972.purs
+    tests/purs/passing/3114.purs
+    tests/purs/passing/3114/VendoredVariant.purs
+    tests/purs/passing/3125.purs
+    tests/purs/passing/3187-UnusedNameClash.purs
+    tests/purs/passing/652.purs
+    tests/purs/passing/810.purs
+    tests/purs/passing/862.purs
+    tests/purs/passing/922.purs
+    tests/purs/passing/Ado.purs
+    tests/purs/passing/AppendInReverse.purs
+    tests/purs/passing/Applicative.purs
+    tests/purs/passing/ArrayType.purs
+    tests/purs/passing/Auto.purs
+    tests/purs/passing/AutoPrelude.purs
+    tests/purs/passing/AutoPrelude2.purs
+    tests/purs/passing/BindersInFunctions.purs
+    tests/purs/passing/BindingGroups.purs
+    tests/purs/passing/BlockString.purs
+    tests/purs/passing/CaseInDo.purs
+    tests/purs/passing/CaseInputWildcard.purs
+    tests/purs/passing/CaseMultipleExpressions.purs
+    tests/purs/passing/CaseStatement.purs
+    tests/purs/passing/CheckFunction.purs
+    tests/purs/passing/CheckSynonymBug.purs
+    tests/purs/passing/CheckTypeClass.purs
+    tests/purs/passing/Church.purs
+    tests/purs/passing/ClassRefSyntax.purs
+    tests/purs/passing/ClassRefSyntax/Lib.purs
+    tests/purs/passing/Collatz.purs
+    tests/purs/passing/Comparisons.purs
+    tests/purs/passing/Conditional.purs
+    tests/purs/passing/Console.purs
+    tests/purs/passing/ConstraintInference.purs
+    tests/purs/passing/ConstraintParens.purs
+    tests/purs/passing/ConstraintParsingIssue.purs
+    tests/purs/passing/ContextSimplification.purs
+    tests/purs/passing/DataAndType.purs
+    tests/purs/passing/DataConsClassConsOverlapOk.purs
+    tests/purs/passing/DctorName.purs
+    tests/purs/passing/DctorOperatorAlias.purs
+    tests/purs/passing/DctorOperatorAlias/List.purs
+    tests/purs/passing/DeepArrayBinder.purs
+    tests/purs/passing/DeepCase.purs
+    tests/purs/passing/DeriveNewtype.purs
+    tests/purs/passing/DeriveWithNestedSynonyms.purs
+    tests/purs/passing/Deriving.purs
+    tests/purs/passing/DerivingFunctor.purs
+    tests/purs/passing/Do.purs
+    tests/purs/passing/Dollar.purs
+    tests/purs/passing/DuplicateProperties.purs
+    tests/purs/passing/EffFn.js
+    tests/purs/passing/EffFn.purs
+    tests/purs/passing/EmptyDataDecls.purs
+    tests/purs/passing/EmptyRow.purs
+    tests/purs/passing/EmptyTypeClass.purs
+    tests/purs/passing/EntailsKindedType.purs
+    tests/purs/passing/Eq1Deriving.purs
+    tests/purs/passing/Eq1InEqDeriving.purs
+    tests/purs/passing/EqOrd.purs
+    tests/purs/passing/ExplicitImportReExport.purs
+    tests/purs/passing/ExplicitImportReExport/Bar.purs
+    tests/purs/passing/ExplicitImportReExport/Foo.purs
+    tests/purs/passing/ExplicitOperatorSections.purs
+    tests/purs/passing/ExportedInstanceDeclarations.purs
+    tests/purs/passing/ExportExplicit.purs
+    tests/purs/passing/ExportExplicit/M1.purs
+    tests/purs/passing/ExportExplicit2.purs
+    tests/purs/passing/ExportExplicit2/M1.purs
+    tests/purs/passing/ExtendedInfixOperators.purs
+    tests/purs/passing/Fib.purs
+    tests/purs/passing/FieldConsPuns.purs
+    tests/purs/passing/FieldPuns.purs
+    tests/purs/passing/FinalTagless.purs
+    tests/purs/passing/ForeignKind.purs
+    tests/purs/passing/ForeignKind/Lib.purs
+    tests/purs/passing/FunctionalDependencies.purs
+    tests/purs/passing/Functions.purs
+    tests/purs/passing/Functions2.purs
+    tests/purs/passing/FunctionScope.purs
+    tests/purs/passing/FunWithFunDeps.js
+    tests/purs/passing/FunWithFunDeps.purs
+    tests/purs/passing/Generalization1.purs
+    tests/purs/passing/GenericsRep.purs
+    tests/purs/passing/Guards.purs
+    tests/purs/passing/HasOwnProperty.purs
+    tests/purs/passing/HoistError.purs
+    tests/purs/passing/IfThenElseMaybe.purs
+    tests/purs/passing/IfWildcard.purs
+    tests/purs/passing/ImplicitEmptyImport.purs
+    tests/purs/passing/Import.purs
+    tests/purs/passing/Import/M1.purs
+    tests/purs/passing/Import/M2.purs
+    tests/purs/passing/ImportExplicit.purs
+    tests/purs/passing/ImportExplicit/M1.purs
+    tests/purs/passing/ImportHiding.purs
+    tests/purs/passing/ImportQualified.purs
+    tests/purs/passing/ImportQualified/M1.purs
+    tests/purs/passing/InferRecFunWithConstrainedArgument.purs
+    tests/purs/passing/InstanceBeforeClass.purs
+    tests/purs/passing/InstanceChain.purs
+    tests/purs/passing/InstanceSigs.purs
+    tests/purs/passing/InstanceSigsGeneral.purs
+    tests/purs/passing/IntAndChar.purs
+    tests/purs/passing/iota.purs
+    tests/purs/passing/JSReserved.purs
+    tests/purs/passing/KindedType.purs
+    tests/purs/passing/LargeSumType.purs
+    tests/purs/passing/Let.purs
+    tests/purs/passing/Let2.purs
+    tests/purs/passing/LetInInstance.purs
+    tests/purs/passing/LetPattern.purs
+    tests/purs/passing/LiberalTypeSynonyms.purs
+    tests/purs/passing/Match.purs
+    tests/purs/passing/Module.purs
+    tests/purs/passing/Module/M1.purs
+    tests/purs/passing/Module/M2.purs
+    tests/purs/passing/ModuleDeps.purs
+    tests/purs/passing/ModuleDeps/M1.purs
+    tests/purs/passing/ModuleDeps/M2.purs
+    tests/purs/passing/ModuleDeps/M3.purs
+    tests/purs/passing/ModuleExport.purs
+    tests/purs/passing/ModuleExport/A.purs
+    tests/purs/passing/ModuleExportDupes.purs
+    tests/purs/passing/ModuleExportDupes/A.purs
+    tests/purs/passing/ModuleExportDupes/B.purs
+    tests/purs/passing/ModuleExportDupes/C.purs
+    tests/purs/passing/ModuleExportExcluded.purs
+    tests/purs/passing/ModuleExportExcluded/A.purs
+    tests/purs/passing/ModuleExportQualified.purs
+    tests/purs/passing/ModuleExportQualified/A.purs
+    tests/purs/passing/ModuleExportSelf.purs
+    tests/purs/passing/ModuleExportSelf/A.purs
+    tests/purs/passing/Monad.purs
+    tests/purs/passing/MonadState.purs
+    tests/purs/passing/MPTCs.purs
+    tests/purs/passing/MultiArgFunctions.purs
+    tests/purs/passing/MutRec.purs
+    tests/purs/passing/MutRec2.purs
+    tests/purs/passing/MutRec3.purs
+    tests/purs/passing/NakedConstraint.purs
+    tests/purs/passing/NamedPatterns.purs
+    tests/purs/passing/NegativeBinder.purs
+    tests/purs/passing/NegativeIntInRange.purs
+    tests/purs/passing/Nested.purs
+    tests/purs/passing/NestedRecordUpdate.purs
+    tests/purs/passing/NestedRecordUpdateWildcards.purs
+    tests/purs/passing/NestedTypeSynonyms.purs
+    tests/purs/passing/NestedWhere.purs
+    tests/purs/passing/NewConsClass.purs
+    tests/purs/passing/Newtype.purs
+    tests/purs/passing/NewtypeClass.purs
+    tests/purs/passing/NewtypeEff.purs
+    tests/purs/passing/NewtypeInstance.purs
+    tests/purs/passing/NewtypeWithRecordUpdate.purs
+    tests/purs/passing/NonConflictingExports.purs
+    tests/purs/passing/NonConflictingExports/A.purs
+    tests/purs/passing/NonOrphanInstanceFunDepExtra.purs
+    tests/purs/passing/NonOrphanInstanceFunDepExtra/Lib.purs
+    tests/purs/passing/NonOrphanInstanceMulti.purs
+    tests/purs/passing/NonOrphanInstanceMulti/Lib.purs
+    tests/purs/passing/NumberLiterals.purs
+    tests/purs/passing/ObjectGetter.purs
+    tests/purs/passing/Objects.purs
+    tests/purs/passing/ObjectSynonym.purs
+    tests/purs/passing/ObjectUpdate.purs
+    tests/purs/passing/ObjectUpdate2.purs
+    tests/purs/passing/ObjectUpdater.purs
+    tests/purs/passing/ObjectWildcards.purs
+    tests/purs/passing/OneConstructor.purs
+    tests/purs/passing/OperatorAlias.purs
+    tests/purs/passing/OperatorAliasElsewhere.purs
+    tests/purs/passing/OperatorAliasElsewhere/Def.purs
+    tests/purs/passing/OperatorAssociativity.purs
+    tests/purs/passing/OperatorInlining.purs
+    tests/purs/passing/Operators.purs
+    tests/purs/passing/Operators/Other.purs
+    tests/purs/passing/OperatorSections.purs
+    tests/purs/passing/OptimizerBug.purs
+    tests/purs/passing/OptionalQualified.purs
+    tests/purs/passing/Ord1Deriving.purs
+    tests/purs/passing/Ord1InOrdDeriving.purs
+    tests/purs/passing/ParensInType.purs
+    tests/purs/passing/ParensInTypedBinder.purs
+    tests/purs/passing/PartialFunction.purs
+    tests/purs/passing/Patterns.purs
+    tests/purs/passing/PendingConflictingImports.purs
+    tests/purs/passing/PendingConflictingImports/A.purs
+    tests/purs/passing/PendingConflictingImports/B.purs
+    tests/purs/passing/PendingConflictingImports2.purs
+    tests/purs/passing/PendingConflictingImports2/A.purs
+    tests/purs/passing/Person.purs
+    tests/purs/passing/PolyLabels.js
+    tests/purs/passing/PolyLabels.purs
+    tests/purs/passing/PrimedTypeName.purs
+    tests/purs/passing/QualifiedNames.purs
+    tests/purs/passing/QualifiedNames/Either.purs
+    tests/purs/passing/QualifiedQualifiedImports.purs
+    tests/purs/passing/Rank2Data.purs
+    tests/purs/passing/Rank2Object.purs
+    tests/purs/passing/Rank2Types.purs
+    tests/purs/passing/Rank2TypeSynonym.purs
+    tests/purs/passing/RebindableSyntax.purs
+    tests/purs/passing/Recursion.purs
+    tests/purs/passing/RedefinedFixity.purs
+    tests/purs/passing/RedefinedFixity/M1.purs
+    tests/purs/passing/RedefinedFixity/M2.purs
+    tests/purs/passing/RedefinedFixity/M3.purs
+    tests/purs/passing/ReExportQualified.purs
+    tests/purs/passing/ReExportQualified/A.purs
+    tests/purs/passing/ReExportQualified/B.purs
+    tests/purs/passing/ReExportQualified/C.purs
+    tests/purs/passing/ReservedWords.purs
+    tests/purs/passing/ResolvableScopeConflict.purs
+    tests/purs/passing/ResolvableScopeConflict/A.purs
+    tests/purs/passing/ResolvableScopeConflict/B.purs
+    tests/purs/passing/ResolvableScopeConflict2.purs
+    tests/purs/passing/ResolvableScopeConflict2/A.purs
+    tests/purs/passing/ResolvableScopeConflict3.purs
+    tests/purs/passing/ResolvableScopeConflict3/A.purs
+    tests/purs/passing/RowConstructors.purs
+    tests/purs/passing/RowInInstanceHeadDetermined.purs
+    tests/purs/passing/RowLacks.purs
+    tests/purs/passing/RowNub.purs
+    tests/purs/passing/RowPolyInstanceContext.purs
+    tests/purs/passing/RowsInInstanceContext.purs
+    tests/purs/passing/RowUnion.js
+    tests/purs/passing/RowUnion.purs
+    tests/purs/passing/RunFnInline.purs
+    tests/purs/passing/RuntimeScopeIssue.purs
+    tests/purs/passing/s.purs
+    tests/purs/passing/ScopedTypeVariables.purs
+    tests/purs/passing/Sequence.purs
+    tests/purs/passing/SequenceDesugared.purs
+    tests/purs/passing/ShadowedModuleName.purs
+    tests/purs/passing/ShadowedModuleName/Test.purs
+    tests/purs/passing/ShadowedName.purs
+    tests/purs/passing/ShadowedRename.purs
+    tests/purs/passing/ShadowedTCO.purs
+    tests/purs/passing/ShadowedTCOLet.purs
+    tests/purs/passing/SignedNumericLiterals.purs
+    tests/purs/passing/SolvingAppendSymbol.purs
+    tests/purs/passing/SolvingCompareSymbol.purs
+    tests/purs/passing/SolvingIsSymbol.purs
+    tests/purs/passing/SolvingIsSymbol/Lib.purs
+    tests/purs/passing/Stream.purs
+    tests/purs/passing/StringEdgeCases.purs
+    tests/purs/passing/StringEdgeCases/Records.purs
+    tests/purs/passing/StringEdgeCases/Symbols.purs
+    tests/purs/passing/StringEscapes.purs
+    tests/purs/passing/Superclasses1.purs
+    tests/purs/passing/Superclasses3.purs
+    tests/purs/passing/TailCall.purs
+    tests/purs/passing/TCO.purs
+    tests/purs/passing/TCOCase.purs
+    tests/purs/passing/Tick.purs
+    tests/purs/passing/TopLevelCase.purs
+    tests/purs/passing/TransitiveImport.purs
+    tests/purs/passing/TransitiveImport/Middle.purs
+    tests/purs/passing/TransitiveImport/Test.purs
+    tests/purs/passing/TypeClasses.purs
+    tests/purs/passing/TypeClassesInOrder.purs
+    tests/purs/passing/TypeClassesWithOverlappingTypeVariables.purs
+    tests/purs/passing/TypeClassMemberOrderChange.purs
+    tests/purs/passing/TypedBinders.purs
+    tests/purs/passing/TypeDecl.purs
+    tests/purs/passing/TypedWhere.purs
+    tests/purs/passing/TypeOperators.purs
+    tests/purs/passing/TypeOperators/A.purs
+    tests/purs/passing/TypeSynonymInData.purs
+    tests/purs/passing/TypeSynonyms.purs
+    tests/purs/passing/TypeWildcards.purs
+    tests/purs/passing/TypeWildcardsRecordExtension.purs
+    tests/purs/passing/TypeWithoutParens.purs
+    tests/purs/passing/TypeWithoutParens/Lib.purs
+    tests/purs/passing/UnderscoreIdent.purs
+    tests/purs/passing/UnicodeIdentifier.purs
+    tests/purs/passing/UnicodeOperators.purs
+    tests/purs/passing/UnicodeType.purs
+    tests/purs/passing/UnifyInTypeInstanceLookup.purs
+    tests/purs/passing/Unit.purs
+    tests/purs/passing/UnknownInTypeClassLookup.purs
+    tests/purs/passing/UnsafeCoerce.purs
+    tests/purs/passing/UntupledConstraints.purs
+    tests/purs/passing/UsableTypeClassMethods.purs
+    tests/purs/passing/UTF8Sourcefile.purs
+    tests/purs/passing/Where.purs
+    tests/purs/passing/WildcardInInstance.purs
+    tests/purs/passing/WildcardType.purs
+    tests/purs/psci/BasicEval.purs
+    tests/purs/psci/Multiline.purs
+    tests/purs/warning/2140.purs
+    tests/purs/warning/2383.purs
+    tests/purs/warning/2411.purs
+    tests/purs/warning/2542.purs
+    tests/purs/warning/CustomWarning.purs
+    tests/purs/warning/CustomWarning2.purs
+    tests/purs/warning/CustomWarning3.purs
+    tests/purs/warning/DuplicateExportRef.purs
+    tests/purs/warning/DuplicateImport.purs
+    tests/purs/warning/DuplicateImportRef.purs
+    tests/purs/warning/DuplicateSelectiveImport.purs
+    tests/purs/warning/HidingImport.purs
+    tests/purs/warning/ImplicitImport.purs
+    tests/purs/warning/ImplicitQualifiedImport.purs
+    tests/purs/warning/ImplicitQualifiedImportReExport.purs
+    tests/purs/warning/MissingTypeDeclaration.purs
+    tests/purs/warning/NewtypeInstance.purs
+    tests/purs/warning/NewtypeInstance2.purs
+    tests/purs/warning/NewtypeInstance3.purs
+    tests/purs/warning/NewtypeInstance4.purs
+    tests/purs/warning/OverlappingPattern.purs
+    tests/purs/warning/ScopeShadowing.purs
+    tests/purs/warning/ScopeShadowing2.purs
+    tests/purs/warning/ShadowedBinderPatternGuard.purs
+    tests/purs/warning/ShadowedNameParens.purs
+    tests/purs/warning/ShadowedTypeVar.purs
+    tests/purs/warning/UnnecessaryFFIModule.js
+    tests/purs/warning/UnnecessaryFFIModule.purs
+    tests/purs/warning/UnusedDctorExplicitImport.purs
+    tests/purs/warning/UnusedDctorImportAll.purs
+    tests/purs/warning/UnusedDctorImportExplicit.purs
+    tests/purs/warning/UnusedExplicitImport.purs
+    tests/purs/warning/UnusedExplicitImportTypeOp.purs
+    tests/purs/warning/UnusedExplicitImportTypeOp/Lib.purs
+    tests/purs/warning/UnusedExplicitImportValOp.purs
+    tests/purs/warning/UnusedFFIImplementations.js
+    tests/purs/warning/UnusedFFIImplementations.purs
+    tests/purs/warning/UnusedImport.purs
+    tests/purs/warning/UnusedTypeVar.purs
+    tests/purs/warning/WildcardInferredType.purs
+    tests/support/bower.json
+    tests/support/package-lock.json
+    tests/support/package.json
+    tests/support/prelude-resolutions.json
+    tests/support/psci/Sample.purs
+    tests/support/pscide/src/CompletionSpecDocs.purs
+    tests/support/pscide/src/FindUsage.purs
+    tests/support/pscide/src/FindUsage/Definition.purs
+    tests/support/pscide/src/FindUsage/Recursive.purs
+    tests/support/pscide/src/FindUsage/RecursiveShadowed.purs
+    tests/support/pscide/src/FindUsage/Reexport.purs
+    tests/support/pscide/src/ImportsSpec.purs
+    tests/support/pscide/src/ImportsSpec1.purs
+    tests/support/pscide/src/MatcherSpec.purs
+    tests/support/pscide/src/RebuildSpecDep.purs
+    tests/support/pscide/src/RebuildSpecSingleModule.fail
+    tests/support/pscide/src/RebuildSpecSingleModule.purs
+    tests/support/pscide/src/RebuildSpecWithDeps.purs
+    tests/support/pscide/src/RebuildSpecWithForeign.js
+    tests/support/pscide/src/RebuildSpecWithForeign.purs
+    tests/support/pscide/src/RebuildSpecWithHiddenIdent.purs
+    tests/support/pscide/src/RebuildSpecWithMissingForeign.fail
+    tests/support/setup-win.cmd
+
+source-repository head
+  type: git
+  location: https://github.com/purescript/purescript
+
+flag release
+  description: Mark this build as a release build: prevents inclusion of extra info e.g. commit SHA in --version output)
+
+  manual: False
+  default: False
+
+library
+  hs-source-dirs:
+      src
+  default-extensions: ConstraintKinds DataKinds DeriveFunctor EmptyDataDecls FlexibleContexts KindSignatures LambdaCase MultiParamTypeClasses NoImplicitPrelude PatternGuards PatternSynonyms RankNTypes RecordWildCards OverloadedStrings ScopedTypeVariables TupleSections ViewPatterns
+  ghc-options: -Wall -O2
+  build-depends:
+      Glob >=0.9 && <0.10
+    , aeson >=1.0 && <1.3
+    , aeson-better-errors >=0.8
+    , ansi-terminal >=0.7.1 && <0.9
+    , base >=4.8 && <4.11
+    , base-compat >=0.6.0
+    , blaze-html >=0.8.1 && <0.10
+    , bower-json >=1.0.0.1 && <1.1
+    , boxes >=0.1.4 && <0.2.0
+    , bytestring
+    , cheapskate >=0.1 && <0.2
+    , clock
+    , containers
+    , data-ordlist >=0.4.7.0
+    , deepseq
+    , directory >=1.2.3
+    , dlist
+    , edit-distance
+    , file-embed
+    , filepath
+    , fsnotify >=0.2.1
+    , haskeline >=0.7.0.0
+    , language-javascript >=0.6.0.9 && <0.7
+    , lens ==4.*
+    , lifted-base >=0.2.3 && <0.2.4
+    , monad-control >=1.0.0.0 && <1.1
+    , monad-logger >=0.3 && <0.4
+    , mtl >=2.1.0 && <2.3.0
+    , parallel >=3.2 && <3.3
+    , parsec >=3.1.10
+    , pattern-arrows >=0.0.2 && <0.1
+    , process >=1.2.0 && <1.7
+    , protolude >=0.1.6
+    , regex-tdfa
+    , safe >=0.3.9 && <0.4
+    , scientific >=0.3.4.9 && <0.4
+    , semigroups >=0.16.2 && <0.19
+    , sourcemap >=0.1.6
+    , spdx ==0.2.*
+    , split
+    , stm >=0.2.4.0
+    , stringsearch
+    , syb
+    , text
+    , time
+    , transformers >=0.3.0 && <0.6
+    , transformers-base >=0.4.0 && <0.5
+    , transformers-compat >=0.3.0
+    , unordered-containers
+    , utf8-string >=1 && <2
+    , vector
+  exposed-modules:
+      Control.Monad.Logger
+      Control.Monad.Supply
+      Control.Monad.Supply.Class
+      Language.PureScript
+      Language.PureScript.AST
+      Language.PureScript.AST.Binders
+      Language.PureScript.AST.Declarations
+      Language.PureScript.AST.Exported
+      Language.PureScript.AST.Literals
+      Language.PureScript.AST.Operators
+      Language.PureScript.AST.SourcePos
+      Language.PureScript.AST.Traversals
+      Language.PureScript.Bundle
+      Language.PureScript.CodeGen
+      Language.PureScript.CodeGen.JS
+      Language.PureScript.CodeGen.JS.Common
+      Language.PureScript.CodeGen.JS.Printer
+      Language.PureScript.Comments
+      Language.PureScript.Constants
+      Language.PureScript.CoreFn
+      Language.PureScript.CoreFn.Ann
+      Language.PureScript.CoreFn.Binders
+      Language.PureScript.CoreFn.Desugar
+      Language.PureScript.CoreFn.Expr
+      Language.PureScript.CoreFn.FromJSON
+      Language.PureScript.CoreFn.Meta
+      Language.PureScript.CoreFn.Module
+      Language.PureScript.CoreFn.Optimizer
+      Language.PureScript.CoreFn.ToJSON
+      Language.PureScript.CoreFn.Traversals
+      Language.PureScript.CoreImp
+      Language.PureScript.CoreImp.AST
+      Language.PureScript.CoreImp.Optimizer
+      Language.PureScript.CoreImp.Optimizer.Blocks
+      Language.PureScript.CoreImp.Optimizer.Common
+      Language.PureScript.CoreImp.Optimizer.Inliner
+      Language.PureScript.CoreImp.Optimizer.MagicDo
+      Language.PureScript.CoreImp.Optimizer.TCO
+      Language.PureScript.CoreImp.Optimizer.Unused
+      Language.PureScript.Crash
+      Language.PureScript.Docs
+      Language.PureScript.Docs.AsHtml
+      Language.PureScript.Docs.AsMarkdown
+      Language.PureScript.Docs.Convert
+      Language.PureScript.Docs.Convert.ReExports
+      Language.PureScript.Docs.Convert.Single
+      Language.PureScript.Docs.Css
+      Language.PureScript.Docs.ParseInPackage
+      Language.PureScript.Docs.Prim
+      Language.PureScript.Docs.Render
+      Language.PureScript.Docs.RenderedCode
+      Language.PureScript.Docs.RenderedCode.RenderKind
+      Language.PureScript.Docs.RenderedCode.RenderType
+      Language.PureScript.Docs.RenderedCode.Types
+      Language.PureScript.Docs.Tags
+      Language.PureScript.Docs.Types
+      Language.PureScript.Docs.Utils.MonoidExtras
+      Language.PureScript.Environment
+      Language.PureScript.Errors
+      Language.PureScript.Errors.JSON
+      Language.PureScript.Externs
+      Language.PureScript.Hierarchy
+      Language.PureScript.Ide
+      Language.PureScript.Ide.CaseSplit
+      Language.PureScript.Ide.Command
+      Language.PureScript.Ide.Completion
+      Language.PureScript.Ide.Error
+      Language.PureScript.Ide.Externs
+      Language.PureScript.Ide.Filter
+      Language.PureScript.Ide.Filter.Declaration
+      Language.PureScript.Ide.Imports
+      Language.PureScript.Ide.Logging
+      Language.PureScript.Ide.Matcher
+      Language.PureScript.Ide.Prim
+      Language.PureScript.Ide.Rebuild
+      Language.PureScript.Ide.Reexports
+      Language.PureScript.Ide.SourceFile
+      Language.PureScript.Ide.State
+      Language.PureScript.Ide.Types
+      Language.PureScript.Ide.Usage
+      Language.PureScript.Ide.Util
+      Language.PureScript.Ide.Watcher
+      Language.PureScript.Interactive
+      Language.PureScript.Interactive.Completion
+      Language.PureScript.Interactive.Directive
+      Language.PureScript.Interactive.IO
+      Language.PureScript.Interactive.Message
+      Language.PureScript.Interactive.Module
+      Language.PureScript.Interactive.Parser
+      Language.PureScript.Interactive.Printer
+      Language.PureScript.Interactive.Types
+      Language.PureScript.Kinds
+      Language.PureScript.Label
+      Language.PureScript.Linter
+      Language.PureScript.Linter.Exhaustive
+      Language.PureScript.Linter.Imports
+      Language.PureScript.Make
+      Language.PureScript.Make.Actions
+      Language.PureScript.Make.BuildPlan
+      Language.PureScript.Make.Monad
+      Language.PureScript.ModuleDependencies
+      Language.PureScript.Names
+      Language.PureScript.Options
+      Language.PureScript.Parser
+      Language.PureScript.Parser.Common
+      Language.PureScript.Parser.Declarations
+      Language.PureScript.Parser.Kinds
+      Language.PureScript.Parser.Lexer
+      Language.PureScript.Parser.State
+      Language.PureScript.Parser.Types
+      Language.PureScript.Pretty
+      Language.PureScript.Pretty.Common
+      Language.PureScript.Pretty.Kinds
+      Language.PureScript.Pretty.Types
+      Language.PureScript.Pretty.Values
+      Language.PureScript.PSString
+      Language.PureScript.Publish
+      Language.PureScript.Publish.BoxesHelpers
+      Language.PureScript.Publish.ErrorsWarnings
+      Language.PureScript.Publish.Utils
+      Language.PureScript.Renamer
+      Language.PureScript.Sugar
+      Language.PureScript.Sugar.AdoNotation
+      Language.PureScript.Sugar.BindingGroups
+      Language.PureScript.Sugar.CaseDeclarations
+      Language.PureScript.Sugar.DoNotation
+      Language.PureScript.Sugar.LetPattern
+      Language.PureScript.Sugar.Names
+      Language.PureScript.Sugar.Names.Common
+      Language.PureScript.Sugar.Names.Env
+      Language.PureScript.Sugar.Names.Exports
+      Language.PureScript.Sugar.Names.Imports
+      Language.PureScript.Sugar.ObjectWildcards
+      Language.PureScript.Sugar.Operators
+      Language.PureScript.Sugar.Operators.Binders
+      Language.PureScript.Sugar.Operators.Common
+      Language.PureScript.Sugar.Operators.Expr
+      Language.PureScript.Sugar.Operators.Types
+      Language.PureScript.Sugar.TypeClasses
+      Language.PureScript.Sugar.TypeClasses.Deriving
+      Language.PureScript.Sugar.TypeDeclarations
+      Language.PureScript.Traversals
+      Language.PureScript.TypeChecker
+      Language.PureScript.TypeChecker.Entailment
+      Language.PureScript.TypeChecker.Kinds
+      Language.PureScript.TypeChecker.Monad
+      Language.PureScript.TypeChecker.Skolems
+      Language.PureScript.TypeChecker.Subsumption
+      Language.PureScript.TypeChecker.Synonyms
+      Language.PureScript.TypeChecker.Types
+      Language.PureScript.TypeChecker.TypeSearch
+      Language.PureScript.TypeChecker.Unify
+      Language.PureScript.TypeClassDictionaries
+      Language.PureScript.Types
+      System.IO.UTF8
+  other-modules:
+      Paths_purescript
+  default-language: Haskell2010
+
+executable purs
+  main-is: Main.hs
+  hs-source-dirs:
+      app
+  ghc-options: -Wall -O2 -fno-warn-unused-do-bind -threaded -rtsopts -with-rtsopts=-N
+  build-depends:
+      Glob >=0.9 && <0.10
+    , aeson >=1.0 && <1.3
+    , aeson-better-errors >=0.8
+    , ansi-terminal >=0.7.1 && <0.9
+    , ansi-wl-pprint
+    , base >=4.8 && <4.11
+    , base-compat >=0.6.0
+    , blaze-html >=0.8.1 && <0.10
+    , bower-json >=1.0.0.1 && <1.1
+    , boxes >=0.1.4 && <0.2.0
+    , bytestring
+    , cheapskate >=0.1 && <0.2
+    , clock
+    , containers
+    , data-ordlist >=0.4.7.0
+    , deepseq
+    , directory >=1.2.3
+    , dlist
+    , edit-distance
+    , file-embed
+    , filepath
+    , fsnotify >=0.2.1
+    , haskeline >=0.7.0.0
+    , http-types
+    , language-javascript >=0.6.0.9 && <0.7
+    , lens ==4.*
+    , lifted-base >=0.2.3 && <0.2.4
+    , monad-control >=1.0.0.0 && <1.1
+    , monad-logger >=0.3 && <0.4
+    , mtl >=2.1.0 && <2.3.0
+    , network
+    , optparse-applicative >=0.13.0
+    , parallel >=3.2 && <3.3
+    , parsec >=3.1.10
+    , pattern-arrows >=0.0.2 && <0.1
+    , process >=1.2.0 && <1.7
+    , protolude >=0.1.6
+    , purescript
+    , regex-tdfa
+    , safe >=0.3.9 && <0.4
+    , scientific >=0.3.4.9 && <0.4
+    , semigroups >=0.16.2 && <0.19
+    , sourcemap >=0.1.6
+    , spdx ==0.2.*
+    , split
+    , stm >=0.2.4.0
+    , stringsearch
+    , syb
+    , text
+    , time
+    , transformers >=0.3.0 && <0.6
+    , transformers-base >=0.4.0 && <0.5
+    , transformers-compat >=0.3.0
+    , unordered-containers
+    , utf8-string >=1 && <2
+    , vector
+    , wai ==3.*
+    , wai-websockets ==3.*
+    , warp ==3.*
+    , websockets >=0.9 && <0.13
+  if flag(release)
+    cpp-options: -DRELEASE
+  else
+    build-depends:
+        gitrev >=1.2.0 && <1.4
+  other-modules:
+      Command.Bundle
+      Command.Compile
+      Command.Docs
+      Command.Docs.Html
+      Command.Hierarchy
+      Command.Ide
+      Command.Publish
+      Command.REPL
+      Paths_purescript
+      Version
+  default-language: Haskell2010
+
+test-suite tests
+  type: exitcode-stdio-1.0
+  main-is: Main.hs
+  hs-source-dirs:
+      tests
+  default-extensions: NoImplicitPrelude
+  ghc-options: -Wall
+  build-depends:
+      Glob >=0.9 && <0.10
+    , HUnit
+    , aeson >=1.0 && <1.3
+    , aeson-better-errors >=0.8
+    , ansi-terminal >=0.7.1 && <0.9
+    , base >=4.8 && <4.11
+    , base-compat >=0.6.0
+    , blaze-html >=0.8.1 && <0.10
+    , bower-json >=1.0.0.1 && <1.1
+    , boxes >=0.1.4 && <0.2.0
+    , bytestring
+    , cheapskate >=0.1 && <0.2
+    , clock
+    , containers
+    , data-ordlist >=0.4.7.0
+    , deepseq
+    , directory >=1.2.3
+    , dlist
+    , edit-distance
+    , file-embed
+    , filepath
+    , fsnotify >=0.2.1
+    , haskeline >=0.7.0.0
+    , hspec
+    , hspec-discover
+    , language-javascript >=0.6.0.9 && <0.7
+    , lens ==4.*
+    , lifted-base >=0.2.3 && <0.2.4
+    , monad-control >=1.0.0.0 && <1.1
+    , monad-logger >=0.3 && <0.4
+    , mtl >=2.1.0 && <2.3.0
+    , parallel >=3.2 && <3.3
+    , parsec >=3.1.10
+    , pattern-arrows >=0.0.2 && <0.1
+    , process >=1.2.0 && <1.7
+    , protolude >=0.1.6
+    , purescript
+    , regex-tdfa
+    , safe >=0.3.9 && <0.4
+    , scientific >=0.3.4.9 && <0.4
+    , semigroups >=0.16.2 && <0.19
+    , sourcemap >=0.1.6
+    , spdx ==0.2.*
+    , split
+    , stm >=0.2.4.0
+    , stringsearch
+    , syb
+    , tasty
+    , tasty-hspec
+    , text
+    , time
+    , transformers >=0.3.0 && <0.6
+    , transformers-base >=0.4.0 && <0.5
+    , transformers-compat >=0.3.0
+    , unordered-containers
+    , utf8-string >=1 && <2
+    , vector
+  other-modules:
+      Language.PureScript.Ide.CompletionSpec
+      Language.PureScript.Ide.FilterSpec
+      Language.PureScript.Ide.ImportsSpec
+      Language.PureScript.Ide.MatcherSpec
+      Language.PureScript.Ide.RebuildSpec
+      Language.PureScript.Ide.ReexportsSpec
+      Language.PureScript.Ide.SourceFileSpec
+      Language.PureScript.Ide.StateSpec
+      Language.PureScript.Ide.Test
+      Language.PureScript.Ide.UsageSpec
+      PscIdeSpec
+      TestCompiler
+      TestCoreFn
+      TestDocs
+      TestHierarchy
+      TestIde
+      TestPrimDocs
+      TestPsci
+      TestPsci.CommandTest
+      TestPsci.CompletionTest
+      TestPsci.EvalTest
+      TestPsci.TestEnv
+      TestPscPublish
+      TestUtils
+      Paths_purescript
   default-language: Haskell2010
diff --git a/src/Language/PureScript/AST/Binders.hs b/src/Language/PureScript/AST/Binders.hs
--- a/src/Language/PureScript/AST/Binders.hs
+++ b/src/Language/PureScript/AST/Binders.hs
@@ -5,6 +5,8 @@
 
 import Prelude.Compat
 
+import Data.Semigroup
+
 import Language.PureScript.AST.SourcePos
 import Language.PureScript.AST.Literals
 import Language.PureScript.Names
@@ -22,20 +24,20 @@
   -- |
   -- A binder which matches a literal
   --
-  | LiteralBinder (Literal Binder)
+  | LiteralBinder SourceSpan (Literal Binder)
   -- |
   -- A binder which binds an identifier
   --
-  | VarBinder Ident
+  | VarBinder SourceSpan Ident
   -- |
   -- A binder which matches a data constructor
   --
-  | ConstructorBinder (Qualified (ProperName 'ConstructorName)) [Binder]
+  | ConstructorBinder SourceSpan (Qualified (ProperName 'ConstructorName)) [Binder]
   -- |
   -- A operator alias binder. During the rebracketing phase of desugaring,
   -- this data constructor will be removed.
   --
-  | OpBinder (Qualified (OpName 'ValueOpName))
+  | OpBinder SourceSpan (Qualified (OpName 'ValueOpName))
   -- |
   -- Binary operator application. During the rebracketing phase of desugaring,
   -- this data constructor will be removed.
@@ -52,7 +54,7 @@
   -- |
   -- A binder which binds its input to an identifier
   --
-  | NamedBinder Ident Binder
+  | NamedBinder SourceSpan Ident Binder
   -- |
   -- A binder with source position information
   --
@@ -61,20 +63,123 @@
   -- A binder with a type annotation
   --
   | TypedBinder Type Binder
-  deriving (Show, Eq, Ord)
+  deriving (Show)
 
+-- Manual Eq and Ord instances for `Binder` were added on 2018-03-05. Comparing
+-- the `SourceSpan` values embedded in some of the data constructors of `Binder`
+-- was expensive. This made exhaustiveness checking observably slow for code
+-- such as the `explode` function in `test/purs/passing/LargeSumTypes.purs`.
+-- Custom instances were written to skip comparing the `SourceSpan` values. Only
+-- the `Ord` instance was needed for the speed-up, but I did not want the `Eq`
+-- to have mismatched behavior.
+instance Eq Binder where
+  (==) NullBinder NullBinder = True
+  (==) NullBinder _ = False
+
+  (==) (LiteralBinder _ lb) (LiteralBinder _ lb') = (==) lb lb'
+  (==) LiteralBinder{} _ = False
+
+  (==) (VarBinder _ ident) (VarBinder _ ident') = (==) ident ident'
+  (==) VarBinder{} _ = False
+
+  (==) (ConstructorBinder _ qpc bs) (ConstructorBinder _ qpc' bs') =
+    (==) qpc qpc' && (==) bs bs'
+  (==) ConstructorBinder{} _ = False
+
+  (==) (OpBinder _ qov) (OpBinder _ qov') =
+    (==) qov qov'
+  (==) OpBinder{} _ = False
+
+  (==) (BinaryNoParensBinder b1 b2 b3) (BinaryNoParensBinder b1' b2' b3') =
+    (==) b1 b1' && (==) b2 b2' && (==) b3 b3'
+  (==) BinaryNoParensBinder{} _ = False
+
+  (==) (ParensInBinder b) (ParensInBinder b') =
+    (==) b b'
+  (==) ParensInBinder{} _ = False
+
+  (==) (NamedBinder _ ident b) (NamedBinder _ ident' b') =
+    (==) ident ident' && (==) b b'
+  (==) NamedBinder{} _ = False
+
+  (==) (PositionedBinder _ comments b) (PositionedBinder _ comments' b') =
+    (==) comments comments' && (==) b b'
+  (==) PositionedBinder{} _ = False
+
+  (==) (TypedBinder ty b) (TypedBinder ty' b') =
+    (==) ty ty' && (==) b b'
+  (==) TypedBinder{} _ = False
+
+instance Ord Binder where
+  compare NullBinder NullBinder = EQ
+  compare NullBinder _ = LT
+
+  compare (LiteralBinder _ lb) (LiteralBinder _ lb') = compare lb lb'
+  compare LiteralBinder{} NullBinder = GT
+  compare LiteralBinder{} _ = LT
+
+  compare (VarBinder _ ident) (VarBinder _ ident') = compare ident ident'
+  compare VarBinder{} NullBinder = GT
+  compare VarBinder{} LiteralBinder{} = GT
+  compare VarBinder{} _ = LT
+
+  compare (ConstructorBinder _ qpc bs) (ConstructorBinder _ qpc' bs') =
+    compare qpc qpc' <> compare bs bs'
+  compare ConstructorBinder{} NullBinder = GT
+  compare ConstructorBinder{} LiteralBinder{} = GT
+  compare ConstructorBinder{} VarBinder{} = GT
+  compare ConstructorBinder{} _ = LT
+
+  compare (OpBinder _ qov) (OpBinder _ qov') =
+    compare qov qov'
+  compare OpBinder{} NullBinder = GT
+  compare OpBinder{} LiteralBinder{} = GT
+  compare OpBinder{} VarBinder{} = GT
+  compare OpBinder{} ConstructorBinder{} = GT
+  compare OpBinder{} _ = LT
+
+  compare (BinaryNoParensBinder b1 b2 b3) (BinaryNoParensBinder b1' b2' b3') =
+    compare b1 b1' <> compare b2 b2' <> compare b3 b3'
+  compare BinaryNoParensBinder{} ParensInBinder{} = LT
+  compare BinaryNoParensBinder{} NamedBinder{} = LT
+  compare BinaryNoParensBinder{} PositionedBinder{} = LT
+  compare BinaryNoParensBinder{} TypedBinder{} = LT
+  compare BinaryNoParensBinder{} _ = GT
+
+  compare (ParensInBinder b) (ParensInBinder b') =
+    compare b b'
+  compare ParensInBinder{} NamedBinder{} = LT
+  compare ParensInBinder{} PositionedBinder{} = LT
+  compare ParensInBinder{} TypedBinder{} = LT
+  compare ParensInBinder{} _ = GT
+
+  compare (NamedBinder _ ident b) (NamedBinder _ ident' b') =
+    compare ident ident' <> compare b b'
+  compare NamedBinder{} PositionedBinder{} = LT
+  compare NamedBinder{} TypedBinder{} = LT
+  compare NamedBinder{} _ = GT
+
+  compare (PositionedBinder _ comments b) (PositionedBinder _ comments' b') =
+    compare comments comments' <> compare b b'
+  compare PositionedBinder{} TypedBinder{} = LT
+  compare PositionedBinder{} _ = GT
+
+  compare (TypedBinder ty b) (TypedBinder ty' b') =
+    compare ty ty' <> compare b b'
+  compare TypedBinder{} _ = GT
+
 -- |
 -- Collect all names introduced in binders in an expression
 --
 binderNames :: Binder -> [Ident]
 binderNames = go []
   where
-  go ns (LiteralBinder b) = lit ns b
-  go ns (VarBinder name) = name : ns
-  go ns (ConstructorBinder _ bs) = foldl go ns bs
+  go ns (LiteralBinder _ b) = lit ns b
+  go ns (VarBinder _ name) = name : ns
+  go ns (ConstructorBinder _ _ bs) = foldl go ns bs
   go ns (BinaryNoParensBinder b1 b2 b3) = foldl go ns [b1, b2, b3]
   go ns (ParensInBinder b) = go ns b
-  go ns (NamedBinder name b) = go (name : ns) b
+  go ns (NamedBinder _ name b) = go (name : ns) b
   go ns (PositionedBinder _ _ b) = go ns b
   go ns (TypedBinder _ b) = go ns b
   go ns _ = ns
@@ -84,8 +189,7 @@
 
 isIrrefutable :: Binder -> Bool
 isIrrefutable NullBinder = True
-isIrrefutable (VarBinder _) = True
+isIrrefutable (VarBinder _ _) = True
 isIrrefutable (PositionedBinder _ _ b) = isIrrefutable b
 isIrrefutable (TypedBinder _ b) = isIrrefutable b
 isIrrefutable _ = False
-
diff --git a/src/Language/PureScript/AST/Declarations.hs b/src/Language/PureScript/AST/Declarations.hs
--- a/src/Language/PureScript/AST/Declarations.hs
+++ b/src/Language/PureScript/AST/Declarations.hs
@@ -69,7 +69,6 @@
   | ErrorParsingFFIModule FilePath (Maybe Bundle.ErrorMessage)
   | ErrorParsingModule P.ParseError
   | MissingFFIModule ModuleName
-  | MultipleFFIModules ModuleName [FilePath]
   | UnnecessaryFFIModule ModuleName FilePath
   | MissingFFIImplementations ModuleName [Ident]
   | UnusedFFIImplementations ModuleName [Ident]
@@ -93,7 +92,7 @@
   | ScopeShadowing Name (Maybe ModuleName) [ModuleName]
   | DeclConflict Name Name
   | ExportConflict (Qualified Name) (Qualified Name)
-  | DuplicateModule ModuleName [SourceSpan]
+  | DuplicateModule ModuleName
   | DuplicateTypeClass (ProperName 'ClassName) SourceSpan
   | DuplicateInstance Ident SourceSpan
   | DuplicateTypeArgument Text
@@ -128,7 +127,8 @@
   | MissingClassMember Ident
   | ExtraneousClassMember Ident (Qualified (ProperName 'ClassName))
   | ExpectedType Type Kind
-  | IncorrectConstructorArity (Qualified (ProperName 'ConstructorName))
+  -- | constructor name, expected argument count, actual argument count
+  | IncorrectConstructorArity (Qualified (ProperName 'ConstructorName)) Int Int
   | ExprDoesNotHaveType Expr Type
   | PropertyIsMissing Label
   | AdditionalProperty Label
@@ -158,6 +158,7 @@
   | DuplicateExportRef Name
   | IntOutOfRange Integer Text Integer Integer
   | ImplicitQualifiedImport ModuleName ModuleName [DeclarationRef]
+  | ImplicitQualifiedImportReExport ModuleName ModuleName [DeclarationRef]
   | ImplicitImport ModuleName [DeclarationRef]
   | HidingImport ModuleName [DeclarationRef]
   | CaseBinderLengthDiffers Int [Binder]
@@ -173,6 +174,9 @@
   | UserDefinedWarning Type
   -- | a declaration couldn't be used because it contained free variables
   | UnusableDeclaration Ident [[Text]]
+  | CannotDefinePrimModules ModuleName
+  | MixedAssociativityError (NEL.NonEmpty (Qualified (OpName 'AnyOpName), Associativity))
+  | NonAssociativeError (NEL.NonEmpty (Qualified (OpName 'AnyOpName)))
   deriving (Show)
 
 -- | Error message hints, providing more detailed information about failure.
@@ -198,7 +202,7 @@
   | ErrorInTypeClassDeclaration (ProperName 'ClassName)
   | ErrorInForeignImport Ident
   | ErrorSolvingConstraint Constraint
-  | PositionedError SourceSpan
+  | PositionedError (NEL.NonEmpty SourceSpan)
   deriving (Show)
 
 -- | Categories of hints
@@ -232,6 +236,10 @@
 getModuleSourceSpan :: Module -> SourceSpan
 getModuleSourceSpan (Module ss _ _ _ _) = ss
 
+-- | Return a module's declarations.
+getModuleDeclarations :: Module -> [Declaration]
+getModuleDeclarations (Module _ _ _ declarations _) = declarations
+
 -- |
 -- Add an import declaration for a module if it does not already explicitly import it.
 --
@@ -255,7 +263,7 @@
 importPrim :: Module -> Module
 importPrim =
   let
-    primModName = ModuleName [ProperName C.prim]
+    primModName = C.Prim
   in
     addDefaultImport (Qualified (Just primModName) primModName)
       . addDefaultImport (Qualified Nothing primModName)
@@ -460,7 +468,7 @@
 getValueDeclaration _ = Nothing
 
 pattern ValueDecl :: SourceAnn -> Ident -> NameKind -> [Binder] -> [GuardedExpr] -> Declaration
-pattern ValueDecl sann ident name binders expr 
+pattern ValueDecl sann ident name binders expr
   = ValueDeclaration (ValueDeclarationData sann ident name binders expr)
 
 -- |
@@ -519,10 +527,10 @@
   --
   | TypeClassDeclaration SourceAnn (ProperName 'ClassName) [(Text, Maybe Kind)] [Constraint] [FunctionalDependency] [Declaration]
   -- |
-  -- A type instance declaration (name, dependencies, class name, instance types, member
-  -- declarations)
+  -- A type instance declaration (instance chain, chain index, name,
+  -- dependencies, class name, instance types, member declarations)
   --
-  | TypeInstanceDeclaration SourceAnn Ident [Constraint] (Qualified (ProperName 'ClassName)) [Type] TypeInstanceBody
+  | TypeInstanceDeclaration SourceAnn [Ident] Integer Ident [Constraint] (Qualified (ProperName 'ClassName)) [Type] TypeInstanceBody
   deriving (Show)
 
 data ValueFixity = ValueFixity Fixity (Qualified (Either Ident (ProperName 'ConstructorName))) (OpName 'ValueOpName)
@@ -572,7 +580,7 @@
 declSourceAnn (FixityDeclaration sa _) = sa
 declSourceAnn (ImportDeclaration sa _ _ _) = sa
 declSourceAnn (TypeClassDeclaration sa _ _ _ _ _) = sa
-declSourceAnn (TypeInstanceDeclaration sa _ _ _ _ _) = sa
+declSourceAnn (TypeInstanceDeclaration sa _ _ _ _ _ _ _) = sa
 
 declSourceSpan :: Declaration -> SourceSpan
 declSourceSpan = fst . declSourceAnn
@@ -587,7 +595,7 @@
 declName (FixityDeclaration _ (Left (ValueFixity _ _ n))) = Just (ValOpName n)
 declName (FixityDeclaration _ (Right (TypeFixity _ _ n))) = Just (TyOpName n)
 declName (TypeClassDeclaration _ n _ _ _ _) = Just (TyClassName n)
-declName (TypeInstanceDeclaration _ n _ _ _ _) = Just (IdentName n)
+declName (TypeInstanceDeclaration _ _ _ n _ _ _ _) = Just (IdentName n)
 declName ImportDeclaration{} = Nothing
 declName BindingGroupDeclaration{} = Nothing
 declName DataBindingGroupDeclaration{} = Nothing
@@ -693,11 +701,11 @@
   -- |
   -- A literal value
   --
-  = Literal (Literal Expr)
+  = Literal SourceSpan (Literal Expr)
   -- |
   -- A prefix -, will be desugared
   --
-  | UnaryMinus Expr
+  | UnaryMinus SourceSpan Expr
   -- |
   -- Binary operator application. During the rebracketing phase of desugaring, this data constructor
   -- will be removed.
@@ -737,12 +745,12 @@
   -- |
   -- Variable
   --
-  | Var (Qualified Ident)
+  | Var SourceSpan (Qualified Ident)
   -- |
   -- An operator. This will be desugared into a function during the "operators"
   -- phase of desugaring.
   --
-  | Op (Qualified (OpName 'ValueOpName))
+  | Op SourceSpan (Qualified (OpName 'ValueOpName))
   -- |
   -- Conditional (if-then-else expression)
   --
@@ -750,7 +758,7 @@
   -- |
   -- A data constructor
   --
-  | Constructor (Qualified (ProperName 'ConstructorName))
+  | Constructor SourceSpan (Qualified (ProperName 'ConstructorName))
   -- |
   -- A case expression. During the case expansion phase of desugaring, top-level binders will get
   -- desugared into case expressions, hence the need for guards and multiple binders per branch here.
@@ -763,12 +771,16 @@
   -- |
   -- A let binding
   --
-  | Let [Declaration] Expr
+  | Let WhereProvenance [Declaration] Expr
   -- |
   -- A do-notation block
   --
   | Do [DoNotationElement]
   -- |
+  -- An ado-notation block
+  --
+  | Ado [DoNotationElement] Expr
+  -- |
   -- An application of a typeclass dictionary constructor. The value should be
   -- an ObjectLiteral.
   --
@@ -796,7 +808,7 @@
   --
   | AnonymousArgument
   -- |
-  -- A typed hole that will be turned into a hint/error duing typechecking
+  -- A typed hole that will be turned into a hint/error during typechecking
   --
   | Hole Text
   -- |
@@ -806,6 +818,20 @@
   deriving (Show)
 
 -- |
+-- Metadata that tells where a let binding originated
+--
+data WhereProvenance
+  -- |
+  -- The let binding was originally a where clause
+  --
+  = FromWhere
+  -- |
+  -- The let binding was always a let binding
+  --
+  | FromLet
+  deriving (Show)
+
+-- |
 -- An alternative in a case statement
 --
 data CaseAlternative = CaseAlternative
@@ -878,9 +904,9 @@
 $(deriveJSON (defaultOptions { sumEncoding = ObjectWithSingleField }) ''ImportDeclarationType)
 
 isTrueExpr :: Expr -> Bool
-isTrueExpr (Literal (BooleanLiteral True)) = True
-isTrueExpr (Var (Qualified (Just (ModuleName [ProperName "Prelude"])) (Ident "otherwise"))) = True
-isTrueExpr (Var (Qualified (Just (ModuleName [ProperName "Data", ProperName "Boolean"])) (Ident "otherwise"))) = True
+isTrueExpr (Literal _ (BooleanLiteral True)) = True
+isTrueExpr (Var _ (Qualified (Just (ModuleName [ProperName "Prelude"])) (Ident "otherwise"))) = True
+isTrueExpr (Var _ (Qualified (Just (ModuleName [ProperName "Data", ProperName "Boolean"])) (Ident "otherwise"))) = True
 isTrueExpr (TypedValue _ e _) = isTrueExpr e
 isTrueExpr (PositionedValue _ _ e) = isTrueExpr e
 isTrueExpr _ = False
diff --git a/src/Language/PureScript/AST/Exported.hs b/src/Language/PureScript/AST/Exported.hs
--- a/src/Language/PureScript/AST/Exported.hs
+++ b/src/Language/PureScript/AST/Exported.hs
@@ -101,7 +101,7 @@
 -- Get all type and type class names referenced by a type instance declaration.
 --
 typeInstanceConstituents :: Declaration -> [Either (Qualified (ProperName 'ClassName)) (Qualified (ProperName 'TypeName))]
-typeInstanceConstituents (TypeInstanceDeclaration _ _ constraints className tys _) =
+typeInstanceConstituents (TypeInstanceDeclaration _ _ _ _ constraints className tys _) =
   Left className : (concatMap fromConstraint constraints ++ concatMap fromType tys)
   where
 
diff --git a/src/Language/PureScript/AST/SourcePos.hs b/src/Language/PureScript/AST/SourcePos.hs
--- a/src/Language/PureScript/AST/SourcePos.hs
+++ b/src/Language/PureScript/AST/SourcePos.hs
@@ -80,3 +80,6 @@
 
 internalModuleSourceSpan :: String -> SourceSpan
 internalModuleSourceSpan name = SourceSpan name (SourcePos 0 0) (SourcePos 0 0)
+
+nullSourceSpan :: SourceSpan
+nullSourceSpan = internalModuleSourceSpan ""
diff --git a/src/Language/PureScript/AST/Traversals.hs b/src/Language/PureScript/AST/Traversals.hs
--- a/src/Language/PureScript/AST/Traversals.hs
+++ b/src/Language/PureScript/AST/Traversals.hs
@@ -58,12 +58,12 @@
   f' (BoundValueDeclaration sa b expr) = f (BoundValueDeclaration sa (h' b) (g' expr))
   f' (BindingGroupDeclaration ds) = f (BindingGroupDeclaration (fmap (\(name, nameKind, val) -> (name, nameKind, g' val)) ds))
   f' (TypeClassDeclaration sa name args implies deps ds) = f (TypeClassDeclaration sa name args implies deps (fmap f' ds))
-  f' (TypeInstanceDeclaration sa name cs className args ds) = f (TypeInstanceDeclaration sa name cs className args (mapTypeInstanceBody (fmap f') ds))
+  f' (TypeInstanceDeclaration sa ch idx name cs className args ds) = f (TypeInstanceDeclaration sa ch idx name cs className args (mapTypeInstanceBody (fmap f') ds))
   f' other = f other
 
   g' :: Expr -> Expr
-  g' (Literal l) = g (Literal (lit g' l))
-  g' (UnaryMinus v) = g (UnaryMinus (g' v))
+  g' (Literal ss l) = g (Literal ss (lit g' l))
+  g' (UnaryMinus ss v) = g (UnaryMinus ss (g' v))
   g' (BinaryNoParens op v1 v2) = g (BinaryNoParens (g' op) (g' v1) (g' v2))
   g' (Parens v) = g (Parens (g' v))
   g' (TypeClassDictionaryConstructorApp name v) = g (TypeClassDictionaryConstructorApp name (g' v))
@@ -75,17 +75,18 @@
   g' (IfThenElse v1 v2 v3) = g (IfThenElse (g' v1) (g' v2) (g' v3))
   g' (Case vs alts) = g (Case (fmap g' vs) (fmap handleCaseAlternative alts))
   g' (TypedValue check v ty) = g (TypedValue check (g' v) ty)
-  g' (Let ds v) = g (Let (fmap f' ds) (g' v))
+  g' (Let w ds v) = g (Let w (fmap f' ds) (g' v))
   g' (Do es) = g (Do (fmap handleDoNotationElement es))
+  g' (Ado es v) = g (Ado (fmap handleDoNotationElement es) (g' v))
   g' (PositionedValue pos com v) = g (PositionedValue pos com (g' v))
   g' other = g other
 
   h' :: Binder -> Binder
-  h' (ConstructorBinder ctor bs) = h (ConstructorBinder ctor (fmap h' bs))
+  h' (ConstructorBinder ss ctor bs) = h (ConstructorBinder ss ctor (fmap h' bs))
   h' (BinaryNoParensBinder b1 b2 b3) = h (BinaryNoParensBinder (h' b1) (h' b2) (h' b3))
   h' (ParensInBinder b) = h (ParensInBinder (h' b))
-  h' (LiteralBinder l) = h (LiteralBinder (lit h' l))
-  h' (NamedBinder name b) = h (NamedBinder name (h' b))
+  h' (LiteralBinder ss l) = h (LiteralBinder ss (lit h' l))
+  h' (NamedBinder ss name b) = h (NamedBinder ss name (h' b))
   h' (PositionedBinder pos com b) = h (PositionedBinder pos com (h' b))
   h' (TypedBinder t b) = h (TypedBinder t (h' b))
   h' other = h other
@@ -130,13 +131,13 @@
      ValueDecl sa name nameKind <$> traverse (h' <=< h) bs <*> traverse (guardedExprM handleGuard (g' <=< g)) val
   f' (BindingGroupDeclaration ds) = BindingGroupDeclaration <$> traverse (\(name, nameKind, val) -> (,,) name nameKind <$> (g val >>= g')) ds
   f' (TypeClassDeclaration sa name args implies deps ds) = TypeClassDeclaration sa name args implies deps <$> traverse (f' <=< f) ds
-  f' (TypeInstanceDeclaration sa name cs className args ds) = TypeInstanceDeclaration sa name cs className args <$> traverseTypeInstanceBody (traverse (f' <=< f)) ds
+  f' (TypeInstanceDeclaration sa ch idx name cs className args ds) = TypeInstanceDeclaration sa ch idx name cs className args <$> traverseTypeInstanceBody (traverse (f' <=< f)) ds
   f' (BoundValueDeclaration sa b expr) = BoundValueDeclaration sa <$> h' b <*> g' expr
   f' other = f other
 
   g' :: Expr -> m Expr
-  g' (Literal l) = Literal <$> litM (g >=> g') l
-  g' (UnaryMinus v) = UnaryMinus <$> (g v >>= g')
+  g' (Literal ss l) = Literal ss <$> litM (g >=> g') l
+  g' (UnaryMinus ss v) = UnaryMinus ss <$> (g v >>= g')
   g' (BinaryNoParens op v1 v2) = BinaryNoParens <$> (g op >>= g') <*> (g v1 >>= g') <*> (g v2 >>= g')
   g' (Parens v) = Parens <$> (g v >>= g')
   g' (TypeClassDictionaryConstructorApp name v) = TypeClassDictionaryConstructorApp name <$> (g v >>= g')
@@ -148,17 +149,18 @@
   g' (IfThenElse v1 v2 v3) = IfThenElse <$> (g v1 >>= g') <*> (g v2 >>= g') <*> (g v3 >>= g')
   g' (Case vs alts) = Case <$> traverse (g' <=< g) vs <*> traverse handleCaseAlternative alts
   g' (TypedValue check v ty) = TypedValue check <$> (g v >>= g') <*> pure ty
-  g' (Let ds v) = Let <$> traverse (f' <=< f) ds <*> (g v >>= g')
+  g' (Let w ds v) = Let w <$> traverse (f' <=< f) ds <*> (g v >>= g')
   g' (Do es) = Do <$> traverse handleDoNotationElement es
+  g' (Ado es v) = Ado <$> traverse handleDoNotationElement es <*> (g v >>= g')
   g' (PositionedValue pos com v) = PositionedValue pos com <$> (g v >>= g')
   g' other = g other
 
   h' :: Binder -> m Binder
-  h' (LiteralBinder l) = LiteralBinder <$> litM (h >=> h') l
-  h' (ConstructorBinder ctor bs) = ConstructorBinder ctor <$> traverse (h' <=< h) bs
+  h' (LiteralBinder ss l) = LiteralBinder ss <$> litM (h >=> h') l
+  h' (ConstructorBinder ss ctor bs) = ConstructorBinder ss ctor <$> traverse (h' <=< h) bs
   h' (BinaryNoParensBinder b1 b2 b3) = BinaryNoParensBinder <$> (h b1 >>= h') <*> (h b2 >>= h') <*> (h b3 >>= h')
   h' (ParensInBinder b) = ParensInBinder <$> (h b >>= h')
-  h' (NamedBinder name b) = NamedBinder name <$> (h b >>= h')
+  h' (NamedBinder ss name b) = NamedBinder ss name <$> (h b >>= h')
   h' (PositionedBinder pos com b) = PositionedBinder pos com <$> (h b >>= h')
   h' (TypedBinder t b) = TypedBinder t <$> (h b >>= h')
   h' other = h other
@@ -194,17 +196,17 @@
 
   f' :: Declaration -> m Declaration
   f' (DataBindingGroupDeclaration ds) = (DataBindingGroupDeclaration <$> traverse f' ds) >>= f
-  f' (ValueDecl sa name nameKind bs val) = 
+  f' (ValueDecl sa name nameKind bs val) =
     ValueDecl sa name nameKind <$> traverse h' bs <*> traverse (guardedExprM handleGuard g') val >>= f
   f' (BindingGroupDeclaration ds) = (BindingGroupDeclaration <$> traverse (\(name, nameKind, val) -> (,,) name nameKind <$> g' val) ds) >>= f
   f' (BoundValueDeclaration sa b expr) = (BoundValueDeclaration sa <$> h' b <*> g' expr) >>= f
   f' (TypeClassDeclaration sa name args implies deps ds) = (TypeClassDeclaration sa name args implies deps <$> traverse f' ds) >>= f
-  f' (TypeInstanceDeclaration sa name cs className args ds) = (TypeInstanceDeclaration sa name cs className args <$> traverseTypeInstanceBody (traverse f') ds) >>= f
+  f' (TypeInstanceDeclaration sa ch idx name cs className args ds) = (TypeInstanceDeclaration sa ch idx name cs className args <$> traverseTypeInstanceBody (traverse f') ds) >>= f
   f' other = f other
 
   g' :: Expr -> m Expr
-  g' (Literal l) = (Literal <$> litM g' l) >>= g
-  g' (UnaryMinus v) = (UnaryMinus <$> g' v) >>= g
+  g' (Literal ss l) = (Literal ss <$> litM g' l) >>= g
+  g' (UnaryMinus ss v) = (UnaryMinus ss <$> g' v) >>= g
   g' (BinaryNoParens op v1 v2) = (BinaryNoParens <$> g' op <*> g' v1 <*> g' v2) >>= g
   g' (Parens v) = (Parens <$> g' v) >>= g
   g' (TypeClassDictionaryConstructorApp name v) = (TypeClassDictionaryConstructorApp name <$> g' v) >>= g
@@ -216,17 +218,18 @@
   g' (IfThenElse v1 v2 v3) = (IfThenElse <$> g' v1 <*> g' v2 <*> g' v3) >>= g
   g' (Case vs alts) = (Case <$> traverse g' vs <*> traverse handleCaseAlternative alts) >>= g
   g' (TypedValue check v ty) = (TypedValue check <$> g' v <*> pure ty) >>= g
-  g' (Let ds v) = (Let <$> traverse f' ds <*> g' v) >>= g
+  g' (Let w ds v) = (Let w <$> traverse f' ds <*> g' v) >>= g
   g' (Do es) = (Do <$> traverse handleDoNotationElement es) >>= g
+  g' (Ado es v) = (Ado <$> traverse handleDoNotationElement es <*> g' v) >>= g
   g' (PositionedValue pos com v) = (PositionedValue pos com <$> g' v) >>= g
   g' other = g other
 
   h' :: Binder -> m Binder
-  h' (LiteralBinder l) = (LiteralBinder <$> litM h' l) >>= h
-  h' (ConstructorBinder ctor bs) = (ConstructorBinder ctor <$> traverse h' bs) >>= h
+  h' (LiteralBinder ss l) = (LiteralBinder ss <$> litM h' l) >>= h
+  h' (ConstructorBinder ss ctor bs) = (ConstructorBinder ss ctor <$> traverse h' bs) >>= h
   h' (BinaryNoParensBinder b1 b2 b3) = (BinaryNoParensBinder <$> h' b1 <*> h' b2 <*> h' b3) >>= h
   h' (ParensInBinder b) = (ParensInBinder <$> h' b) >>= h
-  h' (NamedBinder name b) = (NamedBinder name <$> h' b) >>= h
+  h' (NamedBinder ss name b) = (NamedBinder ss name <$> h' b) >>= h
   h' (PositionedBinder pos com b) = (PositionedBinder pos com <$> h' b) >>= h
   h' (TypedBinder t b) = (TypedBinder t <$> h' b) >>= h
   h' other = h other
@@ -269,13 +272,13 @@
   f' d@(ValueDeclaration vd) = foldl (<>) (f d) (fmap h' (valdeclBinders vd) ++ concatMap (\(GuardedExpr grd v) -> fmap k' grd ++ [g' v]) (valdeclExpression vd))
   f' d@(BindingGroupDeclaration ds) = foldl (<>) (f d) (fmap (\(_, _, val) -> g' val) ds)
   f' d@(TypeClassDeclaration _ _ _ _ _ ds) = foldl (<>) (f d) (fmap f' ds)
-  f' d@(TypeInstanceDeclaration _ _ _ _ _ (ExplicitInstance ds)) = foldl (<>) (f d) (fmap f' ds)
+  f' d@(TypeInstanceDeclaration _ _ _ _ _ _ _ (ExplicitInstance ds)) = foldl (<>) (f d) (fmap f' ds)
   f' d@(BoundValueDeclaration _ b expr) = f d <> h' b <> g' expr
   f' d = f d
 
   g' :: Expr -> r
-  g' v@(Literal l) = lit (g v) g' l
-  g' v@(UnaryMinus v1) = g v <> g' v1
+  g' v@(Literal _ l) = lit (g v) g' l
+  g' v@(UnaryMinus _ v1) = g v <> g' v1
   g' v@(BinaryNoParens op v1 v2) = g v <> g' op <> g' v1 <> g' v2
   g' v@(Parens v1) = g v <> g' v1
   g' v@(TypeClassDictionaryConstructorApp _ v1) = g v <> g' v1
@@ -287,17 +290,18 @@
   g' v@(IfThenElse v1 v2 v3) = g v <> g' v1 <> g' v2 <> g' v3
   g' v@(Case vs alts) = foldl (<>) (foldl (<>) (g v) (fmap g' vs)) (fmap i' alts)
   g' v@(TypedValue _ v1 _) = g v <> g' v1
-  g' v@(Let ds v1) = foldl (<>) (g v) (fmap f' ds) <> g' v1
+  g' v@(Let _ ds v1) = foldl (<>) (g v) (fmap f' ds) <> g' v1
   g' v@(Do es) = foldl (<>) (g v) (fmap j' es)
+  g' v@(Ado es v1) = foldl (<>) (g v) (fmap j' es) <> g' v1
   g' v@(PositionedValue _ _ v1) = g v <> g' v1
   g' v = g v
 
   h' :: Binder -> r
-  h' b@(LiteralBinder l) = lit (h b) h' l
-  h' b@(ConstructorBinder _ bs) = foldl (<>) (h b) (fmap h' bs)
+  h' b@(LiteralBinder _ l) = lit (h b) h' l
+  h' b@(ConstructorBinder _ _ bs) = foldl (<>) (h b) (fmap h' bs)
   h' b@(BinaryNoParensBinder b1 b2 b3) = h b <> h' b1 <> h' b2 <> h' b3
   h' b@(ParensInBinder b1) = h b <> h' b1
-  h' b@(NamedBinder _ b1) = h b <> h' b1
+  h' b@(NamedBinder _ _ b1) = h b <> h' b1
   h' b@(PositionedBinder _ _ b1) = h b <> h' b1
   h' b@(TypedBinder _ b1) = h b <> h' b1
   h' b = h b
@@ -347,15 +351,15 @@
   f' s (ValueDeclaration vd) = foldl (<>) r0 (fmap (h'' s) (valdeclBinders vd) ++ concatMap (\(GuardedExpr grd v) -> fmap (k' s) grd ++ [g'' s v]) (valdeclExpression vd))
   f' s (BindingGroupDeclaration ds) = foldl (<>) r0 (fmap (\(_, _, val) -> g'' s val) ds)
   f' s (TypeClassDeclaration _ _ _ _ _ ds) = foldl (<>) r0 (fmap (f'' s) ds)
-  f' s (TypeInstanceDeclaration _ _ _ _ _ (ExplicitInstance ds)) = foldl (<>) r0 (fmap (f'' s) ds)
+  f' s (TypeInstanceDeclaration _ _ _ _ _ _ _ (ExplicitInstance ds)) = foldl (<>) r0 (fmap (f'' s) ds)
   f' _ _ = r0
 
   g'' :: s -> Expr -> r
   g'' s v = let (s', r) = g s v in r <> g' s' v
 
   g' :: s -> Expr -> r
-  g' s (Literal l) = lit g'' s l
-  g' s (UnaryMinus v1) = g'' s v1
+  g' s (Literal _ l) = lit g'' s l
+  g' s (UnaryMinus _ v1) = g'' s v1
   g' s (BinaryNoParens op v1 v2) = g'' s op <> g'' s v1 <> g'' s v2
   g' s (Parens v1) = g'' s v1
   g' s (TypeClassDictionaryConstructorApp _ v1) = g'' s v1
@@ -367,8 +371,9 @@
   g' s (IfThenElse v1 v2 v3) = g'' s v1 <> g'' s v2 <> g'' s v3
   g' s (Case vs alts) = foldl (<>) (foldl (<>) r0 (fmap (g'' s) vs)) (fmap (i'' s) alts)
   g' s (TypedValue _ v1 _) = g'' s v1
-  g' s (Let ds v1) = foldl (<>) r0 (fmap (f'' s) ds) <> g'' s v1
+  g' s (Let _ ds v1) = foldl (<>) r0 (fmap (f'' s) ds) <> g'' s v1
   g' s (Do es) = foldl (<>) r0 (fmap (j'' s) es)
+  g' s (Ado es v1) = foldl (<>) r0 (fmap (j'' s) es) <> g'' s v1
   g' s (PositionedValue _ _ v1) = g'' s v1
   g' _ _ = r0
 
@@ -376,11 +381,11 @@
   h'' s b = let (s', r) = h s b in r <> h' s' b
 
   h' :: s -> Binder -> r
-  h' s (LiteralBinder l) = lit h'' s l
-  h' s (ConstructorBinder _ bs) = foldl (<>) r0 (fmap (h'' s) bs)
+  h' s (LiteralBinder _ l) = lit h'' s l
+  h' s (ConstructorBinder _ _ bs) = foldl (<>) r0 (fmap (h'' s) bs)
   h' s (BinaryNoParensBinder b1 b2 b3) = h'' s b1 <> h'' s b2 <> h'' s b3
   h' s (ParensInBinder b) = h'' s b
-  h' s (NamedBinder _ b1) = h'' s b1
+  h' s (NamedBinder _ _ b1) = h'' s b1
   h' s (PositionedBinder _ _ b1) = h'' s b1
   h' s (TypedBinder _ b1) = h'' s b1
   h' _ _ = r0
@@ -433,13 +438,13 @@
     ValueDecl sa name nameKind <$> traverse (h'' s) bs <*> traverse (guardedExprM (k' s) (g'' s)) val
   f' s (BindingGroupDeclaration ds) = BindingGroupDeclaration <$> traverse (thirdM (g'' s)) ds
   f' s (TypeClassDeclaration sa name args implies deps ds) = TypeClassDeclaration sa name args implies deps <$> traverse (f'' s) ds
-  f' s (TypeInstanceDeclaration sa name cs className args ds) = TypeInstanceDeclaration sa name cs className args <$> traverseTypeInstanceBody (traverse (f'' s)) ds
+  f' s (TypeInstanceDeclaration sa ch idx name cs className args ds) = TypeInstanceDeclaration sa ch idx name cs className args <$> traverseTypeInstanceBody (traverse (f'' s)) ds
   f' _ other = return other
 
   g'' s = uncurry g' <=< g s
 
-  g' s (Literal l) = Literal <$> lit g'' s l
-  g' s (UnaryMinus v) = UnaryMinus <$> g'' s v
+  g' s (Literal ss l) = Literal ss <$> lit g'' s l
+  g' s (UnaryMinus ss v) = UnaryMinus ss <$> g'' s v
   g' s (BinaryNoParens op v1 v2) = BinaryNoParens <$> g'' s op <*> g'' s v1 <*> g'' s v2
   g' s (Parens v) = Parens <$> g'' s v
   g' s (TypeClassDictionaryConstructorApp name v) = TypeClassDictionaryConstructorApp name <$> g'' s v
@@ -451,18 +456,19 @@
   g' s (IfThenElse v1 v2 v3) = IfThenElse <$> g'' s v1 <*> g'' s v2 <*> g'' s v3
   g' s (Case vs alts) = Case <$> traverse (g'' s) vs <*> traverse (i'' s) alts
   g' s (TypedValue check v ty) = TypedValue check <$> g'' s v <*> pure ty
-  g' s (Let ds v) = Let <$> traverse (f'' s) ds <*> g'' s v
+  g' s (Let w ds v) = Let w <$> traverse (f'' s) ds <*> g'' s v
   g' s (Do es) = Do <$> traverse (j'' s) es
+  g' s (Ado es v) = Ado <$> traverse (j'' s) es <*> g'' s v
   g' s (PositionedValue pos com v) = PositionedValue pos com <$> g'' s v
   g' _ other = return other
 
   h'' s = uncurry h' <=< h s
 
-  h' s (LiteralBinder l) = LiteralBinder <$> lit h'' s l
-  h' s (ConstructorBinder ctor bs) = ConstructorBinder ctor <$> traverse (h'' s) bs
+  h' s (LiteralBinder ss l) = LiteralBinder ss <$> lit h'' s l
+  h' s (ConstructorBinder ss ctor bs) = ConstructorBinder ss ctor <$> traverse (h'' s) bs
   h' s (BinaryNoParensBinder b1 b2 b3) = BinaryNoParensBinder <$> h'' s b1 <*> h'' s b2 <*> h'' s b3
   h' s (ParensInBinder b) = ParensInBinder <$> h'' s b
-  h' s (NamedBinder name b) = NamedBinder name <$> h'' s b
+  h' s (NamedBinder ss name b) = NamedBinder ss name <$> h'' s b
   h' s (PositionedBinder pos com b) = PositionedBinder pos com <$> h'' s b
   h' s (TypedBinder t b) = TypedBinder t <$> h'' s b
   h' _ other = return other
@@ -486,49 +492,55 @@
   k' s (ConditionGuard e) = ConditionGuard <$> g'' s e
   k' s (PatternGuard b e) = PatternGuard <$> h'' s b <*> g'' s e
 
+data ScopedIdent = LocalIdent Ident | ToplevelIdent Ident
+  deriving (Show, Eq, Ord)
+
+inScope :: Ident -> S.Set ScopedIdent -> Bool
+inScope i s = (LocalIdent i `S.member` s) || (ToplevelIdent i `S.member` s)
+
 everythingWithScope
   :: forall r
    . (Monoid r)
-  => (S.Set Ident -> Declaration -> r)
-  -> (S.Set Ident -> Expr -> r)
-  -> (S.Set Ident -> Binder -> r)
-  -> (S.Set Ident -> CaseAlternative -> r)
-  -> (S.Set Ident -> DoNotationElement -> r)
-  -> ( S.Set Ident -> Declaration -> r
-     , S.Set Ident -> Expr -> r
-     , S.Set Ident -> Binder -> r
-     , S.Set Ident -> CaseAlternative -> r
-     , S.Set Ident -> DoNotationElement -> r
+  => (S.Set ScopedIdent -> Declaration -> r)
+  -> (S.Set ScopedIdent -> Expr -> r)
+  -> (S.Set ScopedIdent -> Binder -> r)
+  -> (S.Set ScopedIdent -> CaseAlternative -> r)
+  -> (S.Set ScopedIdent -> DoNotationElement -> r)
+  -> ( S.Set ScopedIdent -> Declaration -> r
+     , S.Set ScopedIdent -> Expr -> r
+     , S.Set ScopedIdent -> Binder -> r
+     , S.Set ScopedIdent -> CaseAlternative -> r
+     , S.Set ScopedIdent -> DoNotationElement -> r
      )
 everythingWithScope f g h i j = (f'', g'', h'', i'', \s -> snd . j'' s)
   where
   -- Avoid importing Data.Monoid and getting shadowed names above
   (<>) = mappend
 
-  f'' :: S.Set Ident -> Declaration -> r
+  f'' :: S.Set ScopedIdent -> Declaration -> r
   f'' s a = f s a <> f' s a
 
-  f' :: S.Set Ident -> Declaration -> r
+  f' :: S.Set ScopedIdent -> Declaration -> r
   f' s (DataBindingGroupDeclaration ds) =
-    let s' = S.union s (S.fromList (mapMaybe getDeclIdent (NEL.toList ds)))
+    let s' = S.union s (S.fromList (map ToplevelIdent (mapMaybe getDeclIdent (NEL.toList ds))))
     in foldMap (f'' s') ds
   f' s (ValueDecl _ name _ bs val) =
-    let s' = S.insert name s
-        s'' = S.union s' (S.fromList (concatMap binderNames bs))
+    let s' = S.insert (ToplevelIdent name) s
+        s'' = S.union s' (S.fromList (concatMap localBinderNames bs))
     in foldMap (h'' s') bs <> foldMap (l' s'') val
   f' s (BindingGroupDeclaration ds) =
-    let s' = S.union s (S.fromList (NEL.toList (fmap (\((_, name), _, _) -> name) ds)))
+    let s' = S.union s (S.fromList (NEL.toList (fmap (\((_, name), _, _) -> ToplevelIdent name) ds)))
     in foldMap (\(_, _, val) -> g'' s' val) ds
   f' s (TypeClassDeclaration _ _ _ _ _ ds) = foldMap (f'' s) ds
-  f' s (TypeInstanceDeclaration _ _ _ _ _ (ExplicitInstance ds)) = foldMap (f'' s) ds
+  f' s (TypeInstanceDeclaration _ _ _ _ _ _ _ (ExplicitInstance ds)) = foldMap (f'' s) ds
   f' _ _ = mempty
 
-  g'' :: S.Set Ident -> Expr -> r
+  g'' :: S.Set ScopedIdent -> Expr -> r
   g'' s a = g s a <> g' s a
 
-  g' :: S.Set Ident -> Expr -> r
-  g' s (Literal l) = lit g'' s l
-  g' s (UnaryMinus v1) = g'' s v1
+  g' :: S.Set ScopedIdent -> Expr -> r
+  g' s (Literal _ l) = lit g'' s l
+  g' s (UnaryMinus _ v1) = g'' s v1
   g' s (BinaryNoParens op v1 v2) = g'' s op <> g'' s v1 <> g'' s v2
   g' s (Parens v1) = g'' s v1
   g' s (TypeClassDictionaryConstructorApp _ v1) = g'' s v1
@@ -536,62 +548,65 @@
   g' s (ObjectUpdate obj vs) = g'' s obj <> foldMap (g'' s . snd) vs
   g' s (ObjectUpdateNested obj vs) = g'' s obj <> foldMap (g'' s) vs
   g' s (Abs b v1) =
-    let s' = S.union (S.fromList (binderNames b)) s
+    let s' = S.union (S.fromList (localBinderNames b)) s
     in h'' s b <> g'' s' v1
   g' s (App v1 v2) = g'' s v1 <> g'' s v2
   g' s (IfThenElse v1 v2 v3) = g'' s v1 <> g'' s v2 <> g'' s v3
   g' s (Case vs alts) = foldMap (g'' s) vs <> foldMap (i'' s) alts
   g' s (TypedValue _ v1 _) = g'' s v1
-  g' s (Let ds v1) =
-    let s' = S.union s (S.fromList (mapMaybe getDeclIdent ds))
+  g' s (Let _ ds v1) =
+    let s' = S.union s (S.fromList (map LocalIdent (mapMaybe getDeclIdent ds)))
     in foldMap (f'' s') ds <> g'' s' v1
   g' s (Do es) = fold . snd . mapAccumL j'' s $ es
+  g' s (Ado es v1) =
+    let s' = S.union s (foldMap (fst . j'' s) es)
+    in g'' s' v1
   g' s (PositionedValue _ _ v1) = g'' s v1
   g' _ _ = mempty
 
-  h'' :: S.Set Ident -> Binder -> r
+  h'' :: S.Set ScopedIdent -> Binder -> r
   h'' s a = h s a <> h' s a
 
-  h' :: S.Set Ident -> Binder -> r
-  h' s (LiteralBinder l) = lit h'' s l
-  h' s (ConstructorBinder _ bs) = foldMap (h'' s) bs
+  h' :: S.Set ScopedIdent -> Binder -> r
+  h' s (LiteralBinder _ l) = lit h'' s l
+  h' s (ConstructorBinder _ _ bs) = foldMap (h'' s) bs
   h' s (BinaryNoParensBinder b1 b2 b3) = foldMap (h'' s) [b1, b2, b3]
   h' s (ParensInBinder b) = h'' s b
-  h' s (NamedBinder name b1) = h'' (S.insert name s) b1
+  h' s (NamedBinder _ name b1) = h'' (S.insert (LocalIdent name) s) b1
   h' s (PositionedBinder _ _ b1) = h'' s b1
   h' s (TypedBinder _ b1) = h'' s b1
   h' _ _ = mempty
 
-  lit :: (S.Set Ident -> a -> r) -> S.Set Ident -> Literal a -> r
+  lit :: (S.Set ScopedIdent -> a -> r) -> S.Set ScopedIdent -> Literal a -> r
   lit go s (ArrayLiteral as) = foldMap (go s) as
   lit go s (ObjectLiteral as) = foldMap (go s . snd) as
   lit _ _ _ = mempty
 
-  i'' :: S.Set Ident -> CaseAlternative -> r
+  i'' :: S.Set ScopedIdent -> CaseAlternative -> r
   i'' s a = i s a <> i' s a
 
-  i' :: S.Set Ident -> CaseAlternative -> r
+  i' :: S.Set ScopedIdent -> CaseAlternative -> r
   i' s (CaseAlternative bs gs) =
-    let s' = S.union s (S.fromList (concatMap binderNames bs))
+    let s' = S.union s (S.fromList (concatMap localBinderNames bs))
     in foldMap (h'' s) bs <> foldMap (l' s') gs
 
-  j'' :: S.Set Ident -> DoNotationElement -> (S.Set Ident, r)
+  j'' :: S.Set ScopedIdent -> DoNotationElement -> (S.Set ScopedIdent, r)
   j'' s a = let (s', r) = j' s a in (s', j s a <> r)
 
-  j' :: S.Set Ident -> DoNotationElement -> (S.Set Ident, r)
+  j' :: S.Set ScopedIdent -> DoNotationElement -> (S.Set ScopedIdent, r)
   j' s (DoNotationValue v) = (s, g'' s v)
   j' s (DoNotationBind b v) =
-    let s' = S.union (S.fromList (binderNames b)) s
+    let s' = S.union (S.fromList (localBinderNames b)) s
     in (s', h'' s b <> g'' s v)
   j' s (DoNotationLet ds) =
-    let s' = S.union s (S.fromList (mapMaybe getDeclIdent ds))
+    let s' = S.union s (S.fromList (map LocalIdent (mapMaybe getDeclIdent ds)))
     in (s', foldMap (f'' s') ds)
   j' s (PositionedDoNotationElement _ _ e1) = j'' s e1
 
-  k' :: S.Set Ident -> Guard -> (S.Set Ident, r)
+  k' :: S.Set ScopedIdent -> Guard -> (S.Set ScopedIdent, r)
   k' s (ConditionGuard e) = (s, g'' s e)
   k' s (PatternGuard b e) =
-    let s' = S.union (S.fromList (binderNames b)) s
+    let s' = S.union (S.fromList (localBinderNames b)) s
     in (s', h'' s b <> g'' s' e)
 
   l' s (GuardedExpr [] e) = g'' s e
@@ -604,6 +619,8 @@
   getDeclIdent (TypeDeclaration td) = Just (tydeclIdent td)
   getDeclIdent _ = Nothing
 
+  localBinderNames = map LocalIdent . binderNames
+
 accumTypes
   :: (Monoid r)
   => (Type -> r)
@@ -618,7 +635,7 @@
   forDecls (DataDeclaration _ _ _ _ dctors) = mconcat (concatMap (fmap f . snd) dctors)
   forDecls (ExternDeclaration _ _ ty) = f ty
   forDecls (TypeClassDeclaration _ _ _ implies _ _) = mconcat (concatMap (fmap f . constraintArgs) implies)
-  forDecls (TypeInstanceDeclaration _ _ cs _ tys _) = mconcat (concatMap (fmap f . constraintArgs) cs) `mappend` mconcat (fmap f tys)
+  forDecls (TypeInstanceDeclaration _ _ _ _ cs _ tys _) = mconcat (concatMap (fmap f . constraintArgs) cs) `mappend` mconcat (fmap f tys)
   forDecls (TypeSynonymDeclaration _ _ _ ty) = f ty
   forDecls (TypeDeclaration td) = f (tydeclType td)
   forDecls _ = mempty
@@ -645,7 +662,7 @@
   forDecls (TypeClassDeclaration _ _ args implies _ _) =
     foldMap (foldMap f . snd) args `mappend`
     foldMap (foldMap forTypes . constraintArgs) implies
-  forDecls (TypeInstanceDeclaration _ _ cs _ tys _) =
+  forDecls (TypeInstanceDeclaration _ _ _ _ cs _ tys _) =
     foldMap (foldMap forTypes . constraintArgs) cs `mappend`
     foldMap forTypes tys
   forDecls (TypeSynonymDeclaration _ _ args ty) =
diff --git a/src/Language/PureScript/Bundle.hs b/src/Language/PureScript/Bundle.hs
--- a/src/Language/PureScript/Bundle.hs
+++ b/src/Language/PureScript/Bundle.hs
@@ -145,12 +145,19 @@
 
 -- | Calculate the ModuleIdentifier which a require(...) statement imports.
 checkImportPath :: String -> ModuleIdentifier -> S.Set String -> Either String ModuleIdentifier
-checkImportPath "./foreign" m _ =
+checkImportPath "./foreign.js" m _ =
   Right (ModuleIdentifier (moduleName m) Foreign)
 checkImportPath name _ names
-  | Just name' <- stripPrefix "../" name
+  | Just name' <- stripSuffix "/index.js" =<< stripPrefix "../" name
   , name' `S.member` names = Right (ModuleIdentifier name' Regular)
 checkImportPath name _ _ = Left name
+
+stripSuffix :: Eq a => [a] -> [a] -> Maybe [a]
+stripSuffix suffix xs =
+  case splitAt (length xs - length suffix) xs of
+    (before, after)
+      | after == suffix -> Just before
+      | otherwise -> Nothing
 
 -- | Compute the dependencies of all elements in a module, and add them to the tree.
 --
diff --git a/src/Language/PureScript/CodeGen/JS.hs b/src/Language/PureScript/CodeGen/JS.hs
--- a/src/Language/PureScript/CodeGen/JS.hs
+++ b/src/Language/PureScript/CodeGen/JS.hs
@@ -15,7 +15,7 @@
 import Control.Monad.Reader (MonadReader, asks)
 import Control.Monad.Supply.Class
 
-import Data.List ((\\), delete, intersect)
+import Data.List ((\\), intersect)
 import qualified Data.Foldable as F
 import qualified Data.Map as M
 import Data.Maybe (fromMaybe, isNothing)
@@ -32,8 +32,8 @@
 import Language.PureScript.CoreFn
 import Language.PureScript.Crash
 import Language.PureScript.Errors (ErrorMessageHint(..), SimpleErrorMessage(..),
-                                   MultipleErrors(..), rethrow,
-                                   errorMessage, rethrowWithPosition, addHint)
+                                   MultipleErrors(..), rethrow, errorMessage,
+                                   errorMessage', rethrowWithPosition, addHint)
 import Language.PureScript.Names
 import Language.PureScript.Options
 import Language.PureScript.PSString (PSString, mkString)
@@ -50,11 +50,12 @@
   => Module Ann
   -> Maybe AST
   -> m [AST]
-moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
+moduleToJs (Module _ coms mn _ imps exps foreigns decls) foreign_ =
   rethrow (addHint (ErrorInModule mn)) $ do
     let usedNames = concatMap getNames decls
     let mnLookup = renameImports usedNames imps
-    jsImports <- traverse (importToJs mnLookup) . delete (ModuleName [ProperName C.prim]) . (\\ [mn]) $ ordNub $ map snd imps
+    jsImports <- traverse (importToJs mnLookup)
+      . (\\ (mn : C.primModules)) $ ordNub $ map snd imps
     let decls' = renameModules mnLookup decls
     jsDecls <- mapM bindToJs decls'
     optimized <- traverse (traverse optimize) jsDecls
@@ -64,7 +65,7 @@
     let header = if comments && not (null coms) then AST.Comment Nothing coms strict else strict
     let foreign' = [AST.VariableIntroduction Nothing "$foreign" foreign_ | not $ null foreigns || isNothing foreign_]
     let moduleBody = header : foreign' ++ jsImports ++ concat optimized
-    let foreignExps = exps `intersect` (fst `map` foreigns)
+    let foreignExps = exps `intersect` foreigns
     let standardExps = exps \\ foreignExps
     let exps' = AST.ObjectLiteral Nothing $ map (mkString . runIdent &&& AST.Var Nothing . identToJs) standardExps
                                ++ map (mkString . runIdent &&& foreignIdent) foreignExps
@@ -103,7 +104,8 @@
   importToJs :: M.Map ModuleName (Ann, ModuleName) -> ModuleName -> m AST
   importToJs mnLookup mn' = do
     let ((ss, _, _, _), mnSafe) = fromMaybe (internalError "Missing value in mnLookup") $ M.lookup mn' mnLookup
-    let moduleBody = AST.App Nothing (AST.Var Nothing "require") [AST.StringLiteral Nothing (fromString (".." </> T.unpack (runModuleName mn')))]
+    let moduleBody = AST.App Nothing (AST.Var Nothing "require")
+          [AST.StringLiteral Nothing (fromString (".." </> T.unpack (runModuleName mn') </> "index.js"))]
     withPos ss $ AST.VariableIntroduction Nothing (moduleNameToJs mnSafe) (Just moduleBody)
 
   -- | Replaces the `ModuleName`s in the AST so that the generated code refers to
@@ -148,7 +150,7 @@
 
   withPos :: SourceSpan -> AST -> m AST
   withPos ss js = do
-    withSM <- asks optionsSourceMaps
+    withSM <- asks (elem JSSourceMap . optionsCodegenTargets)
     return $ if withSM
       then withSourceSpan ss js
       else js
@@ -164,6 +166,7 @@
   accessor :: Ident -> AST -> AST
   accessor (Ident prop) = accessorString $ mkString prop
   accessor (GenIdent _ _) = internalError "GenIdent in accessor"
+  accessor UnusedIdent = internalError "UnusedIdent in accessor"
 
   accessorString :: PSString -> AST -> AST
   accessorString prop = AST.Indexer Nothing (AST.StringLiteral Nothing prop)
@@ -176,7 +179,7 @@
 
   valueToJs' :: Expr Ann -> m AST
   valueToJs' (Literal (pos, _, _, _) l) =
-    rethrowWithPosition pos $ literalToValueJS l
+    rethrowWithPosition pos $ literalToValueJS pos l
   valueToJs' (Var (_, _, _, Just (IsConstructor _ [])) name) =
     return $ accessorString "value" $ qualifiedToJS id name
   valueToJs' (Var (_, _, _, Just (IsConstructor _ _)) name) =
@@ -199,7 +202,10 @@
                                (var name)
   valueToJs' (Abs _ arg val) = do
     ret <- valueToJs val
-    return $ AST.Function Nothing Nothing [identToJs arg] (AST.Block Nothing [AST.Return Nothing ret])
+    let jsArg = case arg of
+                  UnusedIdent -> []
+                  _           -> [identToJs arg]
+    return $ AST.Function Nothing Nothing jsArg (AST.Block Nothing [AST.Return Nothing ret])
   valueToJs' e@App{} = do
     let (f, args) = unApp e []
     args' <- mapM valueToJs args
@@ -251,14 +257,14 @@
   iife :: Text -> [AST] -> AST
   iife v exprs = AST.App Nothing (AST.Function Nothing Nothing [] (AST.Block Nothing $ exprs ++ [AST.Return Nothing $ AST.Var Nothing v])) []
 
-  literalToValueJS :: Literal (Expr Ann) -> m AST
-  literalToValueJS (NumericLiteral (Left i)) = return $ AST.NumericLiteral Nothing (Left i)
-  literalToValueJS (NumericLiteral (Right n)) = return $ AST.NumericLiteral Nothing (Right n)
-  literalToValueJS (StringLiteral s) = return $ AST.StringLiteral Nothing s
-  literalToValueJS (CharLiteral c) = return $ AST.StringLiteral Nothing (fromString [c])
-  literalToValueJS (BooleanLiteral b) = return $ AST.BooleanLiteral Nothing b
-  literalToValueJS (ArrayLiteral xs) = AST.ArrayLiteral Nothing <$> mapM valueToJs xs
-  literalToValueJS (ObjectLiteral ps) = AST.ObjectLiteral Nothing <$> mapM (sndM valueToJs) ps
+  literalToValueJS :: SourceSpan -> Literal (Expr Ann) -> m AST
+  literalToValueJS ss (NumericLiteral (Left i)) = return $ AST.NumericLiteral (Just ss) (Left i)
+  literalToValueJS ss (NumericLiteral (Right n)) = return $ AST.NumericLiteral (Just ss) (Right n)
+  literalToValueJS ss (StringLiteral s) = return $ AST.StringLiteral (Just ss) s
+  literalToValueJS ss (CharLiteral c) = return $ AST.StringLiteral (Just ss) (fromString [c])
+  literalToValueJS ss (BooleanLiteral b) = return $ AST.BooleanLiteral (Just ss) b
+  literalToValueJS ss (ArrayLiteral xs) = AST.ArrayLiteral (Just ss) <$> mapM valueToJs xs
+  literalToValueJS ss (ObjectLiteral ps) = AST.ObjectLiteral (Just ss) <$> mapM (sndM valueToJs) ps
 
   -- | Shallow copy an object.
   extendObj :: AST -> [(PSString, AST)] -> m AST
@@ -419,10 +425,10 @@
       -- the value is `Unary Negate (NumericLiteral (Left 2147483648))`, and
       -- 2147483648 is larger than the maximum allowed int.
       return $ AST.NumericLiteral ss (Left (-i))
-    go js@(AST.NumericLiteral _ (Left i)) =
+    go js@(AST.NumericLiteral ss (Left i)) =
       let minInt = -2147483648
           maxInt = 2147483647
       in if i < minInt || i > maxInt
-         then throwError . errorMessage $ IntOutOfRange i "JavaScript" minInt maxInt
+         then throwError . maybe errorMessage errorMessage' ss $ IntOutOfRange i "JavaScript" minInt maxInt
          else return js
     go other = return other
diff --git a/src/Language/PureScript/CodeGen/JS/Common.hs b/src/Language/PureScript/CodeGen/JS/Common.hs
--- a/src/Language/PureScript/CodeGen/JS/Common.hs
+++ b/src/Language/PureScript/CodeGen/JS/Common.hs
@@ -26,6 +26,7 @@
 identToJs :: Ident -> Text
 identToJs (Ident name) = properToJs name
 identToJs (GenIdent _ _) = internalError "GenIdent in identToJs"
+identToJs UnusedIdent = "$__unused"
 
 properToJs :: Text -> Text
 properToJs name
diff --git a/src/Language/PureScript/Constants.hs b/src/Language/PureScript/Constants.hs
--- a/src/Language/PureScript/Constants.hs
+++ b/src/Language/PureScript/Constants.hs
@@ -2,7 +2,9 @@
 module Language.PureScript.Constants where
 
 import Prelude.Compat
+
 import Data.String (IsString)
+import Language.PureScript.PSString (PSString)
 import Language.PureScript.Names
 
 -- Operators
@@ -100,6 +102,9 @@
 eq :: forall a. (IsString a) => a
 eq = "eq"
 
+eq1 :: forall a. (IsString a) => a
+eq1 = "eq1"
+
 (/=) :: forall a. (IsString a) => a
 (/=) = "/="
 
@@ -109,6 +114,9 @@
 compare :: forall a. (IsString a) => a
 compare = "compare"
 
+compare1 :: forall a. (IsString a) => a
+compare1 = "compare1"
+
 (&&) :: forall a. (IsString a) => a
 (&&) = "&&"
 
@@ -191,6 +199,11 @@
 returnEscaped :: forall a. (IsString a) => a
 returnEscaped = "$return"
 
+unit :: forall a. (IsString a) => a
+unit = "unit"
+
+-- Core lib values
+
 untilE :: forall a. (IsString a) => a
 untilE = "untilE"
 
@@ -221,9 +234,18 @@
 runFn :: forall a. (IsString a) => a
 runFn = "runFn"
 
-unit :: forall a. (IsString a) => a
-unit = "unit"
+mkEffFn :: forall a. (IsString a) => a
+mkEffFn = "mkEffFn"
 
+runEffFn :: forall a. (IsString a) => a
+runEffFn = "runEffFn"
+
+mkEffectFn :: forall a. (IsString a) => a
+mkEffectFn = "mkEffectFn"
+
+runEffectFn :: forall a. (IsString a) => a
+runEffectFn = "runEffectFn"
+
 -- Prim values
 
 undefined :: forall a. (IsString a) => a
@@ -231,14 +253,25 @@
 
 -- Type Class Dictionary Names
 
-monadEffDictionary :: forall a. (IsString a) => a
-monadEffDictionary = "monadEff"
+data EffectDictionaries = EffectDictionaries
+  { edApplicativeDict :: PSString
+  , edBindDict :: PSString
+  , edMonadDict :: PSString
+  }
 
-applicativeEffDictionary :: forall a. (IsString a) => a
-applicativeEffDictionary = "applicativeEff"
+effDictionaries :: EffectDictionaries
+effDictionaries = EffectDictionaries
+  { edApplicativeDict = "applicativeEff"
+  , edBindDict = "bindEff"
+  , edMonadDict = "monadEff"
+  }
 
-bindEffDictionary :: forall a. (IsString a) => a
-bindEffDictionary = "bindEff"
+effectDictionaries :: EffectDictionaries
+effectDictionaries = EffectDictionaries
+  { edApplicativeDict = "applicativeEffect"
+  , edBindDict = "bindEffect"
+  , edMonadDict = "monadEffect"
+  }
 
 discardUnitDictionary :: forall a. (IsString a) => a
 discardUnitDictionary = "discardUnit"
@@ -326,97 +359,141 @@
 toSignature :: forall a. (IsString a) => a
 toSignature = "toSignature"
 
--- Data.Symbol
+-- Main module
 
-pattern DataSymbol :: ModuleName
-pattern DataSymbol = ModuleName [ProperName "Data", ProperName "Symbol"]
+main :: forall a. (IsString a) => a
+main = "main"
 
-pattern IsSymbol :: Qualified (ProperName 'ClassName)
-pattern IsSymbol = Qualified (Just DataSymbol) (ProperName "IsSymbol")
+-- Prim
 
--- Type.Data.Symbol
+partial :: forall a. (IsString a) => a
+partial = "Partial"
 
-pattern TypeDataSymbol :: ModuleName
-pattern TypeDataSymbol = ModuleName [ProperName "Type", ProperName "Data", ProperName "Symbol"]
+pattern Prim :: ModuleName
+pattern Prim = ModuleName [ProperName "Prim"]
 
-pattern CompareSymbol :: Qualified (ProperName 'ClassName)
-pattern CompareSymbol = Qualified (Just TypeDataSymbol) (ProperName "CompareSymbol")
+pattern Partial :: Qualified (ProperName 'ClassName)
+pattern Partial = Qualified (Just Prim) (ProperName "Partial")
 
-pattern AppendSymbol :: Qualified (ProperName 'ClassName)
-pattern AppendSymbol = Qualified (Just TypeDataSymbol) (ProperName "AppendSymbol")
+pattern Record :: Qualified (ProperName 'TypeName)
+pattern Record = Qualified (Just Prim) (ProperName "Record")
 
--- Type.Data.Ordering
+-- Prim.Ordering
 
-typeDataOrdering :: ModuleName
-typeDataOrdering = ModuleName [ProperName "Type", ProperName "Data", ProperName "Ordering"]
+pattern PrimOrdering :: ModuleName
+pattern PrimOrdering = ModuleName [ProperName "Prim", ProperName "Ordering"]
 
 orderingLT :: Qualified (ProperName 'TypeName)
-orderingLT = Qualified (Just typeDataOrdering) (ProperName "LT")
+orderingLT = Qualified (Just PrimOrdering) (ProperName "LT")
 
 orderingEQ :: Qualified (ProperName 'TypeName)
-orderingEQ = Qualified (Just typeDataOrdering) (ProperName "EQ")
+orderingEQ = Qualified (Just PrimOrdering) (ProperName "EQ")
 
 orderingGT :: Qualified (ProperName 'TypeName)
-orderingGT = Qualified (Just typeDataOrdering) (ProperName "GT")
+orderingGT = Qualified (Just PrimOrdering) (ProperName "GT")
 
--- Type.Row
+-- Prim.Row
 
-pattern TypeRow :: ModuleName
-pattern TypeRow = ModuleName [ProperName "Type", ProperName "Row"]
+pattern PrimRow :: ModuleName
+pattern PrimRow = ModuleName [ProperName "Prim", ProperName "Row"]
 
+pattern RowUnion :: Qualified (ProperName 'ClassName)
+pattern RowUnion = Qualified (Just PrimRow) (ProperName "Union")
+
+pattern RowNub :: Qualified (ProperName 'ClassName)
+pattern RowNub = Qualified (Just PrimRow) (ProperName "Nub")
+
+pattern RowCons :: Qualified (ProperName 'ClassName)
+pattern RowCons = Qualified (Just PrimRow) (ProperName "Cons")
+
+pattern RowLacks :: Qualified (ProperName 'ClassName)
+pattern RowLacks = Qualified (Just PrimRow) (ProperName "Lacks")
+
+-- Prim.RowList
+
+pattern PrimRowList :: ModuleName
+pattern PrimRowList = ModuleName [ProperName "Prim", ProperName "RowList"]
+
 pattern RowToList :: Qualified (ProperName 'ClassName)
-pattern RowToList = Qualified (Just TypeRow) (ProperName "RowToList")
+pattern RowToList = Qualified (Just PrimRowList) (ProperName "RowToList")
 
 pattern RowListNil :: Qualified (ProperName 'TypeName)
-pattern RowListNil = Qualified (Just TypeRow) (ProperName "Nil")
+pattern RowListNil = Qualified (Just PrimRowList) (ProperName "Nil")
 
 pattern RowListCons :: Qualified (ProperName 'TypeName)
-pattern RowListCons = Qualified (Just TypeRow) (ProperName "Cons")
+pattern RowListCons = Qualified (Just PrimRowList) (ProperName "Cons")
 
--- Main module
+-- Prim.Symbol
 
-main :: forall a. (IsString a) => a
-main = "main"
+pattern PrimSymbol :: ModuleName
+pattern PrimSymbol = ModuleName [ProperName "Prim", ProperName "Symbol"]
 
--- Prim
+pattern SymbolCompare :: Qualified (ProperName 'ClassName)
+pattern SymbolCompare = Qualified (Just PrimSymbol) (ProperName "Compare")
 
-partial :: forall a. (IsString a) => a
-partial = "Partial"
+pattern SymbolAppend :: Qualified (ProperName 'ClassName)
+pattern SymbolAppend = Qualified (Just PrimSymbol) (ProperName "Append")
 
-pattern Prim :: ModuleName
-pattern Prim = ModuleName [ProperName "Prim"]
+pattern SymbolCons :: Qualified (ProperName 'ClassName)
+pattern SymbolCons = Qualified (Just PrimSymbol) (ProperName "Cons")
 
-pattern Partial :: Qualified (ProperName 'ClassName)
-pattern Partial = Qualified (Just Prim) (ProperName "Partial")
+-- Prim.TypeError
 
+pattern PrimTypeError :: ModuleName
+pattern PrimTypeError = ModuleName [ProperName "Prim", ProperName "TypeError"]
+
 pattern Fail :: Qualified (ProperName 'ClassName)
-pattern Fail = Qualified (Just Prim) (ProperName "Fail")
+pattern Fail = Qualified (Just PrimTypeError) (ProperName "Fail")
 
 pattern Warn :: Qualified (ProperName 'ClassName)
-pattern Warn = Qualified (Just Prim) (ProperName "Warn")
+pattern Warn = Qualified (Just PrimTypeError) (ProperName "Warn")
 
-pattern Union :: Qualified (ProperName 'ClassName)
-pattern Union = Qualified (Just Prim) (ProperName "Union")
+primModules :: [ModuleName]
+primModules = [Prim, PrimOrdering, PrimRow, PrimRowList, PrimSymbol, PrimTypeError]
 
-pattern RowCons :: Qualified (ProperName 'ClassName)
-pattern RowCons = Qualified (Just Prim) (ProperName "RowCons")
+-- Data.Symbol
 
+pattern DataSymbol :: ModuleName
+pattern DataSymbol = ModuleName [ProperName "Data", ProperName "Symbol"]
+
+pattern IsSymbol :: Qualified (ProperName 'ClassName)
+pattern IsSymbol = Qualified (Just DataSymbol) (ProperName "IsSymbol")
+
 typ :: forall a. (IsString a) => a
 typ = "Type"
 
+kindOrdering :: forall a. (IsString a) => a
+kindOrdering = "Ordering"
+
+kindRowList :: forall a. (IsString a) => a
+kindRowList = "RowList"
+
 symbol :: forall a. (IsString a) => a
 symbol = "Symbol"
 
--- Code Generation
-
-__unused :: forall a. (IsString a) => a
-__unused = "__unused"
+doc :: forall a. (IsString a) => a
+doc = "Doc"
 
 -- Modules
 
 prim :: forall a. (IsString a) => a
 prim = "Prim"
 
+moduleOrdering :: forall a. (IsString a) => a
+moduleOrdering = "Ordering"
+
+moduleRow :: forall a. (IsString a) => a
+moduleRow = "Row"
+
+moduleRowList :: forall a. (IsString a) => a
+moduleRowList = "RowList"
+
+moduleSymbol :: forall a. (IsString a) => a
+moduleSymbol = "Symbol"
+
+typeError :: forall a. (IsString a) => a
+typeError = "TypeError"
+
 prelude :: forall a. (IsString a) => a
 prelude = "Prelude"
 
@@ -426,6 +503,9 @@
 eff :: forall a. (IsString a) => a
 eff = "Control_Monad_Eff"
 
+effect :: forall a. (IsString a) => a
+effect = "Effect"
+
 st :: forall a. (IsString a) => a
 st = "Control_Monad_ST"
 
@@ -440,6 +520,12 @@
 
 controlBind :: forall a. (IsString a) => a
 controlBind = "Control_Bind"
+
+controlMonadEffUncurried :: forall a. (IsString a) => a
+controlMonadEffUncurried = "Control_Monad_Eff_Uncurried"
+
+effectUncurried :: forall a. (IsString a) => a
+effectUncurried = "Effect_Uncurried"
 
 dataBounded :: forall a. (IsString a) => a
 dataBounded = "Data_Bounded"
diff --git a/src/Language/PureScript/CoreFn.hs b/src/Language/PureScript/CoreFn.hs
--- a/src/Language/PureScript/CoreFn.hs
+++ b/src/Language/PureScript/CoreFn.hs
@@ -12,4 +12,5 @@
 import Language.PureScript.CoreFn.Expr as C
 import Language.PureScript.CoreFn.Meta as C
 import Language.PureScript.CoreFn.Module as C
+import Language.PureScript.CoreFn.Optimizer as C
 import Language.PureScript.CoreFn.Traversals as C
diff --git a/src/Language/PureScript/CoreFn/Desugar.hs b/src/Language/PureScript/CoreFn/Desugar.hs
--- a/src/Language/PureScript/CoreFn/Desugar.hs
+++ b/src/Language/PureScript/CoreFn/Desugar.hs
@@ -39,7 +39,7 @@
       exps' = ordNub $ concatMap exportToCoreFn exps
       externs = ordNub $ mapMaybe externToCoreFn decls
       decls' = concatMap declToCoreFn decls
-  in Module coms mn imports' exps' externs decls'
+  in Module modSS coms mn (spanName modSS) imports' exps' externs decls'
 
   where
 
@@ -73,19 +73,19 @@
 
   -- | Desugars expressions from AST to CoreFn representation.
   exprToCoreFn :: SourceSpan -> [Comment] -> Maybe Type -> A.Expr -> Expr Ann
-  exprToCoreFn ss com ty (A.Literal lit) =
+  exprToCoreFn _ com ty (A.Literal ss lit) =
     Literal (ss, com, ty, Nothing) (fmap (exprToCoreFn ss com Nothing) lit)
   exprToCoreFn ss com ty (A.Accessor name v) =
     Accessor (ss, com, ty, Nothing) name (exprToCoreFn ss [] Nothing v)
   exprToCoreFn ss com ty (A.ObjectUpdate obj vs) =
     ObjectUpdate (ss, com, ty, Nothing) (exprToCoreFn ss [] Nothing obj) $ fmap (second (exprToCoreFn ss [] Nothing)) vs
-  exprToCoreFn ss com ty (A.Abs (A.VarBinder name) v) =
+  exprToCoreFn ss com ty (A.Abs (A.VarBinder _ name) v) =
     Abs (ss, com, ty, Nothing) name (exprToCoreFn ss [] Nothing v)
   exprToCoreFn _ _ _ (A.Abs _ _) =
     internalError "Abs with Binder argument was not desugared before exprToCoreFn mn"
   exprToCoreFn ss com ty (A.App v1 v2) =
     App (ss, com, ty, Nothing) (exprToCoreFn ss [] Nothing v1) (exprToCoreFn ss [] Nothing v2)
-  exprToCoreFn ss com ty (A.Var ident) =
+  exprToCoreFn _ com ty (A.Var ss ident) =
     Var (ss, com, ty, getValueMeta ident) ident
   exprToCoreFn ss com ty (A.IfThenElse v1 v2 v3) =
     Case (ss, com, ty, Nothing) [exprToCoreFn ss [] Nothing v1]
@@ -93,17 +93,17 @@
                         (Right $ exprToCoreFn ss [] Nothing v2)
       , CaseAlternative [NullBinder (ssAnn ss)]
                         (Right $ exprToCoreFn ss [] Nothing v3) ]
-  exprToCoreFn ss com ty (A.Constructor name) =
+  exprToCoreFn _ com ty (A.Constructor ss name) =
     Var (ss, com, ty, Just $ getConstructorMeta name) $ fmap properToIdent name
   exprToCoreFn ss com ty (A.Case vs alts) =
     Case (ss, com, ty, Nothing) (fmap (exprToCoreFn ss [] Nothing) vs) (fmap (altToCoreFn ss) alts)
   exprToCoreFn ss com _ (A.TypedValue _ v ty) =
     exprToCoreFn ss com (Just ty) v
-  exprToCoreFn ss com ty (A.Let ds v) =
-    Let (ss, com, ty, Nothing) (concatMap declToCoreFn ds) (exprToCoreFn ss [] Nothing v)
-  exprToCoreFn ss com ty (A.TypeClassDictionaryConstructorApp name (A.TypedValue _ lit@(A.Literal (A.ObjectLiteral _)) _)) =
+  exprToCoreFn ss com ty (A.Let w ds v) =
+    Let (ss, com, ty, getLetMeta w) (concatMap declToCoreFn ds) (exprToCoreFn ss [] Nothing v)
+  exprToCoreFn ss com ty (A.TypeClassDictionaryConstructorApp name (A.TypedValue _ lit@(A.Literal _ (A.ObjectLiteral _)) _)) =
     exprToCoreFn ss com ty (A.TypeClassDictionaryConstructorApp name lit)
-  exprToCoreFn ss com _ (A.TypeClassDictionaryConstructorApp name (A.Literal (A.ObjectLiteral vs))) =
+  exprToCoreFn ss com _ (A.TypeClassDictionaryConstructorApp name (A.Literal _ (A.ObjectLiteral vs))) =
     let args = fmap (exprToCoreFn ss [] Nothing . snd) $ sortBy (compare `on` fst) vs
         ctor = Var (ss, [], Nothing, Just IsTypeClassConstructor) (fmap properToIdent name)
     in foldl (App (ss, com, Nothing, Nothing)) ctor args
@@ -133,16 +133,16 @@
 
   -- | Desugars case binders from AST to CoreFn representation.
   binderToCoreFn :: SourceSpan -> [Comment] -> A.Binder -> Binder Ann
-  binderToCoreFn ss com (A.LiteralBinder lit) =
+  binderToCoreFn _ com (A.LiteralBinder ss lit) =
     LiteralBinder (ss, com, Nothing, Nothing) (fmap (binderToCoreFn ss com) lit)
   binderToCoreFn ss com A.NullBinder =
     NullBinder (ss, com, Nothing, Nothing)
-  binderToCoreFn ss com (A.VarBinder name) =
+  binderToCoreFn _ com (A.VarBinder ss name) =
     VarBinder (ss, com, Nothing, Nothing) name
-  binderToCoreFn ss com (A.ConstructorBinder dctor@(Qualified mn' _) bs) =
+  binderToCoreFn _ com (A.ConstructorBinder ss dctor@(Qualified mn' _) bs) =
     let (_, tctor, _, _) = lookupConstructor env dctor
     in ConstructorBinder (ss, com, Nothing, Just $ getConstructorMeta dctor) (Qualified mn' tctor) dctor (fmap (binderToCoreFn ss []) bs)
-  binderToCoreFn ss com (A.NamedBinder name b) =
+  binderToCoreFn _ com (A.NamedBinder ss name b) =
     NamedBinder (ss, com, Nothing, Nothing) name (binderToCoreFn ss [] b)
   binderToCoreFn _ com (A.PositionedBinder ss com1 b) =
     binderToCoreFn ss (com ++ com1) b
@@ -155,6 +155,11 @@
   binderToCoreFn _ _ A.ParensInBinder{} =
     internalError "ParensInBinder should have been desugared before binderToCoreFn"
 
+  -- | Gets metadata for let bindings.
+  getLetMeta :: A.WhereProvenance -> Maybe Meta
+  getLetMeta A.FromWhere = Just IsWhere
+  getLetMeta A.FromLet = Nothing
+
   -- | Gets metadata for values.
   getValueMeta :: Qualified Ident -> Maybe Meta
   getValueMeta name =
@@ -192,14 +197,14 @@
   in f `concatMap` decls
   where
   fqDecls :: A.Declaration -> [ModuleName]
-  fqDecls (A.TypeInstanceDeclaration _ _ _ q _ _) = getQual' q
+  fqDecls (A.TypeInstanceDeclaration _ _ _ _ _ q _ _) = getQual' q
   fqDecls (A.ValueFixityDeclaration _ _ q _) = getQual' q
   fqDecls (A.TypeFixityDeclaration _ _ q _) = getQual' q
   fqDecls _ = []
 
   fqValues :: A.Expr -> [ModuleName]
-  fqValues (A.Var q) = getQual' q
-  fqValues (A.Constructor q) = getQual' q
+  fqValues (A.Var _ q) = getQual' q
+  fqValues (A.Constructor _ q) = getQual' q
   -- Some instances are automatically solved and have their class dictionaries
   -- built inline instead of having a named instance defined and imported.
   -- We therefore need to import these constructors if they aren't already.
@@ -207,7 +212,7 @@
   fqValues _ = []
 
   fqBinders :: A.Binder -> [ModuleName]
-  fqBinders (A.ConstructorBinder q _) = getQual' q
+  fqBinders (A.ConstructorBinder _ q _) = getQual' q
   fqBinders _ = []
 
   getQual' :: Qualified a -> [ModuleName]
@@ -219,8 +224,8 @@
 importToCoreFn _ = Nothing
 
 -- | Desugars foreign declarations from AST to CoreFn representation.
-externToCoreFn :: A.Declaration -> Maybe ForeignDecl
-externToCoreFn (A.ExternDeclaration _ name ty) = Just (name, ty)
+externToCoreFn :: A.Declaration -> Maybe Ident
+externToCoreFn (A.ExternDeclaration _ name _) = Just name
 externToCoreFn _ = Nothing
 
 -- | Desugars export declarations references from AST to CoreFn representation.
diff --git a/src/Language/PureScript/CoreFn/FromJSON.hs b/src/Language/PureScript/CoreFn/FromJSON.hs
new file mode 100644
--- /dev/null
+++ b/src/Language/PureScript/CoreFn/FromJSON.hs
@@ -0,0 +1,293 @@
+-- |
+-- Read the core functional representation from JSON format
+--
+
+module Language.PureScript.CoreFn.FromJSON
+  ( moduleFromJSON
+  ) where
+
+import Prelude.Compat
+
+import           Data.Aeson
+import           Data.Aeson.Types (Parser, Value, listParser)
+import           Data.Text (Text)
+import qualified Data.Text as T
+import           Text.ParserCombinators.ReadP (readP_to_S)
+import qualified Data.Vector as V
+import           Data.Version (Version, parseVersion)
+
+import           Language.PureScript.AST.SourcePos (SourceSpan(SourceSpan))
+import           Language.PureScript.AST.Literals
+import           Language.PureScript.CoreFn.Ann
+import           Language.PureScript.CoreFn
+import           Language.PureScript.Names
+import           Language.PureScript.PSString (PSString)
+
+constructorTypeFromJSON :: Value -> Parser ConstructorType
+constructorTypeFromJSON v = do
+  t <- parseJSON v
+  case t of
+    "ProductType" -> return ProductType
+    "SumType"     -> return SumType
+    _             -> fail ("not recognized ConstructorType: " ++ T.unpack t)
+
+metaFromJSON :: Value -> Parser (Maybe Meta)
+metaFromJSON Null = return Nothing
+metaFromJSON v = withObject "Meta" metaFromObj v
+  where
+    metaFromObj o = do
+      type_ <- o .: "metaType"
+      case type_ of
+        "IsConstructor" -> isConstructorFromJSON o
+        "IsNewtype"     -> return $ Just IsNewtype
+        "IsTypeClassConstructor"
+                        -> return $ Just IsTypeClassConstructor
+        "IsForeign"     -> return $ Just IsForeign
+        "IsWhere"       -> return $ Just IsWhere
+        _               -> fail ("not recognized Meta: " ++ T.unpack type_)
+
+    isConstructorFromJSON o = do
+      ct <- o .: "constructorType" >>= constructorTypeFromJSON
+      is <- o .: "identifiers" >>= listParser identFromJSON
+      return $ Just (IsConstructor ct is)
+
+annFromJSON :: FilePath -> Value -> Parser Ann
+annFromJSON modulePath = withObject "Ann" annFromObj
+  where
+  annFromObj o = do
+    ss <- o .: "sourceSpan" >>= sourceSpanFromJSON modulePath
+    mm <- o .: "meta" >>= metaFromJSON
+    return (ss, [], Nothing, mm)
+
+sourceSpanFromJSON :: FilePath -> Value -> Parser SourceSpan
+sourceSpanFromJSON modulePath = withObject "SourceSpan" $ \o ->
+  SourceSpan modulePath <$>
+    o .: "start" <*>
+    o .: "end"
+
+literalFromJSON :: (Value -> Parser a) -> Value -> Parser (Literal a)
+literalFromJSON t = withObject "Literal" literalFromObj
+  where
+  literalFromObj o = do
+    type_ <- o .: "literalType" :: Parser Text
+    case type_ of
+      "IntLiteral"      -> NumericLiteral . Left <$> o .: "value"
+      "NumberLiteral"   -> NumericLiteral . Right <$> o .: "value"
+      "StringLiteral"   -> StringLiteral <$> o .: "value"
+      "CharLiteral"     -> CharLiteral <$> o .: "value"
+      "BooleanLiteral"  -> BooleanLiteral <$> o .: "value"
+      "ArrayLiteral"    -> parseArrayLiteral o
+      "ObjectLiteral"   -> parseObjectLiteral o
+      _                 -> fail ("error parsing Literal: " ++ show o)
+
+  parseArrayLiteral o = do
+    val <- o .: "value"
+    as <- mapM t (V.toList val)
+    return $ ArrayLiteral as
+
+  parseObjectLiteral o = do
+    val <- o .: "value"
+    ObjectLiteral <$> recordFromJSON t val
+
+identFromJSON :: Value -> Parser Ident
+identFromJSON = withText "Ident" (return . Ident)
+
+properNameFromJSON :: Value -> Parser (ProperName a)
+properNameFromJSON = fmap ProperName . parseJSON
+
+qualifiedFromJSON :: (Text -> a) -> Value -> Parser (Qualified a)
+qualifiedFromJSON f = withObject "Qualified" qualifiedFromObj
+  where
+  qualifiedFromObj o = do
+    mn <- o .:? "moduleName" >>= traverse moduleNameFromJSON
+    i  <- o .: "identifier" >>= withText "Ident" (return . f)
+    return $ Qualified mn i
+
+moduleNameFromJSON :: Value -> Parser ModuleName
+moduleNameFromJSON v = ModuleName <$> listParser properNameFromJSON v
+
+moduleFromJSON :: Value -> Parser (Version, Module Ann)
+moduleFromJSON = withObject "Module" moduleFromObj
+  where
+  moduleFromObj o = do
+    version <- o .: "builtWith" >>= versionFromJSON
+    moduleName <- o .: "moduleName" >>= moduleNameFromJSON
+    modulePath <- o .: "modulePath"
+    moduleSourceSpan <- o .: "sourceSpan" >>= sourceSpanFromJSON modulePath
+    moduleImports <- o .: "imports" >>= listParser (importFromJSON modulePath)
+    moduleExports <- o .: "exports" >>= listParser identFromJSON
+    moduleDecls <- o .: "decls" >>= listParser (bindFromJSON modulePath)
+    moduleForeign <- o .: "foreign" >>= listParser identFromJSON
+    moduleComments <- o .: "comments" >>= listParser parseJSON
+    return (version, Module {..})
+
+  versionFromJSON :: String -> Parser Version
+  versionFromJSON v =
+    case readP_to_S parseVersion v of
+      (r, _) : _ -> return r
+      _ -> fail "failed parsing purs version"
+
+  importFromJSON :: FilePath -> Value -> Parser (Ann, ModuleName)
+  importFromJSON modulePath = withObject "Import"
+    (\o -> do
+      ann <- o .: "annotation" >>= annFromJSON modulePath
+      mn  <- o .: "moduleName" >>= moduleNameFromJSON
+      return (ann, mn))
+
+bindFromJSON :: FilePath -> Value -> Parser (Bind Ann)
+bindFromJSON modulePath = withObject "Bind" bindFromObj
+  where
+  bindFromObj :: Object -> Parser (Bind Ann)
+  bindFromObj o = do
+    type_ <- o .: "bindType" :: Parser Text
+    case type_ of
+      "NonRec"  -> (uncurry . uncurry) NonRec <$> bindFromObj' o
+      "Rec"     -> Rec <$> (o .: "binds" >>= listParser (withObject "Bind" bindFromObj'))
+      _         -> fail ("not recognized bind type \"" ++ T.unpack type_ ++ "\"")
+        
+  bindFromObj' :: Object -> Parser ((Ann, Ident), Expr Ann)
+  bindFromObj' o = do
+    a <- o .: "annotation" >>= annFromJSON modulePath
+    i <- o .: "identifier" >>= identFromJSON
+    e <- o .: "expression" >>= exprFromJSON modulePath
+    return ((a, i), e)
+
+recordFromJSON :: (Value -> Parser a) -> Value -> Parser [(PSString, a)]
+recordFromJSON p = listParser parsePair
+  where
+  parsePair v = do
+    (l, v') <- parseJSON v :: Parser (PSString, Value)
+    a <- p v'
+    return (l, a)
+
+exprFromJSON :: FilePath -> Value -> Parser (Expr Ann)
+exprFromJSON modulePath = withObject "Expr" exprFromObj
+  where
+  exprFromObj o = do
+    type_ <- o .: "type"
+    case type_ of
+      "Var"           -> varFromObj o
+      "Literal"       -> literalExprFromObj o
+      "Constructor"   -> constructorFromObj o
+      "Accessor"      -> accessorFromObj o
+      "ObjectUpdate"  -> objectUpdateFromObj o
+      "Abs"           -> absFromObj o
+      "App"           -> appFromObj o
+      "Case"          -> caseFromObj o
+      "Let"           -> letFromObj o
+      _               -> fail ("not recognized expression type: \"" ++ T.unpack type_ ++ "\"")
+
+  varFromObj o = do
+    ann <- o .: "annotation" >>= annFromJSON modulePath
+    qi <- o .: "value" >>= qualifiedFromJSON Ident
+    return $ Var ann qi
+
+  literalExprFromObj o = do
+    ann <- o .: "annotation" >>= annFromJSON modulePath
+    lit <- o .: "value" >>= literalFromJSON (exprFromJSON modulePath)
+    return $ Literal ann lit
+
+  constructorFromObj o = do
+    ann <- o .: "annotation" >>= annFromJSON modulePath
+    tyn <- o .: "typeName" >>= properNameFromJSON
+    con <- o .: "constructorName" >>= properNameFromJSON
+    is  <- o .: "fieldNames" >>= listParser identFromJSON
+    return $ Constructor ann tyn con is
+
+  accessorFromObj o = do
+    ann <- o .: "annotation" >>= annFromJSON modulePath
+    f   <- o .: "fieldName"
+    e <- o .: "expression" >>= exprFromJSON modulePath
+    return $ Accessor ann f e
+
+  objectUpdateFromObj o = do
+    ann <- o .: "annotation" >>= annFromJSON modulePath
+    e   <- o .: "expression" >>= exprFromJSON modulePath
+    us  <- o .: "updates" >>= recordFromJSON (exprFromJSON modulePath)
+    return $ ObjectUpdate ann e us
+
+  absFromObj o = do
+    ann <- o .: "annotation" >>= annFromJSON modulePath
+    idn <- o .: "argument" >>= identFromJSON
+    e   <- o .: "body" >>= exprFromJSON modulePath
+    return $ Abs ann idn e
+
+  appFromObj o = do
+    ann <- o .: "annotation" >>= annFromJSON modulePath
+    e   <- o .: "abstraction" >>= exprFromJSON modulePath
+    e'  <- o .: "argument" >>= exprFromJSON modulePath
+    return $ App ann e e'
+
+  caseFromObj o = do
+    ann <- o .: "annotation" >>= annFromJSON modulePath
+    cs  <- o .: "caseExpressions" >>= listParser (exprFromJSON modulePath)
+    cas <- o .: "caseAlternatives" >>= listParser (caseAlternativeFromJSON modulePath)
+    return $ Case ann cs cas
+
+  letFromObj o = do
+    ann <- o .: "annotation" >>= annFromJSON modulePath
+    bs  <- o .: "binds" >>= listParser (bindFromJSON modulePath)
+    e   <- o .: "expression" >>= exprFromJSON modulePath
+    return $ Let ann bs e
+
+caseAlternativeFromJSON :: FilePath -> Value -> Parser (CaseAlternative Ann)
+caseAlternativeFromJSON modulePath = withObject "CaseAlternative" caseAlternativeFromObj
+  where
+    caseAlternativeFromObj o = do
+      bs <- o .: "binders" >>= listParser (binderFromJSON modulePath)
+      isGuarded <- o .: "isGuarded"
+      if isGuarded
+        then do
+          es <- o .: "expressions" >>= listParser parseResultWithGuard
+          return $ CaseAlternative bs (Left es)
+        else do
+          e <- o .: "expression" >>= exprFromJSON modulePath
+          return $ CaseAlternative bs (Right e)
+
+    parseResultWithGuard :: Value -> Parser (Guard Ann, Expr Ann)
+    parseResultWithGuard = withObject "parseCaseWithGuards" $
+      \o -> do
+        g <- o .: "guard" >>= exprFromJSON modulePath
+        e <- o .: "expression" >>= exprFromJSON modulePath
+        return (g, e)
+
+binderFromJSON :: FilePath -> Value -> Parser (Binder Ann)
+binderFromJSON modulePath = withObject "Binder" binderFromObj
+  where
+  binderFromObj o = do
+    type_ <- o .: "binderType"
+    case type_ of
+      "NullBinder"        -> nullBinderFromObj o
+      "VarBinder"         -> varBinderFromObj o
+      "LiteralBinder"     -> literalBinderFromObj o
+      "ConstructorBinder" -> constructorBinderFromObj o
+      "NamedBinder"       -> namedBinderFromObj o
+      _                   -> fail ("not recognized binder: \"" ++ T.unpack type_ ++ "\"")
+
+
+  nullBinderFromObj o = do
+    ann <- o .: "annotation" >>= annFromJSON modulePath
+    return $ NullBinder ann
+
+  varBinderFromObj o = do
+    ann <- o .: "annotation" >>= annFromJSON modulePath
+    idn <- o .: "identifier" >>= identFromJSON
+    return $ VarBinder ann idn
+
+  literalBinderFromObj o = do
+    ann <- o .: "annotation" >>= annFromJSON modulePath
+    lit <- o .: "literal" >>= literalFromJSON (binderFromJSON modulePath)
+    return $ LiteralBinder ann lit
+
+  constructorBinderFromObj o = do
+    ann <- o .: "annotation" >>= annFromJSON modulePath
+    tyn <- o .: "typeName" >>= qualifiedFromJSON ProperName
+    con <- o .: "constructorName" >>= qualifiedFromJSON ProperName
+    bs  <- o .: "binders" >>= listParser (binderFromJSON modulePath)
+    return $ ConstructorBinder ann tyn con bs
+
+  namedBinderFromObj o = do
+    ann <- o .: "annotation" >>= annFromJSON modulePath
+    n   <- o .: "identifier" >>= identFromJSON
+    b   <- o .: "binder" >>= binderFromJSON modulePath
+    return $ NamedBinder ann n b
diff --git a/src/Language/PureScript/CoreFn/Meta.hs b/src/Language/PureScript/CoreFn/Meta.hs
--- a/src/Language/PureScript/CoreFn/Meta.hs
+++ b/src/Language/PureScript/CoreFn/Meta.hs
@@ -26,7 +26,12 @@
   -- |
   -- The contained reference is for a foreign member
   --
-  | IsForeign deriving (Show, Eq, Ord)
+  | IsForeign
+  -- |
+  -- The contained value is a where clause
+  --
+  | IsWhere
+  deriving (Show, Eq, Ord)
 
 -- |
 -- Data constructor metadata
diff --git a/src/Language/PureScript/CoreFn/Module.hs b/src/Language/PureScript/CoreFn/Module.hs
--- a/src/Language/PureScript/CoreFn/Module.hs
+++ b/src/Language/PureScript/CoreFn/Module.hs
@@ -2,21 +2,24 @@
 
 import Prelude.Compat
 
+import Language.PureScript.AST.SourcePos
 import Language.PureScript.Comments
 import Language.PureScript.CoreFn.Expr
 import Language.PureScript.Names
-import Language.PureScript.Types
 
 -- |
 -- The CoreFn module representation
 --
+-- The json CoreFn representation does not contain type information.  When
+-- parsing it one gets back `ModuleT () Ann` rathern than `ModuleT Type Ann`,
+-- which is enough for `moduleToJs`.
 data Module a = Module
-  { moduleComments :: [Comment]
+  { moduleSourceSpan :: SourceSpan
+  , moduleComments :: [Comment]
   , moduleName :: ModuleName
+  , modulePath :: FilePath
   , moduleImports :: [(a, ModuleName)]
   , moduleExports :: [Ident]
-  , moduleForeign :: [ForeignDecl]
+  , moduleForeign :: [Ident]
   , moduleDecls :: [Bind a]
   } deriving (Show)
-
-type ForeignDecl = (Ident, Type)
diff --git a/src/Language/PureScript/CoreFn/Optimizer.hs b/src/Language/PureScript/CoreFn/Optimizer.hs
new file mode 100644
--- /dev/null
+++ b/src/Language/PureScript/CoreFn/Optimizer.hs
@@ -0,0 +1,47 @@
+module Language.PureScript.CoreFn.Optimizer (optimizeCoreFn) where
+
+import Protolude hiding (Type)
+
+import Data.List (lookup)
+import Language.PureScript.AST.Literals
+import Language.PureScript.AST.SourcePos
+import Language.PureScript.CoreFn.Ann
+import Language.PureScript.CoreFn.Expr
+import Language.PureScript.CoreFn.Module
+import Language.PureScript.CoreFn.Traversals
+import Language.PureScript.Label
+import Language.PureScript.Types
+import qualified Language.PureScript.Constants as C
+
+-- |
+-- CoreFn optimization pass.
+--
+optimizeCoreFn :: Module Ann -> Module Ann
+optimizeCoreFn m = m {moduleDecls = optimizeModuleDecls $ moduleDecls m}
+
+optimizeModuleDecls :: [Bind Ann] -> [Bind Ann]
+optimizeModuleDecls = map transformBinds
+  where
+  (transformBinds, _, _) = everywhereOnValues identity transformExprs identity
+  transformExprs = optimizeClosedRecordUpdate
+
+optimizeClosedRecordUpdate :: Expr Ann -> Expr Ann
+optimizeClosedRecordUpdate ou@(ObjectUpdate a@(_, _, Just t, _) r updatedFields) =
+  case closedRecordFields t of
+    Nothing -> ou
+    Just allFields -> Literal a (ObjectLiteral (map f allFields))
+      where f (Label l) = case lookup l updatedFields of
+              Nothing -> (l, Accessor (nullSourceSpan, [], Nothing, Nothing) l r)
+              Just e -> (l, e)
+optimizeClosedRecordUpdate e = e
+
+-- | Return the labels of a closed record, or Nothing for other types or open records.
+closedRecordFields :: Type -> Maybe [Label]
+closedRecordFields (TypeApp (TypeConstructor C.Record) row) =
+  collect row
+  where
+    collect :: Type -> Maybe [Label]
+    collect REmpty = Just []
+    collect (RCons l _ r) = collect r >>= return . (l :)
+    collect _ = Nothing
+closedRecordFields _ = Nothing
diff --git a/src/Language/PureScript/CoreFn/ToJSON.hs b/src/Language/PureScript/CoreFn/ToJSON.hs
--- a/src/Language/PureScript/CoreFn/ToJSON.hs
+++ b/src/Language/PureScript/CoreFn/ToJSON.hs
@@ -7,27 +7,85 @@
   ( moduleToJSON
   ) where
 
-import Prelude.Compat
+import           Prelude.Compat
 
-import Data.Maybe (fromMaybe)
-import Data.Aeson
-import Data.Version (Version, showVersion)
-import Data.Text (Text)
+import           Control.Arrow ((***))
+import           Data.Either (isLeft)
+import           Data.Maybe (maybe)
+import           Data.Aeson
+import           Data.Version (Version, showVersion)
+import           Data.Text (Text)
 import qualified Data.Text as T
 
-import Language.PureScript.AST.Literals
-import Language.PureScript.CoreFn
-import Language.PureScript.Names
-import Language.PureScript.PSString (PSString, decodeString)
+import           Language.PureScript.AST.Literals
+import           Language.PureScript.AST.SourcePos (SourceSpan(SourceSpan))
+import           Language.PureScript.CoreFn
+import           Language.PureScript.Names
+import           Language.PureScript.PSString (PSString)
 
+constructorTypeToJSON :: ConstructorType -> Value
+constructorTypeToJSON ProductType = toJSON "ProductType"
+constructorTypeToJSON SumType = toJSON "SumType"
+
+metaToJSON :: Meta -> Value
+metaToJSON (IsConstructor t is)
+  = object
+    [ T.pack "metaType"         .= "IsConstructor"
+    , T.pack "constructorType"  .= constructorTypeToJSON t
+    , T.pack "identifiers"      .= identToJSON `map` is
+    ]
+metaToJSON IsNewtype              = object [ T.pack "metaType"  .= "IsNewtype" ]
+metaToJSON IsTypeClassConstructor = object [ T.pack "metaType"  .= "IsTypeClassConstructor" ]
+metaToJSON IsForeign              = object [ T.pack "metaType"  .= "IsForeign" ]
+metaToJSON IsWhere                = object [ T.pack "metaType"  .= "IsWhere" ]
+
+sourceSpanToJSON :: SourceSpan -> Value
+sourceSpanToJSON (SourceSpan _ spanStart spanEnd) =
+  object [ T.pack "start" .= spanStart
+         , T.pack "end"   .= spanEnd
+         ]
+
+annToJSON :: Ann -> Value
+annToJSON (ss, _, _, m) = object [ T.pack "sourceSpan"  .= sourceSpanToJSON ss
+                                 , T.pack "meta"        .= maybe Null metaToJSON m
+                                 ]
+
 literalToJSON :: (a -> Value) -> Literal a -> Value
-literalToJSON _ (NumericLiteral (Left n)) = toJSON ("IntLiteral", n)
-literalToJSON _ (NumericLiteral (Right n)) = toJSON ("NumberLiteral", n)
-literalToJSON _ (StringLiteral s) = toJSON ("StringLiteral", s)
-literalToJSON _ (CharLiteral c) = toJSON ("CharLiteral", c)
-literalToJSON _ (BooleanLiteral b) = toJSON ("BooleanLiteral", b)
-literalToJSON t (ArrayLiteral xs) = toJSON ("ArrayLiteral", map t xs)
-literalToJSON t (ObjectLiteral xs) = toJSON ("ObjectLiteral", recordToJSON t xs)
+literalToJSON _ (NumericLiteral (Left n))
+  = object
+    [ T.pack "literalType" .= "IntLiteral"
+    , T.pack "value"       .= n
+    ]
+literalToJSON _ (NumericLiteral (Right n))
+  = object
+      [ T.pack "literalType"  .= "NumberLiteral"
+      , T.pack "value"        .= n
+      ]
+literalToJSON _ (StringLiteral s)
+  = object
+    [ T.pack "literalType"  .= "StringLiteral"
+    , T.pack "value"        .= s
+    ]
+literalToJSON _ (CharLiteral c)
+  = object
+    [ T.pack "literalType"  .= "CharLiteral"
+    , T.pack "value"        .= c
+    ]
+literalToJSON _ (BooleanLiteral b)
+  = object
+    [ T.pack "literalType"  .= "BooleanLiteral"
+    , T.pack "value"        .= b
+    ]
+literalToJSON t (ArrayLiteral xs)
+  = object
+    [ T.pack "literalType"  .= "ArrayLiteral"
+    , T.pack "value"        .= map t xs
+    ]
+literalToJSON t (ObjectLiteral xs)
+  = object
+    [ T.pack "literalType"    .= "ObjectLiteral"
+    , T.pack "value"          .= recordToJSON t xs
+    ]
 
 identToJSON :: Ident -> Value
 identToJSON = toJSON . runIdent
@@ -36,94 +94,136 @@
 properNameToJSON = toJSON . runProperName
 
 qualifiedToJSON :: (a -> Text) -> Qualified a -> Value
-qualifiedToJSON f = toJSON . showQualified f
+qualifiedToJSON f (Qualified mn a) = object
+  [ T.pack "moduleName"   .= maybe Null moduleNameToJSON mn
+  , T.pack "identifier"   .= toJSON (f a)
+  ]
 
 moduleNameToJSON :: ModuleName -> Value
-moduleNameToJSON = toJSON . runModuleName
-
-moduleToJSON :: Version -> Module a -> Value
-moduleToJSON v m = object [ T.pack "imports"   .= map (moduleNameToJSON . snd) (moduleImports m)
-                          , T.pack "exports"   .= map identToJSON (moduleExports m)
-                          , T.pack "foreign"   .= map (identToJSON . fst) (moduleForeign m)
-                          , T.pack "decls"     .= map bindToJSON (moduleDecls m)
-                          , T.pack "builtWith" .= toJSON (showVersion v)
-                          ]
+moduleNameToJSON (ModuleName pns) = toJSON $ properNameToJSON `map` pns
 
-bindToJSON :: Bind a -> Value
-bindToJSON (NonRec _ n e) = object [ runIdent n .= exprToJSON e ]
-bindToJSON (Rec bs) = object $ map (\((_, n), e) -> runIdent n .= exprToJSON e) bs
+moduleToJSON :: Version -> Module Ann -> Value
+moduleToJSON v m = object
+  [ T.pack "sourceSpan" .= sourceSpanToJSON (moduleSourceSpan m)
+  , T.pack "moduleName" .= moduleNameToJSON (moduleName m)
+  , T.pack "modulePath" .= toJSON (modulePath m)
+  , T.pack "imports"    .= map importToJSON (moduleImports m)
+  , T.pack "exports"    .= map identToJSON (moduleExports m)
+  , T.pack "foreign"    .= map identToJSON (moduleForeign m)
+  , T.pack "decls"      .= map bindToJSON (moduleDecls m)
+  , T.pack "builtWith"  .= toJSON (showVersion v)
+  , T.pack "comments"   .= map toJSON (moduleComments m)
+  ]
 
--- If all of the labels in the record can safely be converted to JSON strings,
--- we generate a JSON object. Otherwise the labels must be represented as
--- arrays of integers in the JSON, and in this case we generate the record as
--- an array of pairs.
-recordToJSON :: (a -> Value) -> [(PSString, a)] -> Value
-recordToJSON f rec = fromMaybe (asArrayOfPairs rec) (asObject rec)
   where
-  asObject = fmap object . traverse (uncurry maybePair)
-  maybePair label a = fmap (\l -> l .= f a) (decodeString label)
+  importToJSON (ann,mn) = object
+    [ T.pack "annotation" .= annToJSON ann
+    , T.pack "moduleName" .= moduleNameToJSON mn
+    ]
 
-  asArrayOfPairs = toJSON . map (\(label, a) -> (toJSON label, f a))
+bindToJSON :: Bind Ann -> Value
+bindToJSON (NonRec ann n e)
+  = object
+    [ T.pack "bindType"   .= "NonRec"
+    , T.pack "annotation" .= annToJSON ann
+    , T.pack "identifier" .= identToJSON n
+    , T.pack "expression" .= exprToJSON e
+    ]
+bindToJSON (Rec bs)
+  = object
+    [ T.pack "bindType"   .= "Rec"
+    , T.pack "binds"      .= map (\((ann, n), e)
+                                  -> object
+                                      [ T.pack "identifier"  .= identToJSON n
+                                      , T.pack "annotation"   .= annToJSON ann
+                                      , T.pack "expression"   .= exprToJSON e
+                                      ]) bs
+    ]
 
-exprToJSON :: Expr a -> Value
-exprToJSON (Var _ i)              = toJSON ( "Var"
-                                           , qualifiedToJSON runIdent i
-                                           )
-exprToJSON (Literal _ l)          = toJSON ( "Literal"
-                                           , literalToJSON (exprToJSON) l
-                                           )
-exprToJSON (Constructor _ d c is) = toJSON ( "Constructor"
-                                           , properNameToJSON d
-                                           , properNameToJSON c
-                                           , map identToJSON is
-                                           )
-exprToJSON (Accessor _ f r)       = toJSON ( "Accessor"
-                                           , f
-                                           , exprToJSON r
-                                           )
-exprToJSON (ObjectUpdate _ r fs)  = toJSON ( "ObjectUpdate"
-                                           , exprToJSON r
-                                           , recordToJSON exprToJSON fs
-                                           )
-exprToJSON (Abs _ p b)            = toJSON ( "Abs"
-                                           , identToJSON p
-                                           , exprToJSON b
-                                           )
-exprToJSON (App _ f x)            = toJSON ( "App"
-                                           , exprToJSON f
-                                           , exprToJSON x
-                                           )
-exprToJSON (Case _ ss cs)         = toJSON ( "Case"
-                                           , map exprToJSON ss
-                                           , map caseAlternativeToJSON cs
-                                           )
-exprToJSON (Let _ bs e)           = toJSON ( "Let"
-                                           , map bindToJSON bs
-                                           , exprToJSON e
-                                           )
+recordToJSON :: (a -> Value) -> [(PSString, a)] -> Value
+recordToJSON f = toJSON . map (toJSON *** f)
 
-caseAlternativeToJSON :: CaseAlternative a -> Value
+exprToJSON :: Expr Ann -> Value
+exprToJSON (Var ann i)              = object [ T.pack "type"        .= toJSON "Var"
+                                             , T.pack "annotation"  .= annToJSON ann
+                                             , T.pack "value"       .= qualifiedToJSON runIdent i
+                                             ]
+exprToJSON (Literal ann l)          = object [ T.pack "type"        .= "Literal"
+                                             , T.pack "annotation"  .= annToJSON ann
+                                             , T.pack "value"       .=  literalToJSON exprToJSON l
+                                             ]
+exprToJSON (Constructor ann d c is) = object [ T.pack "type"        .= "Constructor"
+                                             , T.pack "annotation"  .= annToJSON ann
+                                             , T.pack "typeName"    .= properNameToJSON d
+                                             , T.pack "constructorName" .= properNameToJSON c
+                                             , T.pack "fieldNames"  .= map identToJSON is
+                                             ]
+exprToJSON (Accessor ann f r)       = object [ T.pack "type"        .= "Accessor"
+                                             , T.pack "annotation"  .= annToJSON ann
+                                             , T.pack "fieldName"   .= f
+                                             , T.pack "expression"  .= exprToJSON r
+                                             ]
+exprToJSON (ObjectUpdate ann r fs)  = object [ T.pack "type"        .= "ObjectUpdate"
+                                             , T.pack "annotation"  .= annToJSON ann
+                                             , T.pack "expression"  .= exprToJSON r
+                                             , T.pack "updates"     .= recordToJSON exprToJSON fs
+                                             ]
+exprToJSON (Abs ann p b)            = object [ T.pack "type"        .= "Abs"
+                                             , T.pack "annotation"  .= annToJSON ann
+                                             , T.pack "argument"    .= identToJSON p
+                                             , T.pack "body"        .= exprToJSON b
+                                             ]
+exprToJSON (App ann f x)            = object [ T.pack "type"        .= "App"
+                                             , T.pack "annotation"  .= annToJSON ann
+                                             , T.pack "abstraction" .= exprToJSON f
+                                             , T.pack "argument"    .= exprToJSON x
+                                             ]
+exprToJSON (Case ann ss cs)         = object [ T.pack "type"        .= "Case"
+                                             , T.pack "annotation"  .= annToJSON ann
+                                             , T.pack "caseExpressions"
+                                                                    .= map exprToJSON ss
+                                             , T.pack "caseAlternatives"
+                                                                    .= map caseAlternativeToJSON cs
+                                             ]
+exprToJSON (Let ann bs e)           = object [ T.pack "type"        .= "Let" 
+                                             , T.pack "annotation"  .= annToJSON ann
+                                             , T.pack "binds"       .= map bindToJSON bs
+                                             , T.pack "expression"  .= exprToJSON e
+                                             ]
+
+caseAlternativeToJSON :: CaseAlternative Ann -> Value
 caseAlternativeToJSON (CaseAlternative bs r') =
-  toJSON [ toJSON (map binderToJSON bs)
-         , case r' of
-             Left rs -> toJSON $ map (\(g, e) -> (exprToJSON g, exprToJSON e)) rs
+  let isGuarded = isLeft r'
+  in object
+      [ T.pack "binders"     .= toJSON (map binderToJSON bs)
+      , T.pack "isGuarded"   .= toJSON isGuarded
+      , T.pack (if isGuarded then "expressions" else "expression")
+         .= case r' of
+             Left rs -> toJSON $ map (\(g, e) -> object [ T.pack "guard" .= exprToJSON g, T.pack "expression" .= exprToJSON e]) rs
              Right r -> exprToJSON r
-         ]
+      ]
 
-binderToJSON :: Binder a -> Value
-binderToJSON (VarBinder _ v)              = toJSON ( "VarBinder"
-                                                   , identToJSON v
-                                                   )
-binderToJSON (NullBinder _)               = toJSON "NullBinder"
-binderToJSON (LiteralBinder _ l)          = toJSON ( "LiteralBinder"
-                                                   , literalToJSON binderToJSON l
-                                                   )
-binderToJSON (ConstructorBinder _ d c bs) = toJSON ( "ConstructorBinder"
-                                                   , qualifiedToJSON runProperName d
-                                                   , qualifiedToJSON runProperName c
-                                                   , map binderToJSON bs
-                                                   )
-binderToJSON (NamedBinder _ n b)          = toJSON ( "NamedBinder"
-                                                   , identToJSON n
-                                                   , binderToJSON b
-                                                   )
+binderToJSON :: Binder Ann -> Value
+binderToJSON (VarBinder ann v)              = object [ T.pack "binderType"  .= "VarBinder"
+                                                     , T.pack "annotation"  .= annToJSON ann
+                                                     , T.pack "identifier"  .= identToJSON v
+                                                     ]
+binderToJSON (NullBinder ann)               = object [ T.pack "binderType"  .= "NullBinder"
+                                                     , T.pack "annotation"  .= annToJSON ann
+                                                     ]
+binderToJSON (LiteralBinder ann l)          = object [ T.pack "binderType"  .= "LiteralBinder"
+                                                     , T.pack "annotation"  .= annToJSON ann
+                                                     , T.pack "literal"     .= literalToJSON binderToJSON l
+                                                     ]
+binderToJSON (ConstructorBinder ann d c bs) = object [ T.pack "binderType"  .= "ConstructorBinder"
+                                                     , T.pack "annotation"  .= annToJSON ann
+                                                     , T.pack "typeName"    .= qualifiedToJSON runProperName d
+                                                     , T.pack "constructorName"
+                                                                            .= qualifiedToJSON runProperName c
+                                                     , T.pack "binders"     .= map binderToJSON bs
+                                                     ]
+binderToJSON (NamedBinder ann n b)          = object [ T.pack "binderType"  .= "NamedBinder"
+                                                     , T.pack "annotation"  .= annToJSON ann
+                                                     , T.pack "identifier"  .= identToJSON n
+                                                     , T.pack "binder"      .= binderToJSON b
+                                                     ]
diff --git a/src/Language/PureScript/CoreImp/Optimizer.hs b/src/Language/PureScript/CoreImp/Optimizer.hs
--- a/src/Language/PureScript/CoreImp/Optimizer.hs
+++ b/src/Language/PureScript/CoreImp/Optimizer.hs
@@ -37,14 +37,15 @@
       [ inlineCommonValues
       , inlineCommonOperators
       ]) js
-    untilFixedPoint (return . tidyUp) . tco . magicDo $ js'
+    untilFixedPoint (return . tidyUp) . tco . inlineST
+      =<< untilFixedPoint (return . magicDo')
+      =<< untilFixedPoint (return . magicDo) js'
   where
     tidyUp :: AST -> AST
     tidyUp = applyAll
       [ collapseNestedBlocks
       , collapseNestedIfs
       , removeCodeAfterReturnStatements
-      , removeUnusedArg
       , removeUndefinedApp
       , unThunk
       , etaConvert
diff --git a/src/Language/PureScript/CoreImp/Optimizer/Inliner.hs b/src/Language/PureScript/CoreImp/Optimizer/Inliner.hs
--- a/src/Language/PureScript/CoreImp/Optimizer/Inliner.hs
+++ b/src/Language/PureScript/CoreImp/Optimizer/Inliner.hs
@@ -24,6 +24,7 @@
 import Language.PureScript.PSString (PSString)
 import Language.PureScript.CoreImp.AST
 import Language.PureScript.CoreImp.Optimizer.Common
+import Language.PureScript.AST (SourceSpan(..))
 import qualified Language.PureScript.Constants as C
 
 -- TODO: Potential bug:
@@ -94,7 +95,6 @@
   convert (App ss (App _ (App _ fn [dict]) [x]) [y])
     | isDict semiringInt dict && isDict fnAdd fn = intOp ss Add x y
     | isDict semiringInt dict && isDict fnMultiply fn = intOp ss Multiply x y
-    | isDict euclideanRingInt dict && isDict fnDivide fn = intOp ss Divide x y
     | isDict ringInt dict && isDict fnSubtract fn = intOp ss Subtract x y
   convert other = other
   fnZero = (C.dataSemiring, C.zero)
@@ -102,7 +102,6 @@
   fnBottom = (C.dataBounded, C.bottom)
   fnTop = (C.dataBounded, C.top)
   fnAdd = (C.dataSemiring, C.add)
-  fnDivide = (C.dataEuclideanRing, C.div)
   fnMultiply = (C.dataSemiring, C.mul)
   fnSubtract = (C.dataRing, C.sub)
   fnNegate = (C.dataRing, C.negate)
@@ -117,7 +116,6 @@
   , unary  ringNumber opNegate Negate
 
   , binary euclideanRingNumber opDiv Divide
-  , binary euclideanRingInt opMod Modulus
 
   , binary eqNumber opEq EqualTo
   , binary eqNumber opNotEq NotEqualTo
@@ -169,7 +167,9 @@
   , inlineNonClassFunction (isModFn (C.dataFunction, C.applyFlipped)) $ \x f -> App Nothing f [x]
   , inlineNonClassFunction (isModFnWithDict (C.dataArray, C.unsafeIndex)) $ flip (Indexer Nothing)
   ] ++
-  [ fn | i <- [0..10], fn <- [ mkFn i, runFn i ] ]
+  [ fn | i <- [0..10], fn <- [ mkFn i, runFn i ] ] ++
+  [ fn | i <- [0..10], fn <- [ mkEffFn C.controlMonadEffUncurried C.mkEffFn i, runEffFn C.controlMonadEffUncurried C.runEffFn i ] ] ++
+  [ fn | i <- [0..10], fn <- [ mkEffFn C.effectUncurried C.mkEffectFn i, runEffFn C.effectUncurried C.runEffectFn i ] ]
   where
   binary :: (Text, PSString) -> (Text, PSString) -> BinaryOperator -> AST -> AST
   binary dict fns op = convert where
@@ -191,37 +191,53 @@
     convert :: AST -> AST
     convert (App ss fn [x]) | isDict (moduleName, fnName) fn = Unary ss op x
     convert other = other
+
   mkFn :: Int -> AST -> AST
-  mkFn 0 = convert where
+  mkFn = mkFn' C.dataFunctionUncurried C.mkFn $ \ss1 ss2 ss3 args js ->
+    Function ss1 Nothing args (Block ss2 [Return ss3 js])
+
+  mkEffFn :: Text -> Text -> Int -> AST -> AST
+  mkEffFn modName fnName = mkFn' modName fnName $ \ss1 ss2 ss3 args js ->
+    Function ss1 Nothing args (Block ss2 [Return ss3 (App ss3 js [])])
+
+  mkFn' :: Text -> Text -> (Maybe SourceSpan -> Maybe SourceSpan -> Maybe SourceSpan -> [Text] -> AST -> AST) -> Int -> AST -> AST
+  mkFn' modName fnName res 0 = convert where
     convert :: AST -> AST
-    convert (App _ mkFnN [Function s1 Nothing [_] (Block s2 js)]) | isNFn C.mkFn 0 mkFnN =
-      Function s1 Nothing [] (Block s2 js)
+    convert (App _ mkFnN [Function s1 Nothing [_] (Block s2 [Return s3 js])]) | isNFn modName fnName 0 mkFnN =
+      res s1 s2 s3 [] js
     convert other = other
-  mkFn n = convert where
+  mkFn' modName fnName res n = convert where
     convert :: AST -> AST
-    convert orig@(App ss mkFnN [fn]) | isNFn C.mkFn n mkFnN =
+    convert orig@(App ss mkFnN [fn]) | isNFn modName fnName n mkFnN =
       case collectArgs n [] fn of
-        Just (args, js) -> Function ss Nothing args (Block ss js)
-        Nothing -> orig
+        Just (args, [Return ss' ret]) -> res ss ss ss' args ret
+        _ -> orig
     convert other = other
     collectArgs :: Int -> [Text] -> AST -> Maybe ([Text], [AST])
     collectArgs 1 acc (Function _ Nothing [oneArg] (Block _ js)) | length acc == n - 1 = Just (reverse (oneArg : acc), js)
     collectArgs m acc (Function _ Nothing [oneArg] (Block _ [Return _ ret])) = collectArgs (m - 1) (oneArg : acc) ret
     collectArgs _ _   _ = Nothing
 
-  isNFn :: Text -> Int -> AST -> Bool
-  isNFn prefix n (Var _ name) = name == (prefix <> T.pack (show n))
-  isNFn prefix n (Indexer _ (StringLiteral _ name) (Var _ dataFunctionUncurried)) | dataFunctionUncurried == C.dataFunctionUncurried =
+  isNFn :: Text -> Text -> Int -> AST -> Bool
+  isNFn expectMod prefix n (Indexer _ (StringLiteral _ name) (Var _ modName)) | modName == expectMod =
     name == fromString (T.unpack prefix <> show n)
-  isNFn _ _ _ = False
+  isNFn _ _ _ _ = False
 
   runFn :: Int -> AST -> AST
-  runFn n = convert where
+  runFn = runFn' C.dataFunctionUncurried C.runFn App
+
+  runEffFn :: Text -> Text -> Int -> AST -> AST
+  runEffFn modName fnName = runFn' modName fnName $ \ss fn acc ->
+    Function ss Nothing [] (Block ss [Return ss (App ss fn acc)])
+
+  runFn' :: Text -> Text -> (Maybe SourceSpan -> AST -> [AST] -> AST) -> Int -> AST -> AST
+  runFn' modName runFnName res n = convert where
     convert :: AST -> AST
     convert js = fromMaybe js $ go n [] js
 
     go :: Int -> [AST] -> AST -> Maybe AST
-    go 0 acc (App ss runFnN [fn]) | isNFn C.runFn n runFnN && length acc == n = Just (App ss fn acc)
+    go 0 acc (App ss runFnN [fn]) | isNFn modName runFnName n runFnN && length acc == n =
+      Just $ res ss fn acc
     go m acc (App _ lhs [arg]) = go (m - 1) (arg : acc) lhs
     go _ _   _ = Nothing
 
@@ -297,9 +313,6 @@
 euclideanRingNumber :: forall a b. (IsString a, IsString b) => (a, b)
 euclideanRingNumber = (C.dataEuclideanRing, C.euclideanRingNumber)
 
-euclideanRingInt :: forall a b. (IsString a, IsString b) => (a, b)
-euclideanRingInt = (C.dataEuclideanRing, C.euclideanRingInt)
-
 eqNumber :: forall a b. (IsString a, IsString b) => (a, b)
 eqNumber = (C.dataEq, C.eqNumber)
 
@@ -377,9 +390,6 @@
 
 opDiv :: forall a b. (IsString a, IsString b) => (a, b)
 opDiv = (C.dataEuclideanRing, C.div)
-
-opMod :: forall a b. (IsString a, IsString b) => (a, b)
-opMod = (C.dataEuclideanRing, C.mod)
 
 opConj :: forall a b. (IsString a, IsString b) => (a, b)
 opConj = (C.dataHeytingAlgebra, C.conj)
diff --git a/src/Language/PureScript/CoreImp/Optimizer/MagicDo.hs b/src/Language/PureScript/CoreImp/Optimizer/MagicDo.hs
--- a/src/Language/PureScript/CoreImp/Optimizer/MagicDo.hs
+++ b/src/Language/PureScript/CoreImp/Optimizer/MagicDo.hs
@@ -1,11 +1,12 @@
 -- | This module implements the "Magic Do" optimization, which inlines calls to return
 -- and bind for the Eff monad, as well as some of its actions.
-module Language.PureScript.CoreImp.Optimizer.MagicDo (magicDo) where
+module Language.PureScript.CoreImp.Optimizer.MagicDo (magicDo, magicDo', inlineST) where
 
 import Prelude.Compat
 import Protolude (ordNub)
 
 import Data.Maybe (fromJust, isJust)
+import Data.Text (Text)
 
 import Language.PureScript.CoreImp.AST
 import Language.PureScript.CoreImp.Optimizer.Common
@@ -27,7 +28,13 @@
 --    ...
 --  }
 magicDo :: AST -> AST
-magicDo = inlineST . everywhere undo . everywhereTopDown convert
+magicDo = magicDo'' C.eff C.effDictionaries
+
+magicDo' :: AST -> AST
+magicDo' = magicDo'' C.effect C.effectDictionaries
+
+magicDo'' :: Text -> C.EffectDictionaries -> AST -> AST
+magicDo'' effectModule C.EffectDictionaries{..} = everywhereTopDown convert
   where
   -- The name of the function block which is added to denote a do block
   fnName = "__do"
@@ -47,18 +54,23 @@
   -- Desugar whileE
   convert (App _ (App _ (App s1 f [arg1]) [arg2]) []) | isEffFunc C.whileE f =
     App s1 (Function s1 Nothing [] (Block s1 [ While s1 (App s1 arg1 []) (Block s1 [ App s1 arg2 [] ]), Return s1 $ ObjectLiteral s1 []])) []
+  -- Inline __do returns
+  convert (Return _ (App _ (Function _ (Just ident) [] body) [])) | ident == fnName = body
+  -- Inline double applications
+  convert (App _ (App s1 (Function s2 Nothing [] (Block ss body)) []) []) =
+    App s1 (Function s2 Nothing [] (Block ss (applyReturns `fmap` body))) []
   convert other = other
   -- Check if an expression represents a monomorphic call to >>= for the Eff monad
-  isBind (App _ fn [dict]) | isDict (C.eff, C.bindEffDictionary) dict && isBindPoly fn = True
+  isBind (App _ fn [dict]) | isDict (effectModule, edBindDict) dict && isBindPoly fn = True
   isBind _ = False
   -- Check if an expression represents a call to @discard@
   isDiscard (App _ (App _ fn [dict1]) [dict2])
     | isDict (C.controlBind, C.discardUnitDictionary) dict1 &&
-      isDict (C.eff, C.bindEffDictionary) dict2 &&
+      isDict (effectModule, edBindDict) dict2 &&
       isDiscardPoly fn = True
   isDiscard _ = False
   -- Check if an expression represents a monomorphic call to pure or return for the Eff applicative
-  isPure (App _ fn [dict]) | isDict (C.eff, C.applicativeEffDictionary) dict && isPurePoly fn = True
+  isPure (App _ fn [dict]) | isDict (effectModule, edApplicativeDict) dict && isPurePoly fn = True
   isPure _ = False
   -- Check if an expression represents the polymorphic >>= function
   isBindPoly = isDict (C.controlBind, C.bind)
@@ -66,14 +78,9 @@
   isPurePoly = isDict (C.controlApplicative, C.pure')
   -- Check if an expression represents the polymorphic discard function
   isDiscardPoly = isDict (C.controlBind, C.discard)
-  -- Check if an expression represents a function in the Eff module
-  isEffFunc name (Indexer _ (StringLiteral _ name') (Var _ eff)) = eff == C.eff && name == name'
+  -- Check if an expression represents a function in the Effect module
+  isEffFunc name (Indexer _ (StringLiteral _ name') (Var _ eff)) = eff == effectModule && name == name'
   isEffFunc _ _ = False
-
-  -- Remove __do function applications which remain after desugaring
-  undo :: AST -> AST
-  undo (Return _ (App _ (Function _ (Just ident) [] body) [])) | ident == fnName = body
-  undo other = other
 
   applyReturns :: AST -> AST
   applyReturns (Return ss ret) = Return ss (App ss ret [])
diff --git a/src/Language/PureScript/CoreImp/Optimizer/Unused.hs b/src/Language/PureScript/CoreImp/Optimizer/Unused.hs
--- a/src/Language/PureScript/CoreImp/Optimizer/Unused.hs
+++ b/src/Language/PureScript/CoreImp/Optimizer/Unused.hs
@@ -1,7 +1,6 @@
 -- | Removes unused variables
 module Language.PureScript.CoreImp.Optimizer.Unused
   ( removeCodeAfterReturnStatements
-  , removeUnusedArg
   , removeUndefinedApp
   ) where
 
@@ -20,12 +19,6 @@
   isReturn (Return _ _) = True
   isReturn (ReturnNoResult _) = True
   isReturn _ = False
-
-removeUnusedArg :: AST -> AST
-removeUnusedArg = everywhere convert
-  where
-  convert (Function ss name [arg] body) | arg == C.__unused = Function ss name [] body
-  convert js = js
 
 removeUndefinedApp :: AST -> AST
 removeUndefinedApp = everywhere convert
diff --git a/src/Language/PureScript/Docs.hs b/src/Language/PureScript/Docs.hs
--- a/src/Language/PureScript/Docs.hs
+++ b/src/Language/PureScript/Docs.hs
@@ -11,5 +11,6 @@
 import Language.PureScript.Docs.ParseInPackage as Docs
 import Language.PureScript.Docs.Render as Docs
 import Language.PureScript.Docs.RenderedCode as Docs
+import Language.PureScript.Docs.Tags as Docs
 import Language.PureScript.Docs.Types as Docs
 import Language.PureScript.Docs.Css as Docs
diff --git a/src/Language/PureScript/Docs/Convert.hs b/src/Language/PureScript/Docs/Convert.hs
--- a/src/Language/PureScript/Docs/Convert.hs
+++ b/src/Language/PureScript/Docs/Convert.hs
@@ -4,6 +4,7 @@
 module Language.PureScript.Docs.Convert
   ( convertModules
   , convertModulesWithEnv
+  , convertTaggedModulesInPackage
   , convertModulesInPackage
   , convertModulesInPackageWithEnv
   ) where
@@ -18,6 +19,7 @@
 
 import Language.PureScript.Docs.Convert.ReExports (updateReExports)
 import Language.PureScript.Docs.Convert.Single (convertSingleModule)
+import Language.PureScript.Docs.Prim (primModules)
 import Language.PureScript.Docs.Types
 import qualified Language.PureScript as P
 
@@ -26,6 +28,31 @@
 import Text.Parsec (eof)
 
 -- |
+-- Like convertModuleInPackage, but with the modules tagged by their
+-- file paths.
+--
+convertTaggedModulesInPackage ::
+  (MonadError P.MultipleErrors m) =>
+  [(FilePath, P.Module)] ->
+  Map P.ModuleName PackageName ->
+  m [(FilePath, Module)]
+convertTaggedModulesInPackage taggedModules modulesDeps =
+  traverse pairDocModule =<< convertModulesInPackage modules modulesDeps
+  where
+  modules = map snd taggedModules
+
+  moduleNameToFileMap =
+    Map.fromList $ swap . fmap P.getModuleName <$> taggedModules
+
+  getModuleFile docModule =
+    case Map.lookup (modName docModule) moduleNameToFileMap of
+      Just filePath -> pure filePath
+      Nothing -> throwError . P.errorMessage $
+        P.ModuleNotFound $ modName docModule
+
+  pairDocModule docModule = (, docModule) <$> getModuleFile docModule
+
+-- |
 -- Like convertModules, except that it takes a list of modules, together with
 -- their dependency status, and discards dependency modules in the resulting
 -- documentation.
@@ -48,8 +75,10 @@
   where
   go =
      convertModulesWithEnv withPackage
-     >>> fmap (first (filter (isLocal . modName)))
+     >>> fmap (first (filter (shouldKeep . modName)))
 
+  shouldKeep mn = isLocal mn && not (P.isBuiltinModuleName mn)
+
   withPackage :: P.ModuleName -> InPackage P.ModuleName
   withPackage mn =
     case Map.lookup mn modulesDeps of
@@ -102,10 +131,25 @@
   (env, convertedModules) <- second (map convertSingleModule) <$> partiallyDesugar modules
 
   modulesWithTypes <- typeCheckIfNecessary modules convertedModules
-  let moduleMap = Map.fromList (map (modName &&& identity) modulesWithTypes)
 
-  let traversalOrder = map P.getModuleName modules
-  pure (Map.elems (updateReExports env traversalOrder withPackage moduleMap), env)
+  -- We add the Prim docs modules here, so that docs generation is still
+  -- possible if the modules we are generating docs for re-export things from
+  -- Prim submodules. Note that the Prim modules do not exist as
+  -- @Language.PureScript.Module@ values because they do not contain anything
+  -- that exists at runtime. However, we have pre-constructed
+  -- @Language.PureScript.Docs.Types.Module@ values for them, which we use
+  -- here.
+  let moduleMap =
+        Map.fromList
+          (map (modName &&& identity)
+               (modulesWithTypes ++ primModules))
+
+  -- Set up the traversal order for re-export handling so that Prim modules
+  -- come first.
+  let primModuleNames = Map.keys P.primEnv
+  let traversalOrder = primModuleNames ++ map P.getModuleName modules
+  let withReExports = updateReExports env traversalOrder withPackage moduleMap
+  pure (Map.elems withReExports, env)
 
 -- |
 -- If any exported value declarations have either wildcard type signatures, or
diff --git a/src/Language/PureScript/Docs/Convert/ReExports.hs b/src/Language/PureScript/Docs/Convert/ReExports.hs
--- a/src/Language/PureScript/Docs/Convert/ReExports.hs
+++ b/src/Language/PureScript/Docs/Convert/ReExports.hs
@@ -172,7 +172,7 @@
   m (P.ModuleName, name)
 findImport imps (name, orig) =
   let
-    matches (P.ImportRecord qual mn _) = P.disqualify qual == name && mn == orig
+    matches (P.ImportRecord qual mn _ _) = P.disqualify qual == name && mn == orig
     matching = filter matches imps
     getQualified (P.Qualified mname _) = mname
   in
@@ -182,6 +182,12 @@
       -- and B). In this case, we just take its first appearance.
       (importedFrom:_) ->
         pure (importedFrom, name)
+
+      -- Builtin modules do not have any Imports in the Env, and therefore must
+      -- be handled specially here.
+      [] | P.isBuiltinModuleName orig ->
+        pure (orig, name)
+
       [] ->
         internalErrorInModule ("findImport: not found: " ++ show (name, orig))
 
@@ -269,9 +275,15 @@
   case ds of
     [d] ->
       pure (importedFrom, [d])
+    [] | P.isBuiltinModuleName importedFrom ->
+      -- Type classes in builtin modules (i.e. submodules of Prim) also have
+      -- corresponding pseudo-types in the primEnv, but since these are an
+      -- implementation detail they do not exist in the Modules, and hence in
+      -- this case, `ds` will be empty.
+      pure (importedFrom, [])
     other ->
       internalErrorInModule
-        ("lookupTypeDeclaration: unexpected result: " ++ show other)
+        ("lookupTypeDeclaration: unexpected result for " ++ show ty ++ ": " ++ show other)
 
 lookupTypeOpDeclaration
   :: (MonadState (Map P.ModuleName Module) m,MonadReader P.ModuleName m)
@@ -305,7 +317,8 @@
       pure (importedFrom, [d])
     other ->
       internalErrorInModule
-        ("lookupTypeClassDeclaration: unexpected result: "
+        ("lookupTypeClassDeclaration: unexpected result for "
+         ++ show tyClass ++ ": "
          ++ (unlines . map show) other)
 
 lookupKindDeclaration
diff --git a/src/Language/PureScript/Docs/Convert/Single.hs b/src/Language/PureScript/Docs/Convert/Single.hs
--- a/src/Language/PureScript/Docs/Convert/Single.hs
+++ b/src/Language/PureScript/Docs/Convert/Single.hs
@@ -90,7 +90,7 @@
 getDeclarationTitle (P.ExternKindDeclaration _ name) = Just (P.runProperName name)
 getDeclarationTitle (P.TypeSynonymDeclaration _ name _ _) = Just (P.runProperName name)
 getDeclarationTitle (P.TypeClassDeclaration _ name _ _ _ _) = Just (P.runProperName name)
-getDeclarationTitle (P.TypeInstanceDeclaration _ name _ _ _ _) = Just (P.showIdent name)
+getDeclarationTitle (P.TypeInstanceDeclaration _ _ _ name _ _ _ _) = Just (P.showIdent name)
 getDeclarationTitle (P.TypeFixityDeclaration _ _ _ op) = Just ("type " <> P.showOp op)
 getDeclarationTitle (P.ValueFixityDeclaration _ _ _ op) = Just (P.showOp op)
 getDeclarationTitle _ = Nothing
@@ -139,7 +139,7 @@
     ChildDeclaration (P.showIdent ident') (convertComments com) (Just ss) (ChildTypeClassMember ty)
   convertClassMember _ =
     P.internalError "convertDeclaration: Invalid argument to convertClassMember."
-convertDeclaration (P.TypeInstanceDeclaration (ss, com) _ constraints className tys _) title =
+convertDeclaration (P.TypeInstanceDeclaration (ss, com) _ _ _ constraints className tys _) title =
   Just (Left ((classNameString, AugmentClass) : map (, AugmentType) typeNameStrings, AugmentChild childDecl))
   where
   classNameString = unQual className
diff --git a/src/Language/PureScript/Docs/ParseInPackage.hs b/src/Language/PureScript/Docs/ParseInPackage.hs
--- a/src/Language/PureScript/Docs/ParseInPackage.hs
+++ b/src/Language/PureScript/Docs/ParseInPackage.hs
@@ -23,14 +23,15 @@
 --    * Parse all of the input and dependency source files
 --    * Associate each dependency module with its package name, thereby
 --      distinguishing these from local modules
---    * Return the parsed modules and a Map mapping module names to package
---      names for modules which come from dependencies. If a module does not
---      exist in the map, it can safely be assumed to be local.
+--    * Return the paths paired with parsed modules, and a Map of module names
+--      to package names for modules which come from dependencies.
+--      If a module does not exist in the map, it can safely be assumed to be
+--      local.
 parseFilesInPackages ::
   (MonadError P.MultipleErrors m, MonadIO m) =>
   [FilePath]
   -> [(PackageName, FilePath)]
-  -> m ([P.Module], Map P.ModuleName PackageName)
+  -> m ([(FilePath, P.Module)], Map P.ModuleName PackageName)
 parseFilesInPackages inputFiles depsFiles = do
   inputFiles' <- traverse (readFileAs . Local) inputFiles
   depsFiles'  <- traverse (readFileAs . uncurry FromDep) depsFiles
@@ -39,7 +40,7 @@
 
   let mnMap = M.fromList (mapMaybe (\(inpkg, m) -> (P.getModuleName m,) <$> inPkgToMaybe inpkg) modules)
 
-  pure (map snd modules, mnMap)
+  pure (map (first fileInfoToString) modules, mnMap)
 
   where
   parse ::
diff --git a/src/Language/PureScript/Docs/Prim.hs b/src/Language/PureScript/Docs/Prim.hs
--- a/src/Language/PureScript/Docs/Prim.hs
+++ b/src/Language/PureScript/Docs/Prim.hs
@@ -1,7 +1,13 @@
--- | This module provides documentation for the builtin Prim module.
-module Language.PureScript.Docs.Prim (primDocsModule) where
+-- | This module provides documentation for the builtin Prim modules.
+module Language.PureScript.Docs.Prim
+  ( primDocsModule
+  , primRowDocsModule
+  , primTypeErrorDocsModule
+  , primModules
+  ) where
 
 import Prelude.Compat hiding (fail)
+import Data.Monoid ((<>))
 import Data.Text (Text)
 import qualified Data.Text as T
 import qualified Data.Map as Map
@@ -9,6 +15,16 @@
 import Language.PureScript.Docs.Types
 import qualified Language.PureScript as P
 
+primModules :: [Module]
+primModules =
+  [ primDocsModule
+  , primOrderingDocsModule
+  , primRowDocsModule
+  , primRowListDocsModule
+  , primSymbolDocsModule
+  , primTypeErrorDocsModule
+  ]
+
 primDocsModule :: Module
 primDocsModule = Module
   { modName = P.moduleNameFromString "Prim"
@@ -23,30 +39,102 @@
       , char
       , boolean
       , partial
-      , fail
-      , warn
-      , union
-      , rowCons
-      , typeConcat
-      , typeString
       , kindType
       , kindSymbol
       ]
   , modReExports = []
   }
 
-unsafeLookup :: forall v (a :: P.ProperNameType).
-  Map.Map (P.Qualified (P.ProperName a)) v -> String -> Text -> v
-unsafeLookup m errorMsg name = go name
+primOrderingDocsModule :: Module
+primOrderingDocsModule = Module
+  { modName = P.moduleNameFromString "Prim.Ordering"
+  , modComments = Just "The Prim.Row module is embedded in the PureScript compiler. Unlike `Prim`, it is not imported implicitly. It contains a type level `Ordering` data structure."
+  , modDeclarations =
+      [ kindOrdering
+      , orderingLT
+      , orderingEQ
+      , orderingGT
+      ]
+  , modReExports = []
+  }
+
+primRowDocsModule :: Module
+primRowDocsModule = Module
+  { modName = P.moduleNameFromString "Prim.Row"
+  , modComments = Just "The Prim.Row module is embedded in the PureScript compiler. Unlike `Prim`, it is not imported implicitly. It contains automatically solved type classes for working with row types."
+  , modDeclarations =
+      [ union
+      , nub
+      , lacks
+      , rowCons
+      ]
+  , modReExports = []
+  }
+
+primRowListDocsModule :: Module
+primRowListDocsModule = Module
+  { modName = P.moduleNameFromString "Prim.RowList"
+  , modComments = Just "The Prim.RowList module is embedded in the PureScript compiler. Unlike `Prim`, it is not imported implicitly. It contains a type level list (`RowList`) that represents an ordered view of a row of types."
+  , modDeclarations =
+      [ kindRowList
+      , rowListCons
+      , rowListNil
+      , rowToList
+      ]
+  , modReExports = []
+  }
+
+primSymbolDocsModule :: Module
+primSymbolDocsModule = Module
+  { modName = P.moduleNameFromString "Prim.Symbol"
+  , modComments = Just "The Prim.Symbol module is embedded in the PureScript compiler. Unlike `Prim`, it is not imported implicitly. It contains automatically solved type classes for working with `Symbols`."
+  , modDeclarations =
+      [ symbolAppend
+      , symbolCompare
+      , symbolCons
+      ]
+  , modReExports = []
+  }
+
+primTypeErrorDocsModule :: Module
+primTypeErrorDocsModule = Module
+  { modName = P.moduleNameFromString "Prim.TypeError"
+  , modComments = Just "The Prim.TypeError module is embedded in the PureScript compiler. Unlike `Prim`, it is not imported implicitly. It contains type classes that provide custom type error and warning functionality."
+  , modDeclarations =
+      [ warn
+      , fail
+      , kindDoc
+      , textDoc
+      , quoteDoc
+      , besideDoc
+      , aboveDoc
+      ]
+  , modReExports = []
+  }
+
+type NameGen a = Text -> P.Qualified (P.ProperName a)
+
+unsafeLookupOf
+  :: forall v (a :: P.ProperNameType)
+  . NameGen a
+  -> Map.Map (P.Qualified (P.ProperName a)) v
+  -> String
+  -> Text
+  -> v
+unsafeLookupOf k m errorMsg name = go name
   where
-  go = fromJust' . flip Map.lookup m . P.primName
+  go = fromJust' . flip Map.lookup m . k
 
   fromJust' (Just x) = x
   fromJust' _ = P.internalError $ errorMsg ++ show name
 
-primKind :: Text -> Text -> Declaration
-primKind title comments =
-  if Set.member (P.primName title) P.primKinds
+primKindOf
+  :: NameGen 'P.KindName
+  -> Text
+  -> Text
+  -> Declaration
+primKindOf g title comments =
+  if Set.member (g title) P.allPrimKinds
      then Declaration
           { declTitle = title
           , declComments = Just comments
@@ -56,32 +144,56 @@
           }
     else P.internalError $ "Docs.Prim: No such Prim kind: " ++ T.unpack title
 
-lookupPrimTypeKind :: Text -> P.Kind
-lookupPrimTypeKind = fst . unsafeLookup P.primTypes "Docs.Prim: No such Prim type: "
+primKind :: Text -> Text -> Declaration
+primKind = primKindOf P.primName
 
+lookupPrimTypeKindOf
+  :: NameGen 'P.TypeName
+  -> Text
+  -> P.Kind
+lookupPrimTypeKindOf k = fst . unsafeLookupOf k
+  ( P.primTypes <>
+    P.primOrderingTypes <>
+    P.primRowTypes <>
+    P.primRowListTypes <>
+    P.primTypeErrorTypes
+  ) "Docs.Prim: No such Prim type: "
+
 primType :: Text -> Text -> Declaration
-primType title comments = Declaration
+primType = primTypeOf P.primName
+
+primTypeOf :: NameGen 'P.TypeName -> Text -> Text -> Declaration
+primTypeOf gen title comments = Declaration
   { declTitle = title
   , declComments = Just comments
   , declSourceSpan = Nothing
   , declChildren = []
-  , declInfo = ExternDataDeclaration (lookupPrimTypeKind title)
+  , declInfo = ExternDataDeclaration (lookupPrimTypeKindOf gen title)
   }
 
 -- | Lookup the TypeClassData of a Prim class. This function is specifically
 -- not exported because it is partial.
-lookupPrimClass :: Text -> P.TypeClassData
-lookupPrimClass = unsafeLookup P.primClasses "Docs.Prim: No such Prim class: "
+lookupPrimClassOf :: NameGen 'P.ClassName -> Text -> P.TypeClassData
+lookupPrimClassOf g = unsafeLookupOf g
+  ( P.primClasses <>
+    P.primRowClasses <>
+    P.primRowListClasses <>
+    P.primSymbolClasses <>
+    P.primTypeErrorClasses
+  ) "Docs.Prim: No such Prim class: "
 
 primClass :: Text -> Text -> Declaration
-primClass title comments = Declaration
+primClass = primClassOf P.primName
+
+primClassOf :: NameGen 'P.ClassName -> Text -> Text -> Declaration
+primClassOf gen title comments = Declaration
   { declTitle = title
   , declComments = Just comments
   , declSourceSpan = Nothing
   , declChildren = []
   , declInfo =
       let
-        tcd = lookupPrimClass title
+        tcd = lookupPrimClassOf gen title
         args = P.typeClassArguments tcd
         superclasses = P.typeClassSuperclasses tcd
         fundeps = convertFundepsToStrings args (P.typeClassDependencies tcd)
@@ -218,8 +330,97 @@
   , "[the Partial type class guide](https://github.com/purescript/documentation/blob/master/guides/The-Partial-type-class.md)."
   ]
 
+kindOrdering :: Declaration
+kindOrdering = primKindOf (P.primSubName "Ordering") "Ordering" $ T.unlines
+  [ "The `Ordering` kind represents the three possibilites of comparing two"
+  , "types of the same kind: `LT` (less than), `EQ` (equal to), and"
+  , "`GT` (greater than)."
+  ]
+
+orderingLT :: Declaration
+orderingLT = primTypeOf (P.primSubName "Ordering") "LT" $ T.unlines
+  [ "The 'less than' ordering type."
+  ]
+
+orderingEQ :: Declaration
+orderingEQ = primTypeOf (P.primSubName "Ordering") "EQ" $ T.unlines
+  [ "The 'equal to' ordering type."
+  ]
+
+orderingGT :: Declaration
+orderingGT = primTypeOf (P.primSubName "Ordering") "GT" $ T.unlines
+  [ "The 'greater than' ordering type."
+  ]
+
+union :: Declaration
+union = primClassOf (P.primSubName "Row") "Union" $ T.unlines
+  [ "The Union type class is used to compute the union of two rows of types"
+  , "(left-biased, including duplicates)."
+  , ""
+  , "The third type argument represents the union of the first two."
+  ]
+
+nub :: Declaration
+nub = primClassOf (P.primSubName "Row") "Nub" $ T.unlines
+  [ "The Nub type class is used to remove duplicate labels from rows."
+  ]
+
+lacks :: Declaration
+lacks = primClassOf (P.primSubName "Row") "Lacks" $ T.unlines
+  [ "The Lacks type class asserts that a label does not occur in a given row."
+  ]
+
+rowCons :: Declaration
+rowCons = primClassOf (P.primSubName "Row") "Cons" $ T.unlines
+  [ "The Cons type class is a 4-way relation which asserts that one row of"
+  , "types can be obtained from another by inserting a new label/type pair on"
+  , "the left."
+  ]
+
+kindRowList :: Declaration
+kindRowList = primKindOf (P.primSubName "RowList") "RowList" $ T.unlines
+  [ "A type level list representation of a row of types."
+  ]
+
+rowListCons :: Declaration
+rowListCons = primTypeOf (P.primSubName "RowList") "Cons" $ T.unlines
+  [ "Constructs a new `RowList` from a label, a type, and an existing tail"
+  , "`RowList`.  E.g: `Cons \"x\" Int (Cons \"y\" Int Nil)`."
+  ]
+
+rowListNil :: Declaration
+rowListNil = primTypeOf (P.primSubName "RowList") "Nil" $ T.unlines
+  [ "The empty `RowList`."
+  ]
+
+rowToList :: Declaration
+rowToList = primClassOf (P.primSubName "RowList") "RowToList" $ T.unlines
+  [ "Compiler solved type class for generating a `RowList` from a closed row"
+  , "of types.  Entries are sorted by label and duplicates are preserved in"
+  , "the order they appeared in the row."
+  ]
+
+symbolAppend :: Declaration
+symbolAppend = primClassOf (P.primSubName "Symbol") "Append" $ T.unlines
+  [ "Compiler solved type class for appending `Symbol`s together."
+  ]
+
+symbolCompare :: Declaration
+symbolCompare = primClassOf (P.primSubName "Symbol") "Compare" $ T.unlines
+  [ "Compiler solved type class for comparing two `Symbol`s."
+  , "Produces an `Ordering`."
+  ]
+
+symbolCons :: Declaration
+symbolCons = primClassOf (P.primSubName "Symbol") "Cons" $ T.unlines
+  [ "Compiler solved type class for either splitting up a symbol into its"
+  , "head and tail or for combining a head and tail into a new symbol."
+  , "Requires the head to be a single character and the combined string"
+  , "cannot be empty."
+  ]
+
 fail :: Declaration
-fail = primClass "Fail" $ T.unlines
+fail = primClassOf (P.primSubName "TypeError") "Fail" $ T.unlines
   [ "The Fail type class is part of the custom type errors feature. To provide"
   , "a custom type error when someone tries to use a particular instance,"
   , "write that instance out with a Fail constraint."
@@ -229,42 +430,54 @@
   ]
 
 warn :: Declaration
-warn = primClass "Warn" $ T.unlines
+warn = primClassOf (P.primSubName "TypeError") "Warn" $ T.unlines
   [ "The Warn type class allows a custom compiler warning to be displayed."
   , ""
   , "For more information, see"
   , "[the Custom Type Errors guide](https://github.com/purescript/documentation/blob/master/guides/Custom-Type-Errors.md)."
   ]
 
-union :: Declaration
-union = primClass "Union" $ T.unlines
-  [ "The Union type class is used to compute the union of two rows of types"
-  , "(left-biased, including duplicates)."
+kindDoc :: Declaration
+kindDoc = primKindOf (P.primSubName "TypeError") "Doc" $ T.unlines
+  [ "`Doc` is the kind of type-level documents."
   , ""
-  , "The third type argument represents the union of the first two."
+  , "This kind is used with the `Fail` and `Warn` type clases."
+  , "Build up a `Doc` with `Text`, `Quote`, `Beside`, and `Above`."
   ]
 
-rowCons :: Declaration
-rowCons = primClass "RowCons" $ T.unlines
-  [ "The RowCons type class is a 4-way relation which asserts that one row of"
-  , "types can be obtained from another by inserting a new label/type pair on"
-  , "the left."
+textDoc :: Declaration
+textDoc = primTypeOf (P.primSubName "TypeError") "Text" $ T.unlines
+  [ "The Text type constructor makes a Doc from a Symbol"
+  , "to be used in a custom type error."
+  , ""
+  , "For more information, see"
+  , "[the Custom Type Errors guide](https://github.com/purescript/documentation/blob/master/guides/Custom-Type-Errors.md)."
   ]
 
-typeConcat :: Declaration
-typeConcat = primType "TypeConcat" $ T.unlines
-  [ "The TypeConcat type constructor concatenates two Symbols in a custom type"
-  , "error."
+quoteDoc :: Declaration
+quoteDoc = primTypeOf (P.primSubName "TypeError") "Quote" $ T.unlines
+  [ "The Quote type constructor renders any concrete type as a Doc"
+  , "to be used in a custom type error."
   , ""
   , "For more information, see"
   , "[the Custom Type Errors guide](https://github.com/purescript/documentation/blob/master/guides/Custom-Type-Errors.md)."
   ]
 
-typeString :: Declaration
-typeString = primType "TypeString" $ T.unlines
-  [ "The TypeString type constructor renders any concrete type into a Symbol"
+besideDoc :: Declaration
+besideDoc = primTypeOf (P.primSubName "TypeError") "Beside" $ T.unlines
+  [ "The Beside type constructor combines two Docs horizontally"
+  , "to be used in a custom type error."
+  , ""
+  , "For more information, see"
+  , "[the Custom Type Errors guide](https://github.com/purescript/documentation/blob/master/guides/Custom-Type-Errors.md)."
+  ]
+
+aboveDoc :: Declaration
+aboveDoc = primTypeOf (P.primSubName "TypeError") "Above" $ T.unlines
+  [ "The Above type constructor combines two Docs vertically"
   , "in a custom type error."
   , ""
   , "For more information, see"
   , "[the Custom Type Errors guide](https://github.com/purescript/documentation/blob/master/guides/Custom-Type-Errors.md)."
   ]
+
diff --git a/src/Language/PureScript/Docs/Render.hs b/src/Language/PureScript/Docs/Render.hs
--- a/src/Language/PureScript/Docs/Render.hs
+++ b/src/Language/PureScript/Docs/Render.hs
@@ -67,10 +67,10 @@
            [syntax "|" | not (null fundeps)]
         ++ [mintersperse
              (syntax "," <> sp)
-             [idents from <> sp <> syntax "->" <> sp <> idents to | (from, to) <- fundeps ]
+             [typeVars from <> sp <> syntax "->" <> sp <> typeVars to | (from, to) <- fundeps ]
            ]
         where
-          idents = mintersperse sp . map ident'
+          typeVars = mintersperse sp . map typeVar
 
     AliasDeclaration (P.Fixity associativity precedence) for ->
       [ keywordFixity associativity
diff --git a/src/Language/PureScript/Docs/Tags.hs b/src/Language/PureScript/Docs/Tags.hs
new file mode 100644
--- /dev/null
+++ b/src/Language/PureScript/Docs/Tags.hs
@@ -0,0 +1,53 @@
+module Language.PureScript.Docs.Tags
+  ( tags
+  , dumpCtags
+  , dumpEtags
+  ) where
+
+import Prelude
+
+import           Control.Arrow (first)
+import           Data.List (sort)
+import           Data.Maybe (mapMaybe)
+import qualified Data.Text as T
+import Language.PureScript.AST (SourceSpan, sourcePosLine, spanStart)
+import Language.PureScript.Docs.Types
+
+tags :: Module -> [(String, Int)]
+tags = map (first T.unpack) . concatMap dtags . modDeclarations
+  where
+    dtags :: Declaration -> [(T.Text, Int)]
+    dtags decl = case declSourceSpan decl of
+      Just ss -> (declTitle decl, pos ss):(mapMaybe subtag $ declChildren decl)
+      Nothing -> mapMaybe subtag $ declChildren decl
+
+    subtag :: ChildDeclaration -> Maybe (T.Text, Int)
+    subtag cdecl = case cdeclSourceSpan cdecl of
+      Just ss -> Just (cdeclTitle cdecl, pos ss)
+      Nothing -> Nothing
+
+    pos :: SourceSpan -> Int
+    pos = sourcePosLine . spanStart
+
+-- etags files appear to be sorted on module file name:
+-- from emacs source, `emacs/lib-src/etags.c`:
+-- "In etags mode, sort by file name."
+dumpEtags :: [(String, Module)] -> [String]
+dumpEtags = concatMap renderModEtags . sort
+
+renderModEtags :: (String, Module) -> [String]
+renderModEtags (path, mdl) = ["\x0c", path ++ "," ++ show tagsLen] ++ tagLines
+  where tagsLen = sum $ map length tagLines
+        tagLines = map tagLine $ tags mdl
+        tagLine (name, line) = "\x7f" ++ name ++ "\x01" ++ show line ++ ","
+
+-- ctags files are required to be sorted: http://ctags.sourceforge.net/FORMAT
+-- "The tags file is sorted on {tagname}.  This allows for a binary search in
+--  the file."
+dumpCtags :: [(String, Module)] -> [String]
+dumpCtags = sort . concatMap renderModCtags
+
+renderModCtags :: (String, Module) -> [String]
+renderModCtags (path, mdl) = sort tagLines
+  where tagLines = map tagLine $ tags mdl
+        tagLine (name, line) = name ++ "\t" ++ path ++ "\t" ++ show line
diff --git a/src/Language/PureScript/Docs/Types.hs b/src/Language/PureScript/Docs/Types.hs
--- a/src/Language/PureScript/Docs/Types.hs
+++ b/src/Language/PureScript/Docs/Types.hs
@@ -425,7 +425,8 @@
 
   -- | A link to a declaration that is built in to the compiler, e.g. the Prim
   -- module. In this case we only need to store the module that the builtin
-  -- comes from (at the time of writing, this will only ever be "Prim").
+  -- comes from. Note that all builtin modules begin with "Prim", and that the
+  -- compiler rejects attempts to define modules whose names start with "Prim".
   | BuiltinModule P.ModuleName
   deriving (Show, Eq, Ord, Generic)
 
@@ -458,11 +459,12 @@
             pkgVersion <- lookup pkgName ctxResolvedDependencies
             return $ DepsModule curMn pkgName pkgVersion destMn
 
-  builtinLinkLocation = do
-    let primMn = P.moduleNameFromString "Prim"
-    guard $ containingMod == OtherModule primMn
-    -- TODO: ensure the declaration exists in the builtin module too
-    return $ BuiltinModule primMn
+  builtinLinkLocation =
+    case containingMod of
+      OtherModule mn | P.isBuiltinModuleName mn ->
+        pure $ BuiltinModule mn
+      _ ->
+        empty
 
 getLinksContext :: Package a -> LinksContext
 getLinksContext Package{..} =
diff --git a/src/Language/PureScript/Environment.hs b/src/Language/PureScript/Environment.hs
--- a/src/Language/PureScript/Environment.hs
+++ b/src/Language/PureScript/Environment.hs
@@ -16,7 +16,7 @@
 import qualified Data.Text as T
 import           Data.Tree (Tree, rootLabel)
 import qualified Data.Graph as G
-import           Data.Foldable (toList)
+import           Data.Foldable (toList, fold)
 
 import           Language.PureScript.Crash
 import           Language.PureScript.Kinds
@@ -37,7 +37,9 @@
   , typeSynonyms :: M.Map (Qualified (ProperName 'TypeName)) ([(Text, Maybe Kind)], Type)
   -- ^ Type synonyms currently in scope
   , typeClassDictionaries :: M.Map (Maybe ModuleName) (M.Map (Qualified (ProperName 'ClassName)) (M.Map (Qualified Ident) NamedDict))
-  -- ^ Available type class dictionaries
+  -- ^ Available type class dictionaries. When looking up 'Nothing' in the
+  -- outer map, this returns the map of type class dictionaries in local
+  -- scope (ie dictionaries brought in by a constrained type).
   , typeClasses :: M.Map (Qualified (ProperName 'ClassName)) TypeClassData
   -- ^ Type classes
   , kinds :: S.Set (Qualified (ProperName 'KindName))
@@ -94,7 +96,7 @@
 
 -- | The initial environment with no values and only the default javascript types defined
 initEnvironment :: Environment
-initEnvironment = Environment M.empty primTypes M.empty M.empty M.empty primClasses primKinds
+initEnvironment = Environment M.empty allPrimTypes M.empty M.empty M.empty allPrimClasses allPrimKinds
 
 -- | A constructor for TypeClassData that computes which type class arguments are fully determined
 -- and argument covering sets.
@@ -259,16 +261,41 @@
 primName :: Text -> Qualified (ProperName a)
 primName = Qualified (Just $ ModuleName [ProperName C.prim]) . ProperName
 
+-- | Construct a 'ProperName' in the @Prim.NAME@ module.
+primSubName :: Text -> Text -> Qualified (ProperName a)
+primSubName sub =
+  Qualified (Just $ ModuleName [ProperName C.prim, ProperName sub]) . ProperName
+
 primKind :: Text -> Kind
 primKind = NamedKind . primName
 
+primSubKind :: Text -> Text -> Kind
+primSubKind sub = NamedKind . primSubName sub
+
 -- | Kind of ground types
 kindType :: Kind
 kindType = primKind C.typ
 
+-- To make reading the kind signatures below easier
+kindConstraint :: Kind
+kindConstraint = kindType
+
+(-:>) :: Kind -> Kind -> Kind
+(-:>) = FunKind
+infixr 4 -:>
+
 kindSymbol :: Kind
 kindSymbol = primKind C.symbol
 
+kindDoc :: Kind
+kindDoc = primSubKind C.typeError C.doc
+
+kindOrdering :: Kind
+kindOrdering = primSubKind C.moduleOrdering C.kindOrdering
+
+kindRowList :: Kind
+kindRowList = primSubKind C.moduleRowList C.kindRowList
+
 -- | Construct a type in the Prim module
 primTy :: Text -> Type
 primTy = TypeConstructor . primName
@@ -321,69 +348,225 @@
 function :: Type -> Type -> Type
 function t1 = TypeApp (TypeApp tyFunction t1)
 
--- | The primitive kinds
+-- | Kinds in @Prim@
 primKinds :: S.Set (Qualified (ProperName 'KindName))
-primKinds =
-  S.fromList
-    [ primName C.typ
-    , primName C.symbol
-    ]
+primKinds = S.fromList
+  [ primName C.typ
+  , primName C.symbol
+  ]
 
+-- | Kinds in @Prim.Ordering@
+primOrderingKinds :: S.Set (Qualified (ProperName 'KindName))
+primOrderingKinds = S.fromList
+  [ primSubName C.moduleOrdering C.kindOrdering
+  ]
+
+-- | Kinds in @Prim.RowList@
+primRowListKinds :: S.Set (Qualified (ProperName 'KindName))
+primRowListKinds = S.fromList
+  [ primSubName C.moduleRowList C.kindRowList
+  ]
+
+-- | Kinds in @Prim.TypeError@
+primTypeErrorKinds :: S.Set (Qualified (ProperName 'KindName))
+primTypeErrorKinds = S.fromList
+  [ primSubName C.typeError C.doc
+  ]
+
+-- | All primitive kinds
+allPrimKinds :: S.Set (Qualified (ProperName 'KindName))
+allPrimKinds = fold
+  [ primKinds
+  , primOrderingKinds
+  , primRowListKinds
+  , primTypeErrorKinds
+  ]
+
 -- | The primitive types in the external javascript environment with their
 -- associated kinds. There are also pseudo `Fail`, `Warn`, and `Partial` types
 -- that correspond to the classes with the same names.
 primTypes :: M.Map (Qualified (ProperName 'TypeName)) (Kind, TypeKind)
-primTypes =
+primTypes = M.fromList
+  [ (primName "Function", (kindType -:> kindType -:> kindType, ExternData))
+  , (primName "Array",    (kindType -:> kindType, ExternData))
+  , (primName "Record",   (Row kindType -:> kindType, ExternData))
+  , (primName "String",   (kindType, ExternData))
+  , (primName "Char",     (kindType, ExternData))
+  , (primName "Number",   (kindType, ExternData))
+  , (primName "Int",      (kindType, ExternData))
+  , (primName "Boolean",  (kindType, ExternData))
+  , (primName "Partial",  (kindConstraint, ExternData))
+  ]
+
+-- | This 'Map' contains all of the prim types from all Prim modules.
+allPrimTypes :: M.Map (Qualified (ProperName 'TypeName)) (Kind, TypeKind)
+allPrimTypes = M.unions
+  [ primTypes
+  , primOrderingTypes
+  , primRowTypes
+  , primRowListTypes
+  , primSymbolTypes
+  , primTypeErrorTypes
+  ]
+
+primOrderingTypes :: M.Map (Qualified (ProperName 'TypeName)) (Kind, TypeKind)
+primOrderingTypes =
   M.fromList
-    [ (primName "Function",   (FunKind kindType (FunKind kindType kindType), ExternData))
-    , (primName "Array",      (FunKind kindType kindType, ExternData))
-    , (primName "Record",     (FunKind (Row kindType) kindType, ExternData))
-    , (primName "String",     (kindType, ExternData))
-    , (primName "Char",       (kindType, ExternData))
-    , (primName "Number",     (kindType, ExternData))
-    , (primName "Int",        (kindType, ExternData))
-    , (primName "Boolean",    (kindType, ExternData))
-    , (primName "Partial",    (kindType, ExternData))
-    , (primName "Union",      (FunKind (Row kindType) (FunKind (Row kindType) (FunKind (Row kindType) kindType)), ExternData))
-    , (primName "RowCons",    (FunKind kindSymbol (FunKind kindType (FunKind (Row kindType) (FunKind (Row kindType) kindType))), ExternData))
-    , (primName "Fail",       (FunKind kindSymbol kindType, ExternData))
-    , (primName "Warn",       (FunKind kindSymbol kindType, ExternData))
-    , (primName "TypeString", (FunKind kindType kindSymbol, ExternData))
-    , (primName "TypeConcat", (FunKind kindSymbol (FunKind kindSymbol kindSymbol), ExternData))
+    [ (primSubName C.moduleOrdering "LT", (kindOrdering, ExternData))
+    , (primSubName C.moduleOrdering "EQ", (kindOrdering, ExternData))
+    , (primSubName C.moduleOrdering "GT", (kindOrdering, ExternData))
     ]
 
--- | The primitive class map. This just contains the `Fail`, `Warn`, and `Partial`
--- classes. `Partial` is used as a kind of magic constraint for partial
--- functions. `Fail` is used for user-defined type errors. `Warn` for
--- user-defined warnings.
+primRowTypes :: M.Map (Qualified (ProperName 'TypeName)) (Kind, TypeKind)
+primRowTypes =
+  M.fromList
+    [ (primSubName C.moduleRow "Union", (Row kindType -:> Row kindType -:> Row kindType -:> kindConstraint, ExternData))
+    , (primSubName C.moduleRow "Nub", (Row kindType -:> Row kindType -:> kindConstraint, ExternData))
+    , (primSubName C.moduleRow "Lacks", (kindSymbol -:> Row kindType -:> kindConstraint, ExternData))
+    , (primSubName C.moduleRow "Cons",  (kindSymbol -:> kindType -:> Row kindType -:> Row kindType -:> kindConstraint, ExternData))
+    ]
+
+primRowListTypes :: M.Map (Qualified (ProperName 'TypeName)) (Kind, TypeKind)
+primRowListTypes =
+  M.fromList
+    [ (primSubName C.moduleRowList "Cons", (kindSymbol -:> kindType -:> kindRowList -:> kindRowList, ExternData))
+    , (primSubName C.moduleRowList "Nil", (kindRowList, ExternData))
+    , (primSubName C.moduleRowList "RowToList",  (Row kindType -:> kindRowList -:> kindConstraint, ExternData))
+    ]
+
+primSymbolTypes :: M.Map (Qualified (ProperName 'TypeName)) (Kind, TypeKind)
+primSymbolTypes =
+  M.fromList
+    [ (primSubName C.moduleSymbol "Append",  (kindSymbol -:> kindSymbol -:> kindSymbol -:> kindConstraint, ExternData))
+    , (primSubName C.moduleSymbol "Compare", (kindSymbol -:> kindSymbol -:> kindOrdering -:> kindConstraint, ExternData))
+    , (primSubName C.moduleSymbol "Cons",  (kindSymbol -:> kindSymbol -:> kindSymbol -:> kindConstraint, ExternData))
+    ]
+
+primTypeErrorTypes :: M.Map (Qualified (ProperName 'TypeName)) (Kind, TypeKind)
+primTypeErrorTypes =
+  M.fromList
+    [ (primSubName C.typeError "Fail", (kindDoc -:> kindConstraint, ExternData))
+    , (primSubName C.typeError "Warn", (kindDoc -:> kindConstraint, ExternData))
+    , (primSubName C.typeError "Text", (kindSymbol -:> kindDoc, ExternData))
+    , (primSubName C.typeError "Quote", (kindType -:> kindDoc, ExternData))
+    , (primSubName C.typeError "Beside", (kindDoc -:> kindDoc -:> kindDoc, ExternData))
+    , (primSubName C.typeError "Above", (kindDoc -:> kindDoc -:> kindDoc, ExternData))
+    ]
+
+-- | The primitive class map. This just contains the `Partial` class.
+-- `Partial` is used as a kind of magic constraint for partial functions.
 primClasses :: M.Map (Qualified (ProperName 'ClassName)) TypeClassData
 primClasses =
   M.fromList
     [ (primName "Partial", (makeTypeClassData [] [] [] []))
+    ]
+
+-- | This contains all of the type classes from all Prim modules.
+allPrimClasses :: M.Map (Qualified (ProperName 'ClassName)) TypeClassData
+allPrimClasses = M.unions
+  [ primClasses
+  , primRowClasses
+  , primRowListClasses
+  , primSymbolClasses
+  , primTypeErrorClasses
+  ]
+
+primRowClasses :: M.Map (Qualified (ProperName 'ClassName)) TypeClassData
+primRowClasses =
+  M.fromList
+    -- class Union (left :: # Type) (right :: # Type) (union :: # Type) | left right -> union, right union -> left, union left -> right
+    [ (primSubName C.moduleRow "Union", makeTypeClassData
+        [ ("left", Just (Row kindType))
+        , ("right", Just (Row kindType))
+        , ("union", Just (Row kindType))
+        ] [] []
+        [ FunctionalDependency [0, 1] [2]
+        , FunctionalDependency [1, 2] [0]
+        , FunctionalDependency [2, 0] [1]
+        ])
+
+    -- class Nub (original :: # Type) (nubbed :: # Type) | i -> o
+    , (primSubName C.moduleRow "Nub", makeTypeClassData
+        [ ("original", Just (Row kindType))
+        , ("nubbed", Just (Row kindType))
+        ] [] []
+        [ FunctionalDependency [0] [1]
+        ])
+
+    -- class Lacks (label :: Symbol) (row :: # Type)
+    , (primSubName C.moduleRow "Lacks", makeTypeClassData
+        [ ("label", Just kindSymbol)
+        , ("row", Just (Row kindType))
+        ] [] [] [])
+
+    -- class RowCons (label :: Symbol) (a :: Type) (tail :: # Type) (row :: # Type) | label tail a -> row, label row -> tail a
+    , (primSubName C.moduleRow "Cons", makeTypeClassData
+        [ ("label", Just kindSymbol)
+        , ("a", Just kindType)
+        , ("tail", Just (Row kindType))
+        , ("row", Just (Row kindType))
+        ] [] []
+        [ FunctionalDependency [0, 1, 2] [3]
+        , FunctionalDependency [0, 3] [1, 2]
+        ])
+    ]
+
+primRowListClasses :: M.Map (Qualified (ProperName 'ClassName)) TypeClassData
+primRowListClasses =
+  M.fromList
+    -- class RowToList (row :: # Type) (list :: RowList) | row -> list
+    [ (primSubName C.moduleRowList "RowToList", makeTypeClassData
+        [ ("row", Just (Row kindType))
+        , ("list", Just kindRowList)
+        ] [] []
+        [ FunctionalDependency [0] [1]
+        ])
+    ]
+
+primSymbolClasses :: M.Map (Qualified (ProperName 'ClassName)) TypeClassData
+primSymbolClasses =
+  M.fromList
+    -- class Append (left :: Symbol) (right :: Symbol) (appended :: Symbol) | left right -> appended, right appended -> left, appended left -> right
+    [ (primSubName C.moduleSymbol "Append", makeTypeClassData
+        [ ("left", Just kindSymbol)
+        , ("right", Just kindSymbol)
+        , ("appended", Just kindSymbol)
+        ] [] []
+        [ FunctionalDependency [0, 1] [2]
+        , FunctionalDependency [1, 2] [0]
+        , FunctionalDependency [2, 0] [1]
+        ])
+
+    -- class Compare (left :: Symbol) (right :: Symbol) (ordering :: Ordering) | left right -> ordering
+    , (primSubName C.moduleSymbol "Compare", makeTypeClassData
+        [ ("left", Just kindSymbol)
+        , ("right", Just kindSymbol)
+        , ("ordering", Just kindOrdering)
+        ] [] []
+        [ FunctionalDependency [0, 1] [2]
+        ])
+
+    -- class Cons (head :: Symbol) (tail :: Symbol) (symbol :: Symbol) | head tail -> symbol, symbol -> head tail
+    , (primSubName C.moduleSymbol "Cons", makeTypeClassData
+        [ ("head", Just kindSymbol)
+        , ("tail", Just kindSymbol)
+        , ("symbol", Just kindSymbol)
+        ] [] []
+        [ FunctionalDependency [0, 1] [2]
+        , FunctionalDependency [2] [0, 1]
+        ])
+    ]
+
+primTypeErrorClasses :: M.Map (Qualified (ProperName 'ClassName)) TypeClassData
+primTypeErrorClasses =
+  M.fromList
     -- class Fail (message :: Symbol)
-    , (primName "Fail",    (makeTypeClassData [("message", Just kindSymbol)] [] [] []))
+    [ (primSubName C.typeError "Fail", makeTypeClassData
+        [("message", Just kindDoc)] [] [] [])
+
     -- class Warn (message :: Symbol)
-    , (primName "Warn",    (makeTypeClassData [("message", Just kindSymbol)] [] [] []))
-    -- class Union (l :: # Type) (r :: # Type) (u :: # Type) | l r -> u, r u -> l, u l -> r
-    , (primName "Union",   (makeTypeClassData
-                             [ ("l", Just (Row kindType))
-                             , ("r", Just (Row kindType))
-                             , ("u", Just (Row kindType))
-                             ] [] []
-                             [ FunctionalDependency [0, 1] [2]
-                             , FunctionalDependency [1, 2] [0]
-                             , FunctionalDependency [2, 0] [1]
-                             ]))
-    -- class RowCons (l :: Symbol) (a :: Type) (i :: # Type) (o :: # Type) | l i a -> o, l o -> a i
-    , (primName "RowCons", (makeTypeClassData
-                             [ ("l", Just kindSymbol)
-                             , ("a", Just kindType)
-                             , ("i", Just (Row kindType))
-                             , ("o", Just (Row kindType))
-                             ] [] []
-                             [ FunctionalDependency [0, 1, 2] [3]
-                             , FunctionalDependency [0, 3] [1, 2]
-                             ]))
+    , (primSubName C.typeError "Warn", makeTypeClassData
+        [("message", Just kindDoc)] [] [] [])
     ]
 
 -- | Finds information about data constructors from the current environment.
diff --git a/src/Language/PureScript/Errors.hs b/src/Language/PureScript/Errors.hs
--- a/src/Language/PureScript/Errors.hs
+++ b/src/Language/PureScript/Errors.hs
@@ -47,7 +47,7 @@
 newtype ErrorSuggestion = ErrorSuggestion Text
 
 -- | Get the source span for an error
-errorSpan :: ErrorMessage -> Maybe SourceSpan
+errorSpan :: ErrorMessage -> Maybe (NEL.NonEmpty SourceSpan)
 errorSpan = findHint matchSpan
   where
   matchSpan (PositionedError ss) = Just ss
@@ -78,7 +78,6 @@
   ErrorParsingFFIModule{} -> "ErrorParsingFFIModule"
   ErrorParsingModule{} -> "ErrorParsingModule"
   MissingFFIModule{} -> "MissingFFIModule"
-  MultipleFFIModules{} -> "MultipleFFIModules"
   UnnecessaryFFIModule{} -> "UnnecessaryFFIModule"
   MissingFFIImplementations{} -> "MissingFFIImplementations"
   UnusedFFIImplementations{} -> "UnusedFFIImplementations"
@@ -167,6 +166,7 @@
   DuplicateExportRef{} -> "DuplicateExportRef"
   IntOutOfRange{} -> "IntOutOfRange"
   ImplicitQualifiedImport{} -> "ImplicitQualifiedImport"
+  ImplicitQualifiedImportReExport{} -> "ImplicitQualifiedImportReExport"
   ImplicitImport{} -> "ImplicitImport"
   HidingImport{} -> "HidingImport"
   CaseBinderLengthDiffers{} -> "CaseBinderLengthDiffers"
@@ -179,6 +179,9 @@
   ClassInstanceArityMismatch{} -> "ClassInstanceArityMismatch"
   UserDefinedWarning{} -> "UserDefinedWarning"
   UnusableDeclaration{} -> "UnusableDeclaration"
+  CannotDefinePrimModules{} -> "CannotDefinePrimModules"
+  MixedAssociativityError{} -> "MixedAssociativityError"
+  NonAssociativeError{} -> "NonAssociativeError"
 
 -- | A stack trace for an error
 newtype MultipleErrors = MultipleErrors
@@ -195,8 +198,12 @@
 
 -- | Create an error set from a single simple error message and source annotation
 errorMessage' :: SourceSpan -> SimpleErrorMessage -> MultipleErrors
-errorMessage' ss err = MultipleErrors [ErrorMessage [PositionedError ss] err]
+errorMessage' ss err = MultipleErrors [ErrorMessage [positionedError ss] err]
 
+-- | Create an error set from a single simple error message and source annotations
+errorMessage'' :: NEL.NonEmpty SourceSpan -> SimpleErrorMessage -> MultipleErrors
+errorMessage'' sss err = MultipleErrors [ErrorMessage [PositionedError sss] err]
+
 -- | Create an error set from a single error message
 singleError :: ErrorMessage -> MultipleErrors
 singleError = MultipleErrors . pure
@@ -309,6 +316,7 @@
       UnusedDctorExplicitImport mn _ _ qual refs -> suggest $ importSuggestion mn refs qual
       ImplicitImport mn refs -> suggest $ importSuggestion mn refs Nothing
       ImplicitQualifiedImport mn asModule refs -> suggest $ importSuggestion mn refs (Just asModule)
+      ImplicitQualifiedImportReExport mn asModule refs -> suggest $ importSuggestion mn refs (Just asModule)
       HidingImport mn refs -> suggest $ importSuggestion mn refs Nothing
       MissingTypeDeclaration ident ty -> suggest $ showIdent ident <> " :: " <> T.pack (prettyPrintSuggestedType ty)
       WildcardInferredType ty _ -> suggest $ T.pack (prettyPrintSuggestedType ty)
@@ -327,7 +335,10 @@
 
 suggestionSpan :: ErrorMessage -> Maybe SourceSpan
 suggestionSpan e =
-  getSpan (unwrapErrorMessage e) <$> errorSpan e
+  -- The `NEL.head` is a bit arbitrary here, but I don't think we'll
+  -- have errors-with-suggestions that also have multiple source
+  -- spans. -garyb
+  getSpan (unwrapErrorMessage e) . NEL.head <$> errorSpan e
   where
     startOnly SourceSpan{spanName, spanStart} = SourceSpan {spanName, spanStart, spanEnd = spanStart}
 
@@ -479,10 +490,6 @@
                 , line "Note that exported identifiers in FFI modules must be valid PureScript identifiers."
                 ]
             ]
-    renderSimpleErrorMessage (MultipleFFIModules mn paths) =
-      paras [ line $ "Multiple foreign module implementations have been provided for module " <> markCode (runModuleName mn) <> ": "
-            , indent . paras $ map lineS paths
-            ]
     renderSimpleErrorMessage InvalidDoBind =
       line "The last statement in a 'do' block must be an expression, but this block ends with a binder."
     renderSimpleErrorMessage InvalidDoLet =
@@ -534,10 +541,8 @@
       line $ "Declaration for " <> printName (Qualified Nothing new) <> " conflicts with an existing " <> nameType existing <> " of the same name."
     renderSimpleErrorMessage (ExportConflict new existing) =
       line $ "Export for " <> printName new <> " conflicts with " <> runName existing
-    renderSimpleErrorMessage (DuplicateModule mn ss) =
-      paras [ line ("Module " <> markCode (runModuleName mn) <> " has been defined multiple times:")
-            , indent . paras $ map (line . displaySourceSpan relPath) ss
-            ]
+    renderSimpleErrorMessage (DuplicateModule mn) =
+      line $ "Module " <> markCode (runModuleName mn) <> " has been defined multiple times"
     renderSimpleErrorMessage (DuplicateTypeClass pn ss) =
       paras [ line ("Type class " <> markCode (runProperName pn) <> " has been defined multiple times:")
             , indent $ line $ displaySourceSpan relPath ss
@@ -610,18 +615,16 @@
             , line "with type"
             , markCodeBox $ indent $ typeAsBox t2
             ]
-    renderSimpleErrorMessage (OverlappingInstances nm ts (d : ds)) =
+    renderSimpleErrorMessage (OverlappingInstances _ _ []) = internalError "OverlappingInstances: empty instance list"
+    renderSimpleErrorMessage (OverlappingInstances nm ts ds) =
       paras [ line "Overlapping type class instances found for"
             , markCodeBox $ indent $ Box.hsep 1 Box.left
                 [ line (showQualified runProperName nm)
                 , Box.vcat Box.left (map typeAtomAsBox ts)
                 ]
             , line "The following instances were found:"
-            , indent $ paras (line (showQualified showIdent d <> " (chosen)") : map (line . showQualified showIdent) ds)
-            , line "Overlapping type class instances can lead to different behavior based on the order of module imports, and for that reason are not recommended."
-            , line "They may be disallowed completely in a future version of the compiler."
+            , indent $ paras (map (line . showQualified showIdent) ds)
             ]
-    renderSimpleErrorMessage OverlappingInstances{} = internalError "OverlappingInstances: empty instance list"
     renderSimpleErrorMessage (UnknownClass nm) =
       paras [ line "No type class instance was found for class"
             , markCodeBox $ indent $ line (showQualified runProperName nm)
@@ -762,8 +765,10 @@
             , indent $ line $ markCode $ prettyPrintKind kind
             , line "instead."
             ]
-    renderSimpleErrorMessage (IncorrectConstructorArity nm) =
-      line $ "Data constructor " <> markCode (showQualified runProperName nm) <> " was given the wrong number of arguments in a case expression."
+    renderSimpleErrorMessage (IncorrectConstructorArity nm expected actual) =
+      paras [ line $ "Data constructor " <> markCode (showQualified runProperName nm) <> " was given " <> T.pack (show actual) <> " arguments in a case expression, but expected " <> T.pack (show expected) <> " arguments."
+            , line $ "This problem can be fixed by giving " <> markCode (showQualified runProperName nm) <> " " <> T.pack (show expected) <> " arguments."
+            ]
     renderSimpleErrorMessage (ExprDoesNotHaveType expr ty) =
       paras [ line "Expression"
             , markCodeBox $ indent $ prettyPrintValue valueDepth expr
@@ -910,6 +915,11 @@
             , line $ "As there are multiple modules being imported as " <> markCode (runModuleName asModule) <> ", consider using the explicit form:"
             , indent $ line $ markCode $ showSuggestion msg
             ]
+    renderSimpleErrorMessage msg@(ImplicitQualifiedImportReExport importedModule asModule _) =
+      paras [ line $ "Module " <> markCode (runModuleName importedModule) <> " was imported as " <> markCode (runModuleName asModule) <> " with unspecified imports."
+            , line $ "As this module is being re-exported, consider using the explicit form:"
+            , indent $ line $ markCode $ showSuggestion msg
+            ]
 
     renderSimpleErrorMessage msg@(ImplicitImport mn _) =
       paras [ line $ "Module " <> markCode (runModuleName mn) <> " has unspecified imports, consider using the explicit form: "
@@ -976,7 +986,7 @@
 
         case unexplained of
           [required] ->
-            [ line $ "These arguments are: { " <> T.intercalate "," required <> "}"
+            [ line $ "These arguments are: { " <> T.intercalate ", " required <> " }"
             ]
 
           options  ->
@@ -985,6 +995,33 @@
                 map (\set -> line $ "{ " <> T.intercalate ", " set <> " }") options
             ]
 
+    renderSimpleErrorMessage (CannotDefinePrimModules mn) =
+      paras $
+        [ line $ "The module name " <> markCode (runModuleName mn) <> " is in the Prim namespace."
+        , line $ "The Prim namespace is reserved for compiler-defined terms."
+        ]
+
+    renderSimpleErrorMessage (MixedAssociativityError opsWithAssoc) =
+      paras
+        [ line "Cannot parse an expression that uses operators of the same precedence but mixed associativity:"
+        , indent $ paras $ map (\(name, assoc) -> line $ markCode (showQualified showOp name) <> " is " <> markCode (T.pack (showAssoc assoc))) (NEL.toList opsWithAssoc)
+        , line "Use parentheses to resolve this ambiguity."
+        ]
+
+    renderSimpleErrorMessage (NonAssociativeError ops) =
+      if NEL.length ops == 1
+        then
+          paras
+            [ line $ "Cannot parse an expression that uses multiple instances of the non-associative operator " <> markCode (showQualified showOp (NEL.head ops)) <> "."
+            , line "Use parentheses to resolve this ambiguity."
+            ]
+        else
+          paras
+            [ line "Cannot parse an expression that uses multiple non-associative operators of the same precedence:"
+            , indent $ paras $ map (line . markCode . showQualified showOp) (NEL.toList ops)
+            , line "Use parentheses to resolve this ambiguity."
+            ]
+
     renderHint :: ErrorMessageHint -> Box.Box -> Box.Box
     renderHint (ErrorUnifyingTypes t1 t2) detail =
       paras [ detail
@@ -1110,7 +1147,7 @@
                 ]
             ]
     renderHint (PositionedError srcSpan) detail =
-      paras [ line $ "at " <> displaySourceSpan relPath srcSpan
+      paras [ line $ "at " <> displaySourceSpan relPath (NEL.head srcSpan)
             , detail
             ]
 
@@ -1365,10 +1402,15 @@
 toTypelevelString (TypeLevelString s) =
   Just . Box.text $ decodeStringWithReplacement s
 toTypelevelString (TypeApp (TypeConstructor f) x)
-  | f == primName "TypeString" = Just (typeAsBox x)
+  | f == primSubName C.typeError "Text" = toTypelevelString x
+toTypelevelString (TypeApp (TypeConstructor f) x)
+  | f == primSubName C.typeError "Quote" = Just (typeAsBox x)
 toTypelevelString (TypeApp (TypeApp (TypeConstructor f) x) ret)
-  | f == primName "TypeConcat" =
+  | f == primSubName C.typeError "Beside" =
     (Box.<>) <$> toTypelevelString x <*> toTypelevelString ret
+toTypelevelString (TypeApp (TypeApp (TypeConstructor f) x) ret)
+  | f == primSubName C.typeError "Above" =
+    (Box.//) <$> toTypelevelString x <*> toTypelevelString ret
 toTypelevelString _ = Nothing
 
 -- | Rethrow an error with a more detailed error message in the case of failure
@@ -1395,7 +1437,10 @@
 warnAndRethrowWithPosition pos = rethrowWithPosition pos . warnWithPosition pos
 
 withPosition :: SourceSpan -> ErrorMessage -> ErrorMessage
-withPosition pos (ErrorMessage hints se) = ErrorMessage (PositionedError pos : hints) se
+withPosition pos (ErrorMessage hints se) = ErrorMessage (positionedError pos : hints) se
+
+positionedError :: SourceSpan -> ErrorMessageHint
+positionedError = PositionedError . pure
 
 -- | Runs a computation listening for warnings and then escalating any warnings
 -- that match the predicate to error status.
diff --git a/src/Language/PureScript/Errors/JSON.hs b/src/Language/PureScript/Errors/JSON.hs
--- a/src/Language/PureScript/Errors/JSON.hs
+++ b/src/Language/PureScript/Errors/JSON.hs
@@ -5,6 +5,7 @@
 import Prelude.Compat
 
 import qualified Data.Aeson.TH as A
+import qualified Data.List.NonEmpty as NEL
 import Data.Monoid ((<>))
 import qualified Data.Text as T
 import Data.Text (Text)
@@ -31,6 +32,7 @@
   , filename :: Maybe String
   , moduleName :: Maybe Text
   , suggestion :: Maybe ErrorSuggestion
+  , allSpans :: [P.SourceSpan]
   } deriving (Show, Eq)
 
 data JSONResult = JSONResult
@@ -43,22 +45,22 @@
 $(A.deriveJSON A.defaultOptions ''JSONResult)
 $(A.deriveJSON A.defaultOptions ''ErrorSuggestion)
 
-
 toJSONErrors :: Bool -> P.Level -> P.MultipleErrors -> [JSONError]
 toJSONErrors verbose level = map (toJSONError verbose level) . P.runMultipleErrors
 
 toJSONError :: Bool -> P.Level -> P.ErrorMessage -> JSONError
 toJSONError verbose level e =
-  JSONError (toErrorPosition <$> sspan)
+  JSONError (toErrorPosition <$> fmap NEL.head spans)
             (P.renderBox (P.prettyPrintSingleError (P.PPEOptions Nothing verbose level False mempty) (P.stripModuleAndSpan e)))
             (P.errorCode e)
             (P.errorDocUri e)
-            (P.spanName <$> sspan)
+            (P.spanName <$> fmap NEL.head spans)
             (P.runModuleName <$> P.errorModule e)
             (toSuggestion e)
+            (maybe [] NEL.toList spans)
   where
-  sspan :: Maybe P.SourceSpan
-  sspan = P.errorSpan e
+  spans :: Maybe (NEL.NonEmpty P.SourceSpan)
+  spans = P.errorSpan e
 
   toErrorPosition :: P.SourceSpan -> ErrorPosition
   toErrorPosition ss =
diff --git a/src/Language/PureScript/Externs.hs b/src/Language/PureScript/Externs.hs
--- a/src/Language/PureScript/Externs.hs
+++ b/src/Language/PureScript/Externs.hs
@@ -134,6 +134,8 @@
       , edInstanceName            :: Ident
       , edInstanceTypes           :: [Type]
       , edInstanceConstraints     :: Maybe [Constraint]
+      , edInstanceChain           :: [Qualified Ident]
+      , edInstanceChainIndex      :: Integer
       }
   -- | A kind declaration
   | EDKind
@@ -152,10 +154,10 @@
   applyDecl env (EDValue ident ty) = env { names = M.insert (Qualified (Just efModuleName) ident) (ty, External, Defined) (names env) }
   applyDecl env (EDClass pn args members cs deps) = env { typeClasses = M.insert (qual pn) (makeTypeClassData args members cs deps) (typeClasses env) }
   applyDecl env (EDKind pn) = env { kinds = S.insert (qual pn) (kinds env) }
-  applyDecl env (EDInstance className ident tys cs) = env { typeClassDictionaries = updateMap (updateMap (M.insert (qual ident) dict) className) (Just efModuleName) (typeClassDictionaries env) }
+  applyDecl env (EDInstance className ident tys cs ch idx) = env { typeClassDictionaries = updateMap (updateMap (M.insert (qual ident) dict) className) (Just efModuleName) (typeClassDictionaries env) }
     where
     dict :: NamedDict
-    dict = TypeClassDictionaryInScope (qual ident) [] className tys cs
+    dict = TypeClassDictionaryInScope ch idx (qual ident) [] className tys cs
 
     updateMap :: (Ord k, Monoid a) => (a -> a) -> k -> M.Map k a -> M.Map k a
     updateMap f = M.alter (Just . f . fold)
@@ -219,7 +221,7 @@
       , EDClass className typeClassArguments typeClassMembers typeClassSuperclasses typeClassDependencies
       ]
   toExternsDeclaration (TypeInstanceRef _ ident)
-    = [ EDInstance tcdClassName ident tcdInstanceTypes tcdDependencies
+    = [ EDInstance tcdClassName ident tcdInstanceTypes tcdDependencies tcdChain tcdIndex
       | m1 <- maybeToList (M.lookup (Just mn) (typeClassDictionaries env))
       , m2 <- M.elems m1
       , TypeClassDictionaryInScope{..} <- maybeToList (M.lookup (Qualified (Just mn) ident) m2)
diff --git a/src/Language/PureScript/Ide.hs b/src/Language/PureScript/Ide.hs
--- a/src/Language/PureScript/Ide.hs
+++ b/src/Language/PureScript/Ide.hs
@@ -18,11 +18,12 @@
        ( handleCommand
        ) where
 
-import           Protolude
+import           Protolude hiding (moduleName)
 
 import           "monad-logger" Control.Monad.Logger
+import qualified Data.Map                           as Map
+import qualified Data.Text                          as T
 import qualified Language.PureScript                as P
-import qualified Language.PureScript.Constants      as C
 import qualified Language.PureScript.Ide.CaseSplit  as CS
 import           Language.PureScript.Ide.Command
 import           Language.PureScript.Ide.Completion
@@ -32,14 +33,14 @@
 import           Language.PureScript.Ide.Imports    hiding (Import)
 import           Language.PureScript.Ide.Matcher
 import           Language.PureScript.Ide.Prim
-import           Language.PureScript.Ide.Pursuit
 import           Language.PureScript.Ide.Rebuild
 import           Language.PureScript.Ide.SourceFile
 import           Language.PureScript.Ide.State
 import           Language.PureScript.Ide.Types
 import           Language.PureScript.Ide.Util
+import           Language.PureScript.Ide.Usage (findUsages)
 import           System.Directory (getCurrentDirectory, getDirectoryContents, doesDirectoryExist, doesFileExist)
-import           System.FilePath ((</>))
+import           System.FilePath ((</>), normalise)
 import           System.FilePath.Glob (glob)
 
 -- | Accepts a Commmand and runs it against psc-ide's State. This is the main
@@ -61,10 +62,6 @@
     findType search filters currentModule
   Complete filters matcher currentModule complOptions ->
     findCompletions filters matcher currentModule complOptions
-  Pursuit query Package ->
-    findPursuitPackages query
-  Pursuit query Identifier ->
-    findPursuitCompletions query
   List LoadedModules ->
     printModules
   List AvailableModules ->
@@ -75,6 +72,16 @@
     caseSplit l b e wca t
   AddClause l wca ->
     MultilineTextResult <$> CS.addClause l wca
+  FindUsages moduleName ident namespace -> do
+    Map.lookup moduleName <$> getAllModules Nothing >>= \case
+      Nothing -> throwError (GeneralError "Module not found")
+      Just decls -> do
+        case find (\d -> namespaceForDeclaration (discardAnn d) == namespace
+                    && identifierFromIdeDeclaration (discardAnn d) == ident) decls of
+          Nothing -> throwError (GeneralError "Declaration not found")
+          Just declaration -> do
+            let sourceModule = fromMaybe moduleName (declaration & _idaAnnotation & _annExportedFrom)
+            UsagesResult . foldMap toList <$> findUsages (discardAnn declaration) sourceModule
   Import fp outfp _ (AddImplicitImport mn) -> do
     rs <- addImplicitImport fp mn
     answerRequest outfp rs
@@ -92,7 +99,7 @@
   RebuildSync file actualFile ->
     rebuildFileSync file actualFile
   Cwd ->
-    TextResult . toS <$> liftIO getCurrentDirectory
+    TextResult . T.pack <$> liftIO getCurrentDirectory
   Reset ->
     resetIdeState $> TextResult "State has been reset."
   Quit ->
@@ -106,27 +113,21 @@
   -> CompletionOptions
   -> m Success
 findCompletions filters matcher currentModule complOptions = do
-  modules <- getAllModules currentModule
-  let insertPrim = (:) (C.Prim, idePrimDeclarations)
+  modules <- Map.toList <$> getAllModules currentModule
+  let insertPrim = (++) idePrimDeclarations
   pure (CompletionResult (getCompletions filters matcher complOptions (insertPrim modules)))
 
-findType :: Ide m =>
-            Text -> [Filter] -> Maybe P.ModuleName -> m Success
+findType
+  :: Ide m
+  => Text
+  -> [Filter]
+  -> Maybe P.ModuleName
+  -> m Success
 findType search filters currentModule = do
-  modules <- getAllModules currentModule
-  let insertPrim = (:) (C.Prim, idePrimDeclarations)
+  modules <- Map.toList <$> getAllModules currentModule
+  let insertPrim = (++) idePrimDeclarations
   pure (CompletionResult (getExactCompletions search filters (insertPrim modules)))
 
-findPursuitCompletions :: MonadIO m =>
-                          PursuitQuery -> m Success
-findPursuitCompletions (PursuitQuery q) =
-  PursuitResult <$> liftIO (searchPursuitForDeclarations q)
-
-findPursuitPackages :: MonadIO m =>
-                       PursuitQuery -> m Success
-findPursuitPackages (PursuitQuery q) =
-  PursuitResult <$> liftIO (findPackagesForModuleIdent q)
-
 printModules :: Ide m => m Success
 printModules = ModuleList . map P.runModuleName <$> getLoadedModulenames
 
@@ -156,7 +157,7 @@
 findAvailableExterns = do
   oDir <- outputDirectory
   unlessM (liftIO (doesDirectoryExist oDir))
-    (throwError (GeneralError "Couldn't locate your output directory."))
+    (throwError (GeneralError $ "Couldn't locate your output directory at: " <> (T.pack (normalise oDir))))
   liftIO $ do
     directories <- getDirectoryContents oDir
     moduleNames <- filterM (containsExterns oDir) directories
diff --git a/src/Language/PureScript/Ide/CaseSplit.hs b/src/Language/PureScript/Ide/CaseSplit.hs
--- a/src/Language/PureScript/Ide/CaseSplit.hs
+++ b/src/Language/PureScript/Ide/CaseSplit.hs
@@ -131,7 +131,7 @@
         P.runTokenParser "" (P.parseDeclaration <* Parsec.eof) ts
   in
     case x of
-      Right (P.TypeDeclaration td) -> pure (P.unwrapTypeDeclaration td)
+      Right (P.TypeDeclaration td : _) -> pure (P.unwrapTypeDeclaration td)
       Right _ -> throwError (GeneralError "Found a non-type-declaration")
       Left err ->
         throwError (GeneralError ("Parsing the type signature failed with: "
diff --git a/src/Language/PureScript/Ide/Command.hs b/src/Language/PureScript/Ide/Command.hs
--- a/src/Language/PureScript/Ide/Command.hs
+++ b/src/Language/PureScript/Ide/Command.hs
@@ -38,10 +38,6 @@
       , completeCurrentModule :: Maybe P.ModuleName
       , completeOptions       :: CompletionOptions
       }
-    | Pursuit
-      { pursuitQuery      :: PursuitQuery
-      , pursuitSearchType :: PursuitSearchType
-      }
     | CaseSplit
       { caseSplitLine        :: Text
       , caseSplitBegin       :: Int
@@ -53,6 +49,11 @@
       { addClauseLine        :: Text
       , addClauseAnnotations :: WildcardAnnotations
       }
+    | FindUsages
+      { usagesModule :: P.ModuleName
+      , usagesIdentifier :: Text
+      , usagesNamespace :: IdeNamespace
+      }
       -- Import InputFile OutputFile
     | Import FilePath (Maybe FilePath) [Filter] ImportCommand
     | List { listType :: ListType }
@@ -68,9 +69,9 @@
   LoadSync{} -> "LoadSync"
   Type{} -> "Type"
   Complete{} -> "Complete"
-  Pursuit{} -> "Pursuit"
   CaseSplit{} -> "CaseSplit"
   AddClause{} -> "AddClause"
+  FindUsages{} -> "FindUsages"
   Import{} -> "Import"
   List{} -> "List"
   Rebuild{} -> "Rebuild"
@@ -140,11 +141,6 @@
           <*> params .:? "matcher" .!= mempty
           <*> (fmap P.moduleNameFromString <$> params .:? "currentModule")
           <*> params .:? "options" .!= defaultCompletionOptions
-      "pursuit" -> do
-        params <- o .: "params"
-        Pursuit
-          <$> params .: "query"
-          <*> params .: "type"
       "caseSplit" -> do
         params <- o .: "params"
         CaseSplit
@@ -158,6 +154,12 @@
         AddClause
           <$> params .: "line"
           <*> (mkAnnotations <$> params .: "annotations")
+      "usages" -> do
+        params <- o .: "params"
+        FindUsages
+          <$> (map P.moduleNameFromString (params .: "module"))
+          <*> params .: "identifier"
+          <*> params .: "namespace"
       "import" -> do
         params <- o .: "params"
         Import
diff --git a/src/Language/PureScript/Ide/Imports.hs b/src/Language/PureScript/Ide/Imports.hs
--- a/src/Language/PureScript/Ide/Imports.hs
+++ b/src/Language/PureScript/Ide/Imports.hs
@@ -34,12 +34,15 @@
 
 import           Control.Lens                       ((^.), (%~), ix)
 import           Data.List                          (findIndex, nubBy, partition)
+import qualified Data.Map                           as Map
 import qualified Data.Text                          as T
 import qualified Language.PureScript                as P
+import qualified Language.PureScript.Constants      as C
 import           Language.PureScript.Ide.Completion
 import           Language.PureScript.Ide.Error
 import           Language.PureScript.Ide.Filter
 import           Language.PureScript.Ide.State
+import           Language.PureScript.Ide.Prim
 import           Language.PureScript.Ide.Types
 import           Language.PureScript.Ide.Util
 import           System.IO.UTF8                     (writeUTF8FileT)
@@ -48,7 +51,7 @@
 data Import = Import P.ModuleName P.ImportDeclarationType (Maybe P.ModuleName)
               deriving (Eq, Show)
 
--- | Reads a file and returns the parsed modulename as well as the parsed
+-- | Reads a file and returns the parsed module name as well as the parsed
 -- imports, while ignoring eventual parse errors that aren't relevant to the
 -- import section
 parseImportsFromFile
@@ -63,10 +66,12 @@
 
 -- | Reads a file and returns the (lines before the imports, the imports, the
 -- lines after the imports)
-parseImportsFromFile' :: (MonadIO m, MonadError IdeError m) =>
-                        FilePath -> m (P.ModuleName, [Text], [Import], [Text])
+parseImportsFromFile'
+  :: (MonadIO m, MonadError IdeError m)
+  => FilePath
+  -> m (P.ModuleName, [Text], [Import], [Text])
 parseImportsFromFile' fp = do
-  file <- ideReadFile fp
+  (_, file) <- ideReadFile fp
   case sliceImportSection (T.lines file) of
     Right res -> pure res
     Left err -> throwError (GeneralError err)
@@ -100,12 +105,13 @@
 sliceImportSection fileLines = first show $ do
   tokens <- P.lexLenient "<psc-ide>" file
   ImportParse{..} <- P.runTokenParser "<psc-ide>" parseModuleHeader tokens
-  pure ( ipModuleName
-       , sliceFile (P.SourcePos 1 1) (prevPos ipStart)
-       , ipImports
-       -- Not sure why I need to drop 1 here, but it makes the tests pass
-       , drop 1 (sliceFile (nextPos ipEnd) (P.SourcePos (length fileLines) (lineLength (length fileLines))))
-       )
+  pure
+    ( ipModuleName
+    , sliceFile (P.SourcePos 1 1) (prevPos ipStart)
+    , ipImports
+    -- Not sure why I need to drop 1 here, but it makes the tests pass
+    , drop 1 (sliceFile (nextPos ipEnd) (P.SourcePos (length fileLines) (lineLength (length fileLines))))
+    )
   where
     prevPos (P.SourcePos l c)
       | l == 1 && c == 1 = P.SourcePos l c
@@ -180,14 +186,20 @@
 addExplicitImport' decl moduleName qualifier imports =
   let
     isImplicitlyImported =
-      not . null $ filter (\case
-                              (Import mn P.Implicit qualifier') -> mn == moduleName && qualifier == qualifier'
-                              _ -> False) imports
+        any (\case
+          Import mn P.Implicit qualifier' -> mn == moduleName && qualifier == qualifier'
+          _ -> False) imports
+    isNotExplicitlyImportedFromPrim =
+      moduleName == C.Prim &&
+        not (any (\case
+          Import C.Prim (P.Explicit _) Nothing -> True
+          _ -> False) imports)
+
     matches (Import mn (P.Explicit _) qualifier') = mn == moduleName && qualifier == qualifier'
     matches _ = False
     freshImport = Import moduleName (P.Explicit [refFromDeclaration decl]) qualifier
   in
-    if isImplicitlyImported
+    if isImplicitlyImported || isNotExplicitlyImportedFromPrim
     then imports
     else updateAtFirstOrPrepend matches (insertDeclIntoImport decl) freshImport imports
   where
@@ -253,16 +265,17 @@
 --
 -- * If more than one possible imports are found, reports the possibilities as a
 -- list of completions.
-addImportForIdentifier :: (Ide m, MonadError IdeError m)
-                          => FilePath -- ^ The Sourcefile to read from
-                          -> Text     -- ^ The identifier to import
-                          -> Maybe P.ModuleName  -- ^ The optional qualifier under which to import
-                          -> [Filter] -- ^ Filters to apply before searching for
-                                      -- the identifier
-                          -> m (Either [Match IdeDeclaration] [Text])
+addImportForIdentifier
+  :: (Ide m, MonadError IdeError m)
+  => FilePath -- ^ The Sourcefile to read from
+  -> Text     -- ^ The identifier to import
+  -> Maybe P.ModuleName  -- ^ The optional qualifier under which to import
+  -> [Filter] -- ^ Filters to apply before searching for the identifier
+  -> m (Either [Match IdeDeclaration] [Text])
 addImportForIdentifier fp ident qual filters = do
-  modules <- getAllModules Nothing
-  case map (fmap discardAnn) (getExactMatches ident filters modules) of
+  let addPrim = (++) idePrimDeclarations
+  modules <- Map.toList <$> getAllModules Nothing
+  case map (fmap discardAnn) (getExactMatches ident filters (addPrim modules)) of
     [] ->
       throwError (NotFound "Couldn't find the given identifier. \
                            \Have you loaded the corresponding module?")
diff --git a/src/Language/PureScript/Ide/Prim.hs b/src/Language/PureScript/Ide/Prim.hs
--- a/src/Language/PureScript/Ide/Prim.hs
+++ b/src/Language/PureScript/Ide/Prim.hs
@@ -4,17 +4,64 @@
 import qualified Data.Map as Map
 import qualified Data.Set as Set
 import qualified Language.PureScript as P
+import qualified Language.PureScript.Constants as C
 import qualified Language.PureScript.Environment as PEnv
 import           Language.PureScript.Ide.Types
 
-idePrimDeclarations :: [IdeDeclarationAnn]
+idePrimDeclarations :: [(P.ModuleName, [IdeDeclarationAnn])]
 idePrimDeclarations =
-  primTypes <> primKinds <> primClasses
+  [ ( C.Prim
+    , mconcat [primTypes, primKinds, primClasses]
+    )
+  , ( C.PrimOrdering
+    , mconcat [primOrderingTypes, primOrderingKinds]
+    )
+  , ( C.PrimRow
+    , mconcat [primRowTypes, primRowClasses]
+    )
+  , ( C.PrimRowList
+    , mconcat [primRowListTypes, primRowListClasses, primRowListKinds]
+    )
+  , ( C.PrimSymbol
+    , mconcat [primSymbolTypes, primSymbolClasses]
+    )
+  , ( C.PrimTypeError
+    , mconcat [primTypeErrorTypes, primTypeErrorClasses, primTypeErrorKinds]
+    )
+  ]
   where
-    primTypes = foreach (Map.toList PEnv.primTypes) $ \(tn, (kind, _)) ->
+    annType tys = foreach (Map.toList tys) $ \(tn, (kind, _)) ->
       IdeDeclarationAnn emptyAnn (IdeDeclType (IdeType (P.disqualify tn) kind []))
-    primKinds = foreach (Set.toList PEnv.primKinds) $ \kn ->
-      IdeDeclarationAnn emptyAnn (IdeDeclKind (P.disqualify kn))
-    primClasses = foreach (Map.toList PEnv.primClasses) $ \(cn, _) ->
+    annClass cls = foreach (Map.toList cls) $ \(cn, _) ->
       -- Dummy kind and instances here, but we primarily care about the name completion
       IdeDeclarationAnn emptyAnn (IdeDeclTypeClass (IdeTypeClass (P.disqualify cn) P.kindType []) )
+    -- The Environment for typechecking holds both a type class as well as a
+    -- type declaration for every class, but we filter the types out when we
+    -- load the Externs, so we do the same here
+    removeClasses types classes =
+      Map.difference types (Map.mapKeys (map P.coerceProperName) classes)
+
+    primTypes = annType (removeClasses PEnv.primTypes PEnv.primClasses)
+    primOrderingTypes = annType PEnv.primOrderingTypes
+    primRowTypes = annType (removeClasses PEnv.primRowTypes PEnv.primRowClasses)
+    primRowListTypes = annType (removeClasses PEnv.primRowListTypes PEnv.primRowListClasses)
+    primSymbolTypes = annType (removeClasses PEnv.primSymbolTypes PEnv.primSymbolClasses)
+    primTypeErrorTypes = annType (removeClasses PEnv.primTypeErrorTypes PEnv.primTypeErrorClasses)
+
+    primClasses = annClass PEnv.primClasses
+    primRowClasses = annClass PEnv.primRowClasses
+    primRowListClasses = annClass PEnv.primRowListClasses
+    primSymbolClasses = annClass PEnv.primSymbolClasses
+    primTypeErrorClasses = annClass PEnv.primTypeErrorClasses
+
+    primKinds = foreach (Set.toList PEnv.primKinds) $ \kn ->
+      IdeDeclarationAnn emptyAnn (IdeDeclKind (P.disqualify kn))
+
+    primOrderingKinds = foreach (Set.toList PEnv.primOrderingKinds) $ \kn ->
+      IdeDeclarationAnn emptyAnn (IdeDeclKind (P.disqualify kn))
+
+    primRowListKinds = foreach (Set.toList PEnv.primRowListKinds) $ \kn ->
+      IdeDeclarationAnn emptyAnn (IdeDeclKind (P.disqualify kn))
+
+    primTypeErrorKinds = foreach (Set.toList PEnv.primTypeErrorKinds) $ \kn ->
+      IdeDeclarationAnn emptyAnn (IdeDeclKind (P.disqualify kn))
diff --git a/src/Language/PureScript/Ide/Pursuit.hs b/src/Language/PureScript/Ide/Pursuit.hs
deleted file mode 100644
--- a/src/Language/PureScript/Ide/Pursuit.hs
+++ /dev/null
@@ -1,69 +0,0 @@
------------------------------------------------------------------------------
---
--- Module      : Language.PureScript.Ide.Pursuit
--- Description : Pursuit client for psc-ide
--- Copyright   : Christoph Hegemann 2016
--- License     : MIT (http://opensource.org/licenses/MIT)
---
--- Maintainer  : Christoph Hegemann <christoph.hegemann1337@gmail.com>
--- Stability   : experimental
---
--- |
--- Pursuit client for psc-ide
------------------------------------------------------------------------------
-
-module Language.PureScript.Ide.Pursuit
-  ( searchPursuitForDeclarations
-  , findPackagesForModuleIdent
-  ) where
-
-import           Protolude                     hiding (fromStrict)
-
-import qualified Control.Exception             as E
-import           Data.Aeson
-import           Data.ByteString.Lazy          (fromStrict)
-import           Data.String
-import qualified Data.Text                     as T
-import           Language.PureScript.Ide.Types
-import           Network.HTTP.Types.Header     (hAccept)
-import           Pipes.HTTP
-import qualified Pipes.Prelude                 as P
-
-queryPursuit :: Text -> IO ByteString
-queryPursuit q = do
-  req' <- parseRequest "https://pursuit.purescript.org/search"
-  let req = req'
-        { queryString= "q=" <> (fromString . T.unpack) q
-        , requestHeaders=[(hAccept, "application/json")]
-        }
-  m <- newManager tlsManagerSettings
-  withHTTP req m $ \resp ->
-    P.fold (<>) "" identity (responseBody resp)
-
-
-handler :: HttpException -> IO [a]
-handler _ = pure []
-
-searchPursuitForDeclarations :: Text -> IO [PursuitResponse]
-searchPursuitForDeclarations query =
-    (do r <- queryPursuit query
-        let results' = decode (fromStrict r) :: Maybe Array
-        case results' of
-          Nothing -> pure []
-          Just results -> pure (mapMaybe (isDeclarationResponse . fromJSON) (toList results))) `E.catch`
-    handler
-  where
-    isDeclarationResponse (Success a@DeclarationResponse{}) = Just a
-    isDeclarationResponse _ = Nothing
-
-findPackagesForModuleIdent :: Text -> IO [PursuitResponse]
-findPackagesForModuleIdent query =
-  (do r <- queryPursuit query
-      let results' = decode (fromStrict r) :: Maybe Array
-      case results' of
-        Nothing -> pure []
-        Just results -> pure (mapMaybe (isModuleResponse . fromJSON) (toList results))) `E.catch`
-  handler
-  where
-    isModuleResponse (Success a@ModuleResponse{}) = Just a
-    isModuleResponse _ = Nothing
diff --git a/src/Language/PureScript/Ide/Rebuild.hs b/src/Language/PureScript/Ide/Rebuild.hs
--- a/src/Language/PureScript/Ide/Rebuild.hs
+++ b/src/Language/PureScript/Ide/Rebuild.hs
@@ -49,7 +49,7 @@
 
   input <- ideReadFile file
 
-  m <- case snd <$> P.parseModuleFromFile (maybe identity const actualFile) (file, input) of
+  m <- case snd <$> P.parseModuleFromFile (maybe identity const actualFile) input of
     Left parseError ->
       throwError (RebuildError (P.MultipleErrors [P.toPositionedError parseError]))
     Right m -> pure m
diff --git a/src/Language/PureScript/Ide/SourceFile.hs b/src/Language/PureScript/Ide/SourceFile.hs
--- a/src/Language/PureScript/Ide/SourceFile.hs
+++ b/src/Language/PureScript/Ide/SourceFile.hs
@@ -35,8 +35,8 @@
   => FilePath
   -> m (Either FilePath (FilePath, P.Module))
 parseModule path = do
-  contents <- ideReadFile path
-  pure (parseModule' path contents)
+  (absPath, contents) <- ideReadFile path
+  pure (parseModule' absPath contents)
 
 parseModule' :: FilePath -> Text -> Either FilePath (FilePath, P.Module)
 parseModule' path file =
@@ -49,7 +49,7 @@
   => [FilePath]
   -> m [Either FilePath (FilePath, P.Module)]
 parseModulesFromFiles paths = do
-  files <- traverse (\p -> (p,) <$> ideReadFile p) paths
+  files <- traverse ideReadFile paths
   pure (inParallel (map (uncurry parseModule') files))
   where
     inParallel :: [Either e (k, a)] -> [Either e (k, a)]
diff --git a/src/Language/PureScript/Ide/State.hs b/src/Language/PureScript/Ide/State.hs
--- a/src/Language/PureScript/Ide/State.hs
+++ b/src/Language/PureScript/Ide/State.hs
@@ -20,6 +20,7 @@
 module Language.PureScript.Ide.State
   ( getLoadedModulenames
   , getExternFiles
+  , getFileState
   , resetIdeState
   , cacheRebuild
   , cachedRebuild
@@ -114,12 +115,12 @@
 -- | Checks if the given ModuleName matches the last rebuild cache and if it
 -- does returns all loaded definitions + the definitions inside the rebuild
 -- cache
-getAllModules :: Ide m => Maybe P.ModuleName -> m [(P.ModuleName, [IdeDeclarationAnn])]
+getAllModules :: Ide m => Maybe P.ModuleName -> m (ModuleMap [IdeDeclarationAnn])
 getAllModules mmoduleName = do
   declarations <- vsDeclarations <$> getVolatileState
   rebuild <- cachedRebuild
   case mmoduleName of
-    Nothing -> pure (Map.toList declarations)
+    Nothing -> pure declarations
     Just moduleName ->
       case rebuild of
         Just (cachedModulename, ef)
@@ -135,8 +136,8 @@
                 resolved =
                   Map.adjust (resolveOperatorsForModule tmp) moduleName tmp
 
-              pure (Map.toList resolved)
-        _ -> pure (Map.toList declarations)
+              pure resolved
+        _ -> pure declarations
 
 -- | Adds an ExternsFile into psc-ide's FileState. This does not populate the
 -- VolatileState, which needs to be done after all the necessary Externs and
diff --git a/src/Language/PureScript/Ide/Types.hs b/src/Language/PureScript/Ide/Types.hs
--- a/src/Language/PureScript/Ide/Types.hs
+++ b/src/Language/PureScript/Ide/Types.hs
@@ -224,8 +224,8 @@
 data Success =
   CompletionResult [Completion]
   | TextResult Text
+  | UsagesResult [P.SourceSpan]
   | MultilineTextResult [Text]
-  | PursuitResult [PursuitResponse]
   | ImportList (P.ModuleName, [(P.ModuleName, P.ImportDeclarationType, Maybe P.ModuleName)])
   | ModuleList [ModuleIdent]
   | RebuildSuccess P.MultipleErrors
@@ -238,8 +238,8 @@
 instance ToJSON Success where
   toJSON (CompletionResult cs) = encodeSuccess cs
   toJSON (TextResult t) = encodeSuccess t
+  toJSON (UsagesResult ssp) = encodeSuccess ssp
   toJSON (MultilineTextResult ts) = encodeSuccess ts
-  toJSON (PursuitResult resp) = encodeSuccess resp
   toJSON (ImportList (moduleName, imports)) = object [ "resultType" .= ("success" :: Text)
                                                      , "result" .= object [ "imports" .= map encodeImport imports
                                                                           , "moduleName" .= P.runModuleName moduleName]]
@@ -262,61 +262,6 @@
              , "importType" .= ("hiding" :: Text)
              , "identifiers" .= (identifierFromDeclarationRef <$> refs)
              ] ++ map (\x -> "qualifier" .= x) (maybeToList qualifier)
-
-newtype PursuitQuery = PursuitQuery Text
-                     deriving (Show, Eq)
-
-data PursuitSearchType = Package | Identifier
-                       deriving (Show, Eq)
-
-instance FromJSON PursuitSearchType where
-  parseJSON (String t) = case t of
-    "package"    -> pure Package
-    "completion" -> pure Identifier
-    _            -> mzero
-  parseJSON _ = mzero
-
-instance FromJSON PursuitQuery where
-  parseJSON o = PursuitQuery <$> parseJSON o
-
-data PursuitResponse =
-  -- | A Pursuit Response for a module. Consists of the modules name and the
-  -- package it belongs to
-  ModuleResponse ModuleIdent Text
-  -- | A Pursuit Response for a declaration. Consist of the declaration's
-  -- module, name, package, type summary text
-  | DeclarationResponse Text ModuleIdent Text (Maybe Text) Text
-  deriving (Show,Eq)
-
-instance FromJSON PursuitResponse where
-  parseJSON (Object o) = do
-    package <- o .: "package"
-    info <- o .: "info"
-    (type' :: Text) <- info .: "type"
-    case type' of
-      "module" -> do
-        name <- info .: "module"
-        pure (ModuleResponse name package)
-      "declaration" -> do
-        moduleName <- info .: "module"
-        ident <- info .: "title"
-        (text :: Text) <- o .: "text"
-        typ <- info .:? "typeText"
-        pure (DeclarationResponse moduleName ident package typ text)
-      _ -> mzero
-  parseJSON _ = mzero
-
-instance ToJSON PursuitResponse where
-  toJSON (ModuleResponse name package) =
-    object ["module" .= name, "package" .= package]
-  toJSON (DeclarationResponse module' ident package type' text) =
-    object
-      [ "module"  .= module'
-      , "ident"   .= ident
-      , "type"    .= type'
-      , "package" .= package
-      , "text"    .= text
-      ]
 
 -- | Denotes the different namespaces a name in PureScript can reside in.
 data IdeNamespace = IdeNSValue | IdeNSType | IdeNSKind
diff --git a/src/Language/PureScript/Ide/Usage.hs b/src/Language/PureScript/Ide/Usage.hs
new file mode 100644
--- /dev/null
+++ b/src/Language/PureScript/Ide/Usage.hs
@@ -0,0 +1,161 @@
+module Language.PureScript.Ide.Usage
+  ( findReexportingModules
+  , directDependants
+  , eligibleModules
+  , applySearch
+  , findUsages
+  ) where
+
+import           Protolude hiding (moduleName)
+
+import           Control.Lens (preview)
+import qualified Data.Map as Map
+import qualified Data.Set as Set
+import qualified Language.PureScript as P
+import           Language.PureScript.Ide.State (getAllModules, getFileState)
+import           Language.PureScript.Ide.Types
+import           Language.PureScript.Ide.Util
+
+-- |
+-- How we find usages, given an IdeDeclaration and the module it was defined in:
+--
+-- 1. Find all modules that reexport the given declaration
+-- 2. Find all modules that import from those modules, and while traversing the
+-- imports build a specification for how the identifier can be found in the
+-- module.
+-- 3. Apply the collected search specifications and collect the results
+findUsages
+  :: (MonadIO m, Ide m)
+  => IdeDeclaration
+  -> P.ModuleName
+  -> m (ModuleMap (NonEmpty P.SourceSpan))
+findUsages declaration moduleName = do
+  ms <- getAllModules Nothing
+  asts <- Map.map fst . fsModules <$> getFileState
+  let elig = eligibleModules (moduleName, declaration) ms asts
+  pure
+    $ Map.mapMaybe nonEmpty
+    $ Map.mapWithKey (\mn searches ->
+        foldMap (\m -> foldMap (applySearch m) searches) (Map.lookup mn asts)) elig
+
+-- | A declaration can either be imported qualified, or unqualified. All the
+-- information we need to find usages through a Traversal is thus captured in
+-- the `Search` type.
+type Search = P.Qualified IdeDeclaration
+
+findReexportingModules
+  :: (P.ModuleName, IdeDeclaration)
+  -- ^ The declaration and the module it is defined in for which we are
+  -- searching usages
+  -> ModuleMap [IdeDeclarationAnn]
+  -- ^ Our declaration cache. Needs to have reexports resolved
+  -> [P.ModuleName]
+  -- ^ All the modules that reexport the declaration. This does NOT include
+  -- the defining module
+findReexportingModules (moduleName, declaration) decls =
+  Map.keys (Map.filter (any hasReexport) decls)
+  where
+    hasReexport d =
+      (d & _idaDeclaration & identifierFromIdeDeclaration) == identifierFromIdeDeclaration declaration
+      && (d & _idaAnnotation & _annExportedFrom) == Just moduleName
+      && (d & _idaDeclaration & namespaceForDeclaration) == namespaceForDeclaration declaration
+
+directDependants :: IdeDeclaration -> ModuleMap P.Module -> P.ModuleName -> ModuleMap (NonEmpty Search)
+directDependants declaration modules mn = Map.mapMaybe (nonEmpty . go) modules
+  where
+    go :: P.Module -> [Search]
+    go = foldMap isImporting . P.getModuleDeclarations
+
+    isImporting d = case d of
+      P.ImportDeclaration _ mn' it qual | mn == mn' -> P.Qualified qual <$> case it of
+        P.Implicit -> pure declaration
+        P.Explicit refs
+          | any (declaration `matchesRef`) refs -> pure declaration
+        P.Explicit _ -> []
+        P.Hiding refs
+          | not (any (declaration `matchesRef`) refs) -> pure declaration
+        P.Hiding _ -> []
+      _ -> []
+
+-- | Determines whether an IdeDeclaration is referenced by a DeclarationRef.
+--
+-- TODO(Christoph): We should also extract the spans of matching refs here,
+-- since they also count as a usage (at least for rename refactorings)
+matchesRef :: IdeDeclaration -> P.DeclarationRef -> Bool
+matchesRef declaration ref = case declaration of
+  IdeDeclValue valueDecl -> case ref of
+    P.ValueRef _ i -> i == _ideValueIdent valueDecl
+    _ -> False
+  IdeDeclType typeDecl -> case ref of
+    P.TypeRef _ tn _ -> tn == _ideTypeName typeDecl
+    _ -> False
+  IdeDeclTypeSynonym synonym -> case ref of
+    P.TypeRef _ tn _ -> tn == _ideSynonymName synonym
+    _ -> False
+  IdeDeclDataConstructor dtor -> case ref of
+    P.TypeRef _ tn dtors
+    -- We check if the given data constructor constructs the type imported
+    -- here.
+    -- This way we match `Just` with an import like `import Data.Maybe (Maybe(..))`
+      | _ideDtorTypeName dtor == tn ->
+          maybe True (elem (_ideDtorName dtor)) dtors
+    _ -> False
+  IdeDeclTypeClass typeClass -> case ref of
+    P.TypeClassRef _ name -> name == _ideTCName typeClass
+    _ -> False
+  IdeDeclValueOperator valueOperator -> case ref of
+    P.ValueOpRef _ opName -> opName == _ideValueOpName valueOperator
+    _ -> False
+  IdeDeclTypeOperator typeOperator -> case ref of
+    P.TypeOpRef _ opName -> opName == _ideTypeOpName typeOperator
+    _ -> False
+  IdeDeclKind kind -> case ref of
+    P.KindRef _ kindName -> kindName == kind
+    _ -> False
+
+eligibleModules
+  :: (P.ModuleName, IdeDeclaration)
+  -> ModuleMap [IdeDeclarationAnn]
+  -> ModuleMap P.Module
+  -> ModuleMap (NonEmpty Search)
+eligibleModules query@(moduleName, declaration) decls modules =
+  let
+    searchDefiningModule = P.Qualified Nothing declaration :| []
+  in
+    Map.insert moduleName searchDefiningModule $
+      foldMap (directDependants declaration modules) (moduleName :| findReexportingModules query decls)
+
+-- | Finds all usages for a given `Search` throughout a module
+applySearch :: P.Module -> Search -> [P.SourceSpan]
+applySearch module_ search =
+  foldMap findUsageInDeclaration decls
+  where
+    decls = P.getModuleDeclarations module_
+    findUsageInDeclaration =
+      let
+        (extr, _, _, _, _) = P.everythingWithScope mempty goExpr goBinder mempty mempty
+      in
+        extr mempty
+
+    goExpr scope expr = case expr of
+      P.Var sp i
+        | Just ideValue <- preview _IdeDeclValue (P.disqualify search)
+        , P.isQualified search
+          || not (P.LocalIdent (_ideValueIdent ideValue) `Set.member` scope) ->
+          [sp | map P.runIdent i == map identifierFromIdeDeclaration search]
+      P.Constructor sp name
+        | Just ideDtor <- traverse (preview _IdeDeclDataConstructor) search ->
+          [sp | name == map _ideDtorName ideDtor]
+      P.Op sp opName
+        | Just ideOp <- traverse (preview _IdeDeclValueOperator) search ->
+          [sp | opName == map _ideValueOpName ideOp]
+      _ -> []
+
+    goBinder _ binder = case binder of
+      P.ConstructorBinder sp ctorName _
+        | Just ideDtor <- traverse (preview _IdeDeclDataConstructor) search ->
+          [sp | ctorName == map _ideDtorName ideDtor]
+      P.OpBinder sp opName
+        | Just op <- traverse (preview _IdeDeclValueOperator) search ->
+          [sp | opName == map _ideValueOpName op]
+      _ -> []
diff --git a/src/Language/PureScript/Ide/Util.hs b/src/Language/PureScript/Ide/Util.hs
--- a/src/Language/PureScript/Ide/Util.hs
+++ b/src/Language/PureScript/Ide/Util.hs
@@ -34,7 +34,6 @@
 
 import           Control.Lens                        hiding ((&), op)
 import           Data.Aeson
-import qualified Data.Text                           as T
 import qualified Data.Text.Lazy                      as TL
 import           Data.Text.Lazy.Encoding             as TLE
 import qualified Language.PureScript                 as P
@@ -42,6 +41,7 @@
 import           Language.PureScript.Ide.Logging
 import           Language.PureScript.Ide.Types
 import           System.IO.UTF8                      (readUTF8FileT)
+import           System.Directory                    (makeAbsolute)
 
 identifierFromIdeDeclaration :: IdeDeclaration -> Text
 identifierFromIdeDeclaration d = case d of
@@ -103,13 +103,22 @@
   :: (MonadIO m, MonadError IdeError m)
   => (FilePath -> IO Text)
   -> FilePath
-  -> m Text
+  -> m (FilePath, Text)
 ideReadFile' fileReader fp = do
-  contents :: Either IOException Text <- liftIO (try (fileReader fp))
-  either
-    (\_ -> throwError (GeneralError ("Couldn't find file at: " <> T.pack fp)))
-    pure
-    contents
+  absPath <- liftIO (try (makeAbsolute fp)) >>= \case
+    Left (err :: IOException) ->
+      throwError
+        (GeneralError
+          ("Couldn't resolve path for: " <> show fp <> ", Error: " <> show err))
+    Right absPath -> pure absPath
+  contents <- liftIO (try (fileReader absPath)) >>= \case
+    Left (err :: IOException) ->
+      throwError
+        (GeneralError
+          ("Couldn't find file at: " <> show absPath <> ", Error: " <> show err))
+    Right contents ->
+      pure contents
+  pure (absPath, contents)
 
-ideReadFile :: (MonadIO m, MonadError IdeError m) => FilePath -> m Text
+ideReadFile :: (MonadIO m, MonadError IdeError m) => FilePath -> m (FilePath, Text)
 ideReadFile = ideReadFile' readUTF8FileT
diff --git a/src/Language/PureScript/Interactive.hs b/src/Language/PureScript/Interactive.hs
--- a/src/Language/PureScript/Interactive.hs
+++ b/src/Language/PureScript/Interactive.hs
@@ -14,9 +14,10 @@
 import           Protolude (ordNub)
 
 import           Data.List (sort, find, foldl')
-import           Data.Maybe (mapMaybe)
+import           Data.Maybe (fromMaybe, mapMaybe)
 import qualified Data.Map as M
 import           Data.Monoid ((<>))
+import qualified Data.Set as S
 import           Data.Text (Text)
 import qualified Data.Text as T
 
@@ -29,6 +30,7 @@
 
 import qualified Language.PureScript as P
 import qualified Language.PureScript.Names as N
+import qualified Language.PureScript.Constants as C
 
 import           Language.PureScript.Interactive.Completion   as Interactive
 import           Language.PureScript.Interactive.IO           as Interactive
@@ -167,7 +169,7 @@
   -> m ()
 handleDecls ds = do
   st <- gets (updateLets (++ ds))
-  let m = createTemporaryModule False st (P.Literal (P.ObjectLiteral []))
+  let m = createTemporaryModule False st (P.Literal P.nullSourceSpan (P.ObjectLiteral []))
   e <- liftIO . runMake $ rebuild (map snd (psciLoadedExterns st)) m
   case e of
     Left err -> printErrors err
@@ -190,9 +192,8 @@
   => (String -> m ())
   -> m ()
 handleShowImportedModules print' = do
-  PSCiState { psciImportedModules = importedModules } <- get
+  importedModules <- psciImportedModules <$> get
   print' $ showModules importedModules
-  return ()
   where
   showModules = unlines . sort . map (T.unpack . showModule)
   showModule (mn, declType, asQ) =
@@ -292,22 +293,20 @@
 handleBrowse print' moduleName = do
   st <- get
   env <- asks psciEnvironment
-  if isModInEnv moduleName st
-    then print' $ printModuleSignatures moduleName env
-    else case lookupUnQualifiedModName moduleName st of
-      Just unQualifiedName ->
-        if isModInEnv unQualifiedName st
-          then print' $ printModuleSignatures unQualifiedName env
-          else failNotInEnv moduleName
-      Nothing ->
-        failNotInEnv moduleName
+  case findMod moduleName (psciLoadedExterns st) (psciImportedModules st) of
+    Just qualName -> print' $ printModuleSignatures qualName env
+    Nothing       -> failNotInEnv moduleName
   where
-    isModInEnv modName =
-        any ((== modName) . P.getModuleName . fst) . psciLoadedExterns
-    failNotInEnv modName =
-        print' $ T.unpack $ "Module '" <> N.runModuleName modName <> "' is not valid."
-    lookupUnQualifiedModName quaModName st =
-        (\(modName,_,_) -> modName) <$> find ( \(_, _, mayQuaName) -> mayQuaName == Just quaModName) (psciImportedModules st)
+    findMod needle externs imports =
+      let qualMod = fromMaybe needle (lookupUnQualifiedModName needle imports)
+          modules = S.fromList (C.primModules <> (P.getModuleName . fst <$> externs))
+      in if qualMod `S.member` modules
+           then Just qualMod
+           else Nothing
+
+    failNotInEnv modName = print' $ T.unpack $ "Module '" <> N.runModuleName modName <> "' is not valid."
+    lookupUnQualifiedModName needle imports =
+        (\(modName,_,_) -> modName) <$> find (\(_,_,mayQuaName) -> mayQuaName == Just needle) imports
 
 -- | Return output as would be returned by tab completion, for tools integration etc.
 handleComplete
diff --git a/src/Language/PureScript/Interactive/Completion.hs b/src/Language/PureScript/Interactive/Completion.hs
--- a/src/Language/PureScript/Interactive/Completion.hs
+++ b/src/Language/PureScript/Interactive/Completion.hs
@@ -9,19 +9,16 @@
 import Prelude.Compat
 import Protolude (ordNub)
 
-import           Control.Arrow (second)
 import           Control.Monad.IO.Class (MonadIO(..))
 import           Control.Monad.State.Class (MonadState(..))
 import           Control.Monad.Trans.Reader (asks, runReaderT, ReaderT)
-import           Data.Function (on)
-import           Data.List (nubBy, isPrefixOf, sortBy, stripPrefix)
+import           Data.List (nub, isPrefixOf, isInfixOf, isSuffixOf, sortBy, stripPrefix)
+import           Data.Map (keys)
 import           Data.Maybe (mapMaybe)
-import           Data.Text (Text)
 import qualified Data.Text as T
 import qualified Language.PureScript as P
 import qualified Language.PureScript.Interactive.Directive as D
 import           Language.PureScript.Interactive.Types
-import qualified Language.PureScript.Names as N
 import           System.Console.Haskeline
 
 -- Completions may read the state, but not modify it.
@@ -45,7 +42,7 @@
 completion = liftCompletionM . completion'
 
 completion' :: CompletionFunc CompletionM
-completion' = completeWordWithPrev Nothing " \t\n\r" findCompletions
+completion' = completeWordWithPrev Nothing " \t\n\r([" findCompletions
 
 -- | Callback for Haskeline's `completeWordWithPrev`.
 -- Expects:
@@ -66,7 +63,7 @@
         CtxFilePath f        -> map Right <$> listFiles f
         CtxModule            -> map Left <$> getModuleNames
         CtxIdentifier        -> map Left <$> ((++) <$> getIdentNames <*> getDctorNames)
-        CtxType              -> map Left <$> getTypeNames
+        CtxType pre          -> map (Left . (pre ++)) <$> getTypeNames
         CtxFixed str         -> return [Left str]
         CtxDirective d       -> return (map Left (completeDirectives d))
 
@@ -99,7 +96,7 @@
   | CtxFilePath String
   | CtxModule
   | CtxIdentifier
-  | CtxType
+  | CtxType String
   | CtxFixed String
   deriving (Show)
 
@@ -108,36 +105,36 @@
 -- a list of complete words (to the left of the cursor) as the first argument,
 -- and the current word as the second argument.
 completionContext :: [String] -> String -> [CompletionContext]
+completionContext _ w  | "::" `isInfixOf` w = [CtxType (w `endingWith` "::")]
+completionContext ws _ | lastSatisfies ("::" `isSuffixOf`) ws = [CtxType ""]
 completionContext [] _ = [CtxDirective "", CtxIdentifier, CtxFixed "import"]
 completionContext ws w | headSatisfies (":" `isPrefixOf`) ws = completeDirective ws w
 completionContext ws w | headSatisfies (== "import") ws = completeImport ws w
 completionContext _ _ = [CtxIdentifier]
 
+endingWith :: String -> String -> String
+endingWith str stop = aux "" str
+  where
+  aux acc s@(x:xs)
+    | stop `isPrefixOf` s = reverse (stop ++ acc)
+    | otherwise           = aux (x:acc) xs
+  aux acc []              = reverse (stop ++ acc)
+
 completeDirective :: [String] -> String -> [CompletionContext]
 completeDirective ws w =
   case ws of
-    []    -> [CtxDirective w]
-    [dir] -> case D.directivesFor <$> stripPrefix ":" dir of
-                -- only offer completions if the directive is unambiguous
-                Just [dir'] -> directiveArg w dir'
-                _           -> []
-
-    -- All directives take exactly one argument. If we haven't yet matched,
-    -- that means one argument has already been supplied. So don't complete
-    -- any others.
-    _     -> []
+    []     -> [CtxDirective w]
+    (x:xs) -> case D.directivesFor <$> stripPrefix ":" x of
+                 -- only offer completions if the directive is unambiguous
+                 Just [dir] -> directiveArg xs dir
+                 _          -> []
 
-directiveArg :: String -> Directive -> [CompletionContext]
-directiveArg _ Browse      = [CtxModule]
-directiveArg _ Quit        = []
-directiveArg _ Reload      = []
-directiveArg _ Clear       = []
-directiveArg _ Help        = []
-directiveArg _ Paste       = []
-directiveArg _ Show        = map CtxFixed replQueryStrings
-directiveArg _ Type        = [CtxIdentifier]
-directiveArg _ Kind        = [CtxType]
-directiveArg _ Complete    = []
+directiveArg :: [String] -> Directive -> [CompletionContext]
+directiveArg [] Browse = [CtxModule]                    -- only complete very next term
+directiveArg [] Show   = map CtxFixed replQueryStrings  -- only complete very next term
+directiveArg _ Type    = [CtxIdentifier]
+directiveArg _ Kind    = [CtxType ""]
+directiveArg _ _       = []
 
 completeImport :: [String] -> String -> [CompletionContext]
 completeImport ws w' =
@@ -151,82 +148,46 @@
     (c:_)  -> p c
     _     -> False
 
+lastSatisfies :: (a -> Bool) -> [a] -> Bool
+lastSatisfies _ [] = False
+lastSatisfies p xs = p (last xs)
+
 getLoadedModules :: CompletionM [P.Module]
 getLoadedModules = asks (map fst . psciLoadedExterns)
 
 getModuleNames :: CompletionM [String]
 getModuleNames = moduleNames <$> getLoadedModules
 
-mapLoadedModulesAndQualify :: (a -> Text) -> (P.Module -> [(a, P.Declaration)]) -> CompletionM [String]
-mapLoadedModulesAndQualify sho f = do
-  ms <- getLoadedModules
-  let argPairs = do m <- ms
-                    fm <- f m
-                    return (m, fm)
-  concat <$> traverse (uncurry (getAllQualifications sho)) argPairs
-
 getIdentNames :: CompletionM [String]
-getIdentNames = mapLoadedModulesAndQualify P.showIdent identNames
-
-getDctorNames :: CompletionM [String]
-getDctorNames = mapLoadedModulesAndQualify P.runProperName dctorNames
-
-getTypeNames :: CompletionM [String]
-getTypeNames = mapLoadedModulesAndQualify P.runProperName typeDecls
-
--- | Given a module and a declaration in that module, return all possible ways
--- it could have been referenced given the current PSCiState - including fully
--- qualified, qualified using an alias, and unqualified.
-getAllQualifications :: (a -> Text) -> P.Module -> (a, P.Declaration) -> CompletionM [String]
-getAllQualifications sho m (declName, decl) = do
-  imports <- getAllImportsOf m
-  let fullyQualified = qualifyWith (Just (P.getModuleName m))
-  let otherQuals = ordNub (concatMap qualificationsUsing imports)
-  return $ fullyQualified : otherQuals
-  where
-  qualifyWith mMod = T.unpack (P.showQualified sho (P.Qualified mMod declName))
-  referencedBy refs = P.isExported (Just refs) decl
-
-  qualificationsUsing (_, importType, asQ') =
-    let q = qualifyWith asQ'
-    in case importType of
-          P.Implicit      -> [q]
-          P.Explicit refs -> [q | referencedBy refs]
-          P.Hiding refs   -> [q | not $ referencedBy refs]
+getIdentNames = do
+  importedVals <- asks (keys . P.importedValues . psciImports)
+  exportedVals <- asks (keys . P.exportedValues . psciExports)
 
+  importedValOps <- asks (keys . P.importedValueOps . psciImports)
+  exportedValOps <- asks (keys . P.exportedValueOps . psciExports)
 
--- | Returns all the ImportedModule values referring to imports of a particular
--- module.
-getAllImportsOf :: P.Module -> CompletionM [ImportedModule]
-getAllImportsOf = asks . allImportsOf
+  return . nub $ map (T.unpack . P.showQualified P.showIdent) importedVals
+              ++ map (T.unpack . P.showQualified P.runOpName) importedValOps
+              ++ map (T.unpack . P.showIdent) exportedVals
+              ++ map (T.unpack . P.runOpName) exportedValOps
 
-nubOnFst :: Eq a => [(a, b)] -> [(a, b)]
-nubOnFst = nubBy ((==) `on` fst)
+getDctorNames :: CompletionM [String]
+getDctorNames = do
+  imports <- asks (keys . P.importedDataConstructors . psciImports)
+  return . nub $ map (T.unpack . P.showQualified P.runProperName) imports
 
-typeDecls :: P.Module -> [(N.ProperName 'N.TypeName, P.Declaration)]
-typeDecls = mapMaybe getTypeName . filter P.isDataDecl . P.exportedDeclarations
-  where
-  getTypeName :: P.Declaration -> Maybe (N.ProperName 'N.TypeName, P.Declaration)
-  getTypeName d@(P.TypeSynonymDeclaration _ name _ _) = Just (name, d)
-  getTypeName d@(P.DataDeclaration _ _ name _ _) = Just (name, d)
-  getTypeName _ = Nothing
+getTypeNames :: CompletionM [String]
+getTypeNames = do
+  importedTypes <- asks (keys . P.importedTypes . psciImports)
+  exportedTypes <- asks (keys . P.exportedTypes . psciExports)
 
-identNames :: P.Module -> [(N.Ident, P.Declaration)]
-identNames = nubOnFst . concatMap getDeclNames . P.exportedDeclarations
-  where
-  getDeclNames :: P.Declaration -> [(P.Ident, P.Declaration)]
-  getDeclNames d@(P.ValueDecl _ ident _ _ _)  = [(ident, d)]
-  getDeclNames d@(P.TypeDeclaration td) = [(P.tydeclIdent td, d)]
-  getDeclNames d@(P.ExternDeclaration _ ident _) = [(ident, d)]
-  getDeclNames d@(P.TypeClassDeclaration _ _ _ _ _ ds) = map (second (const d)) $ concatMap getDeclNames ds
-  getDeclNames _ = []
+  importedTypeOps <- asks (keys . P.importedTypeOps . psciImports)
+  exportedTypeOps <- asks (keys . P.exportedTypeOps . psciExports)
 
-dctorNames :: P.Module -> [(N.ProperName 'N.ConstructorName, P.Declaration)]
-dctorNames = nubOnFst . concatMap go . P.exportedDeclarations
-  where
-  go :: P.Declaration -> [(N.ProperName 'N.ConstructorName, P.Declaration)]
-  go decl@(P.DataDeclaration _ _ _ _ ctors) = map ((\n -> (n, decl)) . fst) ctors
-  go _ = []
+  return . nub $ map (T.unpack . P.showQualified P.runProperName) importedTypes
+              ++ map (T.unpack . P.showQualified P.runOpName) importedTypeOps
+              ++ map (T.unpack . P.runProperName) exportedTypes
+              ++ map (T.unpack . P.runOpName) exportedTypeOps
 
 moduleNames :: [P.Module] -> [String]
 moduleNames = ordNub . map (T.unpack . P.runModuleName . P.getModuleName)
diff --git a/src/Language/PureScript/Interactive/Module.hs b/src/Language/PureScript/Interactive/Module.hs
--- a/src/Language/PureScript/Interactive/Module.hs
+++ b/src/Language/PureScript/Interactive/Module.hs
@@ -43,22 +43,22 @@
 -- Makes a volatile module to execute the current expression.
 --
 createTemporaryModule :: Bool -> PSCiState -> P.Expr -> P.Module
-createTemporaryModule exec PSCiState{psciImportedModules = imports, psciLetBindings = lets} val =
+createTemporaryModule exec st val =
   let
+    imports       = psciImportedModules st
+    lets          = psciLetBindings st
     moduleName    = P.ModuleName [P.ProperName "$PSCI"]
-    effModuleName = P.moduleNameFromString "Control.Monad.Eff"
-    effImport     = (effModuleName, P.Implicit, Just (P.ModuleName [P.ProperName "$Eff"]))
+    effModuleName = P.moduleNameFromString "Effect"
+    effImport     = (effModuleName, P.Implicit, Just (P.ModuleName [P.ProperName "$Effect"]))
     supportImport = (supportModuleName, P.Implicit, Just (P.ModuleName [P.ProperName "$Support"]))
-    eval          = P.Var (P.Qualified (Just (P.ModuleName [P.ProperName "$Support"])) (P.Ident "eval"))
-    mainValue     = P.App eval (P.Var (P.Qualified Nothing (P.Ident "it")))
+    eval          = P.Var internalSpan (P.Qualified (Just (P.ModuleName [P.ProperName "$Support"])) (P.Ident "eval"))
+    mainValue     = P.App eval (P.Var internalSpan (P.Qualified Nothing (P.Ident "it")))
     itDecl        = P.ValueDecl (internalSpan, []) (P.Ident "it") P.Public [] [P.MkUnguarded val]
     typeDecl      = P.TypeDeclaration
                       (P.TypeDeclarationData (internalSpan, []) (P.Ident "$main")
                         (P.TypeApp
-                          (P.TypeApp
-                            (P.TypeConstructor
-                              (P.Qualified (Just (P.ModuleName [P.ProperName "$Eff"])) (P.ProperName "Eff")))
-                                (P.TypeWildcard internalSpan))
+                          (P.TypeConstructor
+                            (P.Qualified (Just (P.ModuleName [P.ProperName "$Effect"])) (P.ProperName "Effect")))
                                   (P.TypeWildcard internalSpan)))
     mainDecl      = P.ValueDecl (internalSpan, []) (P.Ident "$main") P.Public [] [P.MkUnguarded mainValue]
     decls         = if exec then [itDecl, typeDecl, mainDecl] else [itDecl]
@@ -73,10 +73,12 @@
 -- Makes a volatile module to hold a non-qualified type synonym for a fully-qualified data type declaration.
 --
 createTemporaryModuleForKind :: PSCiState -> P.Type -> P.Module
-createTemporaryModuleForKind PSCiState{psciImportedModules = imports, psciLetBindings = lets} typ =
+createTemporaryModuleForKind st typ =
   let
+    imports    = psciImportedModules st
+    lets       = psciLetBindings st
     moduleName = P.ModuleName [P.ProperName "$PSCI"]
-    itDecl = P.TypeSynonymDeclaration (internalSpan, []) (P.ProperName "IT") [] typ
+    itDecl     = P.TypeSynonymDeclaration (internalSpan, []) (P.ProperName "IT") [] typ
   in
     P.Module internalSpan [] moduleName ((importDecl `map` imports) ++ lets ++ [itDecl]) Nothing
 
@@ -84,8 +86,9 @@
 -- Makes a volatile module to execute the current imports.
 --
 createTemporaryModuleForImports :: PSCiState -> P.Module
-createTemporaryModuleForImports PSCiState{psciImportedModules = imports} =
+createTemporaryModuleForImports st =
   let
+    imports    = psciImportedModules st
     moduleName = P.ModuleName [P.ProperName "$PSCI"]
   in
     P.Module internalSpan [] moduleName (importDecl `map` imports) Nothing
diff --git a/src/Language/PureScript/Interactive/Parser.hs b/src/Language/PureScript/Interactive/Parser.hs
--- a/src/Language/PureScript/Interactive/Parser.hs
+++ b/src/Language/PureScript/Interactive/Parser.hs
@@ -2,11 +2,14 @@
 -- Parser for PSCI.
 --
 module Language.PureScript.Interactive.Parser
-  ( parseCommand
+  ( parseDotFile
+  , parseCommand
   ) where
 
 import           Prelude.Compat hiding (lex)
 
+import           Control.Applicative ((<|>))
+import           Control.Monad (join)
 import           Data.Bifunctor (first)
 import           Data.Char (isSpace)
 import           Data.List (intercalate)
@@ -18,6 +21,16 @@
 import           Language.PureScript.Parser.Common (mark, same)
 
 -- |
+-- Parses a limited set of commands from from .purs-repl
+--
+parseDotFile :: FilePath -> String -> Either String [Command]
+parseDotFile filePath s = first show $ do
+  ts <- P.lex filePath (T.pack s)
+  P.runTokenParser filePath (many parser <* eof) ts
+  where
+  parser  = psciImport <|> fail "The .purs-repl file only supports import declarations"
+
+-- |
 -- Parses PSCI metacommands or expressions input from the user.
 --
 parseCommand :: String -> Either String Command
@@ -71,6 +84,7 @@
     Type     -> TypeOf <$> parseRest P.parseValue arg
     Kind     -> KindOf <$> parseRest P.parseType arg
     Complete -> return (CompleteStr arg)
+
 -- |
 -- Parses expressions entered at the PSCI repl.
 --
@@ -87,11 +101,12 @@
 -- | Any declaration that we don't need a 'special case' parser for
 -- (like import declarations).
 psciDeclaration :: P.TokenParser Command
-psciDeclaration = fmap Decls $ mark $ many1 $ same *> do
-  decl <- P.parseDeclaration
-  if acceptable decl
-    then return decl
-    else fail "this kind of declaration is not supported in psci"
+psciDeclaration = fmap Decls $ mark $ fmap join (many1 $ same *>
+  (traverse accept =<< P.parseDeclaration))
+  where
+  accept decl
+    | acceptable decl = return decl
+    | otherwise = fail "this kind of declaration is not supported in psci"
 
 acceptable :: P.Declaration -> Bool
 acceptable P.DataDeclaration{} = True
diff --git a/src/Language/PureScript/Interactive/Types.hs b/src/Language/PureScript/Interactive/Types.hs
--- a/src/Language/PureScript/Interactive/Types.hs
+++ b/src/Language/PureScript/Interactive/Types.hs
@@ -1,12 +1,39 @@
 -- |
 -- Type declarations and associated basic functions for PSCI.
 --
-module Language.PureScript.Interactive.Types where
+module Language.PureScript.Interactive.Types
+  ( PSCiConfig(..)
+  , PSCiState -- constructor is not exported, to prevent psciImports and psciExports from
+              -- becoming inconsistent with importedModules, letBindings and loadedExterns
+  , ImportedModule
+  , psciExports
+  , psciImports
+  , psciLoadedExterns
+  , psciImportedModules
+  , psciLetBindings
+  , initialPSCiState
+  , psciImportedModuleNames
+  , updateImportedModules
+  , updateLoadedExterns
+  , updateLets
+  , Command(..)
+  , ReplQuery(..)
+  , replQueries
+  , replQueryStrings
+  , showReplQuery
+  , parseReplQuery
+  , Directive(..)
+  ) where
 
 import Prelude.Compat
 
 import qualified Language.PureScript as P
+import qualified Data.Map as M
+import           Language.PureScript.Sugar.Names.Env (nullImports, primExports)
+import           Control.Monad.Trans.Except (runExceptT)
+import           Control.Monad.Writer.Strict (runWriterT)
 
+
 -- | The PSCI configuration.
 --
 -- These configuration values do not change during execution.
@@ -19,16 +46,37 @@
 -- | The PSCI state.
 --
 -- Holds a list of imported modules, loaded files, and partial let bindings.
--- The let bindings are partial,
--- because it makes more sense to apply the binding to the final evaluated expression.
+-- The let bindings are partial, because it makes more sense to apply the
+-- binding to the final evaluated expression.
+--
+-- The last two fields are derived from the first three via updateImportExports
+-- each time a module is imported, a let binding is added, or the session is
+-- cleared or reloaded
 data PSCiState = PSCiState
-  { psciImportedModules     :: [ImportedModule]
-  , psciLetBindings         :: [P.Declaration]
-  , psciLoadedExterns       :: [(P.Module, P.ExternsFile)]
-  } deriving Show
+  [ImportedModule]
+  [P.Declaration]
+  [(P.Module, P.ExternsFile)]
+  P.Imports
+  P.Exports
+  deriving Show
 
+psciImportedModules :: PSCiState -> [ImportedModule]
+psciImportedModules (PSCiState x _ _ _ _) = x
+
+psciLetBindings :: PSCiState -> [P.Declaration]
+psciLetBindings (PSCiState _ x _ _ _) = x
+
+psciLoadedExterns :: PSCiState -> [(P.Module, P.ExternsFile)]
+psciLoadedExterns (PSCiState _ _ x _ _) = x
+
+psciImports :: PSCiState -> P.Imports
+psciImports (PSCiState _ _ _ x _) = x
+
+psciExports :: PSCiState -> P.Exports
+psciExports (PSCiState _ _ _ _ x) = x
+
 initialPSCiState :: PSCiState
-initialPSCiState = PSCiState [] [] []
+initialPSCiState = PSCiState [] [] [] nullImports primExports
 
 -- | All of the data that is contained by an ImportDeclaration in the AST.
 -- That is:
@@ -42,29 +90,59 @@
 type ImportedModule = (P.ModuleName, P.ImportDeclarationType, Maybe P.ModuleName)
 
 psciImportedModuleNames :: PSCiState -> [P.ModuleName]
-psciImportedModuleNames PSCiState{psciImportedModules = is} =
-  map (\(mn, _, _) -> mn) is
+psciImportedModuleNames st =
+  map (\(mn, _, _) -> mn) (psciImportedModules st)
 
-allImportsOf :: P.Module -> PSCiState -> [ImportedModule]
-allImportsOf m PSCiState{psciImportedModules = is} =
-  filter isImportOfThis is
+-- * State helpers
+
+-- This function updates the Imports and Exports values in the PSCiState, which are used for
+-- handling completions. This function must be called whenever the PSCiState is modified to
+-- ensure that completions remain accurate.
+updateImportExports :: PSCiState -> PSCiState
+updateImportExports st@(PSCiState modules lets externs _ _) =
+  case desugarModule [temporaryModule] of
+    Left _          -> st -- TODO: can this fail and what should we do?
+    Right (env, _)  ->
+      case M.lookup temporaryName env of
+        Just (_, is, es)  -> PSCiState modules lets externs is es
+        _                 -> st -- impossible
   where
-  name = P.getModuleName m
-  isImportOfThis (name', _, _) = name == name'
 
--- * State helpers
+  desugarModule :: [P.Module] -> Either P.MultipleErrors (P.Env, [P.Module])
+  desugarModule = runExceptT =<< hushWarnings . P.desugarImportsWithEnv (map snd externs)
+  hushWarnings  = fmap fst . runWriterT
 
+  temporaryName :: P.ModuleName
+  temporaryName = P.ModuleName [P.ProperName "$PSCI"]
+
+  temporaryModule :: P.Module
+  temporaryModule =
+    let
+      prim = (P.ModuleName [P.ProperName "Prim"], P.Implicit, Nothing)
+      decl = (importDecl `map` (prim : modules)) ++ lets
+    in
+      P.Module internalSpan [] temporaryName decl Nothing
+
+  importDecl :: ImportedModule -> P.Declaration
+  importDecl (mn, declType, asQ) = P.ImportDeclaration (internalSpan, []) mn declType asQ
+
+  internalSpan :: P.SourceSpan
+  internalSpan = P.internalModuleSourceSpan "<internal>"
+
 -- | Updates the imported modules in the state record.
 updateImportedModules :: ([ImportedModule] -> [ImportedModule]) -> PSCiState -> PSCiState
-updateImportedModules f st = st { psciImportedModules = f (psciImportedModules st) }
+updateImportedModules f (PSCiState x a b c d) =
+  updateImportExports (PSCiState (f x) a b c d)
 
 -- | Updates the loaded externs files in the state record.
 updateLoadedExterns :: ([(P.Module, P.ExternsFile)] -> [(P.Module, P.ExternsFile)]) -> PSCiState -> PSCiState
-updateLoadedExterns f st = st { psciLoadedExterns = f (psciLoadedExterns st) }
+updateLoadedExterns f (PSCiState a b x c d) =
+  PSCiState a b (f x) c d
 
 -- | Updates the let bindings in the state record.
 updateLets :: ([P.Declaration] -> [P.Declaration]) -> PSCiState -> PSCiState
-updateLets f st = st { psciLetBindings = f (psciLetBindings st) }
+updateLets f (PSCiState a x b c d) =
+  updateImportExports (PSCiState a (f x) b c d)
 
 -- * Commands
 
diff --git a/src/Language/PureScript/Kinds.hs b/src/Language/PureScript/Kinds.hs
--- a/src/Language/PureScript/Kinds.hs
+++ b/src/Language/PureScript/Kinds.hs
@@ -81,8 +81,8 @@
   primKind :: Text -> Kind
   primKind = NamedKind . primName
 
-  kindType = primKind "Type"
-  kindSymbol = primKind "Symbol"
+  kindType = primKind C.typ
+  kindSymbol = primKind C.symbol
 
 instance A.FromJSON Kind where
   parseJSON = toAesonParser id kindFromJSON
diff --git a/src/Language/PureScript/Linter.hs b/src/Language/PureScript/Linter.hs
--- a/src/Language/PureScript/Linter.hs
+++ b/src/Language/PureScript/Linter.hs
@@ -28,13 +28,13 @@
 lint :: forall m. (MonadWriter MultipleErrors m) => Module -> m ()
 lint (Module _ _ mn ds _) = censor (addHint (ErrorInModule mn)) $ mapM_ lintDeclaration ds
   where
-  moduleNames :: S.Set Ident
-  moduleNames = S.fromList (ordNub (mapMaybe getDeclIdent ds))
+  moduleNames :: S.Set ScopedIdent
+  moduleNames = S.fromList (map ToplevelIdent (mapMaybe getDeclIdent ds))
 
   getDeclIdent :: Declaration -> Maybe Ident
   getDeclIdent (ValueDeclaration vd) = Just (valdeclIdent vd)
   getDeclIdent (ExternDeclaration _ ident _) = Just ident
-  getDeclIdent (TypeInstanceDeclaration _ ident _ _ _ _) = Just ident
+  getDeclIdent (TypeInstanceDeclaration _ _ _ ident _ _ _ _) = Just ident
   getDeclIdent BindingGroupDeclaration{} = internalError "lint: binding groups should not be desugared yet."
   getDeclIdent _ = Nothing
 
@@ -48,54 +48,61 @@
     f dec = f' S.empty dec
 
     f' :: S.Set Text -> Declaration -> MultipleErrors
-    f' s dec@(ValueDeclaration vd) = addHint (ErrorInValueDeclaration (valdeclIdent vd)) (warningsInDecl moduleNames dec <> checkTypeVarsInDecl s dec)
-    f' s (TypeDeclaration td) = addHint (ErrorInTypeDeclaration (tydeclIdent td)) (checkTypeVars s (tydeclType td))
+    f' s dec@(ValueDeclaration vd) =
+      addHint (ErrorInValueDeclaration (valdeclIdent vd)) (warningsInDecl moduleNames dec <> checkTypeVarsInDecl s dec)
+    f' s (TypeDeclaration td@(TypeDeclarationData (ss, _) _ _)) =
+      addHint (ErrorInTypeDeclaration (tydeclIdent td)) (checkTypeVars ss s (tydeclType td))
     f' s dec = warningsInDecl moduleNames dec <> checkTypeVarsInDecl s dec
 
-    stepE :: S.Set Ident -> Expr -> MultipleErrors
-    stepE s (Abs (VarBinder name) _) | name `S.member` s = errorMessage (ShadowedName name)
-    stepE s (Let ds' _) = foldMap go ds'
+    stepE :: S.Set ScopedIdent -> Expr -> MultipleErrors
+    stepE s (Abs (VarBinder ss name) _) | name `inScope` s = errorMessage' ss (ShadowedName name)
+    stepE s (Let _ ds' _) = foldMap go ds'
       where
       go d | Just i <- getDeclIdent d
-           , i `S.member` s = errorMessage (ShadowedName i)
+           , inScope i s = errorMessage' (declSourceSpan d) (ShadowedName i)
            | otherwise = mempty
     stepE _ _ = mempty
 
-    stepB :: S.Set Ident -> Binder -> MultipleErrors
-    stepB s (VarBinder name) | name `S.member` s = errorMessage (ShadowedName name)
-    stepB s (NamedBinder name _) | name `S.member` s = errorMessage (ShadowedName name)
+    stepB :: S.Set ScopedIdent -> Binder -> MultipleErrors
+    stepB s (VarBinder ss name)
+      | name `inScope` s
+      = errorMessage' ss (ShadowedName name)
+    stepB s (NamedBinder ss name _)
+      | inScope name s
+      = errorMessage' ss (ShadowedName name)
     stepB _ _ = mempty
 
-    stepDo :: S.Set Ident -> DoNotationElement -> MultipleErrors
+    stepDo :: S.Set ScopedIdent -> DoNotationElement -> MultipleErrors
     stepDo s (DoNotationLet ds') = foldMap go ds'
       where
-      go d | Just i <- getDeclIdent d
-           , i `S.member` s = errorMessage (ShadowedName i)
-           | otherwise = mempty
+      go d
+        | Just i <- getDeclIdent d, i `inScope` s = errorMessage' (declSourceSpan d) (ShadowedName i)
+        | otherwise = mempty
     stepDo _ _ = mempty
 
   checkTypeVarsInDecl :: S.Set Text -> Declaration -> MultipleErrors
-  checkTypeVarsInDecl s d = let (f, _, _, _, _) = accumTypes (checkTypeVars s) in f d
+  checkTypeVarsInDecl s d = let (f, _, _, _, _) = accumTypes (checkTypeVars (declSourceSpan d) s) in f d
 
-  checkTypeVars :: S.Set Text -> Type -> MultipleErrors
-  checkTypeVars set ty = everythingWithContextOnTypes set mempty mappend step ty <> findUnused ty
+  checkTypeVars :: SourceSpan -> S.Set Text -> Type -> MultipleErrors
+  checkTypeVars ss set ty = everythingWithContextOnTypes set mempty mappend step ty <> findUnused ty
     where
     step :: S.Set Text -> Type -> (S.Set Text, MultipleErrors)
     step s (ForAll tv _ _) = bindVar s tv
     step s _ = (s, mempty)
     bindVar :: S.Set Text -> Text -> (S.Set Text, MultipleErrors)
-    bindVar = bind ShadowedTypeVar
+    bindVar = bind ss ShadowedTypeVar
     findUnused :: Type -> MultipleErrors
     findUnused ty' =
       let used = usedTypeVariables ty'
           declared = everythingOnTypes (++) go ty'
           unused = ordNub declared \\ ordNub used
-      in foldl (<>) mempty $ map (errorMessage . UnusedTypeVar) unused
+      in foldl (<>) mempty $ map (errorMessage' ss . UnusedTypeVar) unused
       where
       go :: Type -> [Text]
       go (ForAll tv _ _) = [tv]
       go _ = []
 
-  bind :: (Ord a) => (a -> SimpleErrorMessage) -> S.Set a -> a -> (S.Set a, MultipleErrors)
-  bind mkError s name | name `S.member` s = (s, errorMessage (mkError name))
-                      | otherwise = (S.insert name s, mempty)
+  bind :: (Ord a) => SourceSpan -> (a -> SimpleErrorMessage) -> S.Set a -> a -> (S.Set a, MultipleErrors)
+  bind ss mkError s name
+    | name `S.member` s = (s, errorMessage' ss (mkError name))
+    | otherwise = (S.insert name s, mempty)
diff --git a/src/Language/PureScript/Linter/Exhaustive.hs b/src/Language/PureScript/Linter/Exhaustive.hs
--- a/src/Language/PureScript/Linter/Exhaustive.hs
+++ b/src/Language/PureScript/Linter/Exhaustive.hs
@@ -115,23 +115,23 @@
 --
 missingCasesSingle :: Environment -> ModuleName -> Binder -> Binder -> ([Binder], Either RedundancyError Bool)
 missingCasesSingle _ _ _ NullBinder = ([], return True)
-missingCasesSingle _ _ _ (VarBinder _) = ([], return True)
-missingCasesSingle env mn (VarBinder _) b = missingCasesSingle env mn NullBinder b
-missingCasesSingle env mn br (NamedBinder _ bl) = missingCasesSingle env mn br bl
-missingCasesSingle env mn NullBinder cb@(ConstructorBinder con _) =
+missingCasesSingle _ _ _ (VarBinder _ _) = ([], return True)
+missingCasesSingle env mn (VarBinder _ _) b = missingCasesSingle env mn NullBinder b
+missingCasesSingle env mn br (NamedBinder _ _ bl) = missingCasesSingle env mn br bl
+missingCasesSingle env mn NullBinder cb@(ConstructorBinder ss con _) =
   (concatMap (\cp -> fst $ missingCasesSingle env mn cp cb) allPatterns, return True)
   where
-  allPatterns = map (\(p, t) -> ConstructorBinder (qualifyName p mn con) (initialize $ length t))
+  allPatterns = map (\(p, t) -> ConstructorBinder ss (qualifyName p mn con) (initialize $ length t))
                   $ getConstructors env mn con
-missingCasesSingle env mn cb@(ConstructorBinder con bs) (ConstructorBinder con' bs')
-  | con == con' = let (bs'', pr) = missingCasesMultiple env mn bs bs' in (map (ConstructorBinder con) bs'', pr)
+missingCasesSingle env mn cb@(ConstructorBinder ss con bs) (ConstructorBinder _ con' bs')
+  | con == con' = let (bs'', pr) = missingCasesMultiple env mn bs bs' in (map (ConstructorBinder ss con) bs'', pr)
   | otherwise = ([cb], return False)
-missingCasesSingle env mn NullBinder (LiteralBinder (ObjectLiteral bs)) =
-  (map (LiteralBinder . ObjectLiteral . zip (map fst bs)) allMisses, pr)
+missingCasesSingle env mn NullBinder (LiteralBinder ss (ObjectLiteral bs)) =
+  (map (LiteralBinder ss . ObjectLiteral . zip (map fst bs)) allMisses, pr)
   where
   (allMisses, pr) = missingCasesMultiple env mn (initialize $ length bs) (map snd bs)
-missingCasesSingle env mn (LiteralBinder (ObjectLiteral bs)) (LiteralBinder (ObjectLiteral bs')) =
-  (map (LiteralBinder . ObjectLiteral . zip sortedNames) allMisses, pr)
+missingCasesSingle env mn (LiteralBinder _ (ObjectLiteral bs)) (LiteralBinder ss (ObjectLiteral bs')) =
+  (map (LiteralBinder ss . ObjectLiteral . zip sortedNames) allMisses, pr)
   where
   (allMisses, pr) = uncurry (missingCasesMultiple env mn) (unzip binders)
 
@@ -148,10 +148,10 @@
   compBS e s b b' = (s, compB e b b')
 
   (sortedNames, binders) = unzip $ genericMerge (compBS NullBinder) sbs sbs'
-missingCasesSingle _ _ NullBinder (LiteralBinder (BooleanLiteral b)) = ([LiteralBinder . BooleanLiteral $ not b], return True)
-missingCasesSingle _ _ (LiteralBinder (BooleanLiteral bl)) (LiteralBinder (BooleanLiteral br))
+missingCasesSingle _ _ NullBinder (LiteralBinder ss (BooleanLiteral b)) = ([LiteralBinder ss . BooleanLiteral $ not b], return True)
+missingCasesSingle _ _ (LiteralBinder ss (BooleanLiteral bl)) (LiteralBinder _ (BooleanLiteral br))
   | bl == br = ([], return True)
-  | otherwise = ([LiteralBinder $ BooleanLiteral bl], return False)
+  | otherwise = ([LiteralBinder ss $ BooleanLiteral bl], return False)
 missingCasesSingle env mn b (PositionedBinder _ _ cb) = missingCasesSingle env mn b cb
 missingCasesSingle env mn b (TypedBinder _ cb) = missingCasesSingle env mn b cb
 missingCasesSingle _ _ b _ = ([b], Left Unknown)
@@ -290,16 +290,17 @@
     var <- freshName
     return $
       Let
+        FromLet
         [ partial var tyVar ]
-        $ App (Var (Qualified Nothing (Ident C.__unused))) e
+        $ App (Var ss (Qualified Nothing UnusedIdent)) e
     where
       partial :: Text -> Text -> Declaration
       partial var tyVar =
-        ValueDecl (ss, []) (Ident C.__unused) Private [] $
+        ValueDecl (ss, []) UnusedIdent Private [] $
         [MkUnguarded
           (TypedValue
            True
-           (Abs (VarBinder (Ident var)) (Var (Qualified Nothing (Ident var))))
+           (Abs (VarBinder ss (Ident var)) (Var ss (Qualified Nothing (Ident var))))
            (ty tyVar))
         ]
 
@@ -336,9 +337,9 @@
   onDecl decl = return decl
 
   onExpr :: SourceSpan -> Expr -> m Expr
-  onExpr ss (UnaryMinus e) = UnaryMinus <$> onExpr ss e
-  onExpr ss (Literal (ArrayLiteral es)) = Literal . ArrayLiteral <$> mapM (onExpr ss) es
-  onExpr ss (Literal (ObjectLiteral es)) = Literal . ObjectLiteral <$> mapM (sndM (onExpr ss)) es
+  onExpr _ (UnaryMinus ss e) = UnaryMinus ss <$> onExpr ss e
+  onExpr _ (Literal ss (ArrayLiteral es)) = Literal ss . ArrayLiteral <$> mapM (onExpr ss) es
+  onExpr _ (Literal ss (ObjectLiteral es)) = Literal ss . ObjectLiteral <$> mapM (sndM (onExpr ss)) es
   onExpr ss (TypeClassDictionaryConstructorApp x e) = TypeClassDictionaryConstructorApp x <$> onExpr ss e
   onExpr ss (Accessor x e) = Accessor x <$> onExpr ss e
   onExpr ss (ObjectUpdate o es) = ObjectUpdate <$> onExpr ss o <*> mapM (sndM (onExpr ss)) es
@@ -349,7 +350,7 @@
     case' <- Case <$> mapM (onExpr ss) es <*> mapM (onCaseAlternative ss) cas
     checkExhaustive ss env mn (length es) cas case'
   onExpr ss (TypedValue x e y) = TypedValue x <$> onExpr ss e <*> pure y
-  onExpr ss (Let ds e) = Let <$> mapM onDecl ds <*> onExpr ss e
+  onExpr ss (Let w ds e) = Let w <$> mapM onDecl ds <*> onExpr ss e
   onExpr _ (PositionedValue ss x e) = PositionedValue ss x <$> onExpr ss e
   onExpr _ expr = return expr
 
diff --git a/src/Language/PureScript/Linter/Imports.hs b/src/Language/PureScript/Linter/Imports.hs
--- a/src/Language/PureScript/Linter/Imports.hs
+++ b/src/Language/PureScript/Linter/Imports.hs
@@ -82,7 +82,7 @@
         let names = ordNub $ M.findWithDefault [] mni usedImps'
             usedRefs = findUsedRefs ss env mni (Just mnq) names
         unless (null usedRefs) .
-          tell . errorMessage' ss $ ImplicitQualifiedImport mni mnq usedRefs
+          tell . errorMessage' ss $ ImplicitQualifiedImport mni mnq $ map (simplifyTypeRef $ const True) usedRefs
 
   for_ imports $ \(mnq, imps) -> do
 
@@ -106,6 +106,23 @@
         Hiding refs -> refs
         _ -> []
 
+  -- Check re-exported modules to see if we are re-exporting a qualified module
+  -- that has unspecified imports.
+  for_ mexports $ \case
+    ModuleRef _ mnq ->
+      case M.lookup mnq (byQual imports) of
+        -- We only match the single-entry case here as otherwise there will be
+        -- a different warning about implicit imports potentially colliding
+        -- anyway
+        Just [(ss, Implicit, mni)] -> do
+          let names = ordNub $ M.findWithDefault [] mni usedImps'
+              usedRefs = findUsedRefs ss env mni (Just mnq) names
+          tell . errorMessage' ss $
+            ImplicitQualifiedImportReExport mni mnq
+              $ map (simplifyTypeRef $ const True) usedRefs
+        _ -> pure ()
+    _ -> pure ()
+
   where
 
   defQual :: ImportDef -> Maybe ModuleName
@@ -183,6 +200,17 @@
             _ -> internalError "unqualified name in extractByQual"
     go _ = Nothing
 
+
+-- Replace explicit type refs with data constructor lists from listing the
+-- used constructors explicity `T(X, Y, [...])` to `T(..)` for suggestion
+-- message.
+-- Done everywhere when suggesting a completely new explicit imports list, otherwise
+-- maintain the existing form.
+simplifyTypeRef :: (ProperName 'TypeName -> Bool) -> DeclarationRef -> DeclarationRef
+simplifyTypeRef shouldOpen (TypeRef ss name (Just dctors))
+  | not (null dctors) && shouldOpen name = TypeRef ss name Nothing
+simplifyTypeRef _ other = other
+
 lintImportDecl
   :: forall m
    . MonadWriter MultipleErrors m
@@ -214,15 +242,7 @@
   checkImplicit warning =
     if null allRefs
     then unused
-    else warn (warning mni (map simplifyTypeRef allRefs))
-    where
-    -- Replace explicit type refs with data constructor lists from listing the
-    -- used constructors explicity `T(X, Y, [...])` to `T(..)` for suggestion
-    -- message.
-    simplifyTypeRef :: DeclarationRef -> DeclarationRef
-    simplifyTypeRef (TypeRef ss' name (Just dctors))
-      | not (null dctors) = TypeRef ss' name Nothing
-    simplifyTypeRef other = other
+    else warn (warning mni (map (simplifyTypeRef $ const True) allRefs))
 
   checkExplicit
     :: [DeclarationRef]
@@ -236,20 +256,27 @@
     didWarn <- case (length diff, length idents) of
       (0, _) -> return False
       (n, m) | n == m -> unused
-      _ -> warn (UnusedExplicitImport mni diff qualifierName allRefs)
+      _ -> warn (UnusedExplicitImport mni diff qualifierName $ map simplifyTypeRef' allRefs)
 
     didWarn' <- forM (mapMaybe getTypeRef declrefs) $ \(tn, c) -> do
       let allCtors = dctorsForType mni tn
       -- If we've not already warned a type is unused, check its data constructors
       unless' (TyName tn `notElem` usedNames) $
         case (c, dctors `intersect` allCtors) of
-          (_, []) | c /= Just [] -> warn (UnusedDctorImport mni tn qualifierName allRefs)
+          (_, []) | c /= Just [] -> warn (UnusedDctorImport mni tn qualifierName $ map simplifyTypeRef' allRefs)
           (Just ctors, dctors') ->
             let ddiff = ctors \\ dctors'
-            in unless' (null ddiff) . warn $ UnusedDctorExplicitImport mni tn ddiff qualifierName allRefs
+            in unless' (null ddiff) . warn $ UnusedDctorExplicitImport mni tn ddiff qualifierName $ map simplifyTypeRef' allRefs
           _ -> return False
 
     return (didWarn || or didWarn')
+
+    where
+      simplifyTypeRef' :: DeclarationRef -> DeclarationRef
+      simplifyTypeRef' = simplifyTypeRef (\name -> any (isMatch name) declrefs)
+        where
+          isMatch name (TypeRef _ name' Nothing) = name == name'
+          isMatch _ _ = False
 
   unused :: m Bool
   unused = warn (UnusedImport mni)
diff --git a/src/Language/PureScript/Make.hs b/src/Language/PureScript/Make.hs
--- a/src/Language/PureScript/Make.hs
+++ b/src/Language/PureScript/Make.hs
@@ -1,56 +1,30 @@
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-{-# LANGUAGE TypeFamilies #-}
-
 module Language.PureScript.Make
   (
   -- * Make API
-    RebuildPolicy(..)
-  , ProgressMessage(..), renderProgressMessage
-  , MakeActions(..)
-  , Externs()
-  , rebuildModule
+  rebuildModule
   , make
-
-  -- * Implementation of Make API using files on disk
-  , Make(..)
-  , runMake
-  , makeIO
-  , readTextFile
-  , buildMakeActions
   , inferForeignModules
+  , module Monad
+  , module Actions
   ) where
 
 import           Prelude.Compat
 
 import           Control.Concurrent.Lifted as C
 import           Control.Monad hiding (sequence)
-import           Control.Monad.Base (MonadBase(..))
 import           Control.Monad.Error.Class (MonadError(..))
 import           Control.Monad.IO.Class
-import           Control.Monad.Logger
-import           Control.Monad.Reader (MonadReader(..), ReaderT(..), asks)
 import           Control.Monad.Supply
-import           Control.Monad.Trans.Class (MonadTrans(..))
 import           Control.Monad.Trans.Control (MonadBaseControl(..))
-import           Control.Monad.Trans.Except
 import           Control.Monad.Writer.Class (MonadWriter(..))
-import           Data.Aeson (encode, decode)
-import qualified Data.Aeson as Aeson
-import           Data.Either (partitionEithers)
+import           Data.Aeson (encode)
 import           Data.Function (on)
 import           Data.Foldable (for_)
-import           Data.List (foldl', sortBy, groupBy)
-import           Data.Maybe (fromMaybe, catMaybes)
-import           Data.Monoid ((<>))
-import           Data.Time.Clock
-import           Data.Traversable (for)
-import           Data.Version (showVersion)
-import qualified Data.ByteString.Lazy as B
-import qualified Data.ByteString.UTF8 as BU8
+import           Data.List (foldl', sortBy)
+import qualified Data.List.NonEmpty as NEL
+import           Data.Maybe (fromMaybe)
 import qualified Data.Map as M
 import qualified Data.Set as S
-import qualified Data.Text as T
-import qualified Data.Text.Encoding as TE
 import           Language.PureScript.AST
 import           Language.PureScript.Crash
 import           Language.PureScript.Environment
@@ -59,71 +33,16 @@
 import           Language.PureScript.Linter
 import           Language.PureScript.ModuleDependencies
 import           Language.PureScript.Names
-import           Language.PureScript.Options
-import           Language.PureScript.Pretty.Common (SMap(..))
 import           Language.PureScript.Renamer
 import           Language.PureScript.Sugar
 import           Language.PureScript.TypeChecker
-import qualified Language.JavaScript.Parser as JS
-import qualified Language.PureScript.Bundle as Bundle
-import qualified Language.PureScript.CodeGen.JS as J
-import           Language.PureScript.CodeGen.JS.Printer
+import           Language.PureScript.Make.BuildPlan
+import qualified Language.PureScript.Make.BuildPlan as BuildPlan
+import           Language.PureScript.Make.Actions as Actions
+import           Language.PureScript.Make.Monad as Monad
 import qualified Language.PureScript.CoreFn as CF
-import qualified Language.PureScript.CoreFn.ToJSON as CFJ
-import qualified Language.PureScript.CoreImp.AST as Imp
-import qualified Language.PureScript.Parser as PSParser
-import qualified Paths_purescript as Paths
-import           SourceMap
-import           SourceMap.Types
-import           System.Directory (doesFileExist, getModificationTime, createDirectoryIfMissing, getCurrentDirectory)
-import           System.FilePath ((</>), takeDirectory, makeRelative, splitPath, normalise, replaceExtension)
-import           System.IO.Error (tryIOError)
-import qualified Text.Parsec as Parsec
-
--- | Progress messages from the make process
-data ProgressMessage
-  = CompilingModule ModuleName
-  -- ^ Compilation started for the specified module
-  deriving (Show, Eq, Ord)
-
--- | Render a progress message
-renderProgressMessage :: ProgressMessage -> String
-renderProgressMessage (CompilingModule mn) = "Compiling " ++ T.unpack (runModuleName mn)
-
--- | Actions that require implementations when running in "make" mode.
---
--- This type exists to make two things abstract:
---
--- * The particular backend being used (JavaScript, C++11, etc.)
---
--- * The details of how files are read/written etc.
-data MakeActions m = MakeActions
-  { getInputTimestamp :: ModuleName -> m (Either RebuildPolicy (Maybe UTCTime))
-  -- ^ Get the timestamp for the input file(s) for a module. If there are multiple
-  -- files (@.purs@ and foreign files, for example) the timestamp should be for
-  -- the most recently modified file.
-  , getOutputTimestamp :: ModuleName -> m (Maybe UTCTime)
-  -- ^ Get the timestamp for the output files for a module. This should be the
-  -- timestamp for the oldest modified file, or 'Nothing' if any of the required
-  -- output files are missing.
-  , readExterns :: ModuleName -> m (FilePath, Externs)
-  -- ^ Read the externs file for a module as a string and also return the actual
-  -- path for the file.
-  , codegen :: CF.Module CF.Ann -> Environment -> Externs -> SupplyT m ()
-  -- ^ Run the code generator for the module and write any required output files.
-  , progress :: ProgressMessage -> m ()
-  -- ^ Respond to a progress update.
-  }
-
--- | Generated code for an externs file.
-type Externs = B.ByteString
-
--- | Determines when to rebuild a module
-data RebuildPolicy
-  -- | Never rebuild this module
-  = RebuildNever
-  -- | Always rebuild this module
-  | RebuildAlways deriving (Show, Eq, Ord)
+import           System.Directory (doesFileExist)
+import           System.FilePath (replaceExtension)
 
 -- | Rebuild a single module.
 --
@@ -153,7 +72,8 @@
   regrouped <- createBindingGroups moduleName . collapseBindingGroups $ deguarded
   let mod' = Module ss coms moduleName regrouped exps
       corefn = CF.moduleToCoreFn env' mod'
-      [renamed] = renameInModules [corefn]
+      optimized = CF.optimizeCoreFn corefn
+      [renamed] = renameInModules [optimized]
       exts = moduleToExternsFile mod' env'
   evalSupplyT nextVar' . codegen renamed env' . encode $ exts
   return exts
@@ -167,38 +87,56 @@
      -> [Module]
      -> m [ExternsFile]
 make ma@MakeActions{..} ms = do
-  checkModuleNamesAreUnique
+  checkModuleNames
 
   (sorted, graph) <- sortModules ms
 
-  barriers <- zip (map getModuleName sorted) <$> replicateM (length ms) ((,) <$> C.newEmptyMVar <*> C.newEmptyMVar)
+  buildPlan <- BuildPlan.construct ma (sorted, graph)
 
-  for_ sorted $ \m -> fork $ do
+  let toBeRebuilt = filter (BuildPlan.needsRebuild buildPlan . getModuleName) sorted
+  for_ toBeRebuilt $ \m -> fork $ do
     let deps = fromMaybe (internalError "make: module not found in dependency graph.") (lookup (getModuleName m) graph)
-    buildModule barriers (importPrim m) (deps `inOrderOf` map getModuleName sorted)
+    buildModule buildPlan (importPrim m) (deps `inOrderOf` map getModuleName sorted)
 
   -- Wait for all threads to complete, and collect errors.
-  errors <- catMaybes <$> for barriers (takeMVar . snd . snd)
+  errors <- BuildPlan.collectErrors buildPlan
 
   -- All threads have completed, rethrow any caught errors.
   unless (null errors) $ throwError (mconcat errors)
 
-  -- Bundle up all the externs and return them as an Environment
-  (_, externs) <- unzip . fromMaybe (internalError "make: externs were missing but no errors reported.") . sequence <$> for barriers (takeMVar . fst . snd)
-  return externs
+  -- Collect all ExternsFiles
+  results <- BuildPlan.collectResults buildPlan
 
+  -- Here we return all the ExternsFile in the ordering of the topological sort,
+  -- so they can be folded into an Environment. This result is used in the tests
+  -- and in PSCI.
+  let lookupResult mn = fromMaybe (internalError "make: module not found in results") (M.lookup mn results)
+  return (map (lookupResult . getModuleName) sorted)
+
   where
+  checkModuleNames :: m ()
+  checkModuleNames = checkNoPrim *> checkModuleNamesAreUnique
+
+  checkNoPrim :: m ()
+  checkNoPrim =
+    for_ ms $ \m ->
+      let mn = getModuleName m
+      in when (isBuiltinModuleName mn) $
+           throwError
+             . errorMessage' (getModuleSourceSpan m)
+             $ CannotDefinePrimModules mn
+
   checkModuleNamesAreUnique :: m ()
   checkModuleNamesAreUnique =
     for_ (findDuplicates getModuleName ms) $ \mss ->
       throwError . flip foldMap mss $ \ms' ->
-        let mn = getModuleName (head ms')
-        in errorMessage $ DuplicateModule mn (map getModuleSourceSpan ms')
+        let mn = getModuleName (NEL.head ms')
+        in errorMessage'' (fmap getModuleSourceSpan ms') $ DuplicateModule mn
 
   -- Find all groups of duplicate values in a list based on a projection.
-  findDuplicates :: Ord b => (a -> b) -> [a] -> Maybe [[a]]
+  findDuplicates :: Ord b => (a -> b) -> [a] -> Maybe [NEL.NonEmpty a]
   findDuplicates f xs =
-    case filter ((> 1) . length) . groupBy ((==) `on` f) . sortBy (compare `on` f) $ xs of
+    case filter ((> 1) . length) . NEL.groupBy ((==) `on` f) . sortBy (compare `on` f) $ xs of
       [] -> Nothing
       xss -> Just xss
 
@@ -206,86 +144,21 @@
   inOrderOf :: (Ord a) => [a] -> [a] -> [a]
   inOrderOf xs ys = let s = S.fromList xs in filter (`S.member` s) ys
 
-  buildModule :: [(ModuleName, (C.MVar (Maybe (MultipleErrors, ExternsFile)), C.MVar (Maybe MultipleErrors)))] -> Module -> [ModuleName] -> m ()
-  buildModule barriers m@(Module _ _ moduleName _ _) deps = flip catchError (markComplete Nothing . Just) $ do
+  buildModule :: BuildPlan -> Module -> [ModuleName] -> m ()
+  buildModule buildPlan m@(Module _ _ moduleName _ _) deps = flip catchError (complete Nothing . Just) $ do
     -- We need to wait for dependencies to be built, before checking if the current
     -- module should be rebuilt, so the first thing to do is to wait on the
     -- MVars for the module's dependencies.
-    mexterns <- fmap unzip . sequence <$> traverse (readMVar . fst . fromMaybe (internalError "make: no barrier") . flip lookup barriers) deps
+    mexterns <- fmap unzip . sequence <$> traverse (getResult buildPlan) deps
 
     case mexterns of
       Just (_, externs) -> do
-        outputTimestamp <- getOutputTimestamp moduleName
-        dependencyTimestamp <- maximumMaybe <$> traverse (fmap shouldExist . getOutputTimestamp) deps
-        inputTimestamp <- getInputTimestamp moduleName
-
-        let shouldRebuild = case (inputTimestamp, dependencyTimestamp, outputTimestamp) of
-                              (Right (Just t1), Just t3, Just t2) -> t1 > t2 || t3 > t2
-                              (Right (Just t1), Nothing, Just t2) -> t1 > t2
-                              (Left RebuildNever, _, Just _) -> False
-                              _ -> True
-
-        let rebuild = do
-              (exts, warnings) <- listen $ rebuildModule ma externs m
-              markComplete (Just (warnings, exts)) Nothing
-
-        if shouldRebuild
-          then rebuild
-          else do
-            mexts <- decodeExterns . snd <$> readExterns moduleName
-            case mexts of
-              Just exts -> markComplete (Just (mempty, exts)) Nothing
-              Nothing -> rebuild
-      Nothing -> markComplete Nothing Nothing
+        (exts, warnings) <- listen $ rebuildModule ma externs m
+        complete (Just (warnings, exts)) Nothing
+      Nothing -> complete Nothing Nothing
     where
-    markComplete :: Maybe (MultipleErrors, ExternsFile) -> Maybe MultipleErrors -> m ()
-    markComplete externs errors = do
-      putMVar (fst $ fromMaybe (internalError "make: no barrier") $ lookup moduleName barriers) externs
-      putMVar (snd $ fromMaybe (internalError "make: no barrier") $ lookup moduleName barriers) errors
-
-  maximumMaybe :: Ord a => [a] -> Maybe a
-  maximumMaybe [] = Nothing
-  maximumMaybe xs = Just $ maximum xs
-
-  -- Make sure a dependency exists
-  shouldExist :: Maybe UTCTime -> UTCTime
-  shouldExist (Just t) = t
-  shouldExist _ = internalError "make: dependency should already have been built."
-
-  decodeExterns :: Externs -> Maybe ExternsFile
-  decodeExterns bs = do
-    externs <- decode bs
-    guard $ T.unpack (efVersion externs) == showVersion Paths.version
-    return externs
-
--- | A monad for running make actions
-newtype Make a = Make
-  { unMake :: ReaderT Options (ExceptT MultipleErrors (Logger MultipleErrors)) a
-  } deriving (Functor, Applicative, Monad, MonadIO, MonadError MultipleErrors, MonadWriter MultipleErrors, MonadReader Options)
-
-instance MonadBase IO Make where
-  liftBase = liftIO
-
-instance MonadBaseControl IO Make where
-  type StM Make a = Either MultipleErrors a
-  liftBaseWith f = Make $ liftBaseWith $ \q -> f (q . unMake)
-  restoreM = Make . restoreM
-
--- | Execute a 'Make' monad, returning either errors, or the result of the compile plus any warnings.
-runMake :: Options -> Make a -> IO (Either MultipleErrors a, MultipleErrors)
-runMake opts = runLogger' . runExceptT . flip runReaderT opts . unMake
-
--- | Run an 'IO' action in the 'Make' monad, by specifying how IO errors should
--- be rendered as 'ErrorMessage' values.
-makeIO :: (IOError -> ErrorMessage) -> IO a -> Make a
-makeIO f io = do
-  e <- liftIO $ tryIOError io
-  either (throwError . singleError . f) return e
-
--- | Read a text file in the 'Make' monad, capturing any errors using the
--- 'MonadError' instance.
-readTextFile :: FilePath -> Make B.ByteString
-readTextFile path = makeIO (const (ErrorMessage [] $ CannotReadFile path)) $ B.readFile path
+    complete :: Maybe (MultipleErrors, ExternsFile) -> Maybe MultipleErrors -> m ()
+    complete = BuildPlan.markComplete buildPlan moduleName
 
 -- | Infer the module name for a module by looking for the same filename with
 -- a .js extension.
@@ -305,176 +178,3 @@
       if exists
         then return (Just jsFile)
         else return Nothing
-
--- | A set of make actions that read and write modules from the given directory.
-buildMakeActions
-  :: FilePath
-  -- ^ the output directory
-  -> M.Map ModuleName (Either RebuildPolicy FilePath)
-  -- ^ a map between module names and paths to the file containing the PureScript module
-  -> M.Map ModuleName FilePath
-  -- ^ a map between module name and the file containing the foreign javascript for the module
-  -> Bool
-  -- ^ Generate a prefix comment?
-  -> MakeActions Make
-buildMakeActions outputDir filePathMap foreigns usePrefix =
-    MakeActions getInputTimestamp getOutputTimestamp readExterns codegen progress
-  where
-
-  getInputTimestamp :: ModuleName -> Make (Either RebuildPolicy (Maybe UTCTime))
-  getInputTimestamp mn = do
-    let path = fromMaybe (internalError "Module has no filename in 'make'") $ M.lookup mn filePathMap
-    e1 <- traverse getTimestamp path
-    fPath <- maybe (return Nothing) getTimestamp $ M.lookup mn foreigns
-    return $ fmap (max fPath) e1
-
-  getOutputTimestamp :: ModuleName -> Make (Maybe UTCTime)
-  getOutputTimestamp mn = do
-    dumpCoreFn <- asks optionsDumpCoreFn
-    let filePath = T.unpack (runModuleName mn)
-        jsFile = outputDir </> filePath </> "index.js"
-        externsFile = outputDir </> filePath </> "externs.json"
-        coreFnFile = outputDir </> filePath </> "corefn.json"
-        min3 js exts coreFn
-          | dumpCoreFn = min (min js exts) coreFn
-          | otherwise = min js exts
-    min3 <$> getTimestamp jsFile <*> getTimestamp externsFile <*> getTimestamp coreFnFile
-
-  readExterns :: ModuleName -> Make (FilePath, Externs)
-  readExterns mn = do
-    let path = outputDir </> T.unpack (runModuleName mn) </> "externs.json"
-    (path, ) <$> readTextFile path
-
-  codegen :: CF.Module CF.Ann -> Environment -> Externs -> SupplyT Make ()
-  codegen m _ exts = do
-    let mn = CF.moduleName m
-    foreignInclude <- case mn `M.lookup` foreigns of
-      Just path
-        | not $ requiresForeign m -> do
-            tell $ errorMessage $ UnnecessaryFFIModule mn path
-            return Nothing
-        | otherwise -> do
-            checkForeignDecls m path
-            return $ Just $ Imp.App Nothing (Imp.Var Nothing "require") [Imp.StringLiteral Nothing "./foreign"]
-      Nothing | requiresForeign m -> throwError . errorMessage $ MissingFFIModule mn
-              | otherwise -> return Nothing
-    rawJs <- J.moduleToJs m foreignInclude
-    dir <- lift $ makeIO (const (ErrorMessage [] $ CannotGetFileInfo ".")) getCurrentDirectory
-    sourceMaps <- lift $ asks optionsSourceMaps
-    let (pjs, mappings) = if sourceMaps then prettyPrintJSWithSourceMaps rawJs else (prettyPrintJS rawJs, [])
-    let filePath = T.unpack (runModuleName mn)
-        jsFile = outputDir </> filePath </> "index.js"
-        mapFile = outputDir </> filePath </> "index.js.map"
-        externsFile = outputDir </> filePath </> "externs.json"
-        foreignFile = outputDir </> filePath </> "foreign.js"
-        prefix = ["Generated by purs version " <> T.pack (showVersion Paths.version) | usePrefix]
-        js = T.unlines $ map ("// " <>) prefix ++ [pjs]
-        mapRef = if sourceMaps then "//# sourceMappingURL=index.js.map\n" else ""
-    lift $ do
-      writeTextFile jsFile (B.fromStrict $ TE.encodeUtf8 $ js <> mapRef)
-      for_ (mn `M.lookup` foreigns) (readTextFile >=> writeTextFile foreignFile)
-      writeTextFile externsFile exts
-    lift $ when sourceMaps $ genSourceMap dir mapFile (length prefix) mappings
-    dumpCoreFn <- lift $ asks optionsDumpCoreFn
-    when dumpCoreFn $ do
-      let coreFnFile = outputDir </> filePath </> "corefn.json"
-      let jsonPayload = CFJ.moduleToJSON Paths.version m
-      let json = Aeson.object [  (runModuleName mn, jsonPayload) ]
-      lift $ writeTextFile coreFnFile (encode json)
-
-  genSourceMap :: String -> String -> Int -> [SMap] -> Make ()
-  genSourceMap dir mapFile extraLines mappings = do
-    let pathToDir = iterate (".." </>) ".." !! length (splitPath $ normalise outputDir)
-        sourceFile = case mappings of
-                      (SMap file _ _ : _) -> Just $ pathToDir </> makeRelative dir (T.unpack file)
-                      _ -> Nothing
-    let rawMapping = SourceMapping { smFile = "index.js", smSourceRoot = Nothing, smMappings =
-      map (\(SMap _ orig gen) -> Mapping {
-          mapOriginal = Just $ convertPos $ add 0 (-1) orig
-        , mapSourceFile = sourceFile
-        , mapGenerated = convertPos $ add (extraLines+1) 0 gen
-        , mapName = Nothing
-        }) mappings
-    }
-    let mapping = generate rawMapping
-    writeTextFile mapFile (encode mapping)
-    where
-    add :: Int -> Int -> SourcePos -> SourcePos
-    add n m (SourcePos n' m') = SourcePos (n+n') (m+m')
-
-    convertPos :: SourcePos -> Pos
-    convertPos SourcePos { sourcePosLine = l, sourcePosColumn = c } =
-      Pos { posLine = fromIntegral l, posColumn = fromIntegral c }
-
-  requiresForeign :: CF.Module a -> Bool
-  requiresForeign = not . null . CF.moduleForeign
-
-  getTimestamp :: FilePath -> Make (Maybe UTCTime)
-  getTimestamp path = makeIO (const (ErrorMessage [] $ CannotGetFileInfo path)) $ do
-    exists <- doesFileExist path
-    traverse (const $ getModificationTime path) $ guard exists
-
-  writeTextFile :: FilePath -> B.ByteString -> Make ()
-  writeTextFile path text = makeIO (const (ErrorMessage [] $ CannotWriteFile path)) $ do
-    mkdirp path
-    B.writeFile path text
-    where
-    mkdirp :: FilePath -> IO ()
-    mkdirp = createDirectoryIfMissing True . takeDirectory
-
-  progress :: ProgressMessage -> Make ()
-  progress = liftIO . putStrLn . renderProgressMessage
-
--- | Check that the declarations in a given PureScript module match with those
--- in its corresponding foreign module.
-checkForeignDecls :: CF.Module ann -> FilePath -> SupplyT Make ()
-checkForeignDecls m path = do
-  jsStr <- lift $ readTextFile path
-  js <- either (errorParsingModule . Bundle.UnableToParseModule) pure $ JS.parse (BU8.toString (B.toStrict jsStr)) path
-
-  foreignIdentsStrs <- either errorParsingModule pure $ getExps js
-  foreignIdents <- either
-                     errorInvalidForeignIdentifiers
-                     (pure . S.fromList)
-                     (parseIdents foreignIdentsStrs)
-  let importedIdents = S.fromList $ map fst (CF.moduleForeign m)
-
-  let unusedFFI = foreignIdents S.\\ importedIdents
-  unless (null unusedFFI) $
-    tell . errorMessage . UnusedFFIImplementations mname $
-      S.toList unusedFFI
-
-  let missingFFI = importedIdents S.\\ foreignIdents
-  unless (null missingFFI) $
-    throwError . errorMessage . MissingFFIImplementations mname $
-      S.toList missingFFI
-
-  where
-  mname = CF.moduleName m
-
-  errorParsingModule :: Bundle.ErrorMessage -> SupplyT Make a
-  errorParsingModule = throwError . errorMessage . ErrorParsingFFIModule path . Just
-
-  getExps :: JS.JSAST -> Either Bundle.ErrorMessage [String]
-  getExps = Bundle.getExportedIdentifiers (T.unpack (runModuleName mname))
-
-  errorInvalidForeignIdentifiers :: [String] -> SupplyT Make a
-  errorInvalidForeignIdentifiers =
-    throwError . mconcat . map (errorMessage . InvalidFFIIdentifier mname . T.pack)
-
-  parseIdents :: [String] -> Either [String] [Ident]
-  parseIdents strs =
-    case partitionEithers (map parseIdent strs) of
-      ([], idents) ->
-        Right idents
-      (errs, _) ->
-        Left errs
-
-  -- We ignore the error message here, just being told it's an invalid
-  -- identifier should be enough.
-  parseIdent :: String -> Either String Ident
-  parseIdent str = try (T.pack str)
-    where
-    try s = either (const (Left str)) Right $ do
-      ts <- PSParser.lex "" s
-      PSParser.runTokenParser "" (PSParser.parseIdent <* Parsec.eof) ts
diff --git a/src/Language/PureScript/Make/Actions.hs b/src/Language/PureScript/Make/Actions.hs
new file mode 100644
--- /dev/null
+++ b/src/Language/PureScript/Make/Actions.hs
@@ -0,0 +1,281 @@
+module Language.PureScript.Make.Actions
+  ( MakeActions(..)
+  , RebuildPolicy(..)
+  , Externs()
+  , ProgressMessage(..)
+  , buildMakeActions
+  ) where
+
+import           Prelude
+
+import           Control.Monad hiding (sequence)
+import           Control.Monad.Error.Class (MonadError(..))
+import           Control.Monad.IO.Class
+import           Control.Monad.Reader (asks)
+import           Control.Monad.Supply
+import           Control.Monad.Trans.Class (MonadTrans(..))
+import           Control.Monad.Writer.Class (MonadWriter(..))
+import           Data.Aeson (encode)
+import qualified Data.ByteString.Lazy as B
+import qualified Data.ByteString.Lazy as LB
+import qualified Data.ByteString.UTF8 as BU8
+import           Data.Either (partitionEithers)
+import           Data.Foldable (for_, minimum)
+import qualified Data.List.NonEmpty as NEL
+import qualified Data.Map as M
+import           Data.Maybe (fromMaybe)
+import           Data.Monoid ((<>))
+import qualified Data.Set as S
+import qualified Data.Text as T
+import qualified Data.Text.Encoding as TE
+import           Data.Time.Clock (UTCTime)
+import           Data.Version (showVersion)
+import qualified Language.JavaScript.Parser as JS
+import           Language.PureScript.AST
+import qualified Language.PureScript.Bundle as Bundle
+import qualified Language.PureScript.CodeGen.JS as J
+import           Language.PureScript.CodeGen.JS.Printer
+import qualified Language.PureScript.CoreFn as CF
+import qualified Language.PureScript.CoreFn.ToJSON as CFJ
+import qualified Language.PureScript.CoreImp.AST as Imp
+import           Language.PureScript.Crash
+import           Language.PureScript.Environment
+import           Language.PureScript.Errors
+import           Language.PureScript.Make.Monad
+import           Language.PureScript.Names
+import           Language.PureScript.Names (runModuleName, ModuleName)
+import           Language.PureScript.Options
+import qualified Language.PureScript.Parser as PSParser
+import           Language.PureScript.Pretty.Common (SMap(..))
+import qualified Paths_purescript as Paths
+import           SourceMap
+import           SourceMap.Types
+import           System.Directory (doesFileExist, getModificationTime, createDirectoryIfMissing, getCurrentDirectory)
+import           System.FilePath ((</>), takeDirectory, makeRelative, splitPath, normalise)
+import qualified Text.Parsec as Parsec
+
+-- | Determines when to rebuild a module
+data RebuildPolicy
+  -- | Never rebuild this module
+  = RebuildNever
+  -- | Always rebuild this module
+  | RebuildAlways
+  deriving (Show, Eq, Ord)
+
+-- | Progress messages from the make process
+data ProgressMessage
+  = CompilingModule ModuleName
+  -- ^ Compilation started for the specified module
+  deriving (Show, Eq, Ord)
+
+-- | Generated code for an externs file.
+type Externs = LB.ByteString
+
+-- | Render a progress message
+renderProgressMessage :: ProgressMessage -> String
+renderProgressMessage (CompilingModule mn) = "Compiling " ++ T.unpack (runModuleName mn)
+
+-- | Actions that require implementations when running in "make" mode.
+--
+-- This type exists to make two things abstract:
+--
+-- * The particular backend being used (JavaScript, C++11, etc.)
+--
+-- * The details of how files are read/written etc.
+data MakeActions m = MakeActions
+  { getInputTimestamp :: ModuleName -> m (Either RebuildPolicy (Maybe UTCTime))
+  -- ^ Get the timestamp for the input file(s) for a module. If there are multiple
+  -- files (@.purs@ and foreign files, for example) the timestamp should be for
+  -- the most recently modified file.
+  , getOutputTimestamp :: ModuleName -> m (Maybe UTCTime)
+  -- ^ Get the timestamp for the output files for a module. This should be the
+  -- timestamp for the oldest modified file, or 'Nothing' if any of the required
+  -- output files are missing.
+  , readExterns :: ModuleName -> m (FilePath, Externs)
+  -- ^ Read the externs file for a module as a string and also return the actual
+  -- path for the file.
+  , codegen :: CF.Module CF.Ann -> Environment -> Externs -> SupplyT m ()
+  -- ^ Run the code generator for the module and write any required output files.
+  , progress :: ProgressMessage -> m ()
+  -- ^ Respond to a progress update.
+  }
+
+-- | A set of make actions that read and write modules from the given directory.
+buildMakeActions
+  :: FilePath
+  -- ^ the output directory
+  -> M.Map ModuleName (Either RebuildPolicy FilePath)
+  -- ^ a map between module names and paths to the file containing the PureScript module
+  -> M.Map ModuleName FilePath
+  -- ^ a map between module name and the file containing the foreign javascript for the module
+  -> Bool
+  -- ^ Generate a prefix comment?
+  -> MakeActions Make
+buildMakeActions outputDir filePathMap foreigns usePrefix =
+    MakeActions getInputTimestamp getOutputTimestamp readExterns codegen progress
+  where
+
+  getInputTimestamp :: ModuleName -> Make (Either RebuildPolicy (Maybe UTCTime))
+  getInputTimestamp mn = do
+    let path = fromMaybe (internalError "Module has no filename in 'make'") $ M.lookup mn filePathMap
+    e1 <- traverse getTimestamp path
+    fPath <- maybe (return Nothing) getTimestamp $ M.lookup mn foreigns
+    return $ fmap (max fPath) e1
+
+  outputFilename :: ModuleName -> String -> FilePath
+  outputFilename mn fn =
+    let filePath = T.unpack (runModuleName mn)
+    in outputDir </> filePath </> fn
+
+  targetFilename :: ModuleName -> CodegenTarget -> FilePath
+  targetFilename mn = \case
+    JS -> outputFilename mn "index.js"
+    JSSourceMap -> outputFilename mn "index.js.map"
+    CoreFn -> outputFilename mn "corefn.json"
+
+  getOutputTimestamp :: ModuleName -> Make (Maybe UTCTime)
+  getOutputTimestamp mn = do
+    codegenTargets <- asks optionsCodegenTargets
+    let outputPaths = [outputFilename mn "externs.json"] <> fmap (targetFilename mn) (S.toList codegenTargets)
+    timestamps <- traverse getTimestamp outputPaths
+    pure $ fmap minimum . NEL.nonEmpty =<< sequence timestamps
+
+  readExterns :: ModuleName -> Make (FilePath, Externs)
+  readExterns mn = do
+    let path = outputDir </> T.unpack (runModuleName mn) </> "externs.json"
+    (path, ) <$> readTextFile path
+
+  codegen :: CF.Module CF.Ann -> Environment -> Externs -> SupplyT Make ()
+  codegen m _ exts = do
+    let mn = CF.moduleName m
+    lift $ writeTextFile (outputFilename mn "externs.json") exts
+    codegenTargets <- lift $ asks optionsCodegenTargets
+    when (S.member CoreFn codegenTargets) $ do
+      let coreFnFile = targetFilename mn CoreFn
+          json = CFJ.moduleToJSON Paths.version m
+      lift $ writeTextFile coreFnFile (encode json)
+    when (S.member JS codegenTargets) $ do
+      foreignInclude <- case mn `M.lookup` foreigns of
+        Just path
+          | not $ requiresForeign m -> do
+              tell $ errorMessage' (CF.moduleSourceSpan m) $ UnnecessaryFFIModule mn path
+              return Nothing
+          | otherwise -> do
+              checkForeignDecls m path
+              return $ Just $ Imp.App Nothing (Imp.Var Nothing "require") [Imp.StringLiteral Nothing "./foreign.js"]
+        Nothing | requiresForeign m -> throwError . errorMessage' (CF.moduleSourceSpan m) $ MissingFFIModule mn
+                | otherwise -> return Nothing
+      rawJs <- J.moduleToJs m foreignInclude
+      dir <- lift $ makeIO (const (ErrorMessage [] $ CannotGetFileInfo ".")) getCurrentDirectory
+      let sourceMaps = S.member JSSourceMap codegenTargets
+          (pjs, mappings) = if sourceMaps then prettyPrintJSWithSourceMaps rawJs else (prettyPrintJS rawJs, [])
+          foreignFile = outputFilename mn "foreign.js"
+          jsFile = targetFilename mn JS
+          mapFile = targetFilename mn JSSourceMap
+          prefix = ["Generated by purs version " <> T.pack (showVersion Paths.version) | usePrefix]
+          js = T.unlines $ map ("// " <>) prefix ++ [pjs]
+          mapRef = if sourceMaps then "//# sourceMappingURL=index.js.map\n" else ""
+      lift $ do
+        writeTextFile jsFile (B.fromStrict $ TE.encodeUtf8 $ js <> mapRef)
+        for_ (mn `M.lookup` foreigns) (readTextFile >=> writeTextFile foreignFile)
+        when sourceMaps $ genSourceMap dir mapFile (length prefix) mappings
+
+  genSourceMap :: String -> String -> Int -> [SMap] -> Make ()
+  genSourceMap dir mapFile extraLines mappings = do
+    let pathToDir = iterate (".." </>) ".." !! length (splitPath $ normalise outputDir)
+        sourceFile = case mappings of
+                      (SMap file _ _ : _) -> Just $ pathToDir </> makeRelative dir (T.unpack file)
+                      _ -> Nothing
+    let rawMapping = SourceMapping { smFile = "index.js", smSourceRoot = Nothing, smMappings =
+      map (\(SMap _ orig gen) -> Mapping {
+          mapOriginal = Just $ convertPos $ add 0 (-1) orig
+        , mapSourceFile = sourceFile
+        , mapGenerated = convertPos $ add (extraLines+1) 0 gen
+        , mapName = Nothing
+        }) mappings
+    }
+    let mapping = generate rawMapping
+    writeTextFile mapFile (encode mapping)
+    where
+    add :: Int -> Int -> SourcePos -> SourcePos
+    add n m (SourcePos n' m') = SourcePos (n+n') (m+m')
+
+    convertPos :: SourcePos -> Pos
+    convertPos SourcePos { sourcePosLine = l, sourcePosColumn = c } =
+      Pos { posLine = fromIntegral l, posColumn = fromIntegral c }
+
+  requiresForeign :: CF.Module a -> Bool
+  requiresForeign = not . null . CF.moduleForeign
+
+  getTimestamp :: FilePath -> Make (Maybe UTCTime)
+  getTimestamp path = makeIO (const (ErrorMessage [] $ CannotGetFileInfo path)) $ do
+    exists <- doesFileExist path
+    if exists
+      then Just <$> getModificationTime path
+      else pure Nothing
+
+  writeTextFile :: FilePath -> B.ByteString -> Make ()
+  writeTextFile path text = makeIO (const (ErrorMessage [] $ CannotWriteFile path)) $ do
+    mkdirp path
+    B.writeFile path text
+    where
+    mkdirp :: FilePath -> IO ()
+    mkdirp = createDirectoryIfMissing True . takeDirectory
+
+  progress :: ProgressMessage -> Make ()
+  progress = liftIO . putStrLn . renderProgressMessage
+
+-- | Check that the declarations in a given PureScript module match with those
+-- in its corresponding foreign module.
+checkForeignDecls :: CF.Module ann -> FilePath -> SupplyT Make ()
+checkForeignDecls m path = do
+  jsStr <- lift $ readTextFile path
+  js <- either (errorParsingModule . Bundle.UnableToParseModule) pure $ JS.parse (BU8.toString (B.toStrict jsStr)) path
+
+  foreignIdentsStrs <- either errorParsingModule pure $ getExps js
+  foreignIdents <- either
+                     errorInvalidForeignIdentifiers
+                     (pure . S.fromList)
+                     (parseIdents foreignIdentsStrs)
+  let importedIdents = S.fromList (CF.moduleForeign m)
+
+  let unusedFFI = foreignIdents S.\\ importedIdents
+  unless (null unusedFFI) $
+    tell . errorMessage' modSS . UnusedFFIImplementations mname $
+      S.toList unusedFFI
+
+  let missingFFI = importedIdents S.\\ foreignIdents
+  unless (null missingFFI) $
+    throwError . errorMessage' modSS . MissingFFIImplementations mname $
+      S.toList missingFFI
+
+  where
+  mname = CF.moduleName m
+  modSS = CF.moduleSourceSpan m
+
+  errorParsingModule :: Bundle.ErrorMessage -> SupplyT Make a
+  errorParsingModule = throwError . errorMessage' modSS . ErrorParsingFFIModule path . Just
+
+  getExps :: JS.JSAST -> Either Bundle.ErrorMessage [String]
+  getExps = Bundle.getExportedIdentifiers (T.unpack (runModuleName mname))
+
+  errorInvalidForeignIdentifiers :: [String] -> SupplyT Make a
+  errorInvalidForeignIdentifiers =
+    throwError . mconcat . map (errorMessage . InvalidFFIIdentifier mname . T.pack)
+
+  parseIdents :: [String] -> Either [String] [Ident]
+  parseIdents strs =
+    case partitionEithers (map parseIdent strs) of
+      ([], idents) ->
+        Right idents
+      (errs, _) ->
+        Left errs
+
+  -- We ignore the error message here, just being told it's an invalid
+  -- identifier should be enough.
+  parseIdent :: String -> Either String Ident
+  parseIdent str = try (T.pack str)
+    where
+    try s = either (const (Left str)) Right $ do
+      ts <- PSParser.lex "" s
+      PSParser.runTokenParser "" (PSParser.parseIdent <* Parsec.eof) ts
diff --git a/src/Language/PureScript/Make/BuildPlan.hs b/src/Language/PureScript/Make/BuildPlan.hs
new file mode 100644
--- /dev/null
+++ b/src/Language/PureScript/Make/BuildPlan.hs
@@ -0,0 +1,160 @@
+module Language.PureScript.Make.BuildPlan
+  ( BuildPlan()
+  , construct
+  , getResult
+  , collectErrors
+  , collectResults
+  , markComplete
+  , needsRebuild
+  ) where
+
+import           Prelude
+
+import           Control.Concurrent.Lifted as C
+import           Control.Monad hiding (sequence)
+import           Control.Monad.Trans.Control (MonadBaseControl(..))
+import           Data.Aeson (decode)
+import qualified Data.Map as M
+import           Data.Maybe (catMaybes, fromMaybe)
+import qualified Data.Text as T
+import           Data.Time.Clock (UTCTime)
+import           Data.Version (showVersion)
+import           Language.PureScript.AST
+import           Language.PureScript.Crash
+import           Language.PureScript.Errors
+import           Language.PureScript.Externs
+import           Language.PureScript.Make.Actions as Actions
+import           Language.PureScript.Names (ModuleName)
+import qualified Paths_purescript as Paths
+
+-- | The BuildPlan tracks information about our build progress, and holds all
+-- prebuilt modules for incremental builds.
+data BuildPlan = BuildPlan
+  { bpPrebuilt :: M.Map ModuleName Prebuilt
+  , bpBuildJobs :: M.Map ModuleName BuildJob
+  }
+
+data Prebuilt = Prebuilt
+  { pbModificationTime :: UTCTime
+  , pbExternsFile :: ExternsFile
+  }
+
+data BuildJob = BuildJob
+  { bjResult :: C.MVar (Maybe (MultipleErrors, ExternsFile))
+  , bjErrors :: C.MVar (Maybe MultipleErrors)
+  }
+
+-- | Called when we finished compiling a module and want to report back the
+-- compilation result, as well as any potential errors that were thrown.
+markComplete
+  :: (MonadBaseControl IO m)
+  => BuildPlan
+  -> ModuleName
+  -> Maybe (MultipleErrors, ExternsFile)
+  -> Maybe MultipleErrors
+  -> m ()
+markComplete buildPlan moduleName result errors = do
+  let BuildJob rVar eVar = fromMaybe (internalError "make: markComplete no barrier") $ M.lookup moduleName (bpBuildJobs buildPlan)
+  putMVar rVar result
+  putMVar eVar errors
+
+-- | Whether or not the module with the given ModuleName needs to be rebuilt
+needsRebuild :: BuildPlan -> ModuleName -> Bool
+needsRebuild bp moduleName = M.member moduleName (bpBuildJobs bp)
+
+-- | Collects errors for all modules that have been rebuilt. This will block
+-- until all outstanding build jobs are finished.
+collectErrors
+  :: (MonadBaseControl IO m)
+  => BuildPlan
+  -> m [MultipleErrors]
+collectErrors buildPlan  = do
+  errors <- traverse readMVar $ map bjErrors $ M.elems (bpBuildJobs buildPlan)
+  pure (catMaybes errors)
+
+-- | Collects ExternsFiles for all prebuilt as well as rebuilt modules. Panics
+-- if any build job returned an error.
+collectResults
+  :: (MonadBaseControl IO m)
+  => BuildPlan
+  -> m (M.Map ModuleName ExternsFile)
+collectResults buildPlan = do
+  let externs = M.map pbExternsFile (bpPrebuilt buildPlan)
+  barrierResults <- traverse (takeMVar . bjResult) $ bpBuildJobs buildPlan
+  let barrierExterns = M.map (snd . fromMaybe (internalError "make: externs were missing but no errors reported.")) barrierResults
+  pure (M.union externs barrierExterns)
+
+-- | Gets the the build result for a given module name independent of whether it
+-- was rebuilt or prebuilt. Prebuilt modules always return no warnings.
+getResult
+  :: (MonadBaseControl IO m)
+  => BuildPlan
+  -> ModuleName
+  -> m (Maybe (MultipleErrors, ExternsFile))
+getResult buildPlan moduleName =
+  case M.lookup moduleName (bpPrebuilt buildPlan) of
+    Just es ->
+      pure (Just (MultipleErrors [], pbExternsFile es))
+    Nothing ->
+      readMVar $ bjResult $ fromMaybe (internalError "make: no barrier") $ M.lookup moduleName (bpBuildJobs buildPlan)
+
+-- | Constructs a BuildPlan for the given module graph.
+--
+-- The given MakeActions are used to collect various timestamps in order to
+-- determine whether a module needs rebuilding.
+construct
+  :: forall m. (Monad m, MonadBaseControl IO m)
+  => MakeActions m
+  -> ([Module], [(ModuleName, [ModuleName])])
+  -> m BuildPlan
+construct MakeActions{..} (sorted, graph) = do
+  prebuilt <- foldM findExistingExtern M.empty sorted
+  let toBeRebuilt = filter (not . flip M.member prebuilt . getModuleName) sorted
+  buildJobs <- foldM makeBuildJob M.empty (map getModuleName toBeRebuilt)
+  pure $ BuildPlan prebuilt buildJobs
+  where
+    makeBuildJob prev moduleName = do
+      buildJob <- BuildJob <$> C.newEmptyMVar <*> C.newEmptyMVar
+      pure (M.insert moduleName buildJob prev)
+
+    findExistingExtern :: M.Map ModuleName Prebuilt -> Module -> m (M.Map ModuleName Prebuilt)
+    findExistingExtern prev (getModuleName -> moduleName) = do
+      outputTimestamp <- getOutputTimestamp moduleName
+      let deps = fromMaybe (internalError "make: module not found in dependency graph.") (lookup moduleName graph)
+      case traverse (fmap pbModificationTime . flip M.lookup prev) deps of
+        Nothing ->
+          -- If we end up here, one of the dependencies didn't exist in the
+          -- prebuilt map and so we know a dependency needs to be rebuilt, which
+          -- means we need to be rebuilt in turn.
+          pure prev
+        Just modTimes -> do
+          let dependencyTimestamp = maximumMaybe modTimes
+          inputTimestamp <- getInputTimestamp moduleName
+          let
+            existingExtern = case (inputTimestamp, dependencyTimestamp, outputTimestamp) of
+              (Right (Just t1), Just t3, Just t2) ->
+                if t1 > t2 || t3 > t2 then Nothing else Just t2
+              (Right (Just t1), Nothing, Just t2) ->
+                if t1 > t2 then Nothing else Just t2
+              (Left RebuildNever, _, Just t2) ->
+                Just t2
+              _ ->
+                Nothing
+          case existingExtern of
+            Nothing -> pure prev
+            Just outputTime -> do
+              mexts <- decodeExterns . snd <$> readExterns moduleName
+              case mexts of
+                Just exts ->
+                  pure (M.insert moduleName (Prebuilt outputTime exts) prev)
+                Nothing -> pure prev
+
+maximumMaybe :: Ord a => [a] -> Maybe a
+maximumMaybe [] = Nothing
+maximumMaybe xs = Just $ maximum xs
+
+decodeExterns :: Externs -> Maybe ExternsFile
+decodeExterns bs = do
+  externs <- decode bs
+  guard $ T.unpack (efVersion externs) == showVersion Paths.version
+  return externs
diff --git a/src/Language/PureScript/Make/Monad.hs b/src/Language/PureScript/Make/Monad.hs
new file mode 100644
--- /dev/null
+++ b/src/Language/PureScript/Make/Monad.hs
@@ -0,0 +1,54 @@
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+module Language.PureScript.Make.Monad
+  ( -- * Implementation of Make API using files on disk
+    Make(..)
+  , runMake
+  , makeIO
+  , readTextFile
+  ) where
+
+import           Prelude
+
+import           Control.Monad.Base (MonadBase(..))
+import           Control.Monad.Error.Class (MonadError(..))
+import           Control.Monad.IO.Class
+import           Control.Monad.Logger
+import           Control.Monad.Reader (MonadReader(..), ReaderT(..))
+import           Control.Monad.Trans.Control (MonadBaseControl(..))
+import           Control.Monad.Trans.Except
+import           Control.Monad.Writer.Class (MonadWriter(..))
+import qualified Data.ByteString.Lazy as B
+import           Language.PureScript.AST
+import           Language.PureScript.Errors
+import           Language.PureScript.Options
+import           System.IO.Error (tryIOError)
+
+-- | A monad for running make actions
+newtype Make a = Make
+  { unMake :: ReaderT Options (ExceptT MultipleErrors (Logger MultipleErrors)) a
+  } deriving (Functor, Applicative, Monad, MonadIO, MonadError MultipleErrors, MonadWriter MultipleErrors, MonadReader Options)
+
+instance MonadBase IO Make where
+  liftBase = liftIO
+
+instance MonadBaseControl IO Make where
+  type StM Make a = Either MultipleErrors a
+  liftBaseWith f = Make $ liftBaseWith $ \q -> f (q . unMake)
+  restoreM = Make . restoreM
+
+-- | Execute a 'Make' monad, returning either errors, or the result of the compile plus any warnings.
+runMake :: Options -> Make a -> IO (Either MultipleErrors a, MultipleErrors)
+runMake opts = runLogger' . runExceptT . flip runReaderT opts . unMake
+
+-- | Run an 'IO' action in the 'Make' monad, by specifying how IO errors should
+-- be rendered as 'ErrorMessage' values.
+makeIO :: (IOError -> ErrorMessage) -> IO a -> Make a
+makeIO f io = do
+  e <- liftIO $ tryIOError io
+  either (throwError . singleError . f) return e
+
+-- | Read a text file in the 'Make' monad, capturing any errors using the
+-- 'MonadError' instance.
+readTextFile :: FilePath -> Make B.ByteString
+readTextFile path = makeIO (const (ErrorMessage [] $ CannotReadFile path)) $ B.readFile path
diff --git a/src/Language/PureScript/ModuleDependencies.hs b/src/Language/PureScript/ModuleDependencies.hs
--- a/src/Language/PureScript/ModuleDependencies.hs
+++ b/src/Language/PureScript/ModuleDependencies.hs
@@ -7,7 +7,7 @@
 import           Protolude hiding (head)
 
 import           Data.Graph
-import           Data.List (head)
+import           Data.List.NonEmpty (NonEmpty((:|)))
 import qualified Data.Set as S
 import           Language.PureScript.AST
 import qualified Language.PureScript.Constants as C
@@ -42,7 +42,7 @@
     toGraphNode mns m@(Module _ _ mn ds _) = do
       let deps = ordNub (mapMaybe usedModules ds)
       void . parU deps $ \(dep, pos) ->
-        when (dep /= C.Prim && S.notMember dep mns) .
+        when (dep `notElem` C.primModules && S.notMember dep mns) .
           throwError
             . addHint (ErrorInModule mn)
             . errorMessage' pos
@@ -59,8 +59,9 @@
 -- | Convert a strongly connected component of the module graph to a module
 toModule :: MonadError MultipleErrors m => SCC Module -> m Module
 toModule (AcyclicSCC m) = return m
+toModule (CyclicSCC []) = internalError "toModule: empty CyclicSCC"
 toModule (CyclicSCC [m]) = return m
-toModule (CyclicSCC ms) =
+toModule (CyclicSCC (m : ms)) =
   throwError
-    . errorMessage' (getModuleSourceSpan (head ms))
+    . errorMessage'' (fmap getModuleSourceSpan (m :| ms))
     $ CycleInModules (map getModuleName ms)
diff --git a/src/Language/PureScript/Names.hs b/src/Language/PureScript/Names.hs
--- a/src/Language/PureScript/Names.hs
+++ b/src/Language/PureScript/Names.hs
@@ -1,5 +1,7 @@
 {-# LANGUAGE TemplateHaskell #-}
 {-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE DeriveTraversable #-}
+{-# LANGUAGE DeriveFoldable #-}
 
 -- |
 -- Data types for names
@@ -76,6 +78,10 @@
   -- A generated name for an identifier
   --
   | GenIdent (Maybe Text) Integer
+  -- |
+  -- A generated name used only for type-checking
+  --
+  | UnusedIdent
   deriving (Show, Eq, Ord, Generic)
 
 instance NFData Ident
@@ -84,6 +90,7 @@
 runIdent (Ident i) = i
 runIdent (GenIdent Nothing n) = "$" <> T.pack (show n)
 runIdent (GenIdent (Just name) n) = "$" <> name <> T.pack (show n)
+runIdent UnusedIdent = "$__unused"
 
 showIdent :: Ident -> Text
 showIdent = runIdent
@@ -114,8 +121,11 @@
 -- |
 -- The closed set of operator alias types.
 --
-data OpNameType = ValueOpName | TypeOpName
+data OpNameType = ValueOpName | TypeOpName | AnyOpName
 
+eraseOpName :: OpName a -> OpName 'AnyOpName
+eraseOpName = OpName . runOpName
+
 -- |
 -- Proper names, i.e. capitalized names for e.g. module names, type//data constructors.
 --
@@ -167,11 +177,15 @@
     s' -> ProperName w : splitProperNames s''
       where (w, s'') = T.break (== '.') s'
 
+isBuiltinModuleName :: ModuleName -> Bool
+isBuiltinModuleName (ModuleName (ProperName "Prim" : _)) = True
+isBuiltinModuleName _ = False
+
 -- |
 -- A qualified name, i.e. a name with an optional module name
 --
 data Qualified a = Qualified (Maybe ModuleName) a
-  deriving (Show, Eq, Ord, Functor, Generic)
+  deriving (Show, Eq, Ord, Functor, Foldable, Traversable, Generic)
 
 instance NFData a => NFData (Qualified a)
 
diff --git a/src/Language/PureScript/Options.hs b/src/Language/PureScript/Options.hs
--- a/src/Language/PureScript/Options.hs
+++ b/src/Language/PureScript/Options.hs
@@ -2,6 +2,7 @@
 module Language.PureScript.Options where
 
 import Prelude.Compat
+import qualified Data.Set as S
 
 -- | The data type of compiler options
 data Options = Options
@@ -9,12 +10,13 @@
   -- ^ Verbose error message
   , optionsNoComments :: Bool
   -- ^ Remove the comments from the generated js
-  , optionsSourceMaps :: Bool
-  -- ^ Generate source maps
-  , optionsDumpCoreFn :: Bool
-  -- ^ Dump CoreFn
+  , optionsCodegenTargets :: S.Set CodegenTarget
+  -- ^ Codegen targets (JS, CoreFn, etc.)
   } deriving Show
 
 -- Default make options
 defaultOptions :: Options
-defaultOptions = Options False False False False
+defaultOptions = Options False False (S.singleton JS)
+
+data CodegenTarget = JS | JSSourceMap | CoreFn
+  deriving (Eq, Ord, Show)
diff --git a/src/Language/PureScript/Parser/Common.hs b/src/Language/PureScript/Parser/Common.hs
--- a/src/Language/PureScript/Parser/Common.hs
+++ b/src/Language/PureScript/Parser/Common.hs
@@ -154,3 +154,8 @@
   -> P.Parsec [PositionedToken] u a
   -> P.Parsec [PositionedToken] u b
 withSourceSpan' f = withSourceSpan (\ss _ -> f ss)
+
+withSourceSpanF
+  :: P.Parsec [PositionedToken] u (SourceSpan -> a)
+  -> P.Parsec [PositionedToken] u a
+withSourceSpanF = withSourceSpan (\ss _ f -> f ss)
diff --git a/src/Language/PureScript/Parser/Declarations.hs b/src/Language/PureScript/Parser/Declarations.hs
--- a/src/Language/PureScript/Parser/Declarations.hs
+++ b/src/Language/PureScript/Parser/Declarations.hs
@@ -16,10 +16,11 @@
   ) where
 
 import           Prelude hiding (lex)
+import           Protolude (ordNub)
 
 import           Control.Applicative
 import           Control.Arrow ((+++))
-import           Control.Monad (foldM, join)
+import           Control.Monad (foldM, join, zipWithM)
 import           Control.Monad.Error.Class (MonadError(..))
 import           Control.Parallel.Strategies (withStrategy, parList, rseq)
 import           Data.Functor (($>))
@@ -77,7 +78,7 @@
     reserved "where"
     indented
     mark $ P.many1 (same *> parseLocalDeclaration)
-  return $ maybe value (`Let` value) whereClause
+  return $ maybe value (\ds -> Let FromWhere ds value) whereClause
 
 parseValueWithIdentAndBinders :: Ident -> [Binder] -> TokenParser (SourceAnn -> Declaration)
 parseValueWithIdentAndBinders ident bs = do
@@ -100,7 +101,7 @@
     join $ go <$> parseBinder <*> P.many parseBinderNoParens
   where
   go :: Binder -> [Binder] -> TokenParser (SourceAnn -> Declaration)
-  go (VarBinder ident) bs = parseValueWithIdentAndBinders ident bs
+  go (VarBinder _ ident) bs = parseValueWithIdentAndBinders ident bs
   go (PositionedBinder _ _ b) bs = go b bs
   go binder [] = do
     boot <- indented *> equals *> parseValueWithWhereClause
@@ -220,14 +221,14 @@
     return deps
   className <- indented *> parseQualified properName
   ty <- P.many (indented *> parseTypeAtom)
-  return $ \sa -> TypeInstanceDeclaration sa name (fromMaybe [] deps) className ty
+  return $ \sa -> TypeInstanceDeclaration sa [] 0 name (fromMaybe [] deps) className ty
 
 parseTypeInstanceDeclaration :: TokenParser Declaration
 parseTypeInstanceDeclaration = do
   instanceDecl <- parseInstanceDeclaration
   members <- P.option [] $ do
     indented *> reserved "where"
-    mark (P.many (same *> declsInInstance))
+    indented *> mark (P.many (same *> declsInInstance))
   return $ instanceDecl (ExplicitInstance members)
   where
     declsInInstance :: TokenParser Declaration
@@ -236,6 +237,32 @@
       , parseValueDeclaration
       ] P.<?> "type declaration or value declaration in instance"
 
+parseTypeInstanceChainDeclaration :: TokenParser [Declaration]
+parseTypeInstanceChainDeclaration = do
+  instances <- P.sepBy1 parseTypeInstanceDeclaration (reserved "else")
+  ensureSameTypeClass instances
+  chainId <- traverse getTypeInstanceName instances
+  zipWithM (setTypeInstanceChain chainId) instances [0..]
+  where
+    getTypeInstanceName :: Declaration -> TokenParser Ident
+    getTypeInstanceName (TypeInstanceDeclaration _ _ _ name _ _ _ _) = return name
+    getTypeInstanceName _ = P.unexpected "Found non-instance in chain declaration."
+
+    setTypeInstanceChain :: [Ident] -> Declaration -> Integer -> TokenParser Declaration
+    setTypeInstanceChain chain (TypeInstanceDeclaration sa _ _ n d c t b) index = return (TypeInstanceDeclaration sa chain index n d c t b)
+    setTypeInstanceChain _ _ _ = P.unexpected "Found non-instance in chain declaration."
+
+    getTypeInstanceClass :: Declaration -> TokenParser (Qualified (ProperName 'ClassName))
+    getTypeInstanceClass (TypeInstanceDeclaration _ _ _ _ _ tc _ _) = return tc
+    getTypeInstanceClass _ = P.unexpected "Found non-instance in chain declaration."
+
+    ensureSameTypeClass :: [Declaration] -> TokenParser ()
+    ensureSameTypeClass xs = do
+      classNames <- ordNub <$> traverse getTypeInstanceClass xs
+      case classNames of
+        [_] -> return ()
+        _   -> P.unexpected "All instances in a chain must implement the same type class."
+
 parseDerivingInstanceDeclaration :: TokenParser Declaration
 parseDerivingInstanceDeclaration = do
   reserved "derive"
@@ -243,19 +270,19 @@
   instanceDecl <- parseInstanceDeclaration
   return $ instanceDecl ty
 
--- | Parse a single declaration
-parseDeclaration :: TokenParser Declaration
+-- | Parse a single declaration.  May include a collection of instances in a chain.
+parseDeclaration :: TokenParser [Declaration]
 parseDeclaration =
   P.choice
-    [ parseDataDeclaration
-    , parseTypeDeclaration
-    , parseTypeSynonymDeclaration
-    , parseValueDeclaration
-    , parseExternDeclaration
-    , parseFixityDeclaration
-    , parseTypeClassDeclaration
-    , parseTypeInstanceDeclaration
-    , parseDerivingInstanceDeclaration
+    [ pure <$> parseDataDeclaration
+    , pure <$> parseTypeDeclaration
+    , pure <$> parseTypeSynonymDeclaration
+    , pure <$> parseValueDeclaration
+    , pure <$> parseExternDeclaration
+    , pure <$> parseFixityDeclaration
+    , pure <$> parseTypeClassDeclaration
+    , parseTypeInstanceChainDeclaration
+    , pure <$> parseDerivingInstanceDeclaration
     ] P.<?> "declaration"
 
 parseLocalDeclaration :: TokenParser Declaration
@@ -286,7 +313,7 @@
     -- parseModuleHeader function. This should allow us to speed up rebuilds
     -- by only parsing as far as the module header. See PR #2054.
     imports <- P.many (same *> parseImportDeclaration)
-    decls   <- P.many (same *> parseDeclaration)
+    decls   <- join <$> P.many (same *> parseDeclaration)
     return (imports <> decls)
   _ <- P.eof
   end <- P.getPosition
@@ -324,7 +351,7 @@
 
 -- | Converts a 'ParseError' into a 'PositionedError'
 toPositionedError :: P.ParseError -> ErrorMessage
-toPositionedError perr = ErrorMessage [ PositionedError (SourceSpan name start end) ] (ErrorParsingModule perr)
+toPositionedError perr = ErrorMessage [ positionedError (SourceSpan name start end) ] (ErrorParsingModule perr)
   where
   name   = (P.sourceName  . P.errorPos) perr
   start  = (toSourcePos . P.errorPos) perr
@@ -354,8 +381,8 @@
 parseIdentifierAndValue :: TokenParser (PSString, Expr)
 parseIdentifierAndValue =
   do
-    name <- indented *> lname
-    b <- P.option (Var $ Qualified Nothing (Ident name)) rest
+    (ss, name) <- indented *> withSourceSpan' (,) lname
+    b <- P.option (Var ss $ Qualified Nothing (Ident name)) rest
     return (mkString name, b)
   <|> (,) <$> (indented *> stringLiteral) <*> rest
   where
@@ -373,10 +400,10 @@
   toFunction args value = foldr ($) value args
 
 parseVar :: TokenParser Expr
-parseVar = Var <$> parseQualified parseIdent
+parseVar = withSourceSpan' Var $ parseQualified parseIdent
 
 parseConstructor :: TokenParser Expr
-parseConstructor = Constructor <$> parseQualified dataConstructorName
+parseConstructor = withSourceSpan' Constructor $ parseQualified dataConstructorName
 
 parseCase :: TokenParser Expr
 parseCase = Case <$> P.between (reserved "case") (indented *> reserved "of") (commaSep1 parseValue)
@@ -406,26 +433,27 @@
   indented
   reserved "in"
   result <- parseValue
-  return $ Let ds result
+  return $ Let FromLet ds result
 
 parseValueAtom :: TokenParser Expr
 parseValueAtom = withSourceSpan PositionedValue $ P.choice
                  [ parseAnonymousArgument
-                 , Literal <$> parseNumericLiteral
-                 , Literal <$> parseCharLiteral
-                 , Literal <$> parseStringLiteral
-                 , Literal <$> parseBooleanLiteral
-                 , Literal <$> parseArrayLiteral parseValue
-                 , Literal <$> parseObjectLiteral parseIdentifierAndValue
+                 , withSourceSpan' Literal $ parseNumericLiteral
+                 , withSourceSpan' Literal $ parseCharLiteral
+                 , withSourceSpan' Literal $ parseStringLiteral
+                 , withSourceSpan' Literal $ parseBooleanLiteral
+                 , withSourceSpan' Literal $ parseArrayLiteral parseValue
+                 , withSourceSpan' Literal $ parseObjectLiteral parseIdentifierAndValue
                  , parseAbs
                  , P.try parseConstructor
                  , P.try parseVar
                  , parseCase
                  , parseIfThenElse
                  , parseDo
+                 , parseAdo
                  , parseLet
                  , P.try $ Parens <$> parens parseValue
-                 , Op <$> parseQualified (parens parseOperator)
+                 , withSourceSpan' Op $ parseQualified (parens parseOperator)
                  , parseHole
                  ]
 
@@ -433,7 +461,7 @@
 parseInfixExpr :: TokenParser Expr
 parseInfixExpr
   = P.between tick tick parseValue
-  <|> withSourceSpan PositionedValue (Op <$> parseQualified parseOperator)
+  <|> withSourceSpan' Op (parseQualified parseOperator)
 
 parseHole :: TokenParser Expr
 parseHole = Hole <$> holeLit
@@ -451,7 +479,7 @@
     parseNestedUpdate = Branch <$> parseUpdaterBodyFields
 
 parseAccessor :: Expr -> TokenParser Expr
-parseAccessor (Constructor _) = P.unexpected "constructor"
+parseAccessor (Constructor _ _) = P.unexpected "constructor"
 parseAccessor obj = P.try $ Accessor <$> (indented *> dot *> indented *> parseLabel) <*> pure obj
 
 parseDo :: TokenParser Expr
@@ -460,6 +488,14 @@
   indented
   Do <$> mark (P.many1 (same *> mark parseDoNotationElement))
 
+parseAdo :: TokenParser Expr
+parseAdo = do
+  reserved "ado"
+  indented
+  elements <- mark (P.many (same *> mark parseDoNotationElement))
+  yield <- mark (reserved "in" *> parseValue)
+  pure $ Ado elements yield
+
 parseDoNotationLet :: TokenParser DoNotationElement
 parseDoNotationLet = DoNotationLet <$> (reserved "let" *> indented *> mark (P.many1 (same *> parseLocalDeclaration)))
 
@@ -483,15 +519,15 @@
 
 -- | Parse an expression
 parseValue :: TokenParser Expr
-parseValue = withSourceSpan PositionedValue
-  (P.buildExpressionParser operators
-    . buildPostfixParser postfixTable
-    $ indexersAndAccessors) P.<?> "expression"
+parseValue =
+  P.buildExpressionParser operators
+    (buildPostfixParser postfixTable indexersAndAccessors)
+    P.<?> "expression"
   where
   postfixTable = [ \v -> P.try (flip App <$> (indented *> indexersAndAccessors)) <*> pure v
                  , \v -> flip (TypedValue True) <$> (indented *> doubleColon *> parsePolyType) <*> pure v
                  ]
-  operators = [ [ P.Prefix (indented *> symbol' "-" *> return UnaryMinus)
+  operators = [ [ P.Prefix (indented *> withSourceSpan' (\ss _ -> UnaryMinus ss) (symbol' "-"))
                 ]
               , [ P.Infix (P.try (indented *> parseInfixExpr P.<?> "infix expression") >>= \ident ->
                     return (BinaryNoParens ident)) P.AssocRight
@@ -515,7 +551,8 @@
 parseAnonymousArgument = underscore *> pure AnonymousArgument
 
 parseNumberLiteral :: TokenParser Binder
-parseNumberLiteral = LiteralBinder . NumericLiteral <$> (sign <*> number)
+parseNumberLiteral = withSourceSpanF $
+  (\n ss -> LiteralBinder ss (NumericLiteral n)) <$> (sign <*> number)
   where
   sign :: TokenParser (Either Integer Double -> Either Integer Double)
   sign = (symbol' "-" >> return (negate +++ negate))
@@ -523,35 +560,42 @@
          <|> return id
 
 parseNullaryConstructorBinder :: TokenParser Binder
-parseNullaryConstructorBinder = ConstructorBinder <$> parseQualified dataConstructorName <*> pure []
+parseNullaryConstructorBinder = withSourceSpanF $
+  (\name ss -> ConstructorBinder ss name [])
+    <$> parseQualified dataConstructorName
 
 parseConstructorBinder :: TokenParser Binder
-parseConstructorBinder = ConstructorBinder <$> parseQualified dataConstructorName <*> many (indented *> parseBinderNoParens)
+parseConstructorBinder = withSourceSpanF $
+  (\name args ss -> ConstructorBinder ss name args)
+    <$> parseQualified dataConstructorName
+    <*> many (indented *> parseBinderNoParens)
 
 parseObjectBinder:: TokenParser Binder
-parseObjectBinder = LiteralBinder <$> parseObjectLiteral (indented *> parseIdentifierAndBinder)
+parseObjectBinder = withSourceSpanF $
+  flip LiteralBinder <$> parseObjectLiteral (indented *> parseEntry)
+  where
+    parseEntry :: TokenParser (PSString, Binder)
+    parseEntry = var <|> (,) <$> stringLiteral <*> rest
+      where
+        var = withSourceSpanF $ do
+          name <- lname
+          b <- P.option (\ss -> VarBinder ss (Ident name)) (const <$> rest)
+          return $ \ss -> (mkString name, b ss)
+        rest = indented *> colon *> indented *> parseBinder
 
 parseArrayBinder :: TokenParser Binder
-parseArrayBinder = LiteralBinder <$> parseArrayLiteral (indented *> parseBinder)
+parseArrayBinder = withSourceSpanF $
+  flip LiteralBinder <$> parseArrayLiteral (indented *> parseBinder)
 
 parseVarOrNamedBinder :: TokenParser Binder
-parseVarOrNamedBinder = do
+parseVarOrNamedBinder = withSourceSpanF $ do
   name <- parseIdent
-  let parseNamedBinder = NamedBinder name <$> (at *> indented *> parseBinderAtom)
-  parseNamedBinder <|> return (VarBinder name)
+  let parseNamedBinder = (\b ss -> NamedBinder ss name b) <$> (at *> indented *> parseBinderAtom)
+  parseNamedBinder <|> return (`VarBinder` name)
 
 parseNullBinder :: TokenParser Binder
 parseNullBinder = underscore *> return NullBinder
 
-parseIdentifierAndBinder :: TokenParser (PSString, Binder)
-parseIdentifierAndBinder =
-    do name <- lname
-       b <- P.option (VarBinder (Ident name)) rest
-       return (mkString name, b)
-    <|> (,) <$> stringLiteral <*> rest
-  where
-    rest = indented *> colon *> indented *> parseBinder
-
 -- | Parse a binder
 parseBinder :: TokenParser Binder
 parseBinder =
@@ -571,15 +615,15 @@
     postfixTable = [ \b -> flip TypedBinder b <$> (indented *> doubleColon *> parsePolyType) ]
 
     parseOpBinder :: TokenParser Binder
-    parseOpBinder = OpBinder <$> parseQualified parseOperator
+    parseOpBinder = withSourceSpan' OpBinder $ parseQualified parseOperator
 
 parseBinderAtom :: TokenParser Binder
 parseBinderAtom = withSourceSpan PositionedBinder
   (P.choice
    [ parseNullBinder
-   , LiteralBinder <$> parseCharLiteral
-   , LiteralBinder <$> parseStringLiteral
-   , LiteralBinder <$> parseBooleanLiteral
+   , withSourceSpanF $ flip LiteralBinder <$> parseCharLiteral
+   , withSourceSpanF $ flip LiteralBinder <$> parseStringLiteral
+   , withSourceSpanF $ flip LiteralBinder <$> parseBooleanLiteral
    , parseNumberLiteral
    , parseVarOrNamedBinder
    , parseConstructorBinder
@@ -593,9 +637,9 @@
 parseBinderNoParens = withSourceSpan PositionedBinder
   (P.choice
     [ parseNullBinder
-    , LiteralBinder <$> parseCharLiteral
-    , LiteralBinder <$> parseStringLiteral
-    , LiteralBinder <$> parseBooleanLiteral
+    , withSourceSpanF $ flip LiteralBinder <$> parseCharLiteral
+    , withSourceSpanF $ flip LiteralBinder <$> parseStringLiteral
+    , withSourceSpanF $ flip LiteralBinder <$> parseBooleanLiteral
     , parseNumberLiteral
     , parseVarOrNamedBinder
     , parseNullaryConstructorBinder
diff --git a/src/Language/PureScript/Parser/Lexer.hs b/src/Language/PureScript/Parser/Lexer.hs
--- a/src/Language/PureScript/Parser/Lexer.hs
+++ b/src/Language/PureScript/Parser/Lexer.hs
@@ -570,6 +570,7 @@
                   , "then"
                   , "else"
                   , "do"
+                  , "ado"
                   , "let"
                   , "true"
                   , "false"
diff --git a/src/Language/PureScript/Pretty/Values.hs b/src/Language/PureScript/Pretty/Values.hs
--- a/src/Language/PureScript/Pretty/Values.hs
+++ b/src/Language/PureScript/Pretty/Values.hs
@@ -72,19 +72,26 @@
 prettyPrintValue d (Case values binders) =
   (text "case " <> foldr beforeWithSpace (text "of") (map (prettyPrintValueAtom (d - 1)) values)) //
     moveRight 2 (vcat left (map (prettyPrintCaseAlternative (d - 1)) binders))
-prettyPrintValue d (Let ds val) =
+prettyPrintValue d (Let FromWhere ds val) =
+  prettyPrintValue (d - 1) val //
+    moveRight 2 (text "where" //
+                 vcat left (map (prettyPrintDeclaration (d - 1)) ds))
+prettyPrintValue d (Let FromLet ds val) =
   text "let" //
     moveRight 2 (vcat left (map (prettyPrintDeclaration (d - 1)) ds)) //
     (text "in " <> prettyPrintValue (d - 1) val)
 prettyPrintValue d (Do els) =
   text "do " <> vcat left (map (prettyPrintDoNotationElement (d - 1)) els)
+prettyPrintValue d (Ado els yield) =
+  text "ado " <> vcat left (map (prettyPrintDoNotationElement (d - 1)) els) //
+  (text "in " <> prettyPrintValue (d - 1) yield)
 prettyPrintValue _ (TypeClassDictionary (Constraint name tys _) _ _) = foldl1 beforeWithSpace $ text ("#dict " ++ T.unpack (runProperName (disqualify name))) : map typeAtomAsBox tys
 prettyPrintValue _ (DeferredDictionary name _) = text $ "#dict " ++ T.unpack (runProperName (disqualify name))
 prettyPrintValue _ (TypeClassDictionaryAccessor className ident) =
     text "#dict-accessor " <> text (T.unpack (runProperName (disqualify className))) <> text "." <> text (T.unpack (showIdent ident)) <> text ">"
 prettyPrintValue d (TypedValue _ val _) = prettyPrintValue d val
 prettyPrintValue d (PositionedValue _ _ val) = prettyPrintValue d val
-prettyPrintValue d (Literal l) = prettyPrintLiteralValue d l
+prettyPrintValue d (Literal _ l) = prettyPrintLiteralValue d l
 prettyPrintValue _ (Hole name) = text "?" <> textT name
 prettyPrintValue d expr@AnonymousArgument{} = prettyPrintValueAtom d expr
 prettyPrintValue d expr@Constructor{} = prettyPrintValueAtom d expr
@@ -96,19 +103,19 @@
 
 -- | Pretty-print an atomic expression, adding parentheses if necessary.
 prettyPrintValueAtom :: Int -> Expr -> Box
-prettyPrintValueAtom d (Literal l) = prettyPrintLiteralValue d l
+prettyPrintValueAtom d (Literal _ l) = prettyPrintLiteralValue d l
 prettyPrintValueAtom _ AnonymousArgument = text "_"
-prettyPrintValueAtom _ (Constructor name) = text $ T.unpack $ runProperName (disqualify name)
-prettyPrintValueAtom _ (Var ident) = text $ T.unpack $ showIdent (disqualify ident)
+prettyPrintValueAtom _ (Constructor _ name) = text $ T.unpack $ runProperName (disqualify name)
+prettyPrintValueAtom _ (Var _ ident) = text $ T.unpack $ showIdent (disqualify ident)
 prettyPrintValueAtom d (BinaryNoParens op lhs rhs) =
   prettyPrintValue (d - 1) lhs `beforeWithSpace` printOp op `beforeWithSpace` prettyPrintValue (d - 1) rhs
   where
-  printOp (Op (Qualified _ name)) = text $ T.unpack $ runOpName name
+  printOp (Op _ (Qualified _ name)) = text $ T.unpack $ runOpName name
   printOp expr = text "`" <> prettyPrintValue (d - 1) expr `before` text "`"
 prettyPrintValueAtom d (TypedValue _ val _) = prettyPrintValueAtom d val
 prettyPrintValueAtom d (PositionedValue _ _ val) = prettyPrintValueAtom d val
 prettyPrintValueAtom d (Parens expr) = (text "(" <> prettyPrintValue d expr) `before` text ")"
-prettyPrintValueAtom d (UnaryMinus expr) = text "(-" <> prettyPrintValue d expr <> text ")"
+prettyPrintValueAtom d (UnaryMinus _ expr) = text "(-" <> prettyPrintValue d expr <> text ")"
 prettyPrintValueAtom d expr = (text "(" <> prettyPrintValue d expr) `before` text ")"
 
 prettyPrintLiteralValue :: Int -> Literal Expr -> Box
@@ -182,14 +189,14 @@
 
 prettyPrintBinderAtom :: Binder -> Text
 prettyPrintBinderAtom NullBinder = "_"
-prettyPrintBinderAtom (LiteralBinder l) = prettyPrintLiteralBinder l
-prettyPrintBinderAtom (VarBinder ident) = showIdent ident
-prettyPrintBinderAtom (ConstructorBinder ctor []) = runProperName (disqualify ctor)
+prettyPrintBinderAtom (LiteralBinder _ l) = prettyPrintLiteralBinder l
+prettyPrintBinderAtom (VarBinder _ ident) = showIdent ident
+prettyPrintBinderAtom (ConstructorBinder _ ctor []) = runProperName (disqualify ctor)
 prettyPrintBinderAtom b@ConstructorBinder{} = parensT (prettyPrintBinder b)
-prettyPrintBinderAtom (NamedBinder ident binder) = showIdent ident Monoid.<> "@" Monoid.<> prettyPrintBinder binder
+prettyPrintBinderAtom (NamedBinder _ ident binder) = showIdent ident Monoid.<> "@" Monoid.<> prettyPrintBinder binder
 prettyPrintBinderAtom (PositionedBinder _ _ binder) = prettyPrintBinderAtom binder
 prettyPrintBinderAtom (TypedBinder _ binder) = prettyPrintBinderAtom binder
-prettyPrintBinderAtom (OpBinder op) = runOpName (disqualify op)
+prettyPrintBinderAtom (OpBinder _ op) = runOpName (disqualify op)
 prettyPrintBinderAtom (BinaryNoParensBinder op b1 b2) =
   prettyPrintBinderAtom b1 Monoid.<> " " Monoid.<> prettyPrintBinderAtom op Monoid.<> " " Monoid.<> prettyPrintBinderAtom b2
 prettyPrintBinderAtom (ParensInBinder b) = parensT (prettyPrintBinder b)
@@ -216,8 +223,8 @@
 -- Generate a pretty-printed string representing a Binder
 --
 prettyPrintBinder :: Binder -> Text
-prettyPrintBinder (ConstructorBinder ctor []) = runProperName (disqualify ctor)
-prettyPrintBinder (ConstructorBinder ctor args) = (runProperName (disqualify ctor)) Monoid.<> " " Monoid.<> T.unwords (map prettyPrintBinderAtom args)
+prettyPrintBinder (ConstructorBinder _ ctor []) = runProperName (disqualify ctor)
+prettyPrintBinder (ConstructorBinder _ ctor args) = (runProperName (disqualify ctor)) Monoid.<> " " Monoid.<> T.unwords (map prettyPrintBinderAtom args)
 prettyPrintBinder (PositionedBinder _ _ binder) = prettyPrintBinder binder
 prettyPrintBinder (TypedBinder _ binder) = prettyPrintBinder binder
 prettyPrintBinder b = prettyPrintBinderAtom b
diff --git a/src/Language/PureScript/Publish.hs b/src/Language/PureScript/Publish.hs
--- a/src/Language/PureScript/Publish.hs
+++ b/src/Language/PureScript/Publish.hs
@@ -149,7 +149,7 @@
   (inputFiles, depsFiles) <- liftIO (getInputAndDepsFiles paths)
   (modules', moduleMap) <- parseFilesInPackages inputFiles depsFiles
 
-  case runExcept (D.convertModulesInPackage modules' moduleMap) of
+  case runExcept (D.convertModulesInPackage (map snd modules') moduleMap) of
     Right modules -> return (modules, moduleMap)
     Left err -> userError (CompileError err)
 
diff --git a/src/Language/PureScript/Renamer.hs b/src/Language/PureScript/Renamer.hs
--- a/src/Language/PureScript/Renamer.hs
+++ b/src/Language/PureScript/Renamer.hs
@@ -17,7 +17,6 @@
 import Language.PureScript.CoreFn
 import Language.PureScript.Names
 import Language.PureScript.Traversals
-import qualified Language.PureScript.Constants as C
 
 -- |
 -- The state object used in this module
@@ -62,8 +61,8 @@
 updateScope :: Ident -> Rename Ident
 updateScope ident =
   case ident of
-    Ident name | name == C.__unused -> return ident
     GenIdent name _ -> go ident $ Ident (fromMaybe "v" name)
+    UnusedIdent -> return UnusedIdent
     _ -> go ident ident
   where
   go :: Ident -> Ident -> Rename Ident
@@ -88,7 +87,7 @@
 -- Finds the new name to use for an ident.
 --
 lookupIdent :: Ident -> Rename Ident
-lookupIdent i@(Ident name) | name == C.__unused = return i
+lookupIdent UnusedIdent = return UnusedIdent
 lookupIdent name = do
   name' <- gets $ M.lookup name . rsBoundNames
   case name' of
@@ -111,7 +110,7 @@
 renameInModules = map go
   where
   go :: Module Ann -> Module Ann
-  go m@(Module _ _ _ _ _ decls) = m { moduleDecls = map (renameInDecl' (findDeclIdents decls)) decls }
+  go m@(Module _ _ _ _ _ _ _ decls) = m { moduleDecls = map (renameInDecl' (findDeclIdents decls)) decls }
 
   renameInDecl' :: [Ident] -> Bind Ann -> Bind Ann
   renameInDecl' scope = runRename scope . renameInDecl True
diff --git a/src/Language/PureScript/Sugar.hs b/src/Language/PureScript/Sugar.hs
--- a/src/Language/PureScript/Sugar.hs
+++ b/src/Language/PureScript/Sugar.hs
@@ -18,6 +18,7 @@
 import Language.PureScript.Sugar.BindingGroups as S
 import Language.PureScript.Sugar.CaseDeclarations as S
 import Language.PureScript.Sugar.DoNotation as S
+import Language.PureScript.Sugar.AdoNotation as S
 import Language.PureScript.Sugar.LetPattern as S
 import Language.PureScript.Sugar.Names as S
 import Language.PureScript.Sugar.ObjectWildcards as S
@@ -37,6 +38,8 @@
 --
 --  * Desugar do-notation
 --
+--  * Desugar ado-notation
+--
 --  * Desugar top-level case declarations into explicit case expressions
 --
 --  * Desugar type declarations into value declarations with explicit type annotations
@@ -58,6 +61,7 @@
   map desugarSignedLiterals
     >>> traverse desugarObjectConstructors
     >=> traverse desugarDoModule
+    >=> traverse desugarAdoModule
     >=> map desugarLetPatternModule
     >>> traverse desugarCasesModule
     >=> traverse desugarTypeDeclarationsModule
@@ -67,4 +71,3 @@
     >=> traverse (deriveInstances externs)
     >=> desugarTypeClasses externs
     >=> traverse createBindingGroupsModule
-
diff --git a/src/Language/PureScript/Sugar/AdoNotation.hs b/src/Language/PureScript/Sugar/AdoNotation.hs
new file mode 100644
--- /dev/null
+++ b/src/Language/PureScript/Sugar/AdoNotation.hs
@@ -0,0 +1,67 @@
+-- | This module implements the desugaring pass which replaces ado-notation statements with
+-- appropriate calls to pure and apply.
+
+{-# LANGUAGE PatternGuards #-}
+
+module Language.PureScript.Sugar.AdoNotation (desugarAdoModule) where
+
+import           Prelude.Compat hiding (abs)
+
+import           Control.Monad (foldM)
+import           Control.Monad.Error.Class (MonadError(..))
+import           Control.Monad.Supply.Class
+import           Data.List (foldl')
+import           Language.PureScript.AST
+import           Language.PureScript.Errors
+import           Language.PureScript.Names
+import qualified Language.PureScript.Constants as C
+
+-- | Replace all @AdoNotationBind@ and @AdoNotationValue@ constructors with
+-- applications of the pure and apply functions in scope, and all @AdoNotationLet@
+-- constructors with let expressions.
+desugarAdoModule :: forall m. (MonadSupply m, MonadError MultipleErrors m) => Module -> m Module
+desugarAdoModule (Module ss coms mn ds exts) = Module ss coms mn <$> parU ds desugarAdo <*> pure exts
+
+-- | Desugar a single ado statement
+desugarAdo :: forall m. (MonadSupply m, MonadError MultipleErrors m) => Declaration -> m Declaration
+desugarAdo d =
+  let (f, _, _) = everywhereOnValuesM return replace return
+  in f d
+  where
+  pure' :: Expr
+  pure' = Var nullSourceSpan (Qualified Nothing (Ident C.pure'))
+
+  map' :: Expr
+  map' = Var nullSourceSpan (Qualified Nothing (Ident C.map))
+
+  apply :: Expr
+  apply = Var nullSourceSpan (Qualified Nothing (Ident C.apply))
+
+  replace :: Expr -> m Expr
+  replace (Ado els yield) = do
+    (func, args) <- foldM go (yield, []) (reverse els)
+    return $ case args of
+      [] -> App pure' func
+      hd : tl -> foldl' (\a b -> App (App apply a) b) (App (App map' func) hd) tl
+  replace (PositionedValue pos com v) = PositionedValue pos com <$> rethrowWithPosition pos (replace v)
+  replace other = return other
+
+  go :: (Expr, [Expr]) -> DoNotationElement -> m (Expr, [Expr])
+  go (yield, args) (DoNotationValue val) =
+    return (Abs NullBinder yield, val : args)
+  go (yield, args) (DoNotationBind (VarBinder ss ident) val) =
+    return (Abs (VarBinder ss ident) yield, val : args)
+  go (yield, args) (DoNotationBind binder val) = do
+    ident <- freshIdent'
+    let abs = Abs (VarBinder nullSourceSpan ident)
+                  (Case [Var nullSourceSpan (Qualified Nothing ident)]
+                        [CaseAlternative [binder] [MkUnguarded yield]])
+    return (abs, val : args)
+  go (yield, args) (DoNotationLet ds) = do
+    return (Let FromLet ds yield, args)
+  go acc (PositionedDoNotationElement pos com el) =
+    rethrowWithPosition pos $ do
+      (yield, args) <- go acc el
+      return $ case args of
+        [] -> (PositionedValue pos com yield, args)
+        (a : as) -> (yield, PositionedValue pos com a : as)
diff --git a/src/Language/PureScript/Sugar/BindingGroups.hs b/src/Language/PureScript/Sugar/BindingGroups.hs
--- a/src/Language/PureScript/Sugar/BindingGroups.hs
+++ b/src/Language/PureScript/Sugar/BindingGroups.hs
@@ -58,7 +58,7 @@
   (f, _, _) = everywhereOnValuesTopDownM return handleExprs return
 
   handleExprs :: Expr -> m Expr
-  handleExprs (Let ds val) = flip Let val <$> handleDecls ds
+  handleExprs (Let w ds val) = (\ds' -> Let w ds' val) <$> handleDecls ds
   handleExprs other = return other
 
   -- |
@@ -102,7 +102,7 @@
   go other = [other]
 
 collapseBindingGroupsForValue :: Expr -> Expr
-collapseBindingGroupsForValue (Let ds val) = Let (collapseBindingGroups ds) val
+collapseBindingGroupsForValue (Let w ds val) = Let w (collapseBindingGroups ds) val
 collapseBindingGroupsForValue other = other
 
 usedIdents :: ModuleName -> ValueDeclarationData Expr -> [Ident]
@@ -112,11 +112,11 @@
 
   (_, usedIdents', _, _, _) = everythingWithScope def usedNamesE def def def
 
-  usedNamesE :: S.Set Ident -> Expr -> [Ident]
-  usedNamesE scope (Var (Qualified Nothing name))
-    | name `S.notMember` scope = [name]
-  usedNamesE scope (Var (Qualified (Just moduleName') name))
-    | moduleName == moduleName' && name `S.notMember` scope = [name]
+  usedNamesE :: S.Set ScopedIdent -> Expr -> [Ident]
+  usedNamesE scope (Var _ (Qualified Nothing name))
+    | LocalIdent name `S.notMember` scope = [name]
+  usedNamesE scope (Var _ (Qualified (Just moduleName') name))
+    | moduleName == moduleName' && ToplevelIdent name `S.notMember` scope = [name]
   usedNamesE _ _ = []
 
 usedImmediateIdents :: ModuleName -> Declaration -> [Ident]
@@ -127,8 +127,8 @@
   def s _ = (s, [])
 
   usedNamesE :: Bool -> Expr -> (Bool, [Ident])
-  usedNamesE True (Var (Qualified Nothing name)) = (True, [name])
-  usedNamesE True (Var (Qualified (Just moduleName') name))
+  usedNamesE True (Var _ (Qualified Nothing name)) = (True, [name])
+  usedNamesE True (Var _ (Qualified (Just moduleName') name))
     | moduleName == moduleName' = (True, [name])
   usedNamesE True (Abs _ _) = (False, [])
   usedNamesE scope _ = (scope, [])
diff --git a/src/Language/PureScript/Sugar/CaseDeclarations.hs b/src/Language/PureScript/Sugar/CaseDeclarations.hs
--- a/src/Language/PureScript/Sugar/CaseDeclarations.hs
+++ b/src/Language/PureScript/Sugar/CaseDeclarations.hs
@@ -64,14 +64,14 @@
     -- We bind the scrutinee to Vars here to mitigate this case.
     (scrut', scrut_decls) <- unzip <$> forM scrut (\e -> do
       scrut_id <- freshIdent'
-      pure ( Var (Qualified Nothing scrut_id)
+      pure ( Var ss (Qualified Nothing scrut_id)
            , ValueDecl (ss, []) scrut_id Private [] [MkUnguarded e]
            )
       )
-    Let scrut_decls <$> desugarGuardedExprs ss (Case scrut' alternatives)
+    Let FromLet scrut_decls <$> desugarGuardedExprs ss (Case scrut' alternatives)
   where
-    isTrivialExpr (Var _) = True
-    isTrivialExpr (Literal _) = True
+    isTrivialExpr (Var _ _) = True
+    isTrivialExpr (Literal _ _) = True
     isTrivialExpr (Accessor _ e) = isTrivialExpr e
     isTrivialExpr (Parens e) = isTrivialExpr e
     isTrivialExpr (PositionedValue _ _ e) = isTrivialExpr e
@@ -196,7 +196,7 @@
       | isTrueExpr c = desugarGuard gs e match_failed
       | otherwise =
         Case [c]
-          (CaseAlternative [LiteralBinder (BooleanLiteral True)]
+          (CaseAlternative [LiteralBinder ss (BooleanLiteral True)]
             [MkUnguarded (desugarGuard gs e match_failed)] : match_failed)
 
     desugarGuard (PatternGuard vb g : gs) e match_failed =
@@ -226,13 +226,13 @@
 
         let
           goto_rem_case :: Expr
-          goto_rem_case = Var (Qualified Nothing rem_case_id)
-            `App` Literal (BooleanLiteral True)
+          goto_rem_case = Var ss (Qualified Nothing rem_case_id)
+            `App` Literal ss (BooleanLiteral True)
           alt_fail = [CaseAlternative [NullBinder] [MkUnguarded goto_rem_case]]
 
-        pure $ Let [
+        pure $ Let FromLet [
           ValueDecl (ss, []) rem_case_id Private []
-            [MkUnguarded (Abs (VarBinder unused_binder) desugared)]
+            [MkUnguarded (Abs (VarBinder ss unused_binder) desugared)]
           ] (mk_body alt_fail)
 
       | otherwise
@@ -308,11 +308,11 @@
   (f, _, _) = everywhereOnValuesM return replace return
 
   replace :: Expr -> m Expr
-  replace (Abs (stripPositioned -> (VarBinder i)) val) =
-    pure (Abs (VarBinder i) val)
+  replace (Abs (stripPositioned -> (VarBinder ss i)) val) =
+    pure (Abs (VarBinder ss i) val)
   replace (Abs binder val) = do
     ident <- freshIdent'
-    return $ Abs (VarBinder ident) $ Case [Var (Qualified Nothing ident)] [CaseAlternative [binder] [MkUnguarded val]]
+    return $ Abs (VarBinder nullSourceSpan ident) $ Case [Var nullSourceSpan (Qualified Nothing ident)] [CaseAlternative [binder] [MkUnguarded val]]
   replace other = return other
 
 stripPositioned :: Binder -> Binder
@@ -326,14 +326,14 @@
 desugarCases = desugarRest <=< fmap join . flip parU toDecls . groupBy inSameGroup
   where
     desugarRest :: [Declaration] -> m [Declaration]
-    desugarRest (TypeInstanceDeclaration sa name constraints className tys ds : rest) =
-      (:) <$> (TypeInstanceDeclaration sa name constraints className tys <$> traverseTypeInstanceBody desugarCases ds) <*> desugarRest rest
+    desugarRest (TypeInstanceDeclaration sa cd idx name constraints className tys ds : rest) =
+      (:) <$> (TypeInstanceDeclaration sa cd idx name constraints className tys <$> traverseTypeInstanceBody desugarCases ds) <*> desugarRest rest
     desugarRest (ValueDecl sa name nameKind bs result : rest) =
       let (_, f, _) = everywhereOnValuesTopDownM return go return
           f' = mapM (\(GuardedExpr gs e) -> GuardedExpr gs <$> f e)
       in (:) <$> (ValueDecl sa name nameKind bs <$> f' result) <*> desugarRest rest
       where
-      go (Let ds val') = Let <$> desugarCases ds <*> pure val'
+      go (Let w ds val') = Let w <$> desugarCases ds <*> pure val'
       go other = return other
     desugarRest (d : ds) = (:) d <$> desugarRest ds
     desugarRest [] = pure []
@@ -345,13 +345,13 @@
 toDecls :: forall m. (MonadSupply m, MonadError MultipleErrors m) => [Declaration] -> m [Declaration]
 toDecls [ValueDecl sa@(ss, _) ident nameKind bs [MkUnguarded val]] | all isIrrefutable bs = do
   args <- mapM fromVarBinder bs
-  let body = foldr (Abs . VarBinder) val args
+  let body = foldr (Abs . VarBinder ss) val args
   guardWith (errorMessage' ss (OverlappingArgNames (Just ident))) $ length (ordNub args) == length args
   return [ValueDecl sa ident nameKind [] [MkUnguarded body]]
   where
   fromVarBinder :: Binder -> m Ident
   fromVarBinder NullBinder = freshIdent'
-  fromVarBinder (VarBinder name) = return name
+  fromVarBinder (VarBinder _ name) = return name
   fromVarBinder (PositionedBinder _ _ b) = fromVarBinder b
   fromVarBinder (TypedBinder _ b) = fromVarBinder b
   fromVarBinder _ = internalError "fromVarBinder: Invalid argument"
@@ -380,9 +380,9 @@
   args <- if allUnique (catMaybes argNames)
             then mapM argName argNames
             else replicateM (length argNames) freshIdent'
-  let vars = map (Var . Qualified Nothing) args
+  let vars = map (Var ss . Qualified Nothing) args
       binders = [ CaseAlternative bs result | (bs, result) <- alternatives ]
-  let value = foldr (Abs . VarBinder) (Case vars binders) args
+  let value = foldr (Abs . VarBinder ss) (Case vars binders) args
 
   return $ ValueDecl (ss, []) ident Public [] [MkUnguarded value]
   where
@@ -391,7 +391,7 @@
   -- Everything else becomes Nothing, which indicates that we
   -- have to generate a name.
   findName :: Binder -> Maybe Ident
-  findName (VarBinder name) = Just name
+  findName (VarBinder _ name) = Just name
   findName (PositionedBinder _ _ binder) = findName binder
   findName _ = Nothing
 
diff --git a/src/Language/PureScript/Sugar/DoNotation.hs b/src/Language/PureScript/Sugar/DoNotation.hs
--- a/src/Language/PureScript/Sugar/DoNotation.hs
+++ b/src/Language/PureScript/Sugar/DoNotation.hs
@@ -29,10 +29,10 @@
   in rethrowWithPosition (declSourceSpan d) $ f d
   where
   bind :: Expr
-  bind = Var (Qualified Nothing (Ident C.bind))
+  bind = Var nullSourceSpan (Qualified Nothing (Ident C.bind))
 
   discard :: Expr
-  discard = Var (Qualified Nothing (Ident C.discard))
+  discard = Var nullSourceSpan (Qualified Nothing (Ident C.discard))
 
   replace :: Expr -> m Expr
   replace (Do els) = go els
@@ -44,20 +44,20 @@
   go [DoNotationValue val] = return val
   go (DoNotationValue val : rest) = do
     rest' <- go rest
-    return $ App (App discard val) (Abs (VarBinder (Ident C.__unused)) rest')
+    return $ App (App discard val) (Abs (VarBinder nullSourceSpan UnusedIdent) rest')
   go [DoNotationBind _ _] = throwError . errorMessage $ InvalidDoBind
   go (DoNotationBind b _ : _) | First (Just ident) <- foldMap fromIdent (binderNames b) =
       throwError . errorMessage $ CannotUseBindWithDo (Ident ident)
     where
       fromIdent (Ident i) | i `elem` [ C.bind, C.discard ] = First (Just i)
       fromIdent _ = mempty
-  go (DoNotationBind (VarBinder ident) val : rest) = do
+  go (DoNotationBind (VarBinder ss ident) val : rest) = do
     rest' <- go rest
-    return $ App (App bind val) (Abs (VarBinder ident) rest')
+    return $ App (App bind val) (Abs (VarBinder ss ident) rest')
   go (DoNotationBind binder val : rest) = do
     rest' <- go rest
     ident <- freshIdent'
-    return $ App (App bind val) (Abs (VarBinder ident) (Case [Var (Qualified Nothing ident)] [CaseAlternative [binder] [MkUnguarded rest']]))
+    return $ App (App bind val) (Abs (VarBinder nullSourceSpan ident) (Case [Var nullSourceSpan (Qualified Nothing ident)] [CaseAlternative [binder] [MkUnguarded rest']]))
   go [DoNotationLet _] = throwError . errorMessage $ InvalidDoLet
   go (DoNotationLet ds : rest) = do
     let checkBind :: Declaration -> m ()
@@ -66,5 +66,5 @@
         checkBind _ = pure ()
     mapM_ checkBind ds
     rest' <- go rest
-    return $ Let ds rest'
+    return $ Let FromLet ds rest'
   go (PositionedDoNotationElement pos com el : rest) = rethrowWithPosition pos $ PositionedValue pos com <$> go (el : rest)
diff --git a/src/Language/PureScript/Sugar/LetPattern.hs b/src/Language/PureScript/Sugar/LetPattern.hs
--- a/src/Language/PureScript/Sugar/LetPattern.hs
+++ b/src/Language/PureScript/Sugar/LetPattern.hs
@@ -6,37 +6,49 @@
 
 import Prelude.Compat
 
+import Data.List (groupBy, concatMap)
+import Data.Function (on)
+
 import Language.PureScript.AST
+import Language.PureScript.Crash
 
--- |
--- Replace every @BoundValueDeclaration@ in @Let@ expressions with @Case@
+-- | Replace every @BoundValueDeclaration@ in @Let@ expressions with @Case@
 -- expressions.
---
 desugarLetPatternModule :: Module -> Module
 desugarLetPatternModule (Module ss coms mn ds exts) = Module ss coms mn (map desugarLetPattern ds) exts
 
--- |
--- Desugar a single let expression
---
+-- | Desugar a single let expression
 desugarLetPattern :: Declaration -> Declaration
 desugarLetPattern decl =
   let (f, _, _) = everywhereOnValues id replace id
   in f decl
   where
   replace :: Expr -> Expr
-  replace (Let ds e) = go ds e
+  replace (Let w ds e) = go w (partitionDecls ds) e
   replace other = other
 
-  go :: [Declaration]
+  go :: WhereProvenance
+     -- ^ Metadata about whether the let-in was a where clause
+     -> [Either [Declaration] (SourceAnn, Binder, Expr)]
      -- ^ Declarations to desugar
      -> Expr
      -- ^ The original let-in result expression
      -> Expr
-  go [] e = e
-  go (BoundValueDeclaration (pos, com) binder boundE : ds) e =
-    PositionedValue pos com $ Case [boundE] [CaseAlternative [binder] [MkUnguarded $ go ds e]]
-  go (d:ds) e = append d $ go ds e
+  go _ [] e = e
+  go w (Right ((pos, com), binder, boundE) : ds) e =
+    PositionedValue pos com $ Case [boundE] [CaseAlternative [binder] [MkUnguarded $ go w ds e]]
+  go w (Left ds:dss) e = Let w ds (go w dss e)
 
-  append :: Declaration -> Expr -> Expr
-  append d (Let ds e) = Let (d:ds) e
-  append d e = Let [d] e
+partitionDecls :: [Declaration] -> [Either [Declaration] (SourceAnn, Binder, Expr)]
+partitionDecls = concatMap f . groupBy ((==) `on` isBoundValueDeclaration)
+  where
+    f ds@(d:_)
+      | isBoundValueDeclaration d = map (Right . g) ds
+    f ds = [Left ds]
+
+    g (BoundValueDeclaration sa binder expr) = (sa, binder, expr)
+    g _ = internalError "partitionDecls: the impossible happened."
+
+isBoundValueDeclaration :: Declaration -> Bool
+isBoundValueDeclaration BoundValueDeclaration{} = True
+isBoundValueDeclaration _ = False
diff --git a/src/Language/PureScript/Sugar/Names.hs b/src/Language/PureScript/Sugar/Names.hs
--- a/src/Language/PureScript/Sugar/Names.hs
+++ b/src/Language/PureScript/Sugar/Names.hs
@@ -2,6 +2,7 @@
   ( desugarImports
   , desugarImportsWithEnv
   , Env
+  , primEnv
   , ImportRecord(..)
   , ImportProvenance(..)
   , Imports(..)
@@ -209,9 +210,9 @@
         <*> updateConstraints ss implies
         <*> pure deps
         <*> pure ds
-  updateDecl bound (TypeInstanceDeclaration sa@(ss, _) name cs cn ts ds) =
+  updateDecl bound (TypeInstanceDeclaration sa@(ss, _) ch idx name cs cn ts ds) =
     fmap (bound,) $
-      TypeInstanceDeclaration sa name
+      TypeInstanceDeclaration sa ch idx name
         <$> updateConstraints ss cs
         <*> updateClassName cn ss
         <*> traverse (updateTypesEverywhere ss) ts
@@ -252,21 +253,21 @@
     -> m ((SourceSpan, [Ident]), Expr)
   updateValue (_, bound) v@(PositionedValue pos' _ _) =
     return ((pos', bound), v)
-  updateValue (pos, bound) (Abs (VarBinder arg) val') =
-    return ((pos, arg : bound), Abs (VarBinder arg) val')
-  updateValue (pos, bound) (Let ds val') = do
+  updateValue (pos, bound) (Abs (VarBinder ss arg) val') =
+    return ((pos, arg : bound), Abs (VarBinder ss arg) val')
+  updateValue (pos, bound) (Let w ds val') = do
     let args = mapMaybe letBoundVariable ds
     unless (length (ordNub args) == length args) .
       throwError . errorMessage' pos $ OverlappingNamesInLet
-    return ((pos, args ++ bound), Let ds val')
-  updateValue (pos, bound) (Var name'@(Qualified Nothing ident)) | ident `notElem` bound =
-    (,) (pos, bound) <$> (Var <$> updateValueName name' pos)
-  updateValue (pos, bound) (Var name'@(Qualified (Just _) _)) =
-    (,) (pos, bound) <$> (Var <$> updateValueName name' pos)
-  updateValue (pos, bound) (Op op) =
-    (,) (pos, bound) <$> (Op <$> updateValueOpName op pos)
-  updateValue s@(pos, _) (Constructor name) =
-    (,) s <$> (Constructor <$> updateDataConstructorName name pos)
+    return ((pos, args ++ bound), Let w ds val')
+  updateValue (_, bound) (Var ss name'@(Qualified Nothing ident)) | ident `notElem` bound =
+    (,) (ss, bound) <$> (Var ss <$> updateValueName name' ss)
+  updateValue (_, bound) (Var ss name'@(Qualified (Just _) _)) =
+    (,) (ss, bound) <$> (Var ss <$> updateValueName name' ss)
+  updateValue (_, bound) (Op ss op) =
+    (,) (ss, bound) <$> (Op ss <$> updateValueOpName op ss)
+  updateValue (_, bound) (Constructor ss name) =
+    (,) (ss, bound) <$> (Constructor ss <$> updateDataConstructorName name ss)
   updateValue s@(pos, _) (TypedValue check val ty) =
     (,) s <$> (TypedValue check val <$> updateTypesEverywhere pos ty)
   updateValue s v = return (s, v)
@@ -277,10 +278,10 @@
     -> m ((SourceSpan, [Ident]), Binder)
   updateBinder (_, bound) v@(PositionedBinder pos _ _) =
     return ((pos, bound), v)
-  updateBinder s@(pos, _) (ConstructorBinder name b) =
-    (,) s <$> (ConstructorBinder <$> updateDataConstructorName name pos <*> pure b)
-  updateBinder s@(pos, _) (OpBinder op) =
-    (,) s <$> (OpBinder <$> updateValueOpName op pos)
+  updateBinder (_, bound) (ConstructorBinder ss name b) =
+    (,) (ss, bound) <$> (ConstructorBinder ss <$> updateDataConstructorName name ss <*> pure b)
+  updateBinder (_, bound) (OpBinder ss op) =
+    (,) (ss, bound) <$> (OpBinder ss <$> updateValueOpName op ss)
   updateBinder s@(pos, _) (TypedBinder t b) = do
     t' <- updateTypesEverywhere pos t
     return (s, TypedBinder t' b)
@@ -396,7 +397,7 @@
       -- re-exports. If there are multiple options for the name to resolve to
       -- in scope, we throw an error.
       (Just options, _) -> do
-        (mnNew, mnOrig) <- checkImportConflicts mn toName options
+        (mnNew, mnOrig) <- checkImportConflicts pos mn toName options
         modify $ \usedImports ->
           M.insertWith (++) mnNew [fmap toName qname] usedImports
         return $ Qualified (Just mnOrig) name
diff --git a/src/Language/PureScript/Sugar/Names/Env.hs b/src/Language/PureScript/Sugar/Names/Env.hs
--- a/src/Language/PureScript/Sugar/Names/Env.hs
+++ b/src/Language/PureScript/Sugar/Names/Env.hs
@@ -7,6 +7,7 @@
   , nullExports
   , Env
   , primEnv
+  , primExports
   , envModuleSourceSpan
   , envModuleImports
   , envModuleExports
@@ -34,6 +35,7 @@
 import qualified Data.Map as M
 import qualified Data.Set as S
 
+import qualified Language.PureScript.Constants as C
 import Language.PureScript.AST
 import Language.PureScript.Environment
 import Language.PureScript.Errors
@@ -48,6 +50,7 @@
   ImportRecord
     { importName :: Qualified a
     , importSourceModule :: ModuleName
+    , importSourceSpan :: SourceSpan
     , importProvenance :: ImportProvenance
     }
     deriving (Eq, Ord, Show)
@@ -182,22 +185,79 @@
 -- The exported types from the @Prim@ module
 --
 primExports :: Exports
-primExports =
+primExports = mkPrimExports primTypes primClasses primKinds
+
+-- |
+-- The exported types from the @Prim.Ordering@ module
+--
+primOrderingExports :: Exports
+primOrderingExports = mkPrimExports primOrderingTypes mempty primOrderingKinds
+
+-- |
+-- The exported types from the @Prim.Row@ module
+--
+primRowExports :: Exports
+primRowExports = mkPrimExports primRowTypes primRowClasses mempty
+
+-- |
+-- The exported types from the @Prim.RowList@ module
+--
+primRowListExports :: Exports
+primRowListExports = mkPrimExports primRowListTypes primRowListClasses primRowListKinds
+
+-- |
+-- The exported types from the @Prim.Symbol@ module
+--
+primSymbolExports :: Exports
+primSymbolExports = mkPrimExports primSymbolTypes primSymbolClasses mempty
+
+-- |
+-- The exported types from the @Prim.TypeError@ module
+--
+primTypeErrorExports :: Exports
+primTypeErrorExports = mkPrimExports primTypeErrorTypes primTypeErrorClasses primTypeErrorKinds
+
+-- |
+-- Create a set of exports for a Prim module.
+--
+mkPrimExports
+  :: M.Map (Qualified (ProperName 'TypeName)) a
+  -> M.Map (Qualified (ProperName 'ClassName)) b
+  -> S.Set (Qualified (ProperName 'KindName))
+  -> Exports
+mkPrimExports ts cs ks =
   nullExports
-    { exportedTypes = M.fromList $ mkTypeEntry `map` M.keys primTypes
-    , exportedTypeClasses = M.fromList $ mkClassEntry `map` M.keys primClasses
-    , exportedKinds = M.fromList $ mkKindEntry `map` S.toList primKinds
+    { exportedTypes = M.fromList $ mkTypeEntry `map` M.keys ts
+    , exportedTypeClasses = M.fromList $ mkClassEntry `map` M.keys cs
+    , exportedKinds = M.fromList $ mkKindEntry `map` S.toList ks
     }
   where
   mkTypeEntry (Qualified mn name) = (name, ([], fromJust mn))
   mkClassEntry (Qualified mn name) = (name, fromJust mn)
   mkKindEntry (Qualified mn name) = (name, fromJust mn)
 
--- | Environment which only contains the Prim module.
+-- | Environment which only contains the Prim modules.
 primEnv :: Env
-primEnv = M.singleton
-  (ModuleName [ProperName "Prim"])
-  (internalModuleSourceSpan "<Prim>", nullImports, primExports)
+primEnv = M.fromList
+  [ ( C.Prim
+    , (internalModuleSourceSpan "<Prim>", nullImports, primExports)
+    )
+  , ( C.PrimOrdering
+    , (internalModuleSourceSpan "<Prim.Ordering>", nullImports, primOrderingExports)
+    )
+  , ( C.PrimRow
+    , (internalModuleSourceSpan "<Prim.Row>", nullImports, primRowExports)
+    )
+  , ( C.PrimRowList
+    , (internalModuleSourceSpan "<Prim.RowList>", nullImports, primRowListExports)
+    )
+  , ( C.PrimSymbol
+    , (internalModuleSourceSpan "<Prim.Symbol>", nullImports, primSymbolExports)
+    )
+  , ( C.PrimTypeError
+    , (internalModuleSourceSpan "<Prim.TypeError>", nullImports, primTypeErrorExports)
+    )
+  ]
 
 -- |
 -- When updating the `Exports` the behaviour is slightly different depending
@@ -214,13 +274,14 @@
 --
 exportType
   :: MonadError MultipleErrors m
-  => ExportMode
+  => SourceSpan
+  -> ExportMode
   -> Exports
   -> ProperName 'TypeName
   -> [ProperName 'ConstructorName]
   -> ModuleName
   -> m Exports
-exportType exportMode exps name dctors mn = do
+exportType ss exportMode exps name dctors mn = do
   let exTypes = exportedTypes exps
       exClasses = exportedTypeClasses exps
       dctorNameCounts :: [(ProperName 'ConstructorName, Int)]
@@ -242,11 +303,11 @@
     ReExport -> do
       forM_ (name `M.lookup` exTypes) $ \(_, mn') ->
         when (mn /= mn') $
-          throwExportConflict mn mn' (TyName name)
+          throwExportConflict ss mn mn' (TyName name)
       forM_ dctors $ \dctor ->
         forM_ ((elem dctor . fst) `find` exTypes) $ \(_, mn') ->
           when (mn /= mn') $
-            throwExportConflict mn mn' (DctorName dctor)
+            throwExportConflict ss mn mn' (DctorName dctor)
   return $ exps { exportedTypes = M.alter updateOrInsert name exTypes }
   where
   updateOrInsert Nothing = Just (dctors, mn)
@@ -258,12 +319,13 @@
 --
 exportTypeOp
   :: MonadError MultipleErrors m
-  => Exports
+  => SourceSpan
+  -> Exports
   -> OpName 'TypeOpName
   -> ModuleName
   -> m Exports
-exportTypeOp exps op mn = do
-  typeOps <- addExport TyOpName op mn (exportedTypeOps exps)
+exportTypeOp ss exps op mn = do
+  typeOps <- addExport ss TyOpName op mn (exportedTypeOps exps)
   return $ exps { exportedTypeOps = typeOps }
 
 -- |
@@ -271,19 +333,20 @@
 --
 exportTypeClass
   :: MonadError MultipleErrors m
-  => ExportMode
+  => SourceSpan
+  -> ExportMode
   -> Exports
   -> ProperName 'ClassName
   -> ModuleName
   -> m Exports
-exportTypeClass exportMode exps name mn = do
+exportTypeClass ss exportMode exps name mn = do
   let exTypes = exportedTypes exps
   when (exportMode == Internal) $ do
     when (coerceProperName name `M.member` exTypes) $
       throwDeclConflict (TyClassName name) (TyName (coerceProperName name))
     when ((elem (coerceProperName name) . fst) `any` exTypes) $
       throwDeclConflict (TyClassName name) (DctorName (coerceProperName name))
-  classes <- addExport TyClassName name mn (exportedTypeClasses exps)
+  classes <- addExport ss TyClassName name mn (exportedTypeClasses exps)
   return $ exps { exportedTypeClasses = classes }
 
 -- |
@@ -291,12 +354,13 @@
 --
 exportValue
   :: MonadError MultipleErrors m
-  => Exports
+  => SourceSpan
+  -> Exports
   -> Ident
   -> ModuleName
   -> m Exports
-exportValue exps name mn = do
-  values <- addExport IdentName name mn (exportedValues exps)
+exportValue ss exps name mn = do
+  values <- addExport ss IdentName name mn (exportedValues exps)
   return $ exps { exportedValues = values }
 
 -- |
@@ -305,12 +369,13 @@
 --
 exportValueOp
   :: MonadError MultipleErrors m
-  => Exports
+  => SourceSpan
+  -> Exports
   -> OpName 'ValueOpName
   -> ModuleName
   -> m Exports
-exportValueOp exps op mn = do
-  valueOps <- addExport ValOpName op mn (exportedValueOps exps)
+exportValueOp ss exps op mn = do
+  valueOps <- addExport ss ValOpName op mn (exportedValueOps exps)
   return $ exps { exportedValueOps = valueOps }
 
 -- |
@@ -318,12 +383,13 @@
 --
 exportKind
   :: MonadError MultipleErrors m
-  => Exports
+  => SourceSpan
+  -> Exports
   -> ProperName 'KindName
   -> ModuleName
   -> m Exports
-exportKind exps name mn = do
-  kinds <- addExport KiName name mn (exportedKinds exps)
+exportKind ss exps name mn = do
+  kinds <- addExport ss KiName name mn (exportedKinds exps)
   return $ exps { exportedKinds = kinds }
 
 -- |
@@ -332,16 +398,17 @@
 --
 addExport
   :: (MonadError MultipleErrors m, Ord a)
-  => (a -> Name)
+  => SourceSpan
+  -> (a -> Name)
   -> a
   -> ModuleName
   -> M.Map a ModuleName
   -> m (M.Map a ModuleName)
-addExport toName name mn exports =
+addExport ss toName name mn exports =
   case M.lookup name exports of
     Just mn'
       | mn == mn' -> return exports
-      | otherwise -> throwExportConflict mn mn' (toName name)
+      | otherwise -> throwExportConflict ss mn mn' (toName name)
     Nothing ->
       return $ M.insert name mn exports
 
@@ -361,12 +428,13 @@
 --
 throwExportConflict
   :: MonadError MultipleErrors m
-  => ModuleName
+  => SourceSpan
   -> ModuleName
+  -> ModuleName
   -> Name
   -> m a
-throwExportConflict new existing name =
-  throwError . errorMessage $
+throwExportConflict ss new existing name =
+  throwError . errorMessage' ss $
     ExportConflict (Qualified (Just new) name) (Qualified (Just existing) name)
 
 -- |
@@ -386,11 +454,12 @@
 checkImportConflicts
   :: forall m a
    . (MonadError MultipleErrors m, MonadWriter MultipleErrors m)
-  => ModuleName
+  => SourceSpan
+  -> ModuleName
   -> (a -> Name)
   -> [ImportRecord a]
   -> m (ModuleName, ModuleName)
-checkImportConflicts currentModule toName xs =
+checkImportConflicts ss currentModule toName xs =
   let
     byOrig = sortBy (compare `on` importSourceModule) xs
     groups = groupBy ((==) `on` importSourceModule) byOrig
@@ -400,11 +469,11 @@
   in
     if length groups > 1
     then case nonImplicit of
-      [ImportRecord (Qualified (Just mnNew) _) mnOrig _] -> do
+      [ImportRecord (Qualified (Just mnNew) _) mnOrig ss' _] -> do
         let warningModule = if mnNew == currentModule then Nothing else Just mnNew
-        tell . errorMessage $ ScopeShadowing name warningModule $ delete mnNew conflictModules
+        tell . errorMessage' ss' $ ScopeShadowing name warningModule $ delete mnNew conflictModules
         return (mnNew, mnOrig)
-      _ -> throwError . errorMessage $ ScopeConflict name conflictModules
+      _ -> throwError . errorMessage' ss $ ScopeConflict name conflictModules
     else
-      let ImportRecord (Qualified (Just mnNew) _) mnOrig _ = head byOrig
+      let ImportRecord (Qualified (Just mnNew) _) mnOrig _ _ = head byOrig
       in return (mnNew, mnOrig)
diff --git a/src/Language/PureScript/Sugar/Names/Exports.hs b/src/Language/PureScript/Sugar/Names/Exports.hs
--- a/src/Language/PureScript/Sugar/Names/Exports.hs
+++ b/src/Language/PureScript/Sugar/Names/Exports.hs
@@ -34,27 +34,27 @@
 
   updateExports :: Exports -> Declaration -> m Exports
   updateExports exps (TypeClassDeclaration (ss, _) tcn _ _ _ ds') = do
-    exps' <- rethrowWithPosition ss $ exportTypeClass Internal exps tcn mn
+    exps' <- rethrowWithPosition ss $ exportTypeClass ss Internal exps tcn mn
     foldM go exps' ds'
     where
-    go exps'' (TypeDeclaration (TypeDeclarationData (ss', _) name _)) = rethrowWithPosition ss' $ exportValue exps'' name mn
+    go exps'' (TypeDeclaration (TypeDeclarationData (ss', _) name _)) = exportValue ss' exps'' name mn
     go _ _ = internalError "Invalid declaration in TypeClassDeclaration"
-  updateExports exps (DataDeclaration _ _ tn _ dcs) =
-    exportType Internal exps tn (map fst dcs) mn
-  updateExports exps (TypeSynonymDeclaration _ tn _ _) =
-    exportType Internal exps tn [] mn
-  updateExports exps (ExternDataDeclaration _ tn _) =
-    exportType Internal exps tn [] mn
+  updateExports exps (DataDeclaration (ss, _) _ tn _ dcs) =
+    exportType ss Internal exps tn (map fst dcs) mn
+  updateExports exps (TypeSynonymDeclaration (ss, _) tn _ _) =
+    exportType ss Internal exps tn [] mn
+  updateExports exps (ExternDataDeclaration (ss, _) tn _) =
+    exportType ss Internal exps tn [] mn
   updateExports exps (ValueDeclaration vd) =
-    exportValue exps (valdeclIdent vd) mn
-  updateExports exps (ValueFixityDeclaration _ _ _ op) =
-    exportValueOp exps op mn
-  updateExports exps (TypeFixityDeclaration _ _ _ op) =
-    exportTypeOp exps op mn
-  updateExports exps (ExternDeclaration _ name _) =
-    exportValue exps name mn
-  updateExports exps (ExternKindDeclaration _ pn) =
-    exportKind exps pn mn
+    exportValue (fst (valdeclSourceAnn vd)) exps (valdeclIdent vd) mn
+  updateExports exps (ValueFixityDeclaration (ss, _) _ _ op) =
+    exportValueOp ss exps op mn
+  updateExports exps (TypeFixityDeclaration (ss, _) _ _ op) =
+    exportTypeOp ss exps op mn
+  updateExports exps (ExternDeclaration (ss, _) name _) =
+    exportValue ss exps name mn
+  updateExports exps (ExternKindDeclaration (ss, _) pn) =
+    exportKind ss exps pn mn
   updateExports exps _ = return exps
 
 -- |
@@ -103,34 +103,35 @@
     let isPseudo = isPseudoModule name
     when (not isPseudo && not (isImportedModule name))
       . throwError . errorMessage' ss' . UnknownExport $ ModName name
-    reTypes <- extract isPseudo name TyName (importedTypes imps)
-    reTypeOps <- extract isPseudo name TyOpName (importedTypeOps imps)
-    reDctors <- extract isPseudo name DctorName (importedDataConstructors imps)
-    reClasses <- extract isPseudo name TyClassName (importedTypeClasses imps)
-    reValues <- extract isPseudo name IdentName (importedValues imps)
-    reValueOps <- extract isPseudo name ValOpName (importedValueOps imps)
-    reKinds <- extract isPseudo name KiName (importedKinds imps)
-    foldM (\exps' ((tctor, dctors), mn') -> exportType ReExport exps' tctor dctors mn') result (resolveTypeExports reTypes reDctors)
-      >>= flip (foldM (uncurry . exportTypeOp)) (map resolveTypeOp reTypeOps)
-      >>= flip (foldM (uncurry . exportTypeClass ReExport)) (map resolveClass reClasses)
-      >>= flip (foldM (uncurry . exportValue)) (map resolveValue reValues)
-      >>= flip (foldM (uncurry . exportValueOp)) (map resolveValueOp reValueOps)
-      >>= flip (foldM (uncurry . exportKind)) (map resolveKind reKinds)
+    reTypes <- extract ss' isPseudo name TyName (importedTypes imps)
+    reTypeOps <- extract ss' isPseudo name TyOpName (importedTypeOps imps)
+    reDctors <- extract ss' isPseudo name DctorName (importedDataConstructors imps)
+    reClasses <- extract ss' isPseudo name TyClassName (importedTypeClasses imps)
+    reValues <- extract ss' isPseudo name IdentName (importedValues imps)
+    reValueOps <- extract ss' isPseudo name ValOpName (importedValueOps imps)
+    reKinds <- extract ss' isPseudo name KiName (importedKinds imps)
+    foldM (\exps' ((tctor, dctors), mn') -> exportType ss' ReExport exps' tctor dctors mn') result (resolveTypeExports reTypes reDctors)
+      >>= flip (foldM (uncurry . exportTypeOp ss')) (map resolveTypeOp reTypeOps)
+      >>= flip (foldM (uncurry . exportTypeClass ss' ReExport)) (map resolveClass reClasses)
+      >>= flip (foldM (uncurry . exportValue ss')) (map resolveValue reValues)
+      >>= flip (foldM (uncurry . exportValueOp ss')) (map resolveValueOp reValueOps)
+      >>= flip (foldM (uncurry . exportKind ss')) (map resolveKind reKinds)
   elaborateModuleExports result _ = return result
 
   -- Extracts a list of values for a module based on a lookup table. If the
   -- boolean is true the values are filtered by the qualification
   extract
-    :: Bool
+    :: SourceSpan
+    -> Bool
     -> ModuleName
     -> (a -> Name)
     -> M.Map (Qualified a) [ImportRecord a]
     -> m [Qualified a]
-  extract useQual name toName = fmap (map (importName . head . snd)) . go . M.toList
+  extract ss' useQual name toName = fmap (map (importName . head . snd)) . go . M.toList
     where
     go = filterM $ \(name', options) -> do
       let isMatch = if useQual then isQualifiedWith name name' else any (checkUnqual name') options
-      when (isMatch && length options > 1) $ void $ checkImportConflicts mn toName options
+      when (isMatch && length options > 1) $ void $ checkImportConflicts ss' mn toName options
       return isMatch
     checkUnqual name' ir = isUnqualified name' && isQualifiedWith name (importName ir)
 
diff --git a/src/Language/PureScript/Sugar/Names/Imports.hs b/src/Language/PureScript/Sugar/Names/Imports.hs
--- a/src/Language/PureScript/Sugar/Names/Imports.hs
+++ b/src/Language/PureScript/Sugar/Names/Imports.hs
@@ -180,28 +180,28 @@
       >>= flip (foldM (\m (name, _) -> importer m (KindRef ss name))) (M.toList (exportedKinds exps))
 
   importRef :: ImportProvenance -> Imports -> DeclarationRef -> m Imports
-  importRef prov imp (ValueRef _ name) = do
-    let values' = updateImports (importedValues imp) (exportedValues exps) id name prov
+  importRef prov imp (ValueRef ss name) = do
+    let values' = updateImports (importedValues imp) (exportedValues exps) id name ss prov
     return $ imp { importedValues = values' }
-  importRef prov imp (ValueOpRef _ name) = do
-    let valueOps' = updateImports (importedValueOps imp) (exportedValueOps exps) id name prov
+  importRef prov imp (ValueOpRef ss name) = do
+    let valueOps' = updateImports (importedValueOps imp) (exportedValueOps exps) id name ss prov
     return $ imp { importedValueOps = valueOps' }
   importRef prov imp (TypeRef ss name dctors) = do
-    let types' = updateImports (importedTypes imp) (exportedTypes exps) snd name prov
+    let types' = updateImports (importedTypes imp) (exportedTypes exps) snd name ss prov
     let (dctorNames, mn) = allExportedDataConstructors name
         dctorLookup :: M.Map (ProperName 'ConstructorName) ModuleName
         dctorLookup = M.fromList $ map (, mn) dctorNames
     traverse_ (traverse_ $ checkDctorExists ss name dctorNames) dctors
-    let dctors' = foldl (\m d -> updateImports m dctorLookup id d prov) (importedDataConstructors imp) (fromMaybe dctorNames dctors)
+    let dctors' = foldl (\m d -> updateImports m dctorLookup id d ss prov) (importedDataConstructors imp) (fromMaybe dctorNames dctors)
     return $ imp { importedTypes = types', importedDataConstructors = dctors' }
-  importRef prov imp (TypeOpRef _ name) = do
-    let ops' = updateImports (importedTypeOps imp) (exportedTypeOps exps) id name prov
+  importRef prov imp (TypeOpRef ss name) = do
+    let ops' = updateImports (importedTypeOps imp) (exportedTypeOps exps) id name ss prov
     return $ imp { importedTypeOps = ops' }
-  importRef prov imp (TypeClassRef _ name) = do
-    let typeClasses' = updateImports (importedTypeClasses imp) (exportedTypeClasses exps) id name prov
+  importRef prov imp (TypeClassRef ss name) = do
+    let typeClasses' = updateImports (importedTypeClasses imp) (exportedTypeClasses exps) id name ss prov
     return $ imp { importedTypeClasses = typeClasses' }
-  importRef prov imp (KindRef _ name) = do
-    let kinds' = updateImports (importedKinds imp) (exportedKinds exps) id name prov
+  importRef prov imp (KindRef ss name) = do
+    let kinds' = updateImports (importedKinds imp) (exportedKinds exps) id name ss prov
     return $ imp { importedKinds = kinds' }
   importRef _ _ TypeInstanceRef{} = internalError "TypeInstanceRef in importRef"
   importRef _ _ ModuleRef{} = internalError "ModuleRef in importRef"
@@ -222,12 +222,13 @@
     -> M.Map a b
     -> (b -> ModuleName)
     -> a
+    -> SourceSpan
     -> ImportProvenance
     -> M.Map (Qualified a) [ImportRecord a]
-  updateImports imps' exps' expName name prov =
+  updateImports imps' exps' expName name ss prov =
     let
       mnOrig = maybe (internalError "Invalid state in updateImports") expName (name `M.lookup` exps')
-      rec = ImportRecord (Qualified (Just importModule) name) mnOrig prov
+      rec = ImportRecord (Qualified (Just importModule) name) mnOrig ss prov
     in
       M.alter
         (\currNames -> Just $ rec : fromMaybe [] currNames)
diff --git a/src/Language/PureScript/Sugar/ObjectWildcards.hs b/src/Language/PureScript/Sugar/ObjectWildcards.hs
--- a/src/Language/PureScript/Sugar/ObjectWildcards.hs
+++ b/src/Language/PureScript/Sugar/ObjectWildcards.hs
@@ -36,27 +36,27 @@
     | b' <- stripPositionInfo b
     , BinaryNoParens op val u <- b'
     , isAnonymousArgument u = do arg <- freshIdent'
-                                 return $ Abs (VarBinder arg) $ App (App op val) (Var (Qualified Nothing arg))
+                                 return $ Abs (VarBinder nullSourceSpan arg) $ App (App op val) (Var nullSourceSpan (Qualified Nothing arg))
     | b' <- stripPositionInfo b
     , BinaryNoParens op u val <- b'
     , isAnonymousArgument u = do arg <- freshIdent'
-                                 return $ Abs (VarBinder arg) $ App (App op (Var (Qualified Nothing arg))) val
-  desugarExpr (Literal (ObjectLiteral ps)) = wrapLambdaAssoc (Literal . ObjectLiteral) ps
+                                 return $ Abs (VarBinder nullSourceSpan arg) $ App (App op (Var nullSourceSpan (Qualified Nothing arg))) val
+  desugarExpr (Literal ss (ObjectLiteral ps)) = wrapLambdaAssoc (Literal ss . ObjectLiteral) ps
   desugarExpr (ObjectUpdateNested obj ps) = transformNestedUpdate obj ps
   desugarExpr (Accessor prop u)
     | Just props <- peelAnonAccessorChain u = do
       arg <- freshIdent'
-      return $ Abs (VarBinder arg) $ foldr Accessor (argToExpr arg) (prop:props)
+      return $ Abs (VarBinder nullSourceSpan arg) $ foldr Accessor (argToExpr arg) (prop:props)
   desugarExpr (Case args cas) | any isAnonymousArgument args = do
     argIdents <- forM args freshIfAnon
     let args' = zipWith (`maybe` argToExpr) args argIdents
-    return $ foldr (Abs . VarBinder) (Case args' cas) (catMaybes argIdents)
+    return $ foldr (Abs . VarBinder nullSourceSpan) (Case args' cas) (catMaybes argIdents)
   desugarExpr (IfThenElse u t f) | any isAnonymousArgument [u, t, f] = do
     u' <- freshIfAnon u
     t' <- freshIfAnon t
     f' <- freshIfAnon f
     let if_ = IfThenElse (maybe u argToExpr u') (maybe t argToExpr t') (maybe f argToExpr f')
-    return $ foldr (Abs . VarBinder) if_ (catMaybes [u', t', f'])
+    return $ foldr (Abs . VarBinder nullSourceSpan) if_ (catMaybes [u', t', f'])
   desugarExpr e = return e
 
   transformNestedUpdate :: Expr -> PathTree Expr -> m Expr
@@ -66,10 +66,10 @@
     val <- freshIdent'
     let valExpr = argToExpr val
     if isAnonymousArgument obj
-      then Abs (VarBinder val) <$> wrapLambda (buildUpdates valExpr) ps
+      then Abs (VarBinder nullSourceSpan val) <$> wrapLambda (buildUpdates valExpr) ps
       else wrapLambda (buildLet val . buildUpdates valExpr) ps
     where
-      buildLet val = Let [ValueDecl (declSourceSpan d, []) val Public [] [MkUnguarded obj]]
+      buildLet val = Let FromLet [ValueDecl (declSourceSpan d, []) val Public [] [MkUnguarded obj]]
 
       -- recursively build up the nested `ObjectUpdate` expressions
       buildUpdates :: Expr -> PathTree Expr -> Expr
@@ -86,7 +86,7 @@
   wrapLambda :: forall t. Traversable t => (t Expr -> Expr) -> t Expr -> m Expr
   wrapLambda mkVal ps = do
     args <- traverse processExpr ps
-    return $ foldr (Abs . VarBinder) (mkVal (snd <$> args)) (catMaybes $ toList (fst <$> args))
+    return $ foldr (Abs . VarBinder nullSourceSpan) (mkVal (snd <$> args)) (catMaybes $ toList (fst <$> args))
     where
       processExpr :: Expr -> m (Maybe Ident, Expr)
       processExpr e = do
@@ -117,4 +117,4 @@
     | otherwise = return Nothing
 
   argToExpr :: Ident -> Expr
-  argToExpr = Var . Qualified Nothing
+  argToExpr = Var nullSourceSpan . Qualified Nothing
diff --git a/src/Language/PureScript/Sugar/Operators.hs b/src/Language/PureScript/Sugar/Operators.hs
--- a/src/Language/PureScript/Sugar/Operators.hs
+++ b/src/Language/PureScript/Sugar/Operators.hs
@@ -47,7 +47,7 @@
   Module ss coms mn (map f' ds) exts
   where
   (f', _, _) = everywhereOnValues id go id
-  go (UnaryMinus val) = App (Var (Qualified Nothing (Ident C.negate))) val
+  go (UnaryMinus ss' val) = App (Var ss' (Qualified Nothing (Ident C.negate))) val
   go other = other
 
 -- |
@@ -133,54 +133,47 @@
     (goDecl', goExpr', goBinder') = updateTypes goType
     (f', _, _, _, _) =
       everywhereWithContextOnValuesM
-        Nothing
-        (\_ d -> (Just (declSourceSpan d),) <$> goDecl' d)
+        ss
+        (\_ d -> (declSourceSpan d,) <$> goDecl' d)
         (\pos -> uncurry goExpr <=< goExpr' pos)
         (\pos -> uncurry goBinder <=< goBinder' pos)
         defS
         defS
 
-    goExpr :: Maybe SourceSpan -> Expr -> m (Maybe SourceSpan, Expr)
-    goExpr _ e@(PositionedValue pos _ _) = return (Just pos, e)
-    goExpr pos (Op op) =
-      (pos, ) <$> case op `M.lookup` valueAliased of
+    goExpr :: SourceSpan -> Expr -> m (SourceSpan, Expr)
+    goExpr _ e@(PositionedValue pos _ _) = return (pos, e)
+    goExpr _ (Op pos op) =
+      (pos,) <$> case op `M.lookup` valueAliased of
         Just (Qualified mn' (Left alias)) ->
-          return $ Var (Qualified mn' alias)
+          return $ Var pos (Qualified mn' alias)
         Just (Qualified mn' (Right alias)) ->
-          return $ Constructor (Qualified mn' alias)
+          return $ Constructor pos (Qualified mn' alias)
         Nothing ->
-          maybe id rethrowWithPosition pos $
-            throwError . errorMessage . UnknownName $ fmap ValOpName op
+          throwError . errorMessage' pos . UnknownName $ fmap ValOpName op
     goExpr pos other = return (pos, other)
 
-    goBinder :: Maybe SourceSpan -> Binder -> m (Maybe SourceSpan, Binder)
-    goBinder _ b@(PositionedBinder pos _ _) = return (Just pos, b)
-    goBinder pos (BinaryNoParensBinder (OpBinder op) lhs rhs) =
+    goBinder :: SourceSpan -> Binder -> m (SourceSpan, Binder)
+    goBinder _ b@(PositionedBinder pos _ _) = return (pos, b)
+    goBinder _ (BinaryNoParensBinder (OpBinder pos op) lhs rhs) =
       case op `M.lookup` valueAliased of
         Just (Qualified mn' (Left alias)) ->
-          maybe id rethrowWithPosition pos $
-            throwError . errorMessage $
-              InvalidOperatorInBinder op (Qualified mn' alias)
+          throwError . errorMessage' pos $ InvalidOperatorInBinder op (Qualified mn' alias)
         Just (Qualified mn' (Right alias)) ->
-          return (pos, ConstructorBinder (Qualified mn' alias) [lhs, rhs])
+          return (pos, ConstructorBinder pos (Qualified mn' alias) [lhs, rhs])
         Nothing ->
-          maybe id rethrowWithPosition pos $
-            throwError . errorMessage . UnknownName $ fmap ValOpName op
+          throwError . errorMessage' pos . UnknownName $ fmap ValOpName op
     goBinder _ BinaryNoParensBinder{} =
       internalError "BinaryNoParensBinder has no OpBinder"
     goBinder pos other = return (pos, other)
 
-    goType :: Maybe SourceSpan -> Type -> m Type
-    goType pos = maybe id rethrowWithPosition pos . go
-      where
-      go :: Type -> m Type
-      go (BinaryNoParensType (TypeOp op) lhs rhs) =
-        case op `M.lookup` typeAliased of
-          Just alias ->
-            return $ TypeApp (TypeApp (TypeConstructor alias) lhs) rhs
-          Nothing ->
-            throwError . errorMessage $ UnknownName $ fmap TyOpName op
-      go other = return other
+    goType :: SourceSpan -> Type -> m Type
+    goType pos (BinaryNoParensType (TypeOp op) lhs rhs) =
+      case op `M.lookup` typeAliased of
+        Just alias ->
+          return $ TypeApp (TypeApp (TypeConstructor alias) lhs) rhs
+        Nothing ->
+          throwError . errorMessage' pos $ UnknownName $ fmap TyOpName op
+    goType _ other = return other
 
 rebracketModule
   :: forall m
@@ -198,25 +191,22 @@
     fmap (map (\d -> if pred_ d then removeParens d else d)) .
     flip parU (usingPredicate pred_ f)
 
-  (f, _, _) =
-      everywhereOnValuesTopDownM
-        goDecl
-        (goExpr <=< decontextify goExpr')
-        (goBinder <=< decontextify goBinder')
-
-  (goDecl, goExpr', goBinder') = updateTypes (const goType)
-
-  goExpr :: Expr -> m Expr
-  goExpr = return . matchExprOperators valueOpTable
+  (f, _, _, _, _) =
+      everywhereWithContextOnValuesM
+        ss
+        (\_ d -> (declSourceSpan d,) <$> goDecl d)
+        (\pos -> wrap (matchExprOperators valueOpTable) <=< goExpr' pos)
+        (\pos -> wrap (matchBinderOperators valueOpTable) <=< goBinder' pos)
+        defS
+        defS
 
-  goBinder :: Binder -> m Binder
-  goBinder = return . matchBinderOperators valueOpTable
+  (goDecl, goExpr', goBinder') = updateTypes goType
 
-  goType :: Type -> m Type
-  goType = return . matchTypeOperators typeOpTable
+  goType :: SourceSpan -> Type -> m Type
+  goType = flip matchTypeOperators typeOpTable
 
-  decontextify :: (Maybe SourceSpan -> a -> m (Maybe SourceSpan, a)) -> a -> m a
-  decontextify ctxf = fmap snd . ctxf Nothing
+  wrap :: (a -> m a) -> (SourceSpan, a) -> m (SourceSpan, a)
+  wrap go (ss', a) = (ss',) <$> go a
 
 removeParens :: Declaration -> Declaration
 removeParens = f
@@ -242,10 +232,10 @@
   goType t = t
 
   decontextify
-    :: (Maybe SourceSpan -> a -> Identity (Maybe SourceSpan, a))
+    :: (SourceSpan -> a -> Identity (SourceSpan, a))
     -> a
     -> a
-  decontextify ctxf = snd . runIdentity . ctxf Nothing
+  decontextify ctxf = snd . runIdentity . ctxf (internalError "attempted to use SourceSpan in removeParens")
 
 externsFixities :: ExternsFile -> [Either ValueFixityRecord TypeFixityRecord]
 externsFixities ExternsFile{..} =
@@ -312,41 +302,38 @@
 updateTypes
   :: forall m
    . Monad m
-  => (Maybe SourceSpan -> Type -> m Type)
+  => (SourceSpan -> Type -> m Type)
   -> ( Declaration -> m Declaration
-     , Maybe SourceSpan -> Expr -> m (Maybe SourceSpan, Expr)
-     , Maybe SourceSpan -> Binder -> m (Maybe SourceSpan, Binder)
+     , SourceSpan -> Expr -> m (SourceSpan, Expr)
+     , SourceSpan -> Binder -> m (SourceSpan, Binder)
      )
 updateTypes goType = (goDecl, goExpr, goBinder)
   where
 
-  goType' :: Maybe SourceSpan -> Type -> m Type
+  goType' :: SourceSpan -> Type -> m Type
   goType' = everywhereOnTypesTopDownM . goType
 
-  goType'' :: SourceSpan -> Type -> m Type
-  goType'' = goType' . Just
-
   goDecl :: Declaration -> m Declaration
   goDecl (DataDeclaration sa@(ss, _) ddt name args dctors) =
-    DataDeclaration sa ddt name args <$> traverse (sndM (traverse (goType'' ss))) dctors
+    DataDeclaration sa ddt name args <$> traverse (sndM (traverse (goType' ss))) dctors
   goDecl (ExternDeclaration sa@(ss, _) name ty) =
-    ExternDeclaration sa name <$> goType'' ss ty
+    ExternDeclaration sa name <$> goType' ss ty
   goDecl (TypeClassDeclaration sa@(ss, _) name args implies deps decls) = do
-    implies' <- traverse (overConstraintArgs (traverse (goType'' ss))) implies
+    implies' <- traverse (overConstraintArgs (traverse (goType' ss))) implies
     return $ TypeClassDeclaration sa name args implies' deps decls
-  goDecl (TypeInstanceDeclaration sa@(ss, _) name cs className tys impls) = do
-    cs' <- traverse (overConstraintArgs (traverse (goType'' ss))) cs
-    tys' <- traverse (goType'' ss) tys
-    return $ TypeInstanceDeclaration sa name cs' className tys' impls
+  goDecl (TypeInstanceDeclaration sa@(ss, _) ch idx name cs className tys impls) = do
+    cs' <- traverse (overConstraintArgs (traverse (goType' ss))) cs
+    tys' <- traverse (goType' ss) tys
+    return $ TypeInstanceDeclaration sa ch idx name cs' className tys' impls
   goDecl (TypeSynonymDeclaration sa@(ss, _) name args ty) =
-    TypeSynonymDeclaration sa name args <$> goType'' ss ty
+    TypeSynonymDeclaration sa name args <$> goType' ss ty
   goDecl (TypeDeclaration (TypeDeclarationData sa@(ss, _) expr ty)) =
-    TypeDeclaration . TypeDeclarationData sa expr <$> goType'' ss ty
+    TypeDeclaration . TypeDeclarationData sa expr <$> goType' ss ty
   goDecl other =
     return other
 
-  goExpr :: Maybe SourceSpan -> Expr -> m (Maybe SourceSpan, Expr)
-  goExpr _ e@(PositionedValue pos _ _) = return (Just pos, e)
+  goExpr :: SourceSpan -> Expr -> m (SourceSpan, Expr)
+  goExpr _ e@(PositionedValue pos _ _) = return (pos, e)
   goExpr pos (TypeClassDictionary (Constraint name tys info) dicts hints) = do
     tys' <- traverse (goType' pos) tys
     return (pos, TypeClassDictionary (Constraint name tys' info) dicts hints)
@@ -358,8 +345,8 @@
     return (pos, TypedValue check v ty')
   goExpr pos other = return (pos, other)
 
-  goBinder :: Maybe SourceSpan -> Binder -> m (Maybe SourceSpan, Binder)
-  goBinder _ e@(PositionedBinder pos _ _) = return (Just pos, e)
+  goBinder :: SourceSpan -> Binder -> m (SourceSpan, Binder)
+  goBinder _ e@(PositionedBinder pos _ _) = return (pos, e)
   goBinder pos (TypedBinder ty b) = do
     ty' <- goType' pos ty
     return (pos, TypedBinder ty' b)
diff --git a/src/Language/PureScript/Sugar/Operators/Binders.hs b/src/Language/PureScript/Sugar/Operators/Binders.hs
--- a/src/Language/PureScript/Sugar/Operators/Binders.hs
+++ b/src/Language/PureScript/Sugar/Operators/Binders.hs
@@ -2,11 +2,18 @@
 
 import Prelude.Compat
 
+import Control.Monad.Except
+
 import Language.PureScript.AST
+import Language.PureScript.Errors
 import Language.PureScript.Names
 import Language.PureScript.Sugar.Operators.Common
 
-matchBinderOperators :: [[(Qualified (OpName 'ValueOpName), Associativity)]] -> Binder -> Binder
+matchBinderOperators
+  :: MonadError MultipleErrors m
+  => [[(Qualified (OpName 'ValueOpName), Associativity)]] 
+  -> Binder
+  -> m Binder
 matchBinderOperators = matchOperators isBinOp extractOp fromOp reapply id
   where
 
@@ -18,9 +25,9 @@
   extractOp (BinaryNoParensBinder op l r) = Just (op, l, r)
   extractOp _ = Nothing
 
-  fromOp :: Binder -> Maybe (Qualified (OpName 'ValueOpName))
-  fromOp (OpBinder q@(Qualified _ (OpName _))) = Just q
+  fromOp :: Binder -> Maybe (SourceSpan, Qualified (OpName 'ValueOpName))
+  fromOp (OpBinder ss q@(Qualified _ (OpName _))) = Just (ss, q)
   fromOp _ = Nothing
 
-  reapply :: Qualified (OpName 'ValueOpName) -> Binder -> Binder -> Binder
-  reapply = BinaryNoParensBinder . OpBinder
+  reapply :: SourceSpan -> Qualified (OpName 'ValueOpName) -> Binder -> Binder -> Binder
+  reapply ss = BinaryNoParensBinder . OpBinder ss
diff --git a/src/Language/PureScript/Sugar/Operators/Common.hs b/src/Language/PureScript/Sugar/Operators/Common.hs
--- a/src/Language/PureScript/Sugar/Operators/Common.hs
+++ b/src/Language/PureScript/Sugar/Operators/Common.hs
@@ -3,8 +3,14 @@
 import Prelude.Compat
 
 import Control.Monad.State
+import Control.Monad.Except
 
+import Data.Either (rights)
 import Data.Functor.Identity
+import Data.List (sortOn)
+import Data.Maybe (mapMaybe, fromJust)
+import qualified Data.List.NonEmpty as NEL
+import qualified Data.Map as M
 
 import qualified Text.Parsec as P
 import qualified Text.Parsec.Pos as P
@@ -12,10 +18,14 @@
 
 import Language.PureScript.AST
 import Language.PureScript.Crash
+import Language.PureScript.Errors
 import Language.PureScript.Names
 
 type Chain a = [Either a a]
 
+type FromOp nameType a = a -> Maybe (SourceSpan, Qualified (OpName nameType))
+type Reapply nameType a = SourceSpan -> Qualified (OpName nameType) -> a -> a -> a
+
 toAssoc :: Associativity -> P.Assoc
 toAssoc Infixl = P.AssocLeft
 toAssoc Infixr = P.AssocRight
@@ -28,52 +38,107 @@
 parseValue = token (either Just (const Nothing)) P.<?> "expression"
 
 parseOp
-  :: (a -> Maybe (Qualified (OpName nameType)))
-  -> P.Parsec (Chain a) () (Qualified (OpName nameType))
+  :: FromOp nameType a
+  -> P.Parsec (Chain a) () (SourceSpan, Qualified (OpName nameType))
 parseOp fromOp = token (either (const Nothing) fromOp) P.<?> "operator"
 
 matchOp
-  :: (a -> Maybe (Qualified (OpName nameType)))
+  :: FromOp nameType a
   -> Qualified (OpName nameType)
-  -> P.Parsec (Chain a) () ()
+  -> P.Parsec (Chain a) () SourceSpan
 matchOp fromOp op = do
-  ident <- parseOp fromOp
+  (ss, ident) <- parseOp fromOp
   guard $ ident == op
+  pure ss
 
 opTable
   :: [[(Qualified (OpName nameType), Associativity)]]
-  -> (a -> Maybe (Qualified (OpName nameType)))
-  -> (Qualified (OpName nameType) -> a -> a -> a)
+  -> FromOp nameType a
+  -> Reapply nameType a
   -> [[P.Operator (Chain a) () Identity a]]
 opTable ops fromOp reapply =
-  map (map (\(name, a) -> P.Infix (P.try (matchOp fromOp name) >> return (reapply name)) (toAssoc a))) ops
-  ++ [[ P.Infix (P.try (parseOp fromOp >>= \ident -> return (reapply ident))) P.AssocLeft ]]
+  map (map (\(name, a) -> P.Infix (P.try (matchOp fromOp name) >>= \ss -> return (reapply ss name)) (toAssoc a))) ops
 
 matchOperators
-  :: forall a nameType
+  :: forall m a nameType
    . Show a
+  => MonadError MultipleErrors m
   => (a -> Bool)
   -> (a -> Maybe (a, a, a))
-  -> (a -> Maybe (Qualified (OpName nameType)))
-  -> (Qualified (OpName nameType) -> a -> a -> a)
+  -> FromOp nameType a
+  -> Reapply nameType a
   -> ([[P.Operator (Chain a) () Identity a]] -> P.OperatorTable (Chain a) () Identity a)
   -> [[(Qualified (OpName nameType), Associativity)]]
   -> a
-  -> a
+  -> m a
 matchOperators isBinOp extractOp fromOp reapply modOpTable ops = parseChains
   where
-  parseChains :: a -> a
+  parseChains :: a -> m a
   parseChains ty
     | True <- isBinOp ty = bracketChain (extendChain ty)
-    | otherwise = ty
+    | otherwise = pure ty
   extendChain :: a -> Chain a
   extendChain ty
     | Just (op, l, r) <- extractOp ty = Left l : Right op : extendChain r
     | otherwise = [Left ty]
-  bracketChain :: Chain a -> a
-  bracketChain =
-    either
-      (\_ -> internalError "matchTypeOperators: cannot reorder operators")
-      id
-    . P.parse opParser "operator expression"
+  bracketChain :: Chain a -> m a
+  bracketChain chain =
+    case P.parse opParser "operator expression" chain of
+      Right a -> pure a
+      Left _ -> throwError . MultipleErrors $ mkErrors chain
+  opParser :: P.Parsec (Chain a) () a
   opParser = P.buildExpressionParser (modOpTable (opTable ops fromOp reapply)) parseValue <* P.eof
+
+  -- Generating a good error message involves a bit of work here, as the parser
+  -- can't provide one for us.
+  --
+  -- We examine the expression chain, plucking out the operators and then
+  -- grouping them by shared precedence, then if any of the following conditions
+  -- are met, we have something to report:
+  --   1. any of the groups have mixed associativity
+  --   2. there is more than one occurance of a non-associative operator in a
+  --      precedence group
+  mkErrors :: Chain a -> [ErrorMessage]
+  mkErrors chain =
+    let
+      opInfo :: M.Map (Qualified (OpName nameType)) (Integer, Associativity)
+      opInfo = M.fromList $ concatMap (\(n, o) -> map (\(name, assoc) -> (name, (n, assoc))) o) (zip [0..] ops)
+      opPrec :: Qualified (OpName nameType) -> Integer
+      opPrec = fromJust . fmap fst . flip M.lookup opInfo
+      opAssoc :: Qualified (OpName nameType) -> Associativity
+      opAssoc = fromJust . fmap snd . flip M.lookup opInfo
+      chainOpSpans :: M.Map (Qualified (OpName nameType)) (NEL.NonEmpty SourceSpan)
+      chainOpSpans = foldr (\(ss, name) -> M.alter (Just . maybe (pure ss) (NEL.cons ss)) name) M.empty . mapMaybe fromOp $ rights chain
+      opUsages :: Qualified (OpName nameType) -> Int
+      opUsages = maybe 0 NEL.length . flip M.lookup chainOpSpans
+      precGrouped :: [NEL.NonEmpty (Qualified (OpName nameType))]
+      precGrouped = NEL.groupWith opPrec . sortOn opPrec $ M.keys chainOpSpans
+      assocGrouped :: [NEL.NonEmpty (NEL.NonEmpty (Qualified (OpName nameType)))]
+      assocGrouped = fmap (NEL.groupWith1 opAssoc . NEL.sortWith opAssoc) precGrouped
+      mixedAssoc :: [NEL.NonEmpty (Qualified (OpName nameType))]
+      mixedAssoc = fmap join . filter (\precGroup -> NEL.length precGroup > 1) $ assocGrouped
+      nonAssoc :: [NEL.NonEmpty (Qualified (OpName nameType))]
+      nonAssoc = join $ fmap (NEL.filter (\assocGroup -> opAssoc (NEL.head assocGroup) == Infix && sum (fmap opUsages assocGroup) > 1)) assocGrouped
+    in
+      if null (nonAssoc ++ mixedAssoc)
+        then internalError "matchOperators: cannot reorder operators"
+        else
+          map
+            (\grp ->
+              mkPositionedError chainOpSpans grp
+                (MixedAssociativityError (fmap (\name -> (eraseOpName <$> name, opAssoc name)) grp)))
+            mixedAssoc
+          ++ map
+            (\grp ->
+              mkPositionedError chainOpSpans grp
+                (NonAssociativeError (fmap (fmap eraseOpName) grp)))
+            nonAssoc
+
+  mkPositionedError
+    :: M.Map (Qualified (OpName nameType)) (NEL.NonEmpty SourceSpan)
+    -> NEL.NonEmpty (Qualified (OpName nameType))
+    -> SimpleErrorMessage
+    -> ErrorMessage
+  mkPositionedError chainOpSpans grp =
+    ErrorMessage
+      [PositionedError (join . fmap (fromJust . flip M.lookup chainOpSpans) $ grp)]
diff --git a/src/Language/PureScript/Sugar/Operators/Expr.hs b/src/Language/PureScript/Sugar/Operators/Expr.hs
--- a/src/Language/PureScript/Sugar/Operators/Expr.hs
+++ b/src/Language/PureScript/Sugar/Operators/Expr.hs
@@ -2,6 +2,7 @@
 
 import Prelude.Compat
 
+import Control.Monad.Except
 import Data.Functor.Identity
 
 import qualified Text.Parsec as P
@@ -10,8 +11,13 @@
 import Language.PureScript.AST
 import Language.PureScript.Names
 import Language.PureScript.Sugar.Operators.Common
+import Language.PureScript.Errors
 
-matchExprOperators :: [[(Qualified (OpName 'ValueOpName), Associativity)]] -> Expr -> Expr
+matchExprOperators
+  :: MonadError MultipleErrors m
+  => [[(Qualified (OpName 'ValueOpName), Associativity)]]
+  -> Expr
+  -> m Expr
 matchExprOperators = matchOperators isBinOp extractOp fromOp reapply modOpTable
   where
 
@@ -25,12 +31,12 @@
     | otherwise = Just (op, l, r)
   extractOp _ = Nothing
 
-  fromOp :: Expr -> Maybe (Qualified (OpName 'ValueOpName))
-  fromOp (Op q@(Qualified _ (OpName _))) = Just q
+  fromOp :: Expr -> Maybe (SourceSpan, Qualified (OpName 'ValueOpName))
+  fromOp (Op ss q@(Qualified _ (OpName _))) = Just (ss, q)
   fromOp _ = Nothing
 
-  reapply :: Qualified (OpName 'ValueOpName) -> Expr -> Expr -> Expr
-  reapply op t1 = App (App (Op op) t1)
+  reapply :: SourceSpan -> Qualified (OpName 'ValueOpName) -> Expr -> Expr -> Expr
+  reapply ss op t1 = App (App (Op ss op) t1)
 
   modOpTable
     :: [[P.Operator (Chain Expr) () Identity Expr]]
@@ -42,5 +48,5 @@
   parseTicks :: P.Parsec (Chain Expr) () Expr
   parseTicks = token (either (const Nothing) fromOther) P.<?> "infix function"
     where
-    fromOther (Op _) = Nothing
+    fromOther (Op _ _) = Nothing
     fromOther v = Just v
diff --git a/src/Language/PureScript/Sugar/Operators/Types.hs b/src/Language/PureScript/Sugar/Operators/Types.hs
--- a/src/Language/PureScript/Sugar/Operators/Types.hs
+++ b/src/Language/PureScript/Sugar/Operators/Types.hs
@@ -2,13 +2,20 @@
 
 import Prelude.Compat
 
+import Control.Monad.Except
 import Language.PureScript.AST
+import Language.PureScript.Errors
 import Language.PureScript.Names
 import Language.PureScript.Sugar.Operators.Common
 import Language.PureScript.Types
 
-matchTypeOperators :: [[(Qualified (OpName 'TypeOpName), Associativity)]] -> Type -> Type
-matchTypeOperators = matchOperators isBinOp extractOp fromOp reapply id
+matchTypeOperators
+  :: MonadError MultipleErrors m
+  => SourceSpan
+  -> [[(Qualified (OpName 'TypeOpName), Associativity)]]
+  -> Type
+  -> m Type
+matchTypeOperators ss = matchOperators isBinOp extractOp fromOp reapply id
   where
 
   isBinOp :: Type -> Bool
@@ -19,9 +26,9 @@
   extractOp (BinaryNoParensType op l r) = Just (op, l, r)
   extractOp _ = Nothing
 
-  fromOp :: Type -> Maybe (Qualified (OpName 'TypeOpName))
-  fromOp (TypeOp q@(Qualified _ (OpName _))) = Just q
+  fromOp :: Type -> Maybe (SourceSpan, Qualified (OpName 'TypeOpName))
+  fromOp (TypeOp q@(Qualified _ (OpName _))) = Just (ss, q)
   fromOp _ = Nothing
 
-  reapply :: Qualified (OpName 'TypeOpName) -> Type -> Type -> Type
-  reapply = BinaryNoParensType . TypeOp
+  reapply :: a -> Qualified (OpName 'TypeOpName) -> Type -> Type -> Type
+  reapply _ = BinaryNoParensType . TypeOp
diff --git a/src/Language/PureScript/Sugar/TypeClasses.hs b/src/Language/PureScript/Sugar/TypeClasses.hs
--- a/src/Language/PureScript/Sugar/TypeClasses.hs
+++ b/src/Language/PureScript/Sugar/TypeClasses.hs
@@ -48,8 +48,14 @@
   where
   initialState :: MemberMap
   initialState =
-    M.mapKeys (qualify (ModuleName [ProperName C.prim])) primClasses
-    `M.union` M.fromList (externs >>= \ExternsFile{..} -> mapMaybe (fromExternsDecl efModuleName) efDeclarations)
+    mconcat
+      [ M.mapKeys (qualify (ModuleName [ProperName C.prim])) primClasses
+      , M.mapKeys (qualify C.PrimRow) primRowClasses
+      , M.mapKeys (qualify C.PrimRowList) primRowListClasses
+      , M.mapKeys (qualify C.PrimSymbol) primSymbolClasses
+      , M.mapKeys (qualify C.PrimTypeError) primTypeErrorClasses
+      , M.fromList (externs >>= \ExternsFile{..} -> mapMaybe (fromExternsDecl efModuleName) efDeclarations)
+      ]
 
   fromExternsDecl
     :: ModuleName
@@ -179,12 +185,12 @@
   go d@(TypeClassDeclaration sa name args implies deps members) = do
     modify (M.insert (mn, name) (makeTypeClassData args (map memberToNameAndType members) implies deps))
     return (Nothing, d : typeClassDictionaryDeclaration sa name args implies members : map (typeClassMemberToDictionaryAccessor mn name args) members)
-  go (TypeInstanceDeclaration _ _ _ _ _ DerivedInstance) = internalError "Derived instanced should have been desugared"
-  go d@(TypeInstanceDeclaration sa name deps className tys (ExplicitInstance members)) = do
+  go (TypeInstanceDeclaration _ _ _ _ _ _ _ DerivedInstance) = internalError "Derived instanced should have been desugared"
+  go d@(TypeInstanceDeclaration sa _ _ name deps className tys (ExplicitInstance members)) = do
     desugared <- desugarCases members
     dictDecl <- typeInstanceDictionaryDeclaration sa name mn deps className tys desugared
     return (expRef name className tys, [d, dictDecl])
-  go d@(TypeInstanceDeclaration sa name deps className tys (NewtypeInstanceWithDictionary dict)) = do
+  go d@(TypeInstanceDeclaration sa _ _ name deps className tys (NewtypeInstanceWithDictionary dict)) = do
     let dictTy = foldl TypeApp (TypeConstructor (fmap coerceProperName className)) tys
         constrainedTy = quantify (foldr ConstrainedType dictTy deps)
     return (expRef name className tys, [d, ValueDecl sa name Private [] [MkUnguarded (TypedValue True dict constrainedTy)]])
@@ -270,17 +276,17 @@
   -> [Type]
   -> [Declaration]
   -> Desugar m Declaration
-typeInstanceDictionaryDeclaration sa name mn deps className tys decls =
+typeInstanceDictionaryDeclaration sa@(ss, _) name mn deps className tys decls =
   rethrow (addHint (ErrorInInstance className tys)) $ do
   m <- get
 
   -- Lookup the type arguments and member types for the type class
   TypeClassData{..} <-
-    maybe (throwError . errorMessage . UnknownName $ fmap TyClassName className) return $
+    maybe (throwError . errorMessage' ss . UnknownName $ fmap TyClassName className) return $
       M.lookup (qualify mn className) m
 
   case map fst typeClassMembers \\ mapMaybe declIdent decls of
-    member : _ -> throwError . errorMessage $ MissingClassMember member
+    member : _ -> throwError . errorMessage' ss $ MissingClassMember member
     [] -> do
       -- Replace the type arguments with the appropriate types in the member types
       let memberTypes = map (second (replaceAllTypeVars (zip (map fst typeClassArguments) tys))) typeClassMembers
@@ -292,12 +298,12 @@
       -- The type is a record type, but depending on type instance dependencies, may be constrained.
       -- The dictionary itself is a record literal.
       let superclasses = superClassDictionaryNames typeClassSuperclasses `zip`
-            [ Abs (VarBinder (Ident C.__unused)) (DeferredDictionary superclass tyArgs)
+            [ Abs (VarBinder ss UnusedIdent) (DeferredDictionary superclass tyArgs)
             | (Constraint superclass suTyArgs _) <- typeClassSuperclasses
             , let tyArgs = map (replaceAllTypeVars (zip (map fst typeClassArguments) tys)) suTyArgs
             ]
 
-      let props = Literal $ ObjectLiteral $ map (first mkString) (members ++ superclasses)
+      let props = Literal ss $ ObjectLiteral $ map (first mkString) (members ++ superclasses)
           dictTy = foldl TypeApp (TypeConstructor (fmap coerceProperName className)) tys
           constrainedTy = quantify (foldr ConstrainedType dictTy deps)
           dict = TypeClassDictionaryConstructorApp className props
@@ -307,8 +313,8 @@
   where
 
   memberToValue :: [(Ident, Type)] -> Declaration -> Desugar m Expr
-  memberToValue tys' (ValueDecl _ ident _ [] [MkUnguarded val]) = do
-    _ <- maybe (throwError . errorMessage $ ExtraneousClassMember ident className) return $ lookup ident tys'
+  memberToValue tys' (ValueDecl (ss', _) ident _ [] [MkUnguarded val]) = do
+    _ <- maybe (throwError . errorMessage' ss' $ ExtraneousClassMember ident className) return $ lookup ident tys'
     return val
   memberToValue _ _ = internalError "Invalid declaration in type instance definition"
 
diff --git a/src/Language/PureScript/Sugar/TypeClasses/Deriving.hs b/src/Language/PureScript/Sugar/TypeClasses/Deriving.hs
--- a/src/Language/PureScript/Sugar/TypeClasses/Deriving.hs
+++ b/src/Language/PureScript/Sugar/TypeClasses/Deriving.hs
@@ -17,7 +17,6 @@
 import           Data.Ord (comparing)
 import qualified Data.Set as S
 import           Data.Text (Text)
-import qualified Data.Text as T
 import           Language.PureScript.AST
 import qualified Language.PureScript.Constants as C
 import           Language.PureScript.Crash
@@ -27,7 +26,7 @@
 import           Language.PureScript.Kinds
 import           Language.PureScript.Names
 import           Language.PureScript.Label (Label(..))
-import           Language.PureScript.PSString (mkString, decodeStringEither)
+import           Language.PureScript.PSString (mkString)
 import           Language.PureScript.Types
 import           Language.PureScript.TypeChecker (checkNewtype)
 import           Language.PureScript.TypeChecker.Synonyms (SynonymMap, replaceAllTypeSynonymsM)
@@ -100,7 +99,7 @@
 
         fromLocalDecl (TypeClassDeclaration _ cl args cons deps _) =
           NewtypeDerivedInstances (M.singleton (mn, cl) (map fst args, cons, deps)) mempty
-        fromLocalDecl (TypeInstanceDeclaration _ _ _ cl tys _) =
+        fromLocalDecl (TypeInstanceDeclaration _ _ _ _ _ cl tys _) =
           foldMap (\nm -> NewtypeDerivedInstances mempty (S.singleton (qualify mn cl, nm))) (extractNewtypeName mn tys)
         fromLocalDecl _ = mempty
 
@@ -114,33 +113,40 @@
   -> [Declaration]
   -> Declaration
   -> m Declaration
-deriveInstance mn syns _ ds (TypeInstanceDeclaration sa@(ss, _) nm deps className tys DerivedInstance)
-  | className == Qualified (Just dataGeneric) (ProperName C.generic)
+deriveInstance mn syns _ ds (TypeInstanceDeclaration sa@(ss, _) ch idx nm deps className tys DerivedInstance)
+  | className == Qualified (Just dataEq) (ProperName "Eq")
   = case tys of
-      [ty] | Just (Qualified mn' tyCon, args) <- unwrapTypeConstructor ty
+      [ty] | Just (Qualified mn' tyCon, _) <- unwrapTypeConstructor ty
            , mn == fromMaybe mn mn'
-           -> TypeInstanceDeclaration sa nm deps className tys . ExplicitInstance <$> deriveGeneric ss mn syns ds tyCon args
+           -> TypeInstanceDeclaration sa ch idx nm deps className tys . ExplicitInstance <$> deriveEq ss mn syns ds tyCon
            | otherwise -> throwError . errorMessage' ss $ ExpectedTypeConstructor className tys ty
       _ -> throwError . errorMessage' ss $ InvalidDerivedInstance className tys 1
-  | className == Qualified (Just dataEq) (ProperName "Eq")
+  | className == Qualified (Just dataEq) (ProperName "Eq1")
   = case tys of
-      [ty] | Just (Qualified mn' tyCon, _) <- unwrapTypeConstructor ty
+      [ty] | Just (Qualified mn' _, _) <- unwrapTypeConstructor ty
            , mn == fromMaybe mn mn'
-           -> TypeInstanceDeclaration sa nm deps className tys . ExplicitInstance <$> deriveEq ss mn syns ds tyCon
+           -> pure . TypeInstanceDeclaration sa ch idx nm deps className tys . ExplicitInstance $ deriveEq1 ss
            | otherwise -> throwError . errorMessage' ss $ ExpectedTypeConstructor className tys ty
       _ -> throwError . errorMessage' ss $ InvalidDerivedInstance className tys 1
   | className == Qualified (Just dataOrd) (ProperName "Ord")
   = case tys of
       [ty] | Just (Qualified mn' tyCon, _) <- unwrapTypeConstructor ty
            , mn == fromMaybe mn mn'
-           -> TypeInstanceDeclaration sa nm deps className tys . ExplicitInstance <$> deriveOrd ss mn syns ds tyCon
+           -> TypeInstanceDeclaration sa ch idx nm deps className tys . ExplicitInstance <$> deriveOrd ss mn syns ds tyCon
            | otherwise -> throwError . errorMessage' ss $ ExpectedTypeConstructor className tys ty
       _ -> throwError . errorMessage' ss $ InvalidDerivedInstance className tys 1
+  | className == Qualified (Just dataOrd) (ProperName "Ord1")
+  = case tys of
+      [ty] | Just (Qualified mn' _, _) <- unwrapTypeConstructor ty
+           , mn == fromMaybe mn mn'
+           -> pure . TypeInstanceDeclaration sa ch idx nm deps className tys . ExplicitInstance $ deriveOrd1 ss
+           | otherwise -> throwError . errorMessage' ss $ ExpectedTypeConstructor className tys ty
+      _ -> throwError . errorMessage' ss $ InvalidDerivedInstance className tys 1
   | className == Qualified (Just dataFunctor) (ProperName "Functor")
   = case tys of
       [ty] | Just (Qualified mn' tyCon, _) <- unwrapTypeConstructor ty
            , mn == fromMaybe mn mn'
-           -> TypeInstanceDeclaration sa nm deps className tys . ExplicitInstance <$> deriveFunctor ss mn syns ds tyCon
+           -> TypeInstanceDeclaration sa ch idx nm deps className tys . ExplicitInstance <$> deriveFunctor ss mn syns ds tyCon
            | otherwise -> throwError . errorMessage' ss $ ExpectedTypeConstructor className tys ty
       _ -> throwError . errorMessage' ss $ InvalidDerivedInstance className tys 1
   | className == Qualified (Just dataNewtype) (ProperName "Newtype")
@@ -148,8 +154,8 @@
       [wrappedTy, unwrappedTy]
         | Just (Qualified mn' tyCon, args) <- unwrapTypeConstructor wrappedTy
         , mn == fromMaybe mn mn'
-        -> do (inst, actualUnwrappedTy) <- deriveNewtype mn syns ds tyCon args unwrappedTy
-              return $ TypeInstanceDeclaration sa nm deps className [wrappedTy, actualUnwrappedTy] (ExplicitInstance inst)
+        -> do (inst, actualUnwrappedTy) <- deriveNewtype ss mn syns ds tyCon args unwrappedTy
+              return $ TypeInstanceDeclaration sa ch idx nm deps className [wrappedTy, actualUnwrappedTy] (ExplicitInstance inst)
         | otherwise -> throwError . errorMessage' ss $ ExpectedTypeConstructor className tys wrappedTy
       _ -> throwError . errorMessage' ss $ InvalidDerivedInstance className tys 2
   | className == Qualified (Just dataGenericRep) (ProperName C.generic)
@@ -157,16 +163,16 @@
       [actualTy, repTy]
         | Just (Qualified mn' tyCon, args) <- unwrapTypeConstructor actualTy
         , mn == fromMaybe mn mn'
-        -> do (inst, inferredRepTy) <- deriveGenericRep mn syns ds tyCon args repTy
-              return $ TypeInstanceDeclaration sa nm deps className [actualTy, inferredRepTy] (ExplicitInstance inst)
+        -> do (inst, inferredRepTy) <- deriveGenericRep ss mn syns ds tyCon args repTy
+              return $ TypeInstanceDeclaration sa ch idx nm deps className [actualTy, inferredRepTy] (ExplicitInstance inst)
         | otherwise -> throwError . errorMessage' ss $ ExpectedTypeConstructor className tys actualTy
       _ -> throwError . errorMessage' ss $ InvalidDerivedInstance className tys 2
   | otherwise = throwError . errorMessage' ss $ CannotDerive className tys
-deriveInstance mn syns ndis ds (TypeInstanceDeclaration sa@(ss, _) nm deps className tys NewtypeInstance) =
+deriveInstance mn syns ndis ds (TypeInstanceDeclaration sa@(ss, _) ch idx nm deps className tys NewtypeInstance) =
   case tys of
     _ : _ | Just (Qualified mn' tyCon, args) <- unwrapTypeConstructor (last tys)
           , mn == fromMaybe mn mn'
-          -> TypeInstanceDeclaration sa nm deps className tys . NewtypeInstanceWithDictionary <$> deriveNewtypeInstance ss mn syns ndis className ds tys tyCon args
+          -> TypeInstanceDeclaration sa ch idx nm deps className tys . NewtypeInstanceWithDictionary <$> deriveNewtypeInstance ss mn syns ndis className ds tys tyCon args
           | otherwise -> throwError . errorMessage' ss $ ExpectedTypeConstructor className tys (last tys)
     _ -> throwError . errorMessage' ss $ InvalidNewtypeInstance className tys
 deriveInstance _ _ _ _ e = return e
@@ -198,7 +204,7 @@
     tyCon <- findTypeDecl tyConNm ds
     go tyCon
   where
-    go (DataDeclaration _ Newtype _ tyArgNames [(_, [wrapped])])
+    go (DataDeclaration _ Newtype _ tyArgNames [(_, [wrapped])]) = do
       -- The newtype might not be applied to all type arguments.
       -- This is okay as long as the newtype wraps something which ends with
       -- sufficiently many type applications to variables.
@@ -208,10 +214,12 @@
       --
       -- since Array a is a type application which uses the last
       -- type argument
-      | Just wrapped' <- stripRight (takeReverse (length tyArgNames - length dargs) tyArgNames) wrapped =
-          do let subst = zipWith (\(name, _) t -> (name, t)) tyArgNames dargs
-             wrapped'' <- replaceAllTypeSynonymsM syns wrapped'
-             return (DeferredDictionary className (init tys ++ [replaceAllTypeVars subst wrapped'']))
+      wrapped' <- replaceAllTypeSynonymsM syns wrapped
+      case stripRight (takeReverse (length tyArgNames - length dargs) tyArgNames) wrapped' of
+        Just wrapped'' -> do
+          let subst = zipWith (\(name, _) t -> (name, t)) tyArgNames dargs
+          return (DeferredDictionary className (init tys ++ [replaceAllTypeVars subst wrapped'']))
+        Nothing -> throwError . errorMessage' ss $ InvalidNewtypeInstance className tys
     go _ = throwError . errorMessage' ss $ InvalidNewtypeInstance className tys
 
     takeReverse :: Int -> [a] -> [a]
@@ -248,18 +256,9 @@
                       tell . errorMessage' ss $ MissingNewtypeSuperclassInstance constraintClass className tys
                 else tell . errorMessage' ss $ UnverifiableSuperclassInstance constraintClass className tys
 
-dataGeneric :: ModuleName
-dataGeneric = ModuleName [ ProperName "Data", ProperName "Generic" ]
-
 dataGenericRep :: ModuleName
 dataGenericRep = ModuleName [ ProperName "Data", ProperName "Generic", ProperName "Rep" ]
 
-dataMaybe :: ModuleName
-dataMaybe = ModuleName [ ProperName "Data", ProperName "Maybe" ]
-
-typesProxy :: ModuleName
-typesProxy = ModuleName [ ProperName "Type", ProperName "Proxy" ]
-
 dataEq :: ModuleName
 dataEq = ModuleName [ ProperName "Data", ProperName "Eq" ]
 
@@ -275,212 +274,46 @@
 unguarded :: Expr -> [GuardedExpr]
 unguarded e = [MkUnguarded e]
 
-deriveGeneric
-  :: forall m. (MonadError MultipleErrors m, MonadSupply m)
-  => SourceSpan
-  -> ModuleName
-  -> SynonymMap
-  -> [Declaration]
-  -> ProperName 'TypeName
-  -> [Type]
-  -> m [Declaration]
-deriveGeneric ss mn syns ds tyConNm dargs = do
-  tyCon <- findTypeDecl tyConNm ds
-  toSpine <- mkSpineFunction tyCon
-  fromSpine <- mkFromSpineFunction tyCon
-  toSignature <- mkSignatureFunction tyCon dargs
-  return [ ValueDecl (ss, []) (Ident C.toSpine) Public [] (unguarded toSpine)
-         , ValueDecl (ss, []) (Ident C.fromSpine) Public [] (unguarded fromSpine)
-         , ValueDecl (ss, []) (Ident C.toSignature) Public [] (unguarded toSignature)
-         ]
-  where
-    mkSpineFunction :: Declaration -> m Expr
-    mkSpineFunction (DataDeclaration _ _ _ _ args) = do
-      x <- freshIdent'
-      lamCase x <$> mapM mkCtorClause args
-      where
-      prodConstructor :: Expr -> Expr
-      prodConstructor = App (Constructor (Qualified (Just dataGeneric) (ProperName "SProd")))
-
-      recordConstructor :: Expr -> Expr
-      recordConstructor = App (Constructor (Qualified (Just dataGeneric) (ProperName "SRecord")))
-
-      mkCtorClause :: (ProperName 'ConstructorName, [Type]) -> m CaseAlternative
-      mkCtorClause (ctorName, tys) = do
-        idents <- replicateM (length tys) freshIdent'
-        tys' <- mapM (replaceAllTypeSynonymsM syns) tys
-        let caseResult =
-              App (prodConstructor (Literal . StringLiteral . mkString . showQualified runProperName $ Qualified (Just mn) ctorName))
-                . Literal . ArrayLiteral
-                $ zipWith toSpineFun (map (Var . Qualified Nothing) idents) tys'
-        return $ CaseAlternative [ConstructorBinder (Qualified (Just mn) ctorName) (map VarBinder idents)] (unguarded caseResult)
-
-      toSpineFun :: Expr -> Type -> Expr
-      toSpineFun i r | Just rec <- objectType r
-                     , Just fields <- decomposeRec rec =
-        lamNull . recordConstructor . Literal . ArrayLiteral
-          . map
-            (\((Label str),typ) ->
-              Literal $ ObjectLiteral
-                [ ("recLabel", Literal (StringLiteral str))
-                , ("recValue", toSpineFun (Accessor str i) typ)
-                ]
-            )
-          $ fields
-      toSpineFun i _ = lamNull $ App (mkGenVar (Ident C.toSpine)) i
-    mkSpineFunction _ = internalError "mkSpineFunction: expected DataDeclaration"
-
-    mkSignatureFunction :: Declaration -> [Type] -> m Expr
-    mkSignatureFunction (DataDeclaration _ _ name tyArgs args) classArgs = lamNull . mkSigProd <$> mapM mkProdClause args
-      where
-      mkSigProd :: [Expr] -> Expr
-      mkSigProd =
-        App
-          (App
-            (Constructor (Qualified (Just dataGeneric) (ProperName "SigProd")))
-            (Literal (StringLiteral $ mkString (showQualified runProperName (Qualified (Just mn) name))))
-          )
-          . Literal
-          . ArrayLiteral
-
-      mkSigRec :: [Expr] -> Expr
-      mkSigRec = App (Constructor (Qualified (Just dataGeneric) (ProperName "SigRecord"))) . Literal . ArrayLiteral
-
-      proxy :: Type -> Type
-      proxy = TypeApp (TypeConstructor (Qualified (Just typesProxy) (ProperName "Proxy")))
-
-      mkProdClause :: (ProperName 'ConstructorName, [Type]) -> m Expr
-      mkProdClause (ctorName, tys) = do
-        tys' <- mapM (replaceAllTypeSynonymsM syns) tys
-        return $ Literal $ ObjectLiteral
-          [ ("sigConstructor", Literal (StringLiteral $ mkString (showQualified runProperName (Qualified (Just mn) ctorName))))
-          , ("sigValues", Literal . ArrayLiteral . map (mkProductSignature . instantiate) $ tys')
-          ]
-
-      mkProductSignature :: Type -> Expr
-      mkProductSignature r | Just rec <- objectType r
-                           , Just fields <- decomposeRec rec =
-          lamNull . mkSigRec $
-            [ Literal $ ObjectLiteral
-                [ ("recLabel", Literal (StringLiteral str))
-                , ("recValue", mkProductSignature typ)
-                ]
-            | ((Label str), typ) <- fields
-            ]
-      mkProductSignature typ = lamNull $ App (mkGenVar (Ident C.toSignature))
-                               (TypedValue False (mkGenVar (Ident "anyProxy")) (proxy typ))
-      instantiate = replaceAllTypeVars (zipWith (\(arg, _) ty -> (arg, ty)) tyArgs classArgs)
-    mkSignatureFunction _ _ = internalError "mkSignatureFunction: expected DataDeclaration"
-
-    mkFromSpineFunction :: Declaration -> m Expr
-    mkFromSpineFunction (DataDeclaration _ _ _ _ args) = do
-      x <- freshIdent'
-      lamCase x <$> (addCatch <$> mapM mkAlternative args)
-      where
-      mkJust :: Expr -> Expr
-      mkJust = App (Constructor (Qualified (Just dataMaybe) (ProperName "Just")))
-
-      mkNothing :: Expr
-      mkNothing = Constructor (Qualified (Just dataMaybe) (ProperName "Nothing"))
-
-      prodBinder :: [Binder] -> Binder
-      prodBinder = ConstructorBinder (Qualified (Just dataGeneric) (ProperName "SProd"))
-
-      recordBinder :: [Binder] -> Binder
-      recordBinder = ConstructorBinder (Qualified (Just dataGeneric) (ProperName "SRecord"))
-
-      mkAlternative :: (ProperName 'ConstructorName, [Type]) -> m CaseAlternative
-      mkAlternative (ctorName, tys) = do
-        idents <- replicateM (length tys) freshIdent'
-        tys' <- mapM (replaceAllTypeSynonymsM syns) tys
-        return $
-          CaseAlternative
-            [ prodBinder
-                [ LiteralBinder (StringLiteral $ mkString (showQualified runProperName (Qualified (Just mn) ctorName)))
-                , LiteralBinder (ArrayLiteral (map VarBinder idents))
-                ]
-            ]
-            . unguarded
-            $ liftApplicative
-                (mkJust $ Constructor (Qualified (Just mn) ctorName))
-                (zipWith fromSpineFun (map (Var . Qualified Nothing) idents) tys')
-
-      addCatch :: [CaseAlternative] -> [CaseAlternative]
-      addCatch = (++ [catchAll])
-        where
-        catchAll = CaseAlternative [NullBinder] (unguarded mkNothing)
-
-      fromSpineFun :: Expr -> Type -> Expr
-      fromSpineFun e r
-        | Just rec <- objectType r
-        , Just fields <- decomposeRec rec
-        = App (lamCase (Ident "r") [ mkRecCase fields
-                                   , CaseAlternative [NullBinder] (unguarded mkNothing)
-                                   ])
-              (App e unitVal)
-      fromSpineFun e _ = App (mkGenVar (Ident C.fromSpine)) (App e unitVal)
-
-      mkRecCase :: [(Label, Type)] -> CaseAlternative
-      mkRecCase rs =
-        CaseAlternative
-          [ recordBinder [ LiteralBinder (ArrayLiteral (map (VarBinder . labelToIdent . fst) rs)) ] ]
-          . unguarded
-          $ liftApplicative (mkRecFun rs) (map (\(x, y) -> fromSpineFun (Accessor "recValue" (mkVar $ labelToIdent x)) y) rs)
-
-      mkRecFun :: [(Label, Type)] -> Expr
-      mkRecFun xs = mkJust $ foldr (lam . labelToIdent . fst) recLiteral xs
-        where recLiteral = Literal . ObjectLiteral $ map (\(l@(Label s), _) -> (s, mkVar $ labelToIdent l)) xs
-    mkFromSpineFunction _ = internalError "mkFromSpineFunction: expected DataDeclaration"
-
-    -- Helpers
-
-    liftApplicative :: Expr -> [Expr] -> Expr
-    liftApplicative = foldl' (\x e -> App (App applyFn x) e)
-
-    unitVal :: Expr
-    unitVal = mkVarMn (Just (ModuleName [ProperName "Data", ProperName "Unit"])) (Ident "unit")
-
-    applyFn :: Expr
-    applyFn = mkVarMn (Just (ModuleName [ProperName "Control", ProperName "Apply"])) (Ident "apply")
-
-    mkGenVar :: Ident -> Expr
-    mkGenVar = mkVarMn (Just (ModuleName [ProperName "Data", ProperName C.generic]))
-
 deriveGenericRep
   :: forall m
    . (MonadError MultipleErrors m, MonadSupply m)
-  => ModuleName
+  => SourceSpan
+  -> ModuleName
   -> SynonymMap
   -> [Declaration]
   -> ProperName 'TypeName
   -> [Type]
   -> Type
   -> m ([Declaration], Type)
-deriveGenericRep mn syns ds tyConNm tyConArgs repTy = do
-    checkIsWildcard tyConNm repTy
+deriveGenericRep ss mn syns ds tyConNm tyConArgs repTy = do
+    checkIsWildcard ss tyConNm repTy
     go =<< findTypeDecl tyConNm ds
   where
     go :: Declaration -> m ([Declaration], Type)
-    go (DataDeclaration (ss, _) _ _ args dctors) = do
+    go (DataDeclaration (ss', _) _ _ args dctors) = do
       x <- freshIdent "x"
       (reps, to, from) <- unzip3 <$> traverse makeInst dctors
       let rep = toRepTy reps
           inst | null reps =
                    -- If there are no cases, spin
-                   [ ValueDecl (ss, []) (Ident "to") Public [] $ unguarded $
-                       lamCase x [ CaseAlternative [NullBinder]
-                                                   (unguarded (App toName (Var (Qualified Nothing x))))
-                                 ]
-                   , ValueDecl (ss, []) (Ident "from") Public [] $ unguarded $
-                       lamCase x [ CaseAlternative [NullBinder]
-                                                   (unguarded (App fromName (Var (Qualified Nothing x))))
-                                 ]
+                   [ ValueDecl (ss', []) (Ident "to") Public [] $ unguarded $
+                      lamCase ss' x
+                        [ CaseAlternative
+                            [NullBinder]
+                            (unguarded (App toName (Var ss' (Qualified Nothing x))))
+                        ]
+                   , ValueDecl (ss', []) (Ident "from") Public [] $ unguarded $
+                      lamCase ss' x
+                        [ CaseAlternative
+                            [NullBinder]
+                            (unguarded (App fromName (Var ss' (Qualified Nothing x))))
+                        ]
                    ]
                | otherwise =
-                   [ ValueDecl (ss, []) (Ident "to") Public [] $ unguarded $
-                       lamCase x (zipWith ($) (map underBinder (sumBinders (length dctors))) to)
-                   , ValueDecl (ss, []) (Ident "from") Public [] $ unguarded $
-                       lamCase x (zipWith ($) (map underExpr (sumExprs (length dctors))) from)
+                   [ ValueDecl (ss', []) (Ident "to") Public [] $ unguarded $
+                       lamCase ss' x (zipWith ($) (map underBinder (sumBinders (length dctors))) to)
+                   , ValueDecl (ss', []) (Ident "from") Public [] $ unguarded $
+                       lamCase ss' x (zipWith ($) (map underExpr (sumExprs (length dctors))) from)
                    ]
 
           subst = zipWith ((,) . fst) args tyConArgs
@@ -493,10 +326,10 @@
     select l r n = take (n - 1) (iterate (r .) l) ++ [compN (n - 1) r]
 
     sumBinders :: Int -> [Binder -> Binder]
-    sumBinders = select (ConstructorBinder inl . pure) (ConstructorBinder inr . pure)
+    sumBinders = select (ConstructorBinder ss inl . pure) (ConstructorBinder ss inr . pure)
 
     sumExprs :: Int -> [Expr -> Expr]
-    sumExprs = select (App (Constructor inl)) (App (Constructor inr))
+    sumExprs = select (App (Constructor ss inl)) (App (Constructor ss inr))
 
     compN :: Int -> (a -> a) -> a -> a
     compN 0 _ = id
@@ -511,9 +344,9 @@
         return ( TypeApp (TypeApp (TypeConstructor constructor)
                                   (TypeLevelString $ mkString (runProperName ctorName)))
                          ctorTy
-               , CaseAlternative [ ConstructorBinder constructor [matchProduct] ]
-                                 (unguarded (foldl App (Constructor (Qualified (Just mn) ctorName)) ctorArgs))
-               , CaseAlternative [ ConstructorBinder (Qualified (Just mn) ctorName) matchCtor ]
+               , CaseAlternative [ ConstructorBinder ss constructor [matchProduct] ]
+                                 (unguarded (foldl' App (Constructor ss (Qualified (Just mn) ctorName)) ctorArgs))
+               , CaseAlternative [ ConstructorBinder ss (Qualified (Just mn) ctorName) matchCtor ]
                                  (unguarded (constructor' mkProduct))
                )
 
@@ -525,48 +358,20 @@
     makeProduct args = do
       (tys, bs1, es1, bs2, es2) <- unzip5 <$> traverse makeArg args
       pure ( foldr1 (\f -> TypeApp (TypeApp (TypeConstructor productName) f)) tys
-           , foldr1 (\b1 b2 -> ConstructorBinder productName [b1, b2]) bs1
+           , foldr1 (\b1 b2 -> ConstructorBinder ss productName [b1, b2]) bs1
            , es1
            , bs2
-           , foldr1 (\e1 -> App (App (Constructor productName) e1)) es2
+           , foldr1 (\e1 -> App (App (Constructor ss productName) e1)) es2
            )
 
     makeArg :: Type -> m (Type, Binder, Expr, Binder, Expr)
-    makeArg arg | Just rec <- objectType arg
-                , Just fields <- decomposeRec rec = do
-      fieldNames <- traverse freshIdent (map (runIdent . labelToIdent . fst) fields)
-      case fieldNames of
-        [] ->
-          pure ( TypeApp (TypeConstructor record) noArgs
-               , ConstructorBinder record [ NullBinder ]
-               , Literal (ObjectLiteral [])
-               , LiteralBinder (ObjectLiteral [])
-               , record' noArgs'
-               )
-        _ ->
-          pure ( TypeApp (TypeConstructor record)
-                   (foldr1 (\f -> TypeApp (TypeApp (TypeConstructor productName) f))
-                     (map (\((Label name), ty) ->
-                       TypeApp (TypeApp (TypeConstructor field) (TypeLevelString name)) ty) fields))
-               , ConstructorBinder record
-                   [ foldr1 (\b1 b2 -> ConstructorBinder productName [b1, b2])
-                       (map (\ident -> ConstructorBinder field [VarBinder ident]) fieldNames)
-                   ]
-               , Literal . ObjectLiteral $
-                    zipWith (\((Label name), _) ident -> (name, Var (Qualified Nothing ident))) fields fieldNames
-               , LiteralBinder . ObjectLiteral $
-                     zipWith (\((Label name), _) ident -> (name, VarBinder ident)) fields fieldNames
-               , record' $
-                   foldr1 (\e1 -> App (App (Constructor productName) e1))
-                     (map (field' . Var . Qualified Nothing) fieldNames)
-               )
     makeArg arg = do
       argName <- freshIdent "arg"
       pure ( TypeApp (TypeConstructor argument) arg
-           , ConstructorBinder argument [ VarBinder argName ]
-           , Var (Qualified Nothing argName)
-           , VarBinder argName
-           , argument' (Var (Qualified Nothing argName))
+           , ConstructorBinder ss argument [ VarBinder ss argName ]
+           , Var ss (Qualified Nothing argName)
+           , VarBinder ss argName
+           , argument' (Var ss (Qualified Nothing argName))
            )
 
     underBinder :: (Binder -> Binder) -> CaseAlternative -> CaseAlternative
@@ -582,10 +387,10 @@
     toRepTy ctors = foldr1 (\f -> TypeApp (TypeApp sumCtor f)) ctors
 
     toName :: Expr
-    toName = Var (Qualified (Just dataGenericRep) (Ident "to"))
+    toName = Var ss (Qualified (Just dataGenericRep) (Ident "to"))
 
     fromName :: Expr
-    fromName = Var (Qualified (Just dataGenericRep) (Ident "from"))
+    fromName = Var ss (Qualified (Just dataGenericRep) (Ident "from"))
 
     noCtors :: Type
     noCtors = TypeConstructor (Qualified (Just dataGenericRep) (ProperName "NoConstructors"))
@@ -594,7 +399,7 @@
     noArgs = TypeConstructor (Qualified (Just dataGenericRep) (ProperName "NoArguments"))
 
     noArgs' :: Expr
-    noArgs' = Constructor (Qualified (Just dataGenericRep) (ProperName "NoArguments"))
+    noArgs' = Constructor ss (Qualified (Just dataGenericRep) (ProperName "NoArguments"))
 
     sumCtor :: Type
     sumCtor = TypeConstructor (Qualified (Just dataGenericRep) (ProperName "Sum"))
@@ -612,30 +417,18 @@
     constructor = Qualified (Just dataGenericRep) (ProperName "Constructor")
 
     constructor' :: Expr -> Expr
-    constructor' = App (Constructor constructor)
+    constructor' = App (Constructor ss constructor)
 
     argument :: Qualified (ProperName ty)
     argument = Qualified (Just dataGenericRep) (ProperName "Argument")
 
     argument' :: Expr -> Expr
-    argument' = App (Constructor argument)
-
-    record :: Qualified (ProperName ty)
-    record = Qualified (Just dataGenericRep) (ProperName "Rec")
-
-    record' :: Expr -> Expr
-    record' = App (Constructor record)
-
-    field :: Qualified (ProperName ty)
-    field = Qualified (Just dataGenericRep) (ProperName "Field")
-
-    field' :: Expr -> Expr
-    field' = App (Constructor field)
+    argument' = App (Constructor ss argument)
 
-checkIsWildcard :: MonadError MultipleErrors m => ProperName 'TypeName -> Type -> m ()
-checkIsWildcard _ (TypeWildcard _) = return ()
-checkIsWildcard tyConNm _ =
-  throwError . errorMessage $ ExpectedWildcard tyConNm
+checkIsWildcard :: MonadError MultipleErrors m => SourceSpan -> ProperName 'TypeName -> Type -> m ()
+checkIsWildcard _ _ (TypeWildcard _) = return ()
+checkIsWildcard ss tyConNm _ =
+  throwError . errorMessage' ss $ ExpectedWildcard tyConNm
 
 deriveEq
   :: forall m
@@ -652,47 +445,59 @@
   return [ ValueDecl (ss, []) (Ident C.eq) Public [] (unguarded eqFun) ]
   where
     mkEqFunction :: Declaration -> m Expr
-    mkEqFunction (DataDeclaration _ _ _ _ args) = do
+    mkEqFunction (DataDeclaration (ss', _) _ _ _ args) = do
       x <- freshIdent "x"
       y <- freshIdent "y"
-      lamCase2 x y <$> (addCatch <$> mapM mkCtorClause args)
+      lamCase2 ss' x y <$> (addCatch <$> mapM mkCtorClause args)
     mkEqFunction _ = internalError "mkEqFunction: expected DataDeclaration"
 
     preludeConj :: Expr -> Expr -> Expr
-    preludeConj = App . App (Var (Qualified (Just (ModuleName [ProperName "Data", ProperName "HeytingAlgebra"])) (Ident C.conj)))
+    preludeConj = App . App (Var ss (Qualified (Just (ModuleName [ProperName "Data", ProperName "HeytingAlgebra"])) (Ident C.conj)))
 
     preludeEq :: Expr -> Expr -> Expr
-    preludeEq = App . App (Var (Qualified (Just dataEq) (Ident C.eq)))
+    preludeEq = App . App (Var ss (Qualified (Just dataEq) (Ident C.eq)))
 
+    preludeEq1 :: Expr -> Expr -> Expr
+    preludeEq1 = App . App (Var ss (Qualified (Just dataEq) (Ident C.eq1)))
+
     addCatch :: [CaseAlternative] -> [CaseAlternative]
     addCatch xs
       | length xs /= 1 = xs ++ [catchAll]
       | otherwise = xs -- Avoid redundant case
       where
-      catchAll = CaseAlternative [NullBinder, NullBinder] (unguarded (Literal (BooleanLiteral False)))
+      catchAll = CaseAlternative [NullBinder, NullBinder] (unguarded (Literal ss (BooleanLiteral False)))
 
     mkCtorClause :: (ProperName 'ConstructorName, [Type]) -> m CaseAlternative
     mkCtorClause (ctorName, tys) = do
       identsL <- replicateM (length tys) (freshIdent "l")
       identsR <- replicateM (length tys) (freshIdent "r")
       tys' <- mapM (replaceAllTypeSynonymsM syns) tys
-      let tests = zipWith3 toEqTest (map (Var . Qualified Nothing) identsL) (map (Var . Qualified Nothing) identsR) tys'
+      let tests = zipWith3 toEqTest (map (Var ss . Qualified Nothing) identsL) (map (Var ss . Qualified Nothing) identsR) tys'
       return $ CaseAlternative [caseBinder identsL, caseBinder identsR] (unguarded (conjAll tests))
       where
-      caseBinder idents = ConstructorBinder (Qualified (Just mn) ctorName) (map VarBinder idents)
+      caseBinder idents = ConstructorBinder ss (Qualified (Just mn) ctorName) (map (VarBinder ss) idents)
 
     conjAll :: [Expr] -> Expr
-    conjAll [] = Literal (BooleanLiteral True)
+    conjAll [] = Literal ss (BooleanLiteral True)
     conjAll xs = foldl1 preludeConj xs
 
     toEqTest :: Expr -> Expr -> Type -> Expr
-    toEqTest l r ty | Just rec <- objectType ty
-                    , Just fields <- decomposeRec rec =
-      conjAll
-      . map (\((Label str), typ) -> toEqTest (Accessor str l) (Accessor str r) typ)
-      $ fields
-    toEqTest l r _ = preludeEq l r
+    toEqTest l r ty
+      | Just rec <- objectType ty
+      , Just fields <- decomposeRec rec =
+          conjAll
+          . map (\((Label str), typ) -> toEqTest (Accessor str l) (Accessor str r) typ)
+          $ fields
+      | isAppliedVar ty = preludeEq1 l r
+      | otherwise = preludeEq l r
 
+deriveEq1 :: SourceSpan -> [Declaration]
+deriveEq1 ss =
+  [ ValueDecl (ss, []) (Ident C.eq1) Public [] (unguarded preludeEq)]
+  where
+    preludeEq :: Expr
+    preludeEq = Var ss (Qualified (Just dataEq) (Ident C.eq))
+
 deriveOrd
   :: forall m
    . (MonadError MultipleErrors m, MonadSupply m)
@@ -708,10 +513,10 @@
   return [ ValueDecl (ss, []) (Ident C.compare) Public [] (unguarded compareFun) ]
   where
     mkCompareFunction :: Declaration -> m Expr
-    mkCompareFunction (DataDeclaration _ _ _ _ args) = do
+    mkCompareFunction (DataDeclaration (ss', _) _ _ _ args) = do
       x <- freshIdent "x"
       y <- freshIdent "y"
-      lamCase2 x y <$> (addCatch . concat <$> mapM mkCtorClauses (splitLast args))
+      lamCase2 ss' x y <$> (addCatch . concat <$> mapM mkCtorClauses (splitLast args))
     mkCompareFunction _ = internalError "mkCompareFunction: expected DataDeclaration"
 
     splitLast :: [a] -> [(a, Bool)]
@@ -730,26 +535,29 @@
     orderingName = Qualified (Just (ModuleName [ProperName "Data", ProperName "Ordering"])) . ProperName
 
     orderingCtor :: Text -> Expr
-    orderingCtor = Constructor . orderingName
+    orderingCtor = Constructor ss . orderingName
 
     orderingBinder :: Text -> Binder
-    orderingBinder name = ConstructorBinder (orderingName name) []
+    orderingBinder name = ConstructorBinder ss (orderingName name) []
 
     ordCompare :: Expr -> Expr -> Expr
-    ordCompare = App . App (Var (Qualified (Just dataOrd) (Ident C.compare)))
+    ordCompare = App . App (Var ss (Qualified (Just dataOrd) (Ident C.compare)))
 
+    ordCompare1 :: Expr -> Expr -> Expr
+    ordCompare1 = App . App (Var ss (Qualified (Just dataOrd) (Ident C.compare1)))
+
     mkCtorClauses :: ((ProperName 'ConstructorName, [Type]), Bool) -> m [CaseAlternative]
     mkCtorClauses ((ctorName, tys), isLast) = do
       identsL <- replicateM (length tys) (freshIdent "l")
       identsR <- replicateM (length tys) (freshIdent "r")
       tys' <- mapM (replaceAllTypeSynonymsM syns) tys
-      let tests = zipWith3 toOrdering (map (Var . Qualified Nothing) identsL) (map (Var . Qualified Nothing) identsR) tys'
-          extras | not isLast = [ CaseAlternative [ ConstructorBinder (Qualified (Just mn) ctorName) (replicate (length tys) NullBinder)
+      let tests = zipWith3 toOrdering (map (Var ss . Qualified Nothing) identsL) (map (Var ss . Qualified Nothing) identsR) tys'
+          extras | not isLast = [ CaseAlternative [ ConstructorBinder ss (Qualified (Just mn) ctorName) (replicate (length tys) NullBinder)
                                                   , NullBinder
                                                   ]
                                                   (unguarded (orderingCtor "LT"))
                                 , CaseAlternative [ NullBinder
-                                                  , ConstructorBinder (Qualified (Just mn) ctorName) (replicate (length tys) NullBinder)
+                                                  , ConstructorBinder ss (Qualified (Just mn) ctorName) (replicate (length tys) NullBinder)
                                                   ]
                                                   (unguarded (orderingCtor "GT"))
                                 ]
@@ -761,7 +569,7 @@
              : extras
 
       where
-      caseBinder idents = ConstructorBinder (Qualified (Just mn) ctorName) (map VarBinder idents)
+      caseBinder idents = ConstructorBinder ss (Qualified (Just mn) ctorName) (map (VarBinder ss) idents)
 
     appendAll :: [Expr] -> Expr
     appendAll [] = orderingCtor "EQ"
@@ -775,44 +583,54 @@
                                   ]
 
     toOrdering :: Expr -> Expr -> Type -> Expr
-    toOrdering l r ty | Just rec <- objectType ty
-                      , Just fields <- decomposeRec rec =
-      appendAll
-      . map (\((Label str), typ) -> toOrdering (Accessor str l) (Accessor str r) typ)
-      $ fields
-    toOrdering l r _ = ordCompare l r
+    toOrdering l r ty
+      | Just rec <- objectType ty
+      , Just fields <- decomposeRec rec =
+          appendAll
+          . map (\((Label str), typ) -> toOrdering (Accessor str l) (Accessor str r) typ)
+          $ fields
+      | isAppliedVar ty = ordCompare1 l r
+      | otherwise = ordCompare l r
 
+deriveOrd1 :: SourceSpan -> [Declaration]
+deriveOrd1 ss =
+  [ ValueDecl (ss, []) (Ident C.compare1) Public [] (unguarded dataOrdCompare)]
+  where
+    dataOrdCompare :: Expr
+    dataOrdCompare = Var ss (Qualified (Just dataOrd) (Ident C.compare))
+
 deriveNewtype
   :: forall m
    . (MonadError MultipleErrors m, MonadSupply m)
-  => ModuleName
+  => SourceSpan
+  -> ModuleName
   -> SynonymMap
   -> [Declaration]
   -> ProperName 'TypeName
   -> [Type]
   -> Type
   -> m ([Declaration], Type)
-deriveNewtype mn syns ds tyConNm tyConArgs unwrappedTy = do
-    checkIsWildcard tyConNm unwrappedTy
+deriveNewtype ss mn syns ds tyConNm tyConArgs unwrappedTy = do
+    checkIsWildcard ss tyConNm unwrappedTy
     go =<< findTypeDecl tyConNm ds
   where
     go :: Declaration -> m ([Declaration], Type)
-    go (DataDeclaration (ss, _) Data name _ _) =
-      throwError . errorMessage' ss $ CannotDeriveNewtypeForData name
-    go (DataDeclaration (ss, _) Newtype name args dctors) = do
+    go (DataDeclaration (ss', _) Data name _ _) =
+      throwError . errorMessage' ss' $ CannotDeriveNewtypeForData name
+    go (DataDeclaration (ss', _) Newtype name args dctors) = do
       checkNewtype name dctors
       wrappedIdent <- freshIdent "n"
       unwrappedIdent <- freshIdent "a"
       let (ctorName, [ty]) = head dctors
       ty' <- replaceAllTypeSynonymsM syns ty
       let inst =
-            [ ValueDecl (ss, []) (Ident "wrap") Public [] $ unguarded $
-                Constructor (Qualified (Just mn) ctorName)
-            , ValueDecl (ss, []) (Ident "unwrap") Public [] $ unguarded $
-                lamCase wrappedIdent
+            [ ValueDecl (ss', []) (Ident "wrap") Public [] $ unguarded $
+                Constructor ss' (Qualified (Just mn) ctorName)
+            , ValueDecl (ss', []) (Ident "unwrap") Public [] $ unguarded $
+                lamCase ss' wrappedIdent
                   [ CaseAlternative
-                      [ConstructorBinder (Qualified (Just mn) ctorName) [VarBinder unwrappedIdent]]
-                      (unguarded (Var (Qualified Nothing unwrappedIdent)))
+                      [ConstructorBinder ss' (Qualified (Just mn) ctorName) [VarBinder ss' unwrappedIdent]]
+                      (unguarded (Var ss' (Qualified Nothing unwrappedIdent)))
                   ]
             ]
           subst = zipWith ((,) . fst) args tyConArgs
@@ -830,37 +648,27 @@
   isTypeDecl (DataDeclaration _ _ nm _ _) | nm == tyConNm = True
   isTypeDecl _ = False
 
-lam :: Ident -> Expr -> Expr
-lam = Abs . VarBinder
-
-lamNull :: Expr -> Expr
-lamNull = lam (Ident "$q") -- TODO: use GenIdent
+lam :: SourceSpan -> Ident -> Expr -> Expr
+lam ss = Abs . VarBinder ss
 
-lamCase :: Ident -> [CaseAlternative] -> Expr
-lamCase s = lam s . Case [mkVar s]
+lamCase :: SourceSpan -> Ident -> [CaseAlternative] -> Expr
+lamCase ss s = lam ss s . Case [mkVar ss s]
 
-lamCase2 :: Ident -> Ident -> [CaseAlternative] -> Expr
-lamCase2 s t = lam s . lam t . Case [mkVar s, mkVar t]
+lamCase2 :: SourceSpan -> Ident -> Ident -> [CaseAlternative] -> Expr
+lamCase2 ss s t = lam ss s . lam ss t . Case [mkVar ss s, mkVar ss t]
 
-mkVarMn :: Maybe ModuleName -> Ident -> Expr
-mkVarMn mn = Var . Qualified mn
+mkVarMn :: SourceSpan -> Maybe ModuleName -> Ident -> Expr
+mkVarMn ss mn = Var ss . Qualified mn
 
-mkVar :: Ident -> Expr
-mkVar = mkVarMn Nothing
+mkVar :: SourceSpan -> Ident -> Expr
+mkVar ss = mkVarMn ss Nothing
 
--- This function may seem a little obtuse, but it's only this way to ensure
--- that it is injective. Injectivity is important here; without it, we can end
--- up with accidental variable shadowing in the generated code.
-labelToIdent :: Label -> Ident
-labelToIdent =
-  Ident . foldMap (either loneSurrogate char) . decodeStringEither . runLabel
-  where
-  char '_' = "__"
-  char c = T.singleton c
-  loneSurrogate x = "_" <> T.pack (show x) <> "_"
+isAppliedVar :: Type -> Bool
+isAppliedVar (TypeApp (TypeVar _) _) = True
+isAppliedVar _ = False
 
 objectType :: Type -> Maybe Type
-objectType (TypeApp (TypeConstructor (Qualified (Just (ModuleName [ProperName "Prim"])) (ProperName "Record"))) rec) = Just rec
+objectType (TypeApp (TypeConstructor C.Record) rec) = Just rec
 objectType _ = Nothing
 
 decomposeRec :: Type -> Maybe [(Label, Type)]
@@ -894,7 +702,7 @@
       ((iTy, _) : _) -> do
         f <- freshIdent "f"
         m <- freshIdent "m"
-        lam f . lamCase m <$> mapM (mkCtorClause iTy f) ctors
+        lam ss' f . lamCase ss' m <$> mapM (mkCtorClause iTy f) ctors
     mkMapFunction _ = internalError "mkMapFunction: expected DataDeclaration"
 
     mkCtorClause :: Text -> Ident -> (ProperName 'ConstructorName, [Type]) -> m CaseAlternative
@@ -902,17 +710,17 @@
       idents <- replicateM (length ctorTys) (freshIdent "v")
       ctorTys' <- mapM (replaceAllTypeSynonymsM syns) ctorTys
       args <- zipWithM transformArg idents ctorTys'
-      let ctor = Constructor (Qualified (Just mn) ctorName)
-          rebuilt = foldl App ctor args
-          caseBinder = ConstructorBinder (Qualified (Just mn) ctorName) (VarBinder <$> idents)
+      let ctor = Constructor ss (Qualified (Just mn) ctorName)
+          rebuilt = foldl' App ctor args
+          caseBinder = ConstructorBinder ss (Qualified (Just mn) ctorName) (VarBinder ss <$> idents)
       return $ CaseAlternative [caseBinder] (unguarded rebuilt)
       where
-        fVar = mkVar f
-        mapVar = mkVarMn (Just dataFunctor) (Ident C.map)
+        fVar = mkVar ss f
+        mapVar = mkVarMn ss (Just dataFunctor) (Ident C.map)
 
         -- TODO: deal with type synonyms, ala https://github.com/purescript/purescript/pull/2516
         transformArg :: Ident -> Type -> m Expr
-        transformArg ident = fmap (foldr App (mkVar ident)) . goType where
+        transformArg ident = fmap (foldr App (mkVar ss ident)) . goType where
 
           goType :: Type -> m (Maybe Expr)
           -- argument matches the index type
@@ -930,10 +738,17 @@
                                          return ((lbl,) <$> upd)
 
               buildRecord :: [(Label, Expr)] -> m Expr
-              buildRecord updates = do arg <- freshIdent "o"
-                                       let argVar = mkVar arg
-                                           mkAssignment ((Label l), x) = (l, App x (Accessor l argVar))
-                                       return (lam arg (ObjectUpdate argVar (mkAssignment <$> updates)))
+              buildRecord updates = do
+                arg <- freshIdent "o"
+                let argVar = mkVar ss arg
+                    mkAssignment ((Label l), x) = (l, App x (Accessor l argVar))
+                return (lam ss arg (ObjectUpdate argVar (mkAssignment <$> updates)))
+
+          -- quantifiers
+          goType (ForAll scopedVar t _) | scopedVar /= iTyName = goType t
+
+          -- constraints
+          goType (ConstrainedType _ t) = goType t
 
           -- under a `* -> *`, just assume functor for now
           goType (TypeApp _ t) = fmap (App mapVar) <$> goType t
diff --git a/src/Language/PureScript/Sugar/TypeDeclarations.hs b/src/Language/PureScript/Sugar/TypeDeclarations.hs
--- a/src/Language/PureScript/Sugar/TypeDeclarations.hs
+++ b/src/Language/PureScript/Sugar/TypeDeclarations.hs
@@ -46,10 +46,10 @@
     (:) <$> (ValueDecl sa name' nameKind bs <$> f' val)
         <*> desugarTypeDeclarations rest
     where
-    go (Let ds' val') = Let <$> desugarTypeDeclarations ds' <*> pure val'
+    go (Let w ds' val') = Let w <$> desugarTypeDeclarations ds' <*> pure val'
     go other = return other
-  desugarTypeDeclarations (TypeInstanceDeclaration sa nm deps cls args (ExplicitInstance ds') : rest) =
-    (:) <$> (TypeInstanceDeclaration sa nm deps cls args . ExplicitInstance <$> desugarTypeDeclarations ds')
+  desugarTypeDeclarations (TypeInstanceDeclaration sa ch idx nm deps cls args (ExplicitInstance ds') : rest) =
+    (:) <$> (TypeInstanceDeclaration sa ch idx nm deps cls args . ExplicitInstance <$> desugarTypeDeclarations ds')
         <*> desugarTypeDeclarations rest
   desugarTypeDeclarations (d:rest) = (:) d <$> desugarTypeDeclarations rest
   desugarTypeDeclarations [] = return []
diff --git a/src/Language/PureScript/TypeChecker.hs b/src/Language/PureScript/TypeChecker.hs
--- a/src/Language/PureScript/TypeChecker.hs
+++ b/src/Language/PureScript/TypeChecker.hs
@@ -14,7 +14,7 @@
 
 import Control.Monad (when, unless, void, forM)
 import Control.Monad.Error.Class (MonadError(..))
-import Control.Monad.State.Class (MonadState(..), modify)
+import Control.Monad.State.Class (MonadState(..), modify, gets)
 import Control.Monad.Supply.Class (MonadSupply)
 import Control.Monad.Writer.Class (MonadWriter(..))
 import Control.Lens ((^..), _1, _2)
@@ -233,7 +233,7 @@
   where
   go :: Declaration -> m Declaration
   go (DataDeclaration sa@(ss, _) dtype name args dctors) = do
-    warnAndRethrow (addHint (ErrorInTypeConstructor name) . addHint (PositionedError ss)) $ do
+    warnAndRethrow (addHint (ErrorInTypeConstructor name) . addHint (positionedError ss)) $ do
       when (dtype == Newtype) $ checkNewtype name dctors
       checkDuplicateTypeArguments $ map fst args
       ctorKind <- kindsOf True moduleName name args (concatMap snd dctors)
@@ -245,7 +245,8 @@
         syns = mapMaybe toTypeSynonym tysList
         dataDecls = mapMaybe toDataDecl tysList
         bindingGroupNames = ordNub ((syns^..traverse._1) ++ (dataDecls^..traverse._2))
-    warnAndRethrow (addHint (ErrorInDataBindingGroup bindingGroupNames)) $ do
+        sss = fmap declSourceSpan tys
+    warnAndRethrow (addHint (ErrorInDataBindingGroup bindingGroupNames) . addHint (PositionedError sss)) $ do
       (syn_ks, data_ks) <- kindsOfAll moduleName syns (map (\(_, name, args, dctors) -> (name, args, concatMap snd dctors)) dataDecls)
       for_ (zip dataDecls data_ks) $ \((dtype, name, args, dctors), ctorKind) -> do
         when (dtype == Newtype) $ checkNewtype name dctors
@@ -263,7 +264,7 @@
     toDataDecl (DataDeclaration _ dtype nm args dctors) = Just (dtype, nm, args, dctors)
     toDataDecl _ = Nothing
   go (TypeSynonymDeclaration sa@(ss, _) name args ty) = do
-    warnAndRethrow (addHint (ErrorInTypeSynonym name) . addHint (PositionedError ss) ) $ do
+    warnAndRethrow (addHint (ErrorInTypeSynonym name) . addHint (positionedError ss) ) $ do
       checkDuplicateTypeArguments $ map fst args
       kind <- kindsOf False moduleName name args [ty]
       let args' = args `withKinds` kind
@@ -273,7 +274,7 @@
     internalError "Type declarations should have been removed before typeCheckAlld"
   go (ValueDecl sa@(ss, _) name nameKind [] [MkUnguarded val]) = do
     env <- getEnv
-    warnAndRethrow (addHint (ErrorInValueDeclaration name) . addHint (PositionedError ss)) $ do
+    warnAndRethrow (addHint (ErrorInValueDeclaration name) . addHint (positionedError ss)) $ do
       val' <- checkExhaustiveExpr ss env moduleName val
       valueIsNotDefined moduleName name
       [(_, (val'', ty))] <- typesOf NonRecursiveBindingGroup moduleName [((sa, name), val')]
@@ -283,7 +284,8 @@
   go BoundValueDeclaration{} = internalError "BoundValueDeclaration should be desugared"
   go (BindingGroupDeclaration vals) = do
     env <- getEnv
-    warnAndRethrow (addHint (ErrorInBindingGroup (fmap (\((_, ident), _, _) -> ident) vals))) $ do
+    let sss = fmap (\(((ss, _), _), _, _) -> ss) vals
+    warnAndRethrow (addHint (ErrorInBindingGroup (fmap (\((_, ident), _, _) -> ident) vals)) . addHint (PositionedError sss)) $ do
       for_ vals $ \((_, ident), _, _) -> valueIsNotDefined moduleName ident
       vals' <- NEL.toList <$> traverse (\(sai@((ss, _), _), nk, expr) -> (sai, nk,) <$> checkExhaustiveExpr ss env moduleName expr) vals
       tys <- typesOf RecursiveBindingGroup moduleName $ fmap (\(sai, _, ty) -> (sai, ty)) vals'
@@ -304,7 +306,7 @@
     putEnv $ env { kinds = S.insert (Qualified (Just moduleName) name) (kinds env) }
     return d
   go (d@(ExternDeclaration (ss, _) name ty)) = do
-    warnAndRethrow (addHint (ErrorInForeignImport name) . addHint (PositionedError ss)) $ do
+    warnAndRethrow (addHint (ErrorInForeignImport name) . addHint (positionedError ss)) $ do
       env <- getEnv
       kind <- kindOf ty
       guardWith (errorMessage (ExpectedType ty kind)) $ kind == kindType
@@ -315,15 +317,15 @@
   go d@FixityDeclaration{} = return d
   go d@ImportDeclaration{} = return d
   go d@(TypeClassDeclaration (ss, _) pn args implies deps tys) = do
-    warnAndRethrow (addHint (ErrorInTypeClassDeclaration pn) . addHint (PositionedError ss)) $ do
+    warnAndRethrow (addHint (ErrorInTypeClassDeclaration pn) . addHint (positionedError ss)) $ do
       env <- getEnv
       let qualifiedClassName = Qualified (Just moduleName) pn
       guardWith (errorMessage (DuplicateTypeClass pn ss)) $
         not (M.member qualifiedClassName (typeClasses env))
       addTypeClass qualifiedClassName args implies deps tys
       return d
-  go (d@(TypeInstanceDeclaration (ss, _) dictName deps className tys body)) =
-    rethrow (addHint (ErrorInInstance className tys) . addHint (PositionedError ss)) $ do
+  go (d@(TypeInstanceDeclaration (ss, _) ch idx dictName deps className tys body)) =
+    rethrow (addHint (ErrorInInstance className tys) . addHint (positionedError ss)) $ do
       env <- getEnv
       let qualifiedDictName = Qualified (Just moduleName) dictName
       flip (traverse_ . traverse_) (typeClassDictionaries env) $ \dictionaries ->
@@ -334,10 +336,13 @@
         Just typeClass -> do
           checkInstanceArity dictName className typeClass tys
           sequence_ (zipWith (checkTypeClassInstance typeClass) [0..] tys)
-          checkOrphanInstance dictName className typeClass tys
+          let nonOrphanModules = findNonOrphanModules className typeClass tys
+          checkOrphanInstance dictName className tys nonOrphanModules
+          let qualifiedChain = Qualified (Just moduleName) <$> ch
+          checkOverlappingInstance qualifiedChain dictName className typeClass tys nonOrphanModules
           _ <- traverseTypeInstanceBody checkInstanceMembers body
           deps' <- (traverse . overConstraintArgs . traverse) replaceAllTypeSynonyms deps
-          let dict = TypeClassDictionaryInScope qualifiedDictName [] className tys (Just deps')
+          let dict = TypeClassDictionaryInScope qualifiedChain idx qualifiedDictName [] className tys (Just deps')
           addTypeClassDictionaries (Just moduleName) . M.singleton className $ M.singleton (tcdValue dict) dict
           return d
 
@@ -365,21 +370,23 @@
       | otherwise = firstDuplicate xs
     firstDuplicate _ = Nothing
 
-  checkOrphanInstance :: Ident -> Qualified (ProperName 'ClassName) -> TypeClassData -> [Type] -> m ()
-  checkOrphanInstance dictName className@(Qualified (Just mn') _) typeClass tys'
-    | moduleName `S.member` nonOrphanModules' = return ()
-    | otherwise = throwError . errorMessage $ OrphanInstance dictName className nonOrphanModules' tys'
+  findNonOrphanModules
+    :: Qualified (ProperName 'ClassName)
+    -> TypeClassData
+    -> [Type]
+    -> S.Set ModuleName
+  findNonOrphanModules (Qualified (Just mn') _) typeClass tys' = nonOrphanModules
     where
-    nonOrphanModules' :: S.Set ModuleName
-    nonOrphanModules' = S.insert mn' nonOrphanModules
+    nonOrphanModules :: S.Set ModuleName
+    nonOrphanModules = S.insert mn' nonOrphanModules'
 
     typeModule :: Type -> Maybe ModuleName
     typeModule (TypeVar _) = Nothing
     typeModule (TypeLevelString _) = Nothing
     typeModule (TypeConstructor (Qualified (Just mn'') _)) = Just mn''
-    typeModule (TypeConstructor (Qualified Nothing _)) = internalError "Unqualified type name in checkOrphanInstance"
+    typeModule (TypeConstructor (Qualified Nothing _)) = internalError "Unqualified type name in findNonOrphanModules"
     typeModule (TypeApp t1 _) = typeModule t1
-    typeModule _ = internalError "Invalid type in instance in checkOrphanInstance"
+    typeModule _ = internalError "Invalid type in instance in findNonOrphanModules"
 
     modulesByTypeIndex :: M.Map Int (Maybe ModuleName)
     modulesByTypeIndex = M.fromList (zip [0 ..] (typeModule <$> tys'))
@@ -387,17 +394,75 @@
     lookupModule :: Int -> S.Set ModuleName
     lookupModule idx = case M.lookup idx modulesByTypeIndex of
       Just ms -> S.fromList (toList ms)
-      Nothing -> internalError "Unknown type index in checkOrphanInstance"
+      Nothing -> internalError "Unknown type index in findNonOrphanModules"
 
     -- If the instance is declared in a module that wouldn't be found based on a covering set
     -- then it is considered an orphan - because we'd have a situation in which we expect an
     -- instance but can't find it. So a valid module must be applicable across *all* covering
     -- sets - therefore we take the intersection of covering set modules.
-    nonOrphanModules :: S.Set ModuleName
-    nonOrphanModules = foldl1 S.intersection (foldMap lookupModule `S.map` typeClassCoveringSets typeClass)
+    nonOrphanModules' :: S.Set ModuleName
+    nonOrphanModules' = foldl1 S.intersection (foldMap lookupModule `S.map` typeClassCoveringSets typeClass)
+  findNonOrphanModules _ _ _ = internalError "Unqualified class name in findNonOrphanModules"
 
-  checkOrphanInstance _ _ _ _ = internalError "Unqualified class name in checkOrphanInstance"
+  -- Check that the instance currently being declared doesn't overlap with any
+  -- other instance in any module that this instance wouldn't be considered an
+  -- orphan in.  There are overlapping instance situations that won't be caught
+  -- by this, for example when combining multiparametr type classes with
+  -- flexible instances: the instances `Cls X y` and `Cls x Y` overlap and
+  -- could live in different modules but won't be caught here.
+  checkOverlappingInstance
+    :: [Qualified Ident]
+    -> Ident
+    -> Qualified (ProperName 'ClassName)
+    -> TypeClassData
+    -> [Type]
+    -> S.Set ModuleName
+    -> m ()
+  checkOverlappingInstance ch dictName className typeClass tys' nonOrphanModules = do
+    for_ nonOrphanModules $ \m -> do
+      dicts <- M.toList <$> lookupTypeClassDictionariesForClass (Just m) className
 
+      for_ dicts $ \(ident, dict) -> do
+        -- ignore instances in the same instance chain
+        if ch == tcdChain dict ||
+           instancesAreApart (typeClassCoveringSets typeClass) tys' (tcdInstanceTypes dict)
+        then return ()
+        else throwError . errorMessage $
+               OverlappingInstances className
+                                    tys'
+                                    [ident, Qualified (Just moduleName) dictName]
+
+  instancesAreApart
+    :: S.Set (S.Set Int)
+    -> [Type]
+    -> [Type]
+    -> Bool
+  instancesAreApart sets lhs rhs = all (any typesApart . S.toList) (S.toList sets)
+    where
+      typesApart :: Int -> Bool
+      typesApart i = typeHeadsApart (lhs !! i) (rhs !! i)
+
+      -- Note: implementation doesn't need to care about all possible cases:
+      -- TUnknown, Skolem, etc.
+      typeHeadsApart :: Type -> Type -> Bool
+      typeHeadsApart l                 r                 | l == r = False
+      typeHeadsApart (TypeVar _)       _                          = False
+      typeHeadsApart _                 (TypeVar _)                = False
+      typeHeadsApart (KindedType t1 _) t2                         = typeHeadsApart t1 t2
+      typeHeadsApart t1                (KindedType t2 _)          = typeHeadsApart t1 t2
+      typeHeadsApart (TypeApp h1 t1)   (TypeApp h2 t2)            = typeHeadsApart h1 h2 || typeHeadsApart t1 t2
+      typeHeadsApart _                 _                          = True
+
+  checkOrphanInstance
+    :: Ident
+    -> Qualified (ProperName 'ClassName)
+    -> [Type]
+    -> S.Set ModuleName
+    -> m ()
+  checkOrphanInstance dictName className tys' nonOrphanModules
+    | moduleName `S.member` nonOrphanModules = return ()
+    | otherwise = throwError . errorMessage $ OrphanInstance dictName className nonOrphanModules tys'
+
   -- |
   -- This function adds the argument kinds for a type constructor so that they may appear in the externs file,
   -- extracted from the kind of the type constructor itself.
@@ -432,38 +497,100 @@
   warnAndRethrow (addHint (ErrorInModule mn)) $ do
     modify (\s -> s { checkCurrentModule = Just mn })
     decls' <- typeCheckAll mn exps decls
+    checkSuperClassesAreExported <- getSuperClassExportCheck
     for_ exps $ \e -> do
       checkTypesAreExported e
       checkClassMembersAreExported e
       checkClassesAreExported e
+      checkSuperClassesAreExported e
     return $ Module ss coms mn decls' (Just exps)
   where
+  qualify' :: a -> Qualified a
+  qualify' = Qualified (Just mn)
 
+  getSuperClassExportCheck = do
+    classesToSuperClasses <- gets
+      ( M.map
+        ( S.fromList
+        . filter (\(Qualified mn' _) -> mn' == Just mn)
+        . fmap constraintClass
+        . typeClassSuperclasses
+        )
+      . typeClasses
+      . checkEnv
+      )
+    let
+      -- A function that, given a class name, returns the set of
+      -- transitive class dependencies that are defined in this
+      -- module.
+      transitiveSuperClassesFor
+          :: Qualified (ProperName 'ClassName)
+          -> S.Set (Qualified (ProperName 'ClassName))
+      transitiveSuperClassesFor qname =
+        untilSame
+          (\s -> s <> foldMap (\n -> fromMaybe S.empty (M.lookup n classesToSuperClasses)) s)
+          (fromMaybe S.empty (M.lookup qname classesToSuperClasses))
+
+      superClassesFor qname =
+        fromMaybe S.empty (M.lookup qname classesToSuperClasses)
+
+    pure $ checkSuperClassExport superClassesFor transitiveSuperClassesFor
+  moduleClassExports :: S.Set (Qualified (ProperName 'ClassName))
+  moduleClassExports = S.fromList $ mapMaybe (\x -> case x of
+     TypeClassRef _ name -> Just (qualify' name)
+     _ -> Nothing) exps
+
+  untilSame :: Eq a => (a -> a) -> a -> a
+  untilSame f a = let a' = f a in if a == a' then a else untilSame f a'
+
   checkMemberExport :: (Type -> [DeclarationRef]) -> DeclarationRef -> m ()
   checkMemberExport extract dr@(TypeRef _ name dctors) = do
     env <- getEnv
-    case M.lookup (Qualified (Just mn) name) (typeSynonyms env) of
-      Nothing -> return ()
-      Just (_, ty) -> checkExport dr extract ty
-    case dctors of
-      Nothing -> return ()
-      Just dctors' -> for_ dctors' $ \dctor ->
-        case M.lookup (Qualified (Just mn) dctor) (dataConstructors env) of
-          Nothing -> return ()
-          Just (_, _, ty, _) -> checkExport dr extract ty
-    return ()
+    for_ (M.lookup (qualify' name) (types env)) $ \(k, _) -> do
+      let findModuleKinds = everythingOnKinds (++) $ \case
+            NamedKind (Qualified (Just mn') kindName) | mn' == mn -> [kindName]
+            _ -> []
+      checkExport dr $ KindRef (declRefSourceSpan dr) <$> findModuleKinds k
+    for_ (M.lookup (qualify' name) (typeSynonyms env)) $ \(_, ty) ->
+      checkExport dr (extract ty)
+    for_ dctors $ \dctors' ->
+      for_ dctors' $ \dctor ->
+        for_ (M.lookup (qualify' dctor) (dataConstructors env)) $ \(_, _, ty, _) ->
+          checkExport dr (extract ty)
   checkMemberExport extract dr@(ValueRef _ name) = do
-    ty <- lookupVariable (Qualified (Just mn) name)
-    checkExport dr extract ty
+    ty <- lookupVariable (qualify' name)
+    checkExport dr (extract ty)
   checkMemberExport _ _ = return ()
 
-  checkExport :: DeclarationRef -> (Type -> [DeclarationRef]) -> Type -> m ()
-  checkExport dr extract ty = case filter (not . exported) (extract ty) of
+  checkSuperClassExport
+    :: (Qualified (ProperName 'ClassName) -> S.Set (Qualified (ProperName 'ClassName)))
+    -> (Qualified (ProperName 'ClassName) -> S.Set (Qualified (ProperName 'ClassName)))
+    -> DeclarationRef
+    -> m ()
+  checkSuperClassExport superClassesFor transitiveSuperClassesFor dr@(TypeClassRef drss className) = do
+    let superClasses = superClassesFor (qualify' className)
+        -- thanks to laziness, the computation of the transitive
+        -- superclasses defined in-module will only occur if we actually
+        -- throw the error. Constructing the full set of transitive
+        -- superclasses is likely to be costly for every single term.
+        transitiveSuperClasses = transitiveSuperClassesFor (qualify' className)
+        unexported = S.difference superClasses moduleClassExports
+    unless (null unexported)
+      . throwError . errorMessage' drss
+      . TransitiveExportError dr
+      . map (TypeClassRef drss . disqualify)
+      $ toList transitiveSuperClasses
+  checkSuperClassExport _ _ _ =
+    return ()
+
+  checkExport :: DeclarationRef -> [DeclarationRef] -> m ()
+  checkExport dr drs = case filter (not . exported) drs of
     [] -> return ()
     hidden -> throwError . errorMessage' (declRefSourceSpan dr) $ TransitiveExportError dr (nubBy nubEq hidden)
     where
     exported e = any (exports e) exps
     exports (TypeRef _ pn1 _) (TypeRef _ pn2 _) = pn1 == pn2
+    exports (KindRef _ pn1) (KindRef _ pn2) = pn1 == pn2
     exports (ValueRef _ id1) (ValueRef _ id2) = id1 == id2
     exports (TypeClassRef _ pn1) (TypeClassRef _ pn2) = pn1 == pn2
     exports _ _ = False
diff --git a/src/Language/PureScript/TypeChecker/Entailment.hs b/src/Language/PureScript/TypeChecker/Entailment.hs
--- a/src/Language/PureScript/TypeChecker/Entailment.hs
+++ b/src/Language/PureScript/TypeChecker/Entailment.hs
@@ -14,7 +14,7 @@
 import Prelude.Compat
 import Protolude (ordNub)
 
-import Control.Arrow (second)
+import Control.Arrow (second, (&&&))
 import Control.Monad.Error.Class (MonadError(..))
 import Control.Monad.State
 import Control.Monad.Supply.Class (MonadSupply(..))
@@ -23,11 +23,13 @@
 import Data.Foldable (for_, fold, toList)
 import Data.Function (on)
 import Data.Functor (($>))
-import Data.List (minimumBy)
-import Data.Maybe (fromMaybe, maybeToList, mapMaybe)
+import Data.List (minimumBy, groupBy, nubBy, sortBy)
+import Data.Maybe (fromMaybe, mapMaybe)
 import qualified Data.Map as M
 import qualified Data.Set as S
-import Data.Text (Text)
+import Data.Traversable (for)
+import Data.Text (Text, stripPrefix, stripSuffix)
+import qualified Data.Text as T
 
 import Language.PureScript.AST
 import Language.PureScript.Crash
@@ -39,7 +41,7 @@
 import Language.PureScript.TypeClassDictionaries
 import Language.PureScript.Types
 import Language.PureScript.Label (Label(..))
-import Language.PureScript.PSString (PSString, mkString)
+import Language.PureScript.PSString (PSString, mkString, decodeString)
 import qualified Language.PureScript.Constants as C
 
 -- | Describes what sort of dictionary to generate for type class instances
@@ -50,11 +52,7 @@
   -- | Computed instances
   | WarnInstance Type         -- ^ Warn type class with a user-defined warning message
   | IsSymbolInstance PSString -- ^ The IsSymbol type class for a given Symbol literal
-  | CompareSymbolInstance
-  | AppendSymbolInstance
-  | UnionInstance
-  | ConsInstance
-  | RowToListInstance
+  | EmptyClassInstance        -- ^ For any solved type class with no members
   deriving (Show, Eq)
 
 -- | Extract the identifier of a named instance
@@ -131,6 +129,20 @@
   -- ^ Should the solver be allowed to defer errors by skipping constraints?
   }
 
+data Matched t
+  = Match t
+  | Apart
+  | Unknown
+  deriving (Eq, Show, Functor)
+
+instance Monoid t => Monoid (Matched t) where
+  mempty = Match mempty
+
+  mappend (Match l) (Match r) = Match (l <> r)
+  mappend Apart     _         = Apart
+  mappend _         Apart     = Apart
+  mappend _         _         = Unknown
+
 -- | Check that the current set of type class dictionaries entail the specified type class goal, and, if so,
 -- return a type class dictionary reference.
 entails
@@ -152,27 +164,16 @@
     forClassName ctx cn@C.Warn [msg] =
       -- Prefer a warning dictionary in scope if there is one available.
       -- This allows us to defer a warning by propagating the constraint.
-      findDicts ctx cn Nothing ++ [TypeClassDictionaryInScope (WarnInstance msg) [] C.Warn [msg] Nothing]
-    forClassName _ C.IsSymbol [TypeLevelString sym] =
-      [TypeClassDictionaryInScope (IsSymbolInstance sym) [] C.IsSymbol [TypeLevelString sym] Nothing]
-    forClassName _ C.CompareSymbol [arg0@(TypeLevelString lhs), arg1@(TypeLevelString rhs), _] =
-      let ordering = case compare lhs rhs of
-                  LT -> C.orderingLT
-                  EQ -> C.orderingEQ
-                  GT -> C.orderingGT
-          args = [arg0, arg1, TypeConstructor ordering]
-      in [TypeClassDictionaryInScope CompareSymbolInstance [] C.CompareSymbol args Nothing]
-    forClassName _ C.AppendSymbol [arg0@(TypeLevelString lhs), arg1@(TypeLevelString rhs), _] =
-      let args = [arg0, arg1, TypeLevelString (lhs <> rhs)]
-      in [TypeClassDictionaryInScope AppendSymbolInstance [] C.AppendSymbol args Nothing]
-    forClassName _ C.Union [l, r, u]
-      | Just (lOut, rOut, uOut, cst) <- unionRows l r u
-      = [ TypeClassDictionaryInScope UnionInstance [] C.Union [lOut, rOut, uOut] cst ]
-    forClassName _ C.RowCons [TypeLevelString sym, ty, r, _]
-      = [ TypeClassDictionaryInScope ConsInstance [] C.RowCons [TypeLevelString sym, ty, r, RCons (Label sym) ty r] Nothing ]
-    forClassName _ C.RowToList [r, _]
-      | Just entries <- solveRowToList r
-      = [ TypeClassDictionaryInScope RowToListInstance [] C.RowToList [r, entries] Nothing ]
+      findDicts ctx cn Nothing ++ [TypeClassDictionaryInScope [] 0 (WarnInstance msg) [] C.Warn [msg] Nothing]
+    forClassName _ C.IsSymbol args | Just dicts <- solveIsSymbol args = dicts
+    forClassName _ C.SymbolCompare args | Just dicts <- solveSymbolCompare args = dicts
+    forClassName _ C.SymbolAppend args | Just dicts <- solveSymbolAppend args = dicts
+    forClassName _ C.SymbolCons args | Just dicts <- solveSymbolCons args = dicts
+    forClassName _ C.RowUnion args | Just dicts <- solveUnion args = dicts
+    forClassName _ C.RowNub args | Just dicts <- solveNub args = dicts
+    forClassName _ C.RowLacks args | Just dicts <- solveLacks args = dicts
+    forClassName _ C.RowCons args | Just dicts <- solveRowCons args = dicts
+    forClassName _ C.RowToList args | Just dicts <- solveRowToList args = dicts
     forClassName ctx cn@(Qualified (Just mn) _) tys = concatMap (findDicts ctx cn) (ordNub (Nothing : Just mn : map Just (mapMaybe ctorModules tys)))
     forClassName _ _ _ = internalError "forClassName: expected qualified class name"
 
@@ -187,7 +188,7 @@
     findDicts ctx cn = fmap (fmap NamedInstance) . maybe [] M.elems . (>>= M.lookup cn) . flip M.lookup ctx
 
     valUndefined :: Expr
-    valUndefined = Var (Qualified (Just (ModuleName [ProperName C.prim])) (Ident C.undefined))
+    valUndefined = Var nullSourceSpan (Qualified (Just (ModuleName [ProperName C.prim])) (Ident C.undefined))
 
     solve :: Constraint -> WriterT (Any, [(Ident, InstanceContext, Constraint)]) (StateT InstanceContext m) Expr
     solve con = go 0 con
@@ -207,12 +208,21 @@
             TypeClassData{ typeClassDependencies } <- case M.lookup className' classesInScope of
               Nothing -> throwError . errorMessage $ UnknownClass className'
               Just tcd -> pure tcd
-            let instances =
-                  [ (substs, tcd)
-                  | tcd <- forClassName (combineContexts context inferred) className' tys''
-                    -- Make sure the type unifies with the type in the type instance definition
-                  , substs <- maybeToList (matches typeClassDependencies tcd tys'')
-                  ]
+            let instances = do
+                  chain <- groupBy ((==) `on` tcdChain) $
+                           sortBy (compare `on` (tcdChain &&& tcdIndex)) $
+                           forClassName (combineContexts context inferred) className' tys''
+                  -- process instances in a chain in index order
+                  let found = for chain $ \tcd ->
+                                -- Make sure the type unifies with the type in the type instance definition
+                                case matches typeClassDependencies tcd tys'' of
+                                  Apart        -> Right ()                  -- keep searching
+                                  Match substs -> Left (Just (substs, tcd)) -- found a match
+                                  Unknown      -> Left Nothing              -- can't continue with this chain yet, need proof of apartness
+                  case found of
+                    Right _               -> []          -- all apart
+                    Left Nothing          -> []          -- last unknown
+                    Left (Just substsTcd) -> [substsTcd] -- found a match
             solution <- lift . lift $ unique tys'' instances
             case solution of
               Solved substs tcd -> do
@@ -249,7 +259,7 @@
                 modify (combineContexts newContext)
                 -- Mark this constraint for generalization
                 tell (mempty, [(ident, context, unsolved)])
-                return (Var qident)
+                return (Var nullSourceSpan qident)
               Deferred ->
                 -- Constraint was deferred, just return the dictionary unchanged,
                 -- with no unsolved constraints. Hopefully, we can solve this later.
@@ -295,9 +305,8 @@
               | otherwise = throwError . errorMessage $ NoInstanceFound (Constraint className' tyArgs conInfo)
             unique _      [(a, dict)] = return $ Solved a dict
             unique tyArgs tcds
-              | pairwiseAny overlapping (map snd tcds) = do
-                  tell . errorMessage $ OverlappingInstances className' tyArgs (tcds >>= (toList . namedInstanceIdentifier . tcdValue . snd))
-                  return $ uncurry Solved (head tcds)
+              | pairwiseAny overlapping (map snd tcds) =
+                  throwError . errorMessage $ OverlappingInstances className' tyArgs (tcds >>= (toList . namedInstanceIdentifier . tcdValue . snd))
               | otherwise = return $ uncurry Solved (minimumBy (compare `on` length . tcdPath . snd) tcds)
 
             canBeGeneralized :: Type -> Bool
@@ -325,34 +334,91 @@
             solveSubgoals subst (Just subgoals) =
               Just <$> traverse (go (work + 1) . mapConstraintArgs (map (replaceAllTypeVars (M.toList subst)))) subgoals
 
+            -- We need subgoal dictionaries to appear in the term somewhere
+            -- If there aren't any then the dictionary is just undefined
+            useEmptyDict :: Maybe [Expr] -> Expr
+            useEmptyDict args = foldl (App . Abs (VarBinder nullSourceSpan UnusedIdent)) valUndefined (fold args)
+
             -- Make a dictionary from subgoal dictionaries by applying the correct function
             mkDictionary :: Evidence -> Maybe [Expr] -> m Expr
-            mkDictionary (NamedInstance n) args = return $ foldl App (Var n) (fold args)
-            mkDictionary UnionInstance (Just [e]) =
-              -- We need the subgoal dictionary to appear in the term somewhere
-              return $ App (Abs (VarBinder (Ident C.__unused)) valUndefined) e
-            mkDictionary UnionInstance _ = return valUndefined
-            mkDictionary ConsInstance _ = return valUndefined
-            mkDictionary RowToListInstance _ = return valUndefined
-            mkDictionary (WarnInstance msg) _ = do
+            mkDictionary (NamedInstance n) args = return $ foldl App (Var nullSourceSpan n) (fold args)
+            mkDictionary EmptyClassInstance args = return (useEmptyDict args)
+            mkDictionary (WarnInstance msg) args = do
               tell . errorMessage $ UserDefinedWarning msg
               -- We cannot call the type class constructor here because Warn is declared in Prim.
               -- This means that it doesn't have a definition that we can import.
               -- So pass an empty placeholder (undefined) instead.
-              return valUndefined
+              return (useEmptyDict args)
             mkDictionary (IsSymbolInstance sym) _ =
-              let fields = [ ("reflectSymbol", Abs (VarBinder (Ident C.__unused)) (Literal (StringLiteral sym))) ] in
-              return $ TypeClassDictionaryConstructorApp C.IsSymbol (Literal (ObjectLiteral fields))
-            mkDictionary CompareSymbolInstance _ =
-              return $ TypeClassDictionaryConstructorApp C.CompareSymbol (Literal (ObjectLiteral []))
-            mkDictionary AppendSymbolInstance _ =
-              return $ TypeClassDictionaryConstructorApp C.AppendSymbol (Literal (ObjectLiteral []))
+              let fields = [ ("reflectSymbol", Abs (VarBinder nullSourceSpan UnusedIdent) (Literal nullSourceSpan (StringLiteral sym))) ] in
+              return $ TypeClassDictionaryConstructorApp C.IsSymbol (Literal nullSourceSpan (ObjectLiteral fields))
 
         -- Turn a DictionaryValue into a Expr
         subclassDictionaryValue :: Expr -> Qualified (ProperName 'ClassName) -> Integer -> Expr
         subclassDictionaryValue dict className index =
           App (Accessor (mkString (superclassName className index)) dict) valUndefined
 
+    solveIsSymbol :: [Type] -> Maybe [TypeClassDict]
+    solveIsSymbol [TypeLevelString sym] = Just [TypeClassDictionaryInScope [] 0 (IsSymbolInstance sym) [] C.IsSymbol [TypeLevelString sym] Nothing]
+    solveIsSymbol _ = Nothing
+
+    solveSymbolCompare :: [Type] -> Maybe [TypeClassDict]
+    solveSymbolCompare [arg0@(TypeLevelString lhs), arg1@(TypeLevelString rhs), _] =
+      let ordering = case compare lhs rhs of
+                  LT -> C.orderingLT
+                  EQ -> C.orderingEQ
+                  GT -> C.orderingGT
+          args' = [arg0, arg1, TypeConstructor ordering]
+      in Just [TypeClassDictionaryInScope [] 0 EmptyClassInstance [] C.SymbolCompare args' Nothing]
+    solveSymbolCompare _ = Nothing
+
+    solveSymbolAppend :: [Type] -> Maybe [TypeClassDict]
+    solveSymbolAppend [arg0, arg1, arg2] = do
+      (arg0', arg1', arg2') <- appendSymbols arg0 arg1 arg2
+      let args' = [arg0', arg1', arg2']
+      pure [TypeClassDictionaryInScope [] 0 EmptyClassInstance [] C.SymbolAppend args' Nothing]
+    solveSymbolAppend _ = Nothing
+
+    -- | Append type level symbols, or, run backwards, strip a prefix or suffix
+    appendSymbols :: Type -> Type -> Type -> Maybe (Type, Type, Type)
+    appendSymbols arg0@(TypeLevelString lhs) arg1@(TypeLevelString rhs) _ = Just (arg0, arg1, TypeLevelString (lhs <> rhs))
+    appendSymbols arg0@(TypeLevelString lhs) _ arg2@(TypeLevelString out) = do
+      lhs' <- decodeString lhs
+      out' <- decodeString out
+      rhs <- stripPrefix lhs' out'
+      pure (arg0, TypeLevelString (mkString rhs), arg2)
+    appendSymbols _ arg1@(TypeLevelString rhs) arg2@(TypeLevelString out) = do
+      rhs' <- decodeString rhs
+      out' <- decodeString out
+      lhs <- stripSuffix rhs' out'
+      pure (TypeLevelString (mkString lhs), arg1, arg2)
+    appendSymbols _ _ _ = Nothing
+
+    solveSymbolCons :: [Type] -> Maybe [TypeClassDict]
+    solveSymbolCons [arg0, arg1, arg2] = do
+      (arg0', arg1', arg2') <- consSymbol arg0 arg1 arg2
+      let args' = [arg0', arg1', arg2']
+      pure [TypeClassDictionaryInScope [] 0 EmptyClassInstance [] C.SymbolCons args' Nothing]
+    solveSymbolCons _ = Nothing
+
+    consSymbol :: Type -> Type -> Type -> Maybe (Type, Type, Type)
+    consSymbol _ _ arg@(TypeLevelString s) = do
+      (h, t) <- T.uncons =<< decodeString s
+      pure (mkTLString (T.singleton h), mkTLString t, arg)
+      where mkTLString = TypeLevelString . mkString
+    consSymbol arg1@(TypeLevelString h) arg2@(TypeLevelString t) _ = do
+      h' <- decodeString h
+      t' <- decodeString t
+      guard (T.length h' == 1)
+      pure (arg1, arg2, TypeLevelString (mkString $ h' <> t'))
+    consSymbol _ _ _ = Nothing
+
+    solveUnion :: [Type] -> Maybe [TypeClassDict]
+    solveUnion [l, r, u] = do
+      (lOut, rOut, uOut, cst) <- unionRows l r u
+      pure [ TypeClassDictionaryInScope [] 0 EmptyClassInstance [] C.RowUnion [lOut, rOut, uOut] cst ]
+    solveUnion _ = Nothing
+
     -- | Left biased union of two row types
     unionRows :: Type -> Type -> Type -> Maybe (Type, Type, Type, Maybe [Constraint])
     unionRows l r _ =
@@ -373,11 +439,22 @@
             -- Otherwise, the left hand tail might contain the same labels as on
             -- the right hand side, and we can't be certain we won't reorder the
             -- types for such labels.
-            _ -> (not (null fixed), (fixed, rowVar), Just [ Constraint C.Union [rest, r, rowVar] Nothing ])
+            _ -> (not (null fixed), (fixed, rowVar), Just [ Constraint C.RowUnion [rest, r, rowVar] Nothing ])
 
+    solveRowCons :: [Type] -> Maybe [TypeClassDict]
+    solveRowCons [TypeLevelString sym, ty, r, _] =
+      Just [ TypeClassDictionaryInScope [] 0 EmptyClassInstance [] C.RowCons [TypeLevelString sym, ty, r, RCons (Label sym) ty r] Nothing ]
+    solveRowCons _ = Nothing
+
+    solveRowToList :: [Type] -> Maybe [TypeClassDict]
+    solveRowToList [r, _] = do
+      entries <- rowToRowList r
+      pure [ TypeClassDictionaryInScope [] 0 EmptyClassInstance [] C.RowToList [r, entries] Nothing ]
+    solveRowToList _ = Nothing
+
     -- | Convert a closed row to a sorted list of entries
-    solveRowToList :: Type -> Maybe Type
-    solveRowToList r =
+    rowToRowList :: Type -> Maybe Type
+    rowToRowList r =
         guard (REmpty == rest) $>
         foldr rowListCons (TypeConstructor C.RowListNil) fixed
       where
@@ -387,26 +464,59 @@
                                      , ty
                                      , tl ]
 
+    solveNub :: [Type] -> Maybe [TypeClassDict]
+    solveNub [r, _] = do
+      r' <- nubRows r
+      pure [ TypeClassDictionaryInScope [] 0 EmptyClassInstance [] C.RowNub [r, r'] Nothing ]
+    solveNub _ = Nothing
+
+    nubRows :: Type -> Maybe Type
+    nubRows r =
+        guard (REmpty == rest) $>
+        rowFromList (nubBy ((==) `on` fst) fixed, rest)
+      where
+        (fixed, rest) = rowToSortedList r
+
+    solveLacks :: [Type] -> Maybe [TypeClassDict]
+    solveLacks [TypeLevelString sym, r] = do
+      (r', cst) <- rowLacks sym r
+      pure [ TypeClassDictionaryInScope [] 0 EmptyClassInstance [] C.RowLacks [TypeLevelString sym, r'] cst ]
+    solveLacks _ = Nothing
+
+    rowLacks :: PSString -> Type -> Maybe (Type, Maybe [Constraint])
+    rowLacks sym r =
+        guard (lacksSym && canMakeProgress) $> (r, cst)
+      where
+        (fixed, rest) = rowToList r
+
+        lacksSym =
+          not $ sym `elem` (runLabel . fst <$> fixed)
+
+        (canMakeProgress, cst) = case rest of
+            REmpty -> (True, Nothing)
+            _ -> (not (null fixed), Just [ Constraint C.RowLacks [TypeLevelString sym, rest] Nothing ])
+
 -- Check if an instance matches our list of types, allowing for types
 -- to be solved via functional dependencies. If the types match, we return a
 -- substitution which makes them match. If not, we return 'Nothing'.
-matches :: [FunctionalDependency] -> TypeClassDict -> [Type] -> Maybe (Matching [Type])
-matches deps TypeClassDictionaryInScope{..} tys = do
+matches :: [FunctionalDependency] -> TypeClassDict -> [Type] -> Matched (Matching [Type])
+matches deps TypeClassDictionaryInScope{..} tys =
     -- First, find those types which match exactly
-    let matched = zipWith typeHeadsAreEqual tys tcdInstanceTypes
+    let matched = zipWith typeHeadsAreEqual tys tcdInstanceTypes in
     -- Now, use any functional dependencies to infer any remaining types
-    guard $ covers matched
-    -- Verify that any repeated type variables are unifiable
-    let determinedSet = foldMap (S.fromList . fdDetermined) deps
-        solved = map snd . filter ((`S.notMember` determinedSet) . fst) $ zipWith (\(_, ts) i -> (i, ts)) matched [0..]
-    verifySubstitution (M.unionsWith (++) solved)
+    if not (covers matched)
+       then if any ((==) Apart . fst) matched then Apart else Unknown
+       else -- Verify that any repeated type variables are unifiable
+            let determinedSet = foldMap (S.fromList . fdDetermined) deps
+                solved = map snd . filter ((`S.notMember` determinedSet) . fst) $ zipWith (\(_, ts) i -> (i, ts)) matched [0..]
+            in verifySubstitution (M.unionsWith (++) solved)
   where
     -- | Find the closure of a set of functional dependencies.
-    covers :: [(Bool, subst)] -> Bool
+    covers :: [(Matched (), subst)] -> Bool
     covers ms = finalSet == S.fromList [0..length ms - 1]
       where
         initialSet :: S.Set Int
-        initialSet = S.fromList . map snd . filter (fst . fst) $ zip ms [0..]
+        initialSet = S.fromList . map snd . filter ((==) (Match ()) . fst . fst) $ zip ms [0..]
 
         finalSet :: S.Set Int
         finalSet = untilFixedPoint applyAll initialSet
@@ -430,68 +540,74 @@
     -- Check whether the type heads of two types are equal (for the purposes of type class dictionary lookup),
     -- and return a substitution from type variables to types which makes the type heads unify.
     --
-    typeHeadsAreEqual :: Type -> Type -> (Bool, Matching [Type])
+    typeHeadsAreEqual :: Type -> Type -> (Matched (), Matching [Type])
     typeHeadsAreEqual (KindedType t1 _)    t2                              = typeHeadsAreEqual t1 t2
     typeHeadsAreEqual t1                   (KindedType t2 _)               = typeHeadsAreEqual t1 t2
-    typeHeadsAreEqual (TUnknown u1)        (TUnknown u2)        | u1 == u2 = (True, M.empty)
-    typeHeadsAreEqual (Skolem _ s1 _ _)    (Skolem _ s2 _ _)    | s1 == s2 = (True, M.empty)
-    typeHeadsAreEqual t                    (TypeVar v)                     = (True, M.singleton v [t])
-    typeHeadsAreEqual (TypeConstructor c1) (TypeConstructor c2) | c1 == c2 = (True, M.empty)
-    typeHeadsAreEqual (TypeLevelString s1) (TypeLevelString s2) | s1 == s2 = (True, M.empty)
+    typeHeadsAreEqual (TUnknown u1)        (TUnknown u2)        | u1 == u2 = (Match (), M.empty)
+    typeHeadsAreEqual (Skolem _ s1 _ _)    (Skolem _ s2 _ _)    | s1 == s2 = (Match (), M.empty)
+    typeHeadsAreEqual t                    (TypeVar v)                     = (Match (), M.singleton v [t])
+    typeHeadsAreEqual (TypeConstructor c1) (TypeConstructor c2) | c1 == c2 = (Match (), M.empty)
+    typeHeadsAreEqual (TypeLevelString s1) (TypeLevelString s2) | s1 == s2 = (Match (), M.empty)
     typeHeadsAreEqual (TypeApp h1 t1)      (TypeApp h2 t2)                 =
       both (typeHeadsAreEqual h1 h2) (typeHeadsAreEqual t1 t2)
-    typeHeadsAreEqual REmpty REmpty = (True, M.empty)
+    typeHeadsAreEqual REmpty REmpty = (Match (), M.empty)
     typeHeadsAreEqual r1@RCons{} r2@RCons{} =
         foldr both (uncurry go rest) common
       where
         (common, rest) = alignRowsWith typeHeadsAreEqual r1 r2
 
-        go :: ([(Label, Type)], Type) -> ([(Label, Type)], Type) -> (Bool, Matching [Type])
+        go :: ([(Label, Type)], Type) -> ([(Label, Type)], Type) -> (Matched (), Matching [Type])
         go (l,  KindedType t1 _)  (r,  t2)                            = go (l, t1) (r, t2)
         go (l,  t1)               (r,  KindedType t2 _)               = go (l, t1) (r, t2)
-        go ([], REmpty)           ([], REmpty)                        = (True, M.empty)
-        go ([], TUnknown u1)      ([], TUnknown u2)      | u1 == u2   = (True, M.empty)
-        go ([], TypeVar v1)       ([], TypeVar v2)       | v1 == v2   = (True, M.empty)
-        go ([], Skolem _ sk1 _ _) ([], Skolem _ sk2 _ _) | sk1 == sk2 = (True, M.empty)
-        go (sd, r)                ([], TypeVar v)                     = (True, M.singleton v [rowFromList (sd, r)])
-        go _ _                                                        = (False, M.empty)
-    typeHeadsAreEqual _ _ = (False, M.empty)
+        go ([], REmpty)           ([], REmpty)                        = (Match (), M.empty)
+        go ([], TUnknown u1)      ([], TUnknown u2)      | u1 == u2   = (Match (), M.empty)
+        go ([], TypeVar v1)       ([], TypeVar v2)       | v1 == v2   = (Match (), M.empty)
+        go ([], Skolem _ sk1 _ _) ([], Skolem _ sk2 _ _) | sk1 == sk2 = (Match (), M.empty)
+        go ([], TUnknown _)       _                                   = (Unknown, M.empty)
+        go (sd, r)                ([], TypeVar v)                     = (Match (), M.singleton v [rowFromList (sd, r)])
+        go _ _                                                        = (Apart, M.empty)
+    typeHeadsAreEqual (TUnknown _) _ = (Unknown, M.empty)
+    typeHeadsAreEqual _ _ = (Apart, M.empty)
 
-    both :: (Bool, Matching [Type]) -> (Bool, Matching [Type]) -> (Bool, Matching [Type])
-    both (b1, m1) (b2, m2) = (b1 && b2, M.unionWith (++) m1 m2)
 
+    both :: (Matched (), Matching [Type]) -> (Matched (), Matching [Type]) -> (Matched (), Matching [Type])
+    both (b1, m1) (b2, m2) = (b1 <> b2, M.unionWith (++) m1 m2)
+
     -- Ensure that a substitution is valid
-    verifySubstitution :: Matching [Type] -> Maybe (Matching [Type])
-    verifySubstitution = traverse meet where
-      meet ts | pairwiseAll typesAreEqual ts = Just ts
-              | otherwise = Nothing
+    verifySubstitution :: Matching [Type] -> Matched (Matching [Type])
+    verifySubstitution mts = foldMap meet mts $> mts where
+      meet = pairwiseAll typesAreEqual
 
       -- Note that unknowns are only allowed to unify if they came from a type
       -- which was _not_ solved, i.e. one which was inferred by a functional
       -- dependency.
-      typesAreEqual :: Type -> Type -> Bool
+      typesAreEqual :: Type -> Type -> Matched ()
       typesAreEqual (KindedType t1 _)    t2                   = typesAreEqual t1 t2
       typesAreEqual t1                   (KindedType t2 _)    = typesAreEqual t1 t2
-      typesAreEqual (TUnknown u1)        (TUnknown u2)        | u1 == u2 = True
-      typesAreEqual (Skolem _ s1 _ _)    (Skolem _ s2 _ _)    = s1 == s2
-      typesAreEqual (TypeVar v1)         (TypeVar v2)         = v1 == v2
-      typesAreEqual (TypeLevelString s1) (TypeLevelString s2) = s1 == s2
-      typesAreEqual (TypeConstructor c1) (TypeConstructor c2) = c1 == c2
-      typesAreEqual (TypeApp h1 t1)      (TypeApp h2 t2)      = typesAreEqual h1 h2 && typesAreEqual t1 t2
-      typesAreEqual REmpty               REmpty               = True
+      typesAreEqual (TUnknown u1)        (TUnknown u2)        | u1 == u2 = Match ()
+      typesAreEqual (Skolem _ s1 _ _)    (Skolem _ s2 _ _)    | s1 == s2 = Match ()
+      typesAreEqual (Skolem _ _ _ _)     _                    = Unknown
+      typesAreEqual _                    (Skolem _ _ _ _)     = Unknown
+      typesAreEqual (TypeVar v1)         (TypeVar v2)         | v1 == v2 = Match ()
+      typesAreEqual (TypeLevelString s1) (TypeLevelString s2) | s1 == s2 = Match ()
+      typesAreEqual (TypeConstructor c1) (TypeConstructor c2) | c1 == c2 = Match ()
+      typesAreEqual (TypeApp h1 t1)      (TypeApp h2 t2)      = typesAreEqual h1 h2 <> typesAreEqual t1 t2
+      typesAreEqual REmpty               REmpty               = Match ()
       typesAreEqual r1                   r2                   | isRCons r1 || isRCons r2 =
           let (common, rest) = alignRowsWith typesAreEqual r1 r2
-          in and common && uncurry go rest
+          in fold common <> uncurry go rest
         where
-          go :: ([(Label, Type)], Type) -> ([(Label, Type)], Type) -> Bool
+          go :: ([(Label, Type)], Type) -> ([(Label, Type)], Type) -> Matched ()
           go (l, KindedType t1 _)  (r, t2)                          = go (l, t1) (r, t2)
           go (l, t1)               (r, KindedType t2 _)             = go (l, t1) (r, t2)
-          go ([], TUnknown u1)     ([], TUnknown u2)     | u1 == u2 = True
-          go ([], Skolem _ s1 _ _) ([], Skolem _ s2 _ _)            = s1 == s2
-          go ([], REmpty)          ([], REmpty)                     = True
-          go ([], TypeVar v1)      ([], TypeVar v2)                 = v1 == v2
-          go _  _                                                   = False
-      typesAreEqual _ _                                             = False
+          go ([], TUnknown u1)     ([], TUnknown u2)     | u1 == u2 = Match ()
+          go ([], Skolem _ s1 _ _) ([], Skolem _ s2 _ _) | s1 == s2 = Match ()
+          go ([], Skolem _ _ _ _)  _                                = Unknown
+          go _                     ([], Skolem _ _ _ _)             = Unknown
+          go ([], REmpty)          ([], REmpty)                     = Match ()
+          go ([], TypeVar v1)      ([], TypeVar v2)      | v1 == v2 = Match ()
+          go _  _                                                   = Apart
+      typesAreEqual _                    _                    = Apart
 
       isRCons :: Type -> Bool
       isRCons RCons{}    = True
@@ -513,7 +629,7 @@
                                                       name
                                                       (Constraint supName (instantiateSuperclass (map fst typeClassArguments) supArgs instanceTy) Nothing)
                                   ) typeClassSuperclasses [0..]
-    return (TypeClassDictionaryInScope name path className instanceTy Nothing : supDicts)
+    return (TypeClassDictionaryInScope [] 0 name path className instanceTy Nothing : supDicts)
   where
     instantiateSuperclass :: [Text] -> [Type] -> [Type] -> [Type]
     instantiateSuperclass args supArgs tys = map (replaceAllTypeVars (zip args tys)) supArgs
@@ -523,10 +639,10 @@
   fromDict d = M.singleton Nothing (M.singleton (tcdClassName d) (M.singleton (tcdValue d) d))
 
 -- | Check all pairs of values in a list match a predicate
-pairwiseAll :: (a -> a -> Bool) -> [a] -> Bool
-pairwiseAll _ [] = True
-pairwiseAll _ [_] = True
-pairwiseAll p (x : xs) = all (p x) xs && pairwiseAll p xs
+pairwiseAll :: Monoid m => (a -> a -> m) -> [a] -> m
+pairwiseAll _ [] = mempty
+pairwiseAll _ [_] = mempty
+pairwiseAll p (x : xs) = foldMap (p x) xs <> pairwiseAll p xs
 
 -- | Check any pair of values in a list match a predicate
 pairwiseAny :: (a -> a -> Bool) -> [a] -> Bool
diff --git a/src/Language/PureScript/TypeChecker/Monad.hs b/src/Language/PureScript/TypeChecker/Monad.hs
--- a/src/Language/PureScript/TypeChecker/Monad.hs
+++ b/src/Language/PureScript/TypeChecker/Monad.hs
@@ -127,7 +127,7 @@
   => SourceSpan
   -> m a
   -> m a
-rethrowWithPositionTC pos = withErrorMessageHint (PositionedError pos)
+rethrowWithPositionTC pos = withErrorMessageHint (positionedError pos)
 
 warnAndRethrowWithPositionTC
   :: (MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
@@ -162,6 +162,14 @@
   => Maybe ModuleName
   -> m (M.Map (Qualified (ProperName 'ClassName)) (M.Map (Qualified Ident) NamedDict))
 lookupTypeClassDictionaries mn = fromMaybe M.empty . M.lookup mn . typeClassDictionaries . checkEnv <$> get
+
+-- | Lookup type class dictionaries in a module.
+lookupTypeClassDictionariesForClass
+  :: (MonadState CheckState m)
+  => Maybe ModuleName
+  -> Qualified (ProperName 'ClassName)
+  -> m (M.Map (Qualified Ident) NamedDict)
+lookupTypeClassDictionariesForClass mn cn = fromMaybe M.empty . M.lookup cn <$> lookupTypeClassDictionaries mn
 
 -- | Temporarily bind a collection of names to local variables
 bindLocalVariables
diff --git a/src/Language/PureScript/TypeChecker/Skolems.hs b/src/Language/PureScript/TypeChecker/Skolems.hs
--- a/src/Language/PureScript/TypeChecker/Skolems.hs
+++ b/src/Language/PureScript/TypeChecker/Skolems.hs
@@ -100,7 +100,7 @@
     go (scopes, _) (PositionedValue ss _ _) = ((scopes, Just ss), [])
     go (scopes, ssUsed) val@(TypedValue _ _ ty) =
         ( (allScopes, ssUsed)
-        , [ ErrorMessage (maybe id ((:) . PositionedError) ssUsed [ ErrorInExpression val ]) $
+        , [ ErrorMessage (maybe id ((:) . positionedError) ssUsed [ ErrorInExpression val ]) $
               EscapedSkolem name ssBound ty
           | (name, scope, ssBound) <- collectSkolems ty
           , notMember scope allScopes
diff --git a/src/Language/PureScript/TypeChecker/TypeSearch.hs b/src/Language/PureScript/TypeChecker/TypeSearch.hs
--- a/src/Language/PureScript/TypeChecker/TypeSearch.hs
+++ b/src/Language/PureScript/TypeChecker/TypeSearch.hs
@@ -59,7 +59,7 @@
   userT' <- initializeSkolems userT
   envT' <- initializeSkolems envT
 
-  let dummyExpression = P.Var (P.Qualified Nothing (P.Ident "x"))
+  let dummyExpression = P.Var nullSourceSpan (P.Qualified Nothing (P.Ident "x"))
 
   elab <- subsumes envT' userT'
   subst <- gets TC.checkSubstitution
diff --git a/src/Language/PureScript/TypeChecker/Types.hs b/src/Language/PureScript/TypeChecker/Types.hs
--- a/src/Language/PureScript/TypeChecker/Types.hs
+++ b/src/Language/PureScript/TypeChecker/Types.hs
@@ -122,7 +122,7 @@
 
       -- Check skolem variables did not escape their scope
       skolemEscapeCheck val'
-      return ((sai, (foldr (Abs . VarBinder . (\(x, _, _) -> x)) val' unsolved, generalized)), unsolved)
+      return ((sai, (foldr (Abs . VarBinder nullSourceSpan . (\(x, _, _) -> x)) val' unsolved, generalized)), unsolved)
 
     -- Show warnings here, since types in wildcards might have been solved during
     -- instance resolution (by functional dependencies).
@@ -305,20 +305,20 @@
    . (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
   => Expr
   -> m Expr
-infer' v@(Literal (NumericLiteral (Left _))) = return $ TypedValue True v tyInt
-infer' v@(Literal (NumericLiteral (Right _))) = return $ TypedValue True v tyNumber
-infer' v@(Literal (StringLiteral _)) = return $ TypedValue True v tyString
-infer' v@(Literal (CharLiteral _)) = return $ TypedValue True v tyChar
-infer' v@(Literal (BooleanLiteral _)) = return $ TypedValue True v tyBoolean
-infer' (Literal (ArrayLiteral vals)) = do
+infer' v@(Literal _ (NumericLiteral (Left _))) = return $ TypedValue True v tyInt
+infer' v@(Literal _ (NumericLiteral (Right _))) = return $ TypedValue True v tyNumber
+infer' v@(Literal _ (StringLiteral _)) = return $ TypedValue True v tyString
+infer' v@(Literal _ (CharLiteral _)) = return $ TypedValue True v tyChar
+infer' v@(Literal _ (BooleanLiteral _)) = return $ TypedValue True v tyBoolean
+infer' (Literal ss (ArrayLiteral vals)) = do
   ts <- traverse infer vals
   els <- freshType
   ts' <- forM ts $ \(TypedValue ch val t) -> do
     (val', t') <- instantiatePolyTypeWithUnknowns val t
     unifyTypes els t'
     return (TypedValue ch val' t')
-  return $ TypedValue True (Literal (ArrayLiteral ts')) (TypeApp tyArray els)
-infer' (Literal (ObjectLiteral ps)) = do
+  return $ TypedValue True (Literal ss (ArrayLiteral ts')) (TypeApp tyArray els)
+infer' (Literal ss (ObjectLiteral ps)) = do
   ensureNoDuplicateProperties ps
   -- We make a special case for Vars in record labels, since these are the
   -- only types of expressions for which 'infer' can return a polymorphic type.
@@ -337,7 +337,7 @@
         pure (name, valAndType)
   fields <- forM ps inferProperty
   let ty = TypeApp tyRecord $ rowFromList (map (Label *** snd) fields, REmpty)
-  return $ TypedValue True (Literal (ObjectLiteral (map (fmap (uncurry (TypedValue True))) fields))) ty
+  return $ TypedValue True (Literal ss (ObjectLiteral (map (fmap (uncurry (TypedValue True))) fields))) ty
 infer' (ObjectUpdate o ps) = do
   ensureNoDuplicateProperties ps
   row <- freshType
@@ -353,27 +353,27 @@
   typed <- check val (TypeApp tyRecord (RCons (Label prop) field rest))
   return $ TypedValue True (Accessor prop typed) field
 infer' (Abs binder ret)
-  | VarBinder arg <- binder = do
+  | VarBinder ss arg <- binder = do
       ty <- freshType
       withBindingGroupVisible $ bindLocalVariables [(arg, ty, Defined)] $ do
         body@(TypedValue _ _ bodyTy) <- infer' ret
         (body', bodyTy') <- instantiatePolyTypeWithUnknowns body bodyTy
-        return $ TypedValue True (Abs (VarBinder arg) body') (function ty bodyTy')
+        return $ TypedValue True (Abs (VarBinder ss arg) body') (function ty bodyTy')
   | otherwise = internalError "Binder was not desugared"
 infer' (App f arg) = do
   f'@(TypedValue _ _ ft) <- infer f
   (ret, app) <- checkFunctionApplication f' ft arg
   return $ TypedValue True app ret
-infer' (Var var) = do
+infer' (Var ss var) = do
   checkVisibility var
   ty <- introduceSkolemScope <=< replaceAllTypeSynonyms <=< replaceTypeWildcards <=< lookupVariable $ var
   case ty of
     ConstrainedType con ty' -> do
       dicts <- getTypeClassDictionaries
       hints <- getHints
-      return $ TypedValue True (App (Var var) (TypeClassDictionary con dicts hints)) ty'
-    _ -> return $ TypedValue True (Var var) ty
-infer' v@(Constructor c) = do
+      return $ TypedValue True (App (Var ss var) (TypeClassDictionary con dicts hints)) ty'
+    _ -> return $ TypedValue True (Var ss var) ty
+infer' v@(Constructor _ c) = do
   env <- getEnv
   case M.lookup c (dataConstructors env) of
     Nothing -> throwError . errorMessage . UnknownName . fmap DctorName $ c
@@ -392,9 +392,9 @@
   (el'', elTy') <- instantiatePolyTypeWithUnknowns el' elTy
   unifyTypes thTy' elTy'
   return $ TypedValue True (IfThenElse cond' th'' el'') thTy'
-infer' (Let ds val) = do
+infer' (Let w ds val) = do
   (ds', val'@(TypedValue _ _ valTy)) <- inferLetBinding [] ds val infer
-  return $ TypedValue True (Let ds' val') valTy
+  return $ TypedValue True (Let w ds' val') valTy
 infer' (DeferredDictionary className tys) = do
   dicts <- getTypeClassDictionaries
   hints <- getHints
@@ -435,7 +435,7 @@
     let dict = M.singleton (Qualified Nothing ident) (ty, nameKind, Undefined)
     ty' <- introduceSkolemScope <=< replaceAllTypeSynonyms <=< replaceTypeWildcards $ ty
     TypedValue _ val' ty'' <- if checkType then withScopedTypeVars moduleName args (bindNames dict (check val ty')) else return tv
-    bindNames (M.singleton (Qualified Nothing ident) (ty'', nameKind, Defined)) 
+    bindNames (M.singleton (Qualified Nothing ident) (ty'', nameKind, Defined))
       $ inferLetBinding (seen ++ [ValueDecl sa ident nameKind [] [MkUnguarded (TypedValue checkType val' ty'')]]) rest ret j
 inferLetBinding seen (ValueDecl sa@(ss, _) ident nameKind [] [MkUnguarded val] : rest) ret j =
   warnAndRethrowWithPositionTC ss $ do
@@ -443,7 +443,7 @@
     let dict = M.singleton (Qualified Nothing ident) (valTy, nameKind, Undefined)
     TypedValue _ val' valTy' <- bindNames dict $ infer val
     unifyTypes valTy valTy'
-    bindNames (M.singleton (Qualified Nothing ident) (valTy', nameKind, Defined)) 
+    bindNames (M.singleton (Qualified Nothing ident) (valTy', nameKind, Defined))
       $ inferLetBinding (seen ++ [ValueDecl sa ident nameKind [] [MkUnguarded val']]) rest ret j
 inferLetBinding seen (BindingGroupDeclaration ds : rest) ret j = do
   Just moduleName <- checkCurrentModule <$> get
@@ -464,30 +464,32 @@
   -> Binder
   -> m (M.Map Ident Type)
 inferBinder _ NullBinder = return M.empty
-inferBinder val (LiteralBinder (StringLiteral _)) = unifyTypes val tyString >> return M.empty
-inferBinder val (LiteralBinder (CharLiteral _)) = unifyTypes val tyChar >> return M.empty
-inferBinder val (LiteralBinder (NumericLiteral (Left _))) = unifyTypes val tyInt >> return M.empty
-inferBinder val (LiteralBinder (NumericLiteral (Right _))) = unifyTypes val tyNumber >> return M.empty
-inferBinder val (LiteralBinder (BooleanLiteral _)) = unifyTypes val tyBoolean >> return M.empty
-inferBinder val (VarBinder name) = return $ M.singleton name val
-inferBinder val (ConstructorBinder ctor binders) = do
+inferBinder val (LiteralBinder _ (StringLiteral _)) = unifyTypes val tyString >> return M.empty
+inferBinder val (LiteralBinder _ (CharLiteral _)) = unifyTypes val tyChar >> return M.empty
+inferBinder val (LiteralBinder _ (NumericLiteral (Left _))) = unifyTypes val tyInt >> return M.empty
+inferBinder val (LiteralBinder _ (NumericLiteral (Right _))) = unifyTypes val tyNumber >> return M.empty
+inferBinder val (LiteralBinder _ (BooleanLiteral _)) = unifyTypes val tyBoolean >> return M.empty
+inferBinder val (VarBinder _ name) = return $ M.singleton name val
+inferBinder val (ConstructorBinder ss ctor binders) = do
   env <- getEnv
   case M.lookup ctor (dataConstructors env) of
     Just (_, _, ty, _) -> do
       (_, fn) <- instantiatePolyTypeWithUnknowns (internalError "Data constructor types cannot contain constraints") ty
       fn' <- introduceSkolemScope <=< replaceAllTypeSynonyms $ fn
       let (args, ret) = peelArgs fn'
-      unless (length args == length binders) . throwError . errorMessage $ IncorrectConstructorArity ctor
+          expected = length args
+          actual = length binders
+      unless (expected == actual) . throwError . errorMessage' ss $ IncorrectConstructorArity ctor expected actual
       unifyTypes ret val
       M.unions <$> zipWithM inferBinder (reverse args) binders
-    _ -> throwError . errorMessage . UnknownName . fmap DctorName $ ctor
+    _ -> throwError . errorMessage' ss . UnknownName . fmap DctorName $ ctor
   where
   peelArgs :: Type -> ([Type], Type)
   peelArgs = go []
     where
     go args (TypeApp (TypeApp fn arg) ret) | fn == tyFunction = go (arg : args) ret
     go args ret = (args, ret)
-inferBinder val (LiteralBinder (ObjectLiteral props)) = do
+inferBinder val (LiteralBinder _ (ObjectLiteral props)) = do
   row <- freshType
   rest <- freshType
   m1 <- inferRowProperties row rest props
@@ -501,14 +503,15 @@
     m1 <- inferBinder propTy binder
     m2 <- inferRowProperties nrow (RCons (Label name) propTy row) binders
     return $ m1 `M.union` m2
-inferBinder val (LiteralBinder (ArrayLiteral binders)) = do
+inferBinder val (LiteralBinder _ (ArrayLiteral binders)) = do
   el <- freshType
   m1 <- M.unions <$> traverse (inferBinder el) binders
   unifyTypes val (TypeApp tyArray el)
   return m1
-inferBinder val (NamedBinder name binder) = do
-  m <- inferBinder val binder
-  return $ M.insert name val m
+inferBinder val (NamedBinder ss name binder) =
+  warnAndRethrowWithPositionTC ss $ do
+    m <- inferBinder val binder
+    return $ M.insert name val m
 inferBinder val (PositionedBinder pos _ binder) =
   warnAndRethrowWithPositionTC pos $ inferBinder val binder
 inferBinder val (TypedBinder ty binder) = do
@@ -528,8 +531,8 @@
 -- | If this is the case, we need to instantiate any polymorphic types before checking binders.
 binderRequiresMonotype :: Binder -> Bool
 binderRequiresMonotype NullBinder = False
-binderRequiresMonotype (VarBinder _) = False
-binderRequiresMonotype (NamedBinder _ b) = binderRequiresMonotype b
+binderRequiresMonotype (VarBinder _ _) = False
+binderRequiresMonotype (NamedBinder _ _ b) = binderRequiresMonotype b
 binderRequiresMonotype (PositionedBinder _ _ b) = binderRequiresMonotype b
 binderRequiresMonotype (TypedBinder ty b) = isMonoType ty || binderRequiresMonotype b
 binderRequiresMonotype _ = True
@@ -622,39 +625,39 @@
   dictName <- freshIdent ("dict" <> className)
   dicts <- newDictionaries [] (Qualified Nothing dictName) con
   val' <- withBindingGroupVisible $ withTypeClassDictionaries dicts $ check val ty
-  return $ TypedValue True (Abs (VarBinder dictName) val') t
+  return $ TypedValue True (Abs (VarBinder nullSourceSpan dictName) val') t
 check' val u@(TUnknown _) = do
   val'@(TypedValue _ _ ty) <- infer val
   -- Don't unify an unknown with an inferred polytype
   (val'', ty') <- instantiatePolyTypeWithUnknowns val' ty
   unifyTypes ty' u
   return $ TypedValue True val'' ty'
-check' v@(Literal (NumericLiteral (Left _))) t | t == tyInt =
+check' v@(Literal _ (NumericLiteral (Left _))) t | t == tyInt =
   return $ TypedValue True v t
-check' v@(Literal (NumericLiteral (Right _))) t | t == tyNumber =
+check' v@(Literal _ (NumericLiteral (Right _))) t | t == tyNumber =
   return $ TypedValue True v t
-check' v@(Literal (StringLiteral _)) t | t == tyString =
+check' v@(Literal _ (StringLiteral _)) t | t == tyString =
   return $ TypedValue True v t
-check' v@(Literal (CharLiteral _)) t | t == tyChar =
+check' v@(Literal _ (CharLiteral _)) t | t == tyChar =
   return $ TypedValue True v t
-check' v@(Literal (BooleanLiteral _)) t | t == tyBoolean =
+check' v@(Literal _ (BooleanLiteral _)) t | t == tyBoolean =
   return $ TypedValue True v t
-check' (Literal (ArrayLiteral vals)) t@(TypeApp a ty) = do
+check' (Literal ss (ArrayLiteral vals)) t@(TypeApp a ty) = do
   unifyTypes a tyArray
-  array <- Literal . ArrayLiteral <$> forM vals (`check` ty)
+  array <- Literal ss . ArrayLiteral <$> forM vals (`check` ty)
   return $ TypedValue True array t
 check' (Abs binder ret) ty@(TypeApp (TypeApp t argTy) retTy)
-  | VarBinder arg <- binder = do
+  | VarBinder ss arg <- binder = do
       unifyTypes t tyFunction
       ret' <- withBindingGroupVisible $ bindLocalVariables [(arg, argTy, Defined)] $ check ret retTy
-      return $ TypedValue True (Abs (VarBinder arg) ret') ty
+      return $ TypedValue True (Abs (VarBinder ss arg) ret') ty
   | otherwise = internalError "Binder was not desugared"
 check' (App f arg) ret = do
   f'@(TypedValue _ _ ft) <- infer f
   (retTy, app) <- checkFunctionApplication f' ft arg
   elaborate <- subsumes retTy ret
   return $ TypedValue True (elaborate app) ret
-check' v@(Var var) ty = do
+check' v@(Var _ var) ty = do
   checkVisibility var
   repl <- introduceSkolemScope <=< replaceAllTypeSynonyms <=< lookupVariable $ var
   ty' <- introduceSkolemScope <=< replaceAllTypeSynonyms <=< replaceTypeWildcards $ ty
@@ -691,10 +694,10 @@
   th' <- check th ty
   el' <- check el ty
   return $ TypedValue True (IfThenElse cond' th' el') ty
-check' e@(Literal (ObjectLiteral ps)) t@(TypeApp obj row) | obj == tyRecord = do
+check' e@(Literal ss (ObjectLiteral ps)) t@(TypeApp obj row) | obj == tyRecord = do
   ensureNoDuplicateProperties ps
   ps' <- checkProperties e ps row False
-  return $ TypedValue True (Literal (ObjectLiteral ps')) t
+  return $ TypedValue True (Literal ss (ObjectLiteral ps')) t
 check' (TypeClassDictionaryConstructorApp name ps) t = do
   ps' <- check' ps t
   return $ TypedValue True (TypeClassDictionaryConstructorApp name ps') t
@@ -712,7 +715,7 @@
   rest <- freshType
   val' <- check val (TypeApp tyRecord (RCons (Label prop) ty rest))
   return $ TypedValue True (Accessor prop val') ty
-check' v@(Constructor c) ty = do
+check' v@(Constructor _ c) ty = do
   env <- getEnv
   case M.lookup c (dataConstructors env) of
     Nothing -> throwError . errorMessage . UnknownName . fmap DctorName $ c
@@ -721,9 +724,9 @@
       ty' <- introduceSkolemScope ty
       elaborate <- subsumes repl ty'
       return $ TypedValue True (elaborate v) ty'
-check' (Let ds val) ty = do
+check' (Let w ds val) ty = do
   (ds', val') <- inferLetBinding [] ds val (`check` ty)
-  return $ TypedValue True (Let ds' val') ty
+  return $ TypedValue True (Let w ds' val') ty
 check' val kt@(KindedType ty kind) = do
   checkTypeKind ty kind
   val' <- check' val ty
diff --git a/src/Language/PureScript/TypeClassDictionaries.hs b/src/Language/PureScript/TypeClassDictionaries.hs
--- a/src/Language/PureScript/TypeClassDictionaries.hs
+++ b/src/Language/PureScript/TypeClassDictionaries.hs
@@ -18,8 +18,12 @@
 --
 data TypeClassDictionaryInScope v
   = TypeClassDictionaryInScope {
+    -- | The instance chain
+      tcdChain :: [Qualified Ident]
+    -- | Index of the instance chain
+    , tcdIndex :: Integer
     -- | The value with which the dictionary can be accessed at runtime
-      tcdValue :: v
+    , tcdValue :: v
     -- | How to obtain this instance via superclass relationships
     , tcdPath :: [(Qualified (ProperName 'ClassName), Integer)]
     -- | The name of the type class to which this type class instance applies
diff --git a/stack.yaml b/stack.yaml
--- a/stack.yaml
+++ b/stack.yaml
@@ -1,6 +1,4 @@
-resolver: nightly-2017-09-10
+resolver: lts-11.7
 packages:
 - '.'
 extra-deps:
-- pipes-http-1.0.5
-- Win32-notify-0.3.0.3
diff --git a/tests/Language/PureScript/Ide/ImportsSpec.hs b/tests/Language/PureScript/Ide/ImportsSpec.hs
--- a/tests/Language/PureScript/Ide/ImportsSpec.hs
+++ b/tests/Language/PureScript/Ide/ImportsSpec.hs
@@ -9,6 +9,7 @@
 import           Language.PureScript.Ide.Command as Command
 import           Language.PureScript.Ide.Error
 import           Language.PureScript.Ide.Imports
+import           Language.PureScript.Ide.Filter (moduleFilter)
 import qualified Language.PureScript.Ide.Test as Test
 import           Language.PureScript.Ide.Types
 import           System.FilePath
@@ -62,7 +63,7 @@
 preludeImport = testParseImport "import Prelude"
 arrayImport = testParseImport "import Data.Array (head, cons)"
 listImport = testParseImport "import Data.List as List"
-consoleImport = testParseImport "import Control.Monad.Eff.Console (log) as Console"
+consoleImport = testParseImport "import Effect.Console (log) as Console"
 maybeImport = testParseImport "import Data.Maybe (Maybe(Just))"
 
 spec :: Spec
@@ -103,7 +104,7 @@
     it "pretty prints a qualified import" $
       shouldBe (prettyPrintImport' listImport) "import Data.List as List"
     it "pretty prints a qualified explicit import" $
-      shouldBe (prettyPrintImport' consoleImport) "import Control.Monad.Eff.Console (log) as Console"
+      shouldBe (prettyPrintImport' consoleImport) "import Effect.Console (log) as Console"
     it "pretty prints an import with a datatype (and PositionedRef's for the dtors)" $
       shouldBe (prettyPrintImport' maybeImport) "import Data.Maybe (Maybe(Just))"
 
@@ -343,6 +344,10 @@
 addExplicitImport i =
   Command.Import ("src" </> "ImportsSpec.purs") Nothing [] (Command.AddImportForIdentifier i Nothing)
 
+addExplicitImportFiltered :: Text -> [P.ModuleName] -> Command
+addExplicitImportFiltered i ms =
+  Command.Import ("src" </> "ImportsSpec.purs") Nothing [moduleFilter ms] (Command.AddImportForIdentifier i Nothing)
+
 importShouldBe :: [Text] -> [Text] -> Expectation
 importShouldBe res importSection =
   res `shouldBe` [ "module ImportsSpec where" , ""] ++ importSection ++ [ "" , "myId x = x"]
@@ -393,3 +398,12 @@
      \write to the output file" $ do
     result <- runIdeLoaded (addExplicitImport "doesnExist")
     result `shouldSatisfy` isLeft
+  it "doesn't import things from the Prim modules" $ do
+    Right (MultilineTextResult result) <- runIdeLoaded (addExplicitImport "String")
+    result `importShouldBe` []
+  it "imports classes from Prim.* modules" $ do
+    Right (MultilineTextResult result) <- runIdeLoaded (addExplicitImportFiltered "Cons" [Test.mn "Prim.Row"])
+    result `importShouldBe` ["import Prim.Row (class Cons)"]
+  it "imports types from Prim.* modules" $ do
+    Right (MultilineTextResult result) <- runIdeLoaded (addExplicitImportFiltered "Cons" [Test.mn "Prim.RowList"])
+    result `importShouldBe` ["import Prim.RowList (Cons)"]
diff --git a/tests/Language/PureScript/Ide/StateSpec.hs b/tests/Language/PureScript/Ide/StateSpec.hs
--- a/tests/Language/PureScript/Ide/StateSpec.hs
+++ b/tests/Language/PureScript/Ide/StateSpec.hs
@@ -62,6 +62,10 @@
       mempty
       -- , edInstanceConstraints =
       mempty
+      -- , edInstanceChain =
+      mempty
+      -- , edInstanceChainIndex =
+      0
  --     }
     ]
   --, efSourceSpan =
diff --git a/tests/Language/PureScript/Ide/Test.hs b/tests/Language/PureScript/Ide/Test.hs
--- a/tests/Language/PureScript/Ide/Test.hs
+++ b/tests/Language/PureScript/Ide/Test.hs
@@ -23,7 +23,7 @@
   IdeConfiguration
     { confLogLevel = LogNone
     , confOutputPath = "output/"
-    , confGlobs = ["src/*.purs"]
+    , confGlobs = ["src/**/*.purs"]
     , confEditorMode = False
     }
 
@@ -115,10 +115,16 @@
 mn :: Text -> P.ModuleName
 mn = P.moduleNameFromString
 
+projectDir :: FilePath
+projectDir = "." </> "tests" </> "support" </> "pscide"
+
+getProjectDirectory :: IO FilePath
+getProjectDirectory = makeAbsolute projectDir
+
 inProject :: IO a -> IO a
 inProject f = do
   cwd' <- getCurrentDirectory
-  setCurrentDirectory ("." </> "tests" </> "support" </> "pscide")
+  setCurrentDirectory projectDir
   a <- f
   setCurrentDirectory cwd'
   pure a
diff --git a/tests/Language/PureScript/Ide/UsageSpec.hs b/tests/Language/PureScript/Ide/UsageSpec.hs
new file mode 100644
--- /dev/null
+++ b/tests/Language/PureScript/Ide/UsageSpec.hs
@@ -0,0 +1,82 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+module Language.PureScript.Ide.UsageSpec where
+
+import           Protolude
+
+import qualified Data.Text as Text
+import           Language.PureScript.Ide.Command
+import           Language.PureScript.Ide.Types
+import qualified Language.PureScript.Ide.Test as Test
+import qualified Language.PureScript as P
+import           Test.Hspec
+import           Data.Text.Read (decimal)
+import           System.FilePath
+
+load :: [Text] -> Command
+load = LoadSync . map Test.mn
+
+usage :: P.ModuleName -> Text -> IdeNamespace -> Command
+usage mn ident ns = FindUsages mn ident ns
+
+shouldBeUsage :: P.SourceSpan -> (FilePath, Text) -> Expectation
+shouldBeUsage usage' (fp, range) =
+  let
+    [ start, end] = Text.splitOn "-" range
+    unsafeReadInt = fst . either (panic "") identity . decimal
+    [ startLine, startColumn ] = map unsafeReadInt (Text.splitOn ":" start)
+    [ endLine, endColumn ] = map unsafeReadInt (Text.splitOn ":" end)
+  in
+    do
+      projectDir <- Test.getProjectDirectory
+      projectDir </> fp `shouldBe` P.spanName usage'
+
+      (P.sourcePosLine (P.spanStart usage'), P.sourcePosColumn (P.spanStart usage'))
+        `shouldBe`
+        (startLine, startColumn)
+
+      (P.sourcePosLine (P.spanEnd usage'), P.sourcePosColumn (P.spanEnd usage'))
+        `shouldBe`
+        (endLine, endColumn)
+
+spec :: Spec
+spec = describe "Finding Usages" $ do
+    it "finds a simple usage" $ do
+      ([_, Right (UsagesResult [usage1, usage2])], _) <- Test.inProject $
+        Test.runIde [ load ["FindUsage", "FindUsage.Definition", "FindUsage.Reexport"]
+                    , usage (Test.mn "FindUsage.Definition") "usageId" IdeNSValue
+                    ]
+      usage1 `shouldBeUsage` ("src" </> "FindUsage.purs", "12:11-12:18")
+      usage2 `shouldBeUsage` ("src" </> "FindUsage" </> "Definition.purs", "13:18-13:18")
+    it "finds a simple recursive usage" $ do
+      ([_, Right (UsagesResult [usage1])], _) <- Test.inProject $
+        Test.runIde [ load ["FindUsage.Recursive"]
+                    , usage (Test.mn "FindUsage.Recursive") "recursiveUsage" IdeNSValue
+                    ]
+      usage1 `shouldBeUsage` ("src" </> "FindUsage" </> "Recursive.purs", "7:12-7:26")
+    it "ignores a locally shadowed recursive usage" $ do
+      ([_, Right (UsagesResult usageResult)], _) <- Test.inProject $
+        Test.runIde [ load ["FindUsage.RecursiveShadowed"]
+                    , usage (Test.mn "FindUsage.RecursiveShadowed") "recursiveUsage" IdeNSValue
+                    ]
+      usageResult `shouldBe` []
+    it "finds a constructor usage" $ do
+      ([_, Right (UsagesResult [usage1])], _) <- Test.inProject $
+        Test.runIde [ load ["FindUsage", "FindUsage.Definition", "FindUsage.Reexport"]
+                    , usage (Test.mn "FindUsage.Definition") "Used" IdeNSValue
+                    ]
+      usage1 `shouldBeUsage` ("src" </> "FindUsage.purs", "8:3-8:9")
+    it "finds a constructor alias usage" $ do
+      ([_, Right (UsagesResult [usage1])], _) <- Test.inProject $
+        Test.runIde [ load ["FindUsage", "FindUsage.Definition", "FindUsage.Reexport"]
+                    , usage (Test.mn "FindUsage.Definition") "$%" IdeNSValue
+                    ]
+      usage1 `shouldBeUsage` ("src" </> "FindUsage.purs", "9:5-9:7")
+    it "finds a reexported usage" $ do
+      ([_, Right (UsagesResult [usage1])], _) <- Test.inProject $
+        Test.runIde [ load ["FindUsage", "FindUsage.Definition", "FindUsage.Reexport"]
+                    , usage (Test.mn "FindUsage.Reexport") "toBeReexported" IdeNSValue
+                    ]
+        -- TODO(Christoph): Interesting parser bug here. It seems the position
+        -- of the last token in the file has the wrong ending span
+      usage1 `shouldBeUsage` ("src" </> "FindUsage.purs", "12:19-12:19")
diff --git a/tests/Main.hs b/tests/Main.hs
--- a/tests/Main.hs
+++ b/tests/Main.hs
@@ -8,12 +8,15 @@
 import Prelude ()
 import Prelude.Compat
 
+import Test.Tasty
+
 import qualified TestCompiler
+import qualified TestCoreFn
 import qualified TestDocs
 import qualified TestHierarchy
 import qualified TestPrimDocs
 import qualified TestPsci
-import qualified TestPscIde
+import qualified TestIde
 import qualified TestPscPublish
 import qualified TestUtils
 
@@ -26,20 +29,28 @@
 
   heading "Updating support code"
   TestUtils.updateSupportCode
-  heading "Main compiler test suite"
-  TestCompiler.main
-  heading "Documentation test suite"
-  TestDocs.main
-  heading "Hierarchy test suite"
-  TestHierarchy.main
   heading "Prim documentation test suite"
   TestPrimDocs.main
   heading "psc-publish test suite"
   TestPscPublish.main
-  heading "psci test suite"
-  TestPsci.main
-  heading "psc-ide test suite"
-  TestPscIde.main
+
+  ideTests <- TestIde.main
+  compilerTests <- TestCompiler.main
+  psciTests <- TestPsci.main
+  coreFnTests <- TestCoreFn.main
+  docsTests <- TestDocs.main
+  hierarchyTests <- TestHierarchy.main
+
+  defaultMain $
+    testGroup
+      "Tests"
+      [ compilerTests
+      , psciTests
+      , ideTests
+      , coreFnTests
+      , docsTests
+      , hierarchyTests
+      ]
 
   where
   heading msg = do
diff --git a/tests/TestCompiler.hs b/tests/TestCompiler.hs
--- a/tests/TestCompiler.hs
+++ b/tests/TestCompiler.hs
@@ -49,23 +49,23 @@
 import System.Directory
 import System.IO
 import System.IO.UTF8
-import System.IO.Silently
 import qualified System.FilePath.Glob as Glob
 
 import TestUtils
-import Test.Hspec
+import Test.Tasty
+import Test.Tasty.Hspec
 
-main :: IO ()
-main = hspec spec
+main :: IO TestTree
+main = testSpec "compiler" spec
 
 spec :: Spec
 spec = do
 
   (supportModules, supportExterns, supportForeigns, passingTestCases, warningTestCases, failingTestCases) <- runIO $ do
     cwd <- getCurrentDirectory
-    let passing = cwd </> "examples" </> "passing"
-    let warning = cwd </> "examples" </> "warning"
-    let failing = cwd </> "examples" </> "failing"
+    let passing = cwd </> "tests" </> "purs" </> "passing"
+    let warning = cwd </> "tests" </> "purs" </> "warning"
+    let failing = cwd </> "tests" </> "purs" </> "failing"
     passingFiles <- getTestFiles passing <$> testGlob passing
     warningFiles <- getTestFiles warning <$> testGlob warning
     failingFiles <- getTestFiles failing <$> testGlob failing
@@ -169,6 +169,7 @@
 makeActions modules foreigns = (P.buildMakeActions modulesDir (P.internalError "makeActions: input file map was read.") foreigns False)
                                { P.getInputTimestamp = getInputTimestamp
                                , P.getOutputTimestamp = getOutputTimestamp
+                               , P.progress = const (pure ())
                                }
   where
   getInputTimestamp :: P.ModuleName -> P.Make (Either P.RebuildPolicy (Maybe UTCTime))
@@ -194,7 +195,7 @@
   -> [FilePath]
   -> ([P.Module] -> IO ())
   -> IO (Either P.MultipleErrors [P.ExternsFile], P.MultipleErrors)
-compile supportModules supportExterns supportForeigns inputFiles check = silence $ runTest $ do
+compile supportModules supportExterns supportForeigns inputFiles check = runTest $ do
   fs <- liftIO $ readInput inputFiles
   ms <- P.parseModulesFromFiles id fs
   foreigns <- inferForeignModules ms
@@ -226,8 +227,20 @@
 checkShouldFailWith expected errs =
   let actual = map P.errorCode $ P.runMultipleErrors errs
   in if sort expected == sort (map T.unpack actual)
-    then Nothing
-    else Just $ "Expected these errors: " ++ show expected ++ ", but got these: " ++ show actual
+    then checkPositioned errs
+    else Just $ "Expected these errors: " ++ show expected ++ ", but got these: "
+      ++ show actual ++ ", full error messages: \n"
+      ++ unlines (map (P.renderBox . P.prettyPrintSingleError P.defaultPPEOptions) (P.runMultipleErrors errs))
+
+checkPositioned :: P.MultipleErrors -> Maybe String
+checkPositioned errs =
+  case mapMaybe (\err -> maybe (Just err) (const Nothing) (P.errorSpan err)) (P.runMultipleErrors errs) of
+    [] ->
+      Nothing
+    errs' ->
+      Just
+        $ "Found errors with missing source spans:\n"
+        ++ unlines (map (P.renderBox . P.prettyPrintSingleError P.defaultPPEOptions) errs')
 
 assertCompiles
   :: [P.Module]
diff --git a/tests/TestCoreFn.hs b/tests/TestCoreFn.hs
new file mode 100644
--- /dev/null
+++ b/tests/TestCoreFn.hs
@@ -0,0 +1,247 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE DoAndIfThenElse #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+module TestCoreFn (main) where
+
+import Prelude ()
+import Prelude.Compat
+
+import Data.Aeson
+import Data.Aeson.Types
+import Data.Version
+
+import Language.PureScript.AST.Literals
+import Language.PureScript.AST.SourcePos
+import Language.PureScript.Comments
+import Language.PureScript.CoreFn
+import Language.PureScript.CoreFn.FromJSON
+import Language.PureScript.CoreFn.ToJSON
+import Language.PureScript.Names
+import Language.PureScript.PSString
+
+import Test.Tasty
+import Test.Tasty.Hspec
+
+main :: IO TestTree
+main = testSpec "corefn" spec
+
+parseModule :: Value -> Result (Version, Module Ann)
+parseModule = parse moduleFromJSON
+
+-- convert a module to its json CoreFn representation and back
+parseMod :: Module Ann -> Result (Module Ann)
+parseMod m =
+  let v = Version [0] []
+  in snd <$> parseModule (moduleToJSON v m)
+
+isSuccess :: Result a -> Bool
+isSuccess (Success _) = True
+isSuccess _           = False
+
+spec :: Spec
+spec = context "CoreFnFromJsonTest" $ do
+  let mn = ModuleName [ProperName "Example", ProperName "Main"]
+      mp = "src/Example/Main.purs"
+      ss = SourceSpan mp (SourcePos 0 0) (SourcePos 0 0)
+      ann = ssAnn ss
+
+  specify "should parse an empty module" $ do
+    let r = parseMod $ Module ss [] mn mp [] [] [] []
+    r `shouldSatisfy` isSuccess
+    case r of
+      Error _   -> return ()
+      Success m -> moduleName m `shouldBe` mn
+
+  specify "should parse source span" $ do
+    let r = parseMod $ Module ss [] mn mp [] [] [] []
+    r `shouldSatisfy` isSuccess
+    case r of
+      Error _   -> return ()
+      Success m -> moduleSourceSpan m `shouldBe` ss
+
+  specify "should parse module path" $ do
+    let r = parseMod $ Module ss [] mn mp [] [] [] []
+    r `shouldSatisfy` isSuccess
+    case r of
+      Error _   -> return ()
+      Success m -> modulePath m `shouldBe` mp
+
+  specify "should parse imports" $ do
+    let r = parseMod $ Module ss [] mn mp [(ann, mn)] [] [] []
+    r `shouldSatisfy` isSuccess
+    case r of
+      Error _   -> return ()
+      Success m -> moduleImports m `shouldBe` [(ann, mn)]
+
+  specify "should parse exports" $ do
+    let r = parseMod $ Module ss [] mn mp [] [Ident "exp"] [] []
+    r `shouldSatisfy` isSuccess
+    case r of
+      Error _   -> return ()
+      Success m -> moduleExports m `shouldBe` [Ident "exp"]
+
+  specify "should parse foreign" $ do
+    let r = parseMod $ Module ss [] mn mp [] [] [Ident "exp"] []
+    r `shouldSatisfy` isSuccess
+    case r of
+      Error _   -> return ()
+      Success m -> moduleForeign m `shouldBe` [Ident "exp"]
+
+  context "Expr" $ do
+    specify "should parse literals" $ do
+      let m = Module ss [] mn mp [] [] []
+                [ NonRec ann (Ident "x1") $ Literal ann (NumericLiteral (Left 1))
+                , NonRec ann (Ident "x2") $ Literal ann (NumericLiteral (Right 1.0))
+                , NonRec ann (Ident "x3") $ Literal ann (StringLiteral (mkString "abc"))
+                , NonRec ann (Ident "x4") $ Literal ann (CharLiteral 'c')
+                , NonRec ann (Ident "x5") $ Literal ann (BooleanLiteral True)
+                , NonRec ann (Ident "x6") $ Literal ann (ArrayLiteral [Literal ann (CharLiteral 'a')])
+                , NonRec ann (Ident "x7") $ Literal ann (ObjectLiteral [(mkString "a", Literal ann (CharLiteral 'a'))])
+                ]
+      parseMod m `shouldSatisfy` isSuccess
+
+    specify "should parse Constructor" $ do
+      let m = Module ss [] mn mp [] [] []
+                [ NonRec ann (Ident "constructor") $ Constructor ann (ProperName "Either") (ProperName "Left") [Ident "value0"] ]
+      parseMod m `shouldSatisfy` isSuccess
+
+    specify "should parse Accessor" $ do
+      let m = Module ss [] mn mp [] [] []
+                [ NonRec ann (Ident "x") $
+                    Accessor ann (mkString "field") (Literal ann $ ObjectLiteral [(mkString "field", Literal ann (NumericLiteral (Left 1)))]) ]
+      parseMod m `shouldSatisfy` isSuccess
+
+    specify "should parse ObjectUpdate" $ do
+      let m = Module ss [] mn mp [] [] []
+                [ NonRec ann (Ident "objectUpdate") $
+                    ObjectUpdate ann
+                      (Literal ann $ ObjectLiteral [(mkString "field", Literal ann (StringLiteral (mkString "abc")))])
+                      [(mkString "field", Literal ann (StringLiteral (mkString "xyz")))]
+                ]
+      parseMod m `shouldSatisfy` isSuccess
+
+    specify "should parse Abs" $ do
+      let m = Module ss [] mn mp [] [] []
+                [ NonRec ann (Ident "abs")
+                    $ Abs ann (Ident "x") (Var ann (Qualified (Just mn) (Ident "x")))
+                ]
+      parseMod m `shouldSatisfy` isSuccess
+
+    specify "should parse App" $ do
+      let m = Module ss [] mn mp [] [] []
+                [ NonRec ann (Ident "app")
+                    $ App ann
+                        (Abs ann (Ident "x") (Var ann (Qualified Nothing (Ident "x"))))
+                        (Literal ann (CharLiteral 'c'))
+                ]
+      parseMod m `shouldSatisfy` isSuccess
+
+    specify "should parse Case" $ do
+      let m = Module ss [] mn mp [] [] []
+                [ NonRec ann (Ident "case") $
+                    Case ann [Var ann (Qualified Nothing (Ident "x"))]
+                      [ CaseAlternative
+                        [ NullBinder ann ]
+                        (Right (Literal ann (CharLiteral 'a')))
+                      ]
+                ]
+      parseMod m `shouldSatisfy` isSuccess
+
+    specify "should parse Case with guards" $ do
+      let m = Module ss [] mn mp [] [] []
+                [ NonRec ann (Ident "case") $
+                    Case ann [Var ann (Qualified Nothing (Ident "x"))]
+                      [ CaseAlternative
+                        [ NullBinder ann ]
+                        (Left [(Literal ann (BooleanLiteral True), Literal ann (CharLiteral 'a'))])
+                      ]
+                ]
+      parseMod m `shouldSatisfy` isSuccess
+
+    specify "should parse Let" $ do
+      let m = Module ss [] mn mp [] [] []
+                [ NonRec ann (Ident "case") $
+                    Let ann
+                      [ Rec [((ann, Ident "a"), Var ann (Qualified Nothing (Ident "x")))] ]
+                      (Literal ann (BooleanLiteral True))
+                ]
+      parseMod m `shouldSatisfy` isSuccess
+
+  context "Meta" $ do
+    specify "should parse IsConstructor" $ do
+      let m = Module ss [] mn mp [] [] []
+                [ NonRec (ss, [], Nothing, Just (IsConstructor ProductType [Ident "x"])) (Ident "x") $
+                  Literal (ss, [], Nothing, Just (IsConstructor SumType [])) (CharLiteral 'a')
+                ]
+      parseMod m `shouldSatisfy` isSuccess
+
+    specify "should parse IsNewtype" $ do
+      let m = Module ss [] mn mp [] [] []
+                [ NonRec (ss, [], Nothing, Just IsNewtype) (Ident "x") $
+                  Literal ann (CharLiteral 'a')
+                ]
+      parseMod m `shouldSatisfy` isSuccess
+
+    specify "should parse IsTypeClassConstructor" $ do
+      let m = Module ss [] mn mp [] [] []
+                [ NonRec (ss, [], Nothing, Just IsTypeClassConstructor) (Ident "x") $
+                  Literal ann (CharLiteral 'a')
+                ]
+      parseMod m `shouldSatisfy` isSuccess
+
+    specify "should parse IsForeign" $ do
+      let m = Module ss [] mn mp [] [] []
+                [ NonRec (ss, [], Nothing, Just IsForeign) (Ident "x") $
+                  Literal ann (CharLiteral 'a')
+                ]
+      parseMod m `shouldSatisfy` isSuccess
+
+  context "Binders" $ do
+    specify "should parse LiteralBinder" $ do
+      let m = Module ss [] mn mp [] [] []
+                [ NonRec ann (Ident "case") $
+                    Case ann [Var ann (Qualified Nothing (Ident "x"))]
+                      [ CaseAlternative
+                        [ LiteralBinder ann (BooleanLiteral True) ]
+                        (Right (Literal ann (CharLiteral 'a')))
+                      ]
+                ]
+      parseMod m `shouldSatisfy` isSuccess
+
+    specify "should parse VarBinder" $ do
+      let m = Module ss [] mn mp [] [] []
+                [ NonRec ann (Ident "case") $
+                    Case ann [Var ann (Qualified Nothing (Ident "x"))]
+                      [ CaseAlternative
+                        [ ConstructorBinder
+                            ann
+                            (Qualified (Just (ModuleName [ProperName "Data", ProperName "Either"])) (ProperName "Either"))
+                            (Qualified Nothing (ProperName "Left"))
+                            [VarBinder ann (Ident "z")]
+                        ]
+                        (Right (Literal ann (CharLiteral 'a')))
+                      ]
+                ]
+      parseMod m `shouldSatisfy` isSuccess
+
+    specify "should parse NamedBinder" $ do
+      let m = Module ss [] mn mp [] [] []
+                [ NonRec ann (Ident "case") $
+                    Case ann [Var ann (Qualified Nothing (Ident "x"))]
+                      [ CaseAlternative
+                        [ NamedBinder ann (Ident "w") (NamedBinder ann (Ident "w'") (VarBinder ann (Ident "w''"))) ]
+                        (Right (Literal ann (CharLiteral 'a')))
+                      ]
+                ]
+      parseMod m `shouldSatisfy` isSuccess
+
+  context "Comments" $ do
+    specify "should parse LineComment" $ do
+      let m = Module ss [ LineComment "line" ] mn mp [] [] [] []
+      parseMod m `shouldSatisfy` isSuccess
+
+    specify "should parse BlockComment" $ do
+      let m = Module ss [ BlockComment "block" ] mn mp [] [] [] []
+      parseMod m `shouldSatisfy` isSuccess
diff --git a/tests/TestDocs.hs b/tests/TestDocs.hs
--- a/tests/TestDocs.hs
+++ b/tests/TestDocs.hs
@@ -15,6 +15,7 @@
 import Data.List (findIndex)
 import Data.Foldable
 import Safe (headMay)
+import qualified Data.Map as Map
 import Data.Maybe (fromMaybe, mapMaybe)
 import Data.Monoid
 import Data.Text (Text)
@@ -32,8 +33,10 @@
 import Web.Bower.PackageMeta (parsePackageName, runPackageName)
 
 import TestUtils
-import Test.Hspec (Spec, it, context, expectationFailure, runIO, hspec)
 
+import Test.Tasty
+import Test.Tasty.Hspec (Spec, it, context, expectationFailure, runIO, testSpec)
+
 publishOpts :: Publish.PublishOptions
 publishOpts = Publish.defaultPublishOptions
   { Publish.publishGetVersion = return testVersion
@@ -44,11 +47,11 @@
 
 getPackage :: IO (Either Publish.PackageError (Docs.Package Docs.NotYetKnown))
 getPackage =
-  pushd "examples/docs" $
+  pushd "tests/purs/docs" $
     Publish.preparePackage "bower.json" "resolutions.json" publishOpts
 
-main :: IO ()
-main = hspec spec
+main :: IO TestTree
+main = testSpec "docs" spec
 
 spec :: Spec
 spec = do
@@ -62,19 +65,32 @@
 
   let linksCtx = Docs.getLinksContext pkg
 
-  context "Language.PureScript.Docs" $
-    forM_ testCases $ \(mnString, assertions) -> do
-      let mn = P.moduleNameFromString mnString
-          mdl = find ((==) mn . Docs.modName) pkgModules
+  context "Language.PureScript.Docs" $ do
+    context "Doc generation tests:" $
+      forM_ testCases $ \(mnString, assertions) -> do
+        let mn = P.moduleNameFromString mnString
+            mdl = find ((==) mn . Docs.modName) pkgModules
 
-      context ("in module " ++ T.unpack mnString) $ do
-        case mdl of
-          Nothing ->
-            it "exists in docs output" $
-              expectationFailure ("module not found in docs: " ++ T.unpack mnString)
-          Just mdl' ->
-            toHspec linksCtx mdl' assertions
+        context ("in module " ++ T.unpack mnString) $
+          case mdl of
+            Nothing ->
+              it "exists in docs output" $
+                expectationFailure ("module not found in docs: " ++ T.unpack mnString)
+            Just mdl' ->
+              toHspec linksCtx mdl' assertions
 
+    context "Tag generation tests:" $
+      forM_ testTagsCases $ \(mnString, assertions) -> do
+        let mn = P.moduleNameFromString mnString
+            mdl = find ((==) mn . Docs.modName) pkgModules
+        context ("in module " ++ T.unpack mnString) $
+          case mdl of
+            Nothing ->
+              it "exists in docs output" $
+                expectationFailure ("module not found in docs: " ++ T.unpack mnString)
+            Just mdl' ->
+              tagAssertionsToHspec mdl' assertions
+
   where
   toHspec :: Docs.LinksContext -> Docs.Module -> [DocsAssertion] -> Spec
   toHspec linksCtx mdl assertions =
@@ -86,6 +102,17 @@
           Fail reason ->
             expectationFailure (T.unpack (displayAssertionFailure reason))
 
+  tagAssertionsToHspec :: Docs.Module -> [TagsAssertion] -> Spec
+  tagAssertionsToHspec mdl assertions =
+    let tags = Map.fromList $ Docs.tags mdl
+    in forM_ assertions $ \a ->
+      it (T.unpack (displayTagsAssertion a)) $ do
+        case runTagsAssertion a tags of
+          TagsPass ->
+            pure ()
+          TagsFail reason ->
+            expectationFailure (T.unpack (displayTagsAssertionFailure reason))
+
 takeJust :: String -> Maybe a -> a
 takeJust msg = fromMaybe (error msg)
 
@@ -128,6 +155,12 @@
   -- | Assert that a given declaration comes before another in the output
   | ShouldComeBefore P.ModuleName Text Text
 
+data TagsAssertion
+  -- | Assert that a particular declaration is tagged
+  = ShouldBeTagged Text Int
+  -- | Assert that a particular declaration is not tagged
+  | ShouldNotBeTagged Text
+
 displayAssertion :: DocsAssertion -> Text
 displayAssertion = \case
   ShouldBeDocumented mn decl children ->
@@ -165,6 +198,13 @@
     showQual mn declA <> " should come before " <> showQual mn declB <>
     " in the docs"
 
+displayTagsAssertion :: TagsAssertion -> Text
+displayTagsAssertion = \case
+  ShouldBeTagged decl l ->
+    decl <> " should be tagged at line " <> T.pack (show l)
+  ShouldNotBeTagged decl ->
+    decl <> " should not be tagged"
+
 data DocsAssertionFailure
   -- | A declaration was not documented, but should have been
   = NotDocumented P.ModuleName Text
@@ -209,6 +249,14 @@
   -- | Declarations were in the wrong order
   | WrongOrder P.ModuleName Text Text
 
+data TagsAssertionFailure
+  -- | A declaration was not tagged, but should have been
+  = NotTagged Text
+  -- | A declaration was tagged, but should not have been
+  | Tagged Text Int
+  -- | A declaration was tagged on the wrong line
+  | TaggedWrongLine Text Int Int
+
 displayAssertionFailure :: DocsAssertionFailure -> Text
 displayAssertionFailure = \case
   NotDocumented _ decl ->
@@ -249,10 +297,25 @@
   WrongOrder _ before after ->
     "expected to see " <> before <> " before " <> after
 
+displayTagsAssertionFailure :: TagsAssertionFailure -> Text
+displayTagsAssertionFailure = \case
+  NotTagged decl ->
+    decl <> " was not tagged, but should have been"
+  Tagged decl line ->
+    decl <> " was tagged at line " <> T.pack (show line) <>
+    ", but should not have been"
+  TaggedWrongLine decl taggedLine desiredLine ->
+    decl <> " was tagged at line " <> T.pack (show taggedLine) <>
+    ", but should have been tagged at line " <> T.pack (show desiredLine)
+
 data DocsAssertionResult
   = Pass
   | Fail DocsAssertionFailure
 
+data TagsAssertionResult
+  = TagsPass
+  | TagsFail TagsAssertionFailure
+
 runAssertion :: DocsAssertion -> Docs.LinksContext -> Docs.Module -> DocsAssertionResult
 runAssertion assertion linksCtx Docs.Module{..} =
   case assertion of
@@ -421,6 +484,22 @@
         _ ->
           Nothing
 
+runTagsAssertion :: TagsAssertion -> Map.Map String Int -> TagsAssertionResult
+runTagsAssertion assertion tags =
+  case assertion of
+    ShouldBeTagged decl line ->
+      case Map.lookup (T.unpack decl) tags of
+        Just taggedLine ->
+          if taggedLine == line
+            then TagsPass
+            else TagsFail $ TaggedWrongLine decl taggedLine line
+        Nothing -> TagsFail $ NotTagged decl
+
+    ShouldNotBeTagged decl ->
+      case Map.lookup (T.unpack decl) tags of
+        Just taggedLine -> TagsFail $ Tagged decl taggedLine
+        Nothing -> TagsPass
+
 checkConstrained :: P.Type -> Text -> Bool
 checkConstrained ty tyClass =
   case ty of
@@ -581,6 +660,29 @@
 
   shouldBeOrdered mn declNames =
     zipWith (ShouldComeBefore mn) declNames (tail declNames)
+
+testTagsCases :: [(Text, [TagsAssertion])]
+testTagsCases =
+  [ ("DeclOrder",
+      [ -- explicit exports
+        ShouldBeTagged "x1" 10
+      , ShouldBeTagged "x3" 11
+      , ShouldBeTagged "X2" 13
+      , ShouldBeTagged "X4" 14
+      , ShouldBeTagged "A" 16
+      , ShouldBeTagged "B" 17
+      ])
+  , ("Example2",
+      [ -- all symbols exported
+        ShouldBeTagged "one" 3
+      , ShouldBeTagged "two" 6
+      ])
+  , ("ExplicitExport",
+      [ -- only one of two symbols exported
+        ShouldBeTagged "one" 3
+      , ShouldNotBeTagged "two"
+      ])
+  ]
 
 showQual :: P.ModuleName -> Text -> Text
 showQual mn decl =
diff --git a/tests/TestHierarchy.hs b/tests/TestHierarchy.hs
--- a/tests/TestHierarchy.hs
+++ b/tests/TestHierarchy.hs
@@ -1,12 +1,16 @@
 {-# LANGUAGE OverloadedStrings #-}
 module TestHierarchy where
 
+import Prelude
+
 import Language.PureScript.Hierarchy
 import qualified Language.PureScript as P
-import Test.Hspec (describe, hspec, it, shouldBe)
 
-main :: IO ()
-main = hspec $ do
+import Test.Tasty
+import Test.Tasty.Hspec (describe, it, shouldBe, testSpec)
+
+main :: IO TestTree
+main = testSpec "hierarchy" $ do
   describe "Language.PureScript.Hierarchy" $ do
     describe "prettyPrint" $ do
       it "creates just the node when there is no relation" $ do
diff --git a/tests/TestIde.hs b/tests/TestIde.hs
new file mode 100644
--- /dev/null
+++ b/tests/TestIde.hs
@@ -0,0 +1,19 @@
+module TestIde where
+
+import           Prelude
+
+import           Control.Monad (unless)
+import           Language.PureScript.Ide.Test
+import qualified PscIdeSpec
+import           Test.Tasty
+import           Test.Tasty.Hspec
+
+main :: IO TestTree
+main =
+  testSpec "ide" (beforeAll_ setup PscIdeSpec.spec)
+  where
+    setup = do
+      deleteOutputFolder
+      s <- compileTestProject
+      unless s (fail "Failed to compile .purs sources")
+
diff --git a/tests/TestPrimDocs.hs b/tests/TestPrimDocs.hs
--- a/tests/TestPrimDocs.hs
+++ b/tests/TestPrimDocs.hs
@@ -1,6 +1,9 @@
 module TestPrimDocs where
 
+import Prelude
+
 import Control.Monad
+import Data.Monoid ((<>))
 import Data.List ((\\))
 import qualified Data.Map as Map
 import qualified Data.Set as Set
@@ -11,14 +14,20 @@
 main :: IO ()
 main = do
   putStrLn "Test that there are no bottoms hiding in primDocsModule"
-  seq (D.runDocs (D.modulesAsMarkdown [D.primDocsModule])) (return ())
+  seq (D.runDocs (D.modulesAsMarkdown D.primModules)) (return ())
 
   putStrLn "Test that Prim is fully documented"
   let actualPrimNames =
         -- note that prim type classes are listed in P.primTypes
-        (map (P.runProperName . P.disqualify . fst) $ Map.toList P.primTypes) ++
-        (map (P.runProperName . P.disqualify) $ Set.toList P.primKinds)
-  let documentedPrimNames = map D.declTitle (D.modDeclarations D.primDocsModule)
+        (map (P.runProperName . P.disqualify . fst) $ Map.toList
+          ( P.primTypes <>
+            P.primOrderingTypes <>
+            P.primRowTypes <>
+            P.primRowListTypes <>
+            P.primTypeErrorTypes <>
+            P.primSymbolTypes )) ++
+        (map (P.runProperName . P.disqualify) $ Set.toList P.allPrimKinds)
+  let documentedPrimNames = map D.declTitle (concatMap D.modDeclarations D.primModules)
 
   let undocumentedNames = actualPrimNames \\ documentedPrimNames
   let extraNames = documentedPrimNames \\ actualPrimNames
@@ -27,4 +36,4 @@
     error $ "Undocumented Prim names: " ++ show undocumentedNames
 
   when (not (null extraNames)) $
-    error $ "Extra Prim names: " ++ show undocumentedNames
+    error $ "Extra Prim names: " ++ show extraNames
diff --git a/tests/TestPscIde.hs b/tests/TestPscIde.hs
deleted file mode 100644
--- a/tests/TestPscIde.hs
+++ /dev/null
@@ -1,13 +0,0 @@
-module TestPscIde where
-
-import           Control.Monad                       (unless)
-import qualified PscIdeSpec
-import           Language.PureScript.Ide.Test
-import           Test.Hspec
-
-main :: IO ()
-main = do
-  deleteOutputFolder
-  s <- compileTestProject
-  unless s (fail "Failed to compile .purs sources")
-  hspec PscIdeSpec.spec
diff --git a/tests/TestPscPublish.hs b/tests/TestPscPublish.hs
--- a/tests/TestPscPublish.hs
+++ b/tests/TestPscPublish.hs
@@ -4,6 +4,8 @@
 
 module TestPscPublish where
 
+import Prelude
+
 import Control.Monad.IO.Class (liftIO)
 import System.Exit (exitFailure)
 import Data.ByteString.Lazy (ByteString)
diff --git a/tests/TestPsci.hs b/tests/TestPsci.hs
--- a/tests/TestPsci.hs
+++ b/tests/TestPsci.hs
@@ -3,13 +3,15 @@
 import Prelude ()
 import Prelude.Compat
 
-import Test.Hspec
 import TestPsci.CommandTest (commandTests)
 import TestPsci.CompletionTest (completionTests)
 import TestPsci.EvalTest (evalTests)
 
-main :: IO ()
-main = hspec $ do
+import Test.Tasty
+import Test.Tasty.Hspec
+
+main :: IO TestTree
+main = testSpec "repl" $ do
   completionTests
   commandTests
   evalTests
diff --git a/tests/TestPsci/CommandTest.hs b/tests/TestPsci/CommandTest.hs
--- a/tests/TestPsci/CommandTest.hs
+++ b/tests/TestPsci/CommandTest.hs
@@ -35,6 +35,12 @@
 
   specPSCi ":complete" $ do
     ":complete ma" `prints` []
-    ":complete Data.Functor.ma" `prints` (unlines (map ("Data.Functor." ++ ) ["map", "mapFlipped"]))
+    ":complete Data.Functor.ma" `prints` []
     run "import Data.Functor"
-    ":complete ma" `prints` (unlines ["map", "mapFlipped"])
+    ":complete ma" `prints` unlines ["map", "mapFlipped"]
+    run "import Control.Monad as M"
+    ":complete M.a" `prints` unlines ["M.ap", "M.apply"]
+
+  specPSCi ":browse" $ do
+    ":browse Mirp" `printed` flip shouldContain "is not valid"
+    ":browse Prim" `printed` flip shouldContain "class Partial"
diff --git a/tests/TestPsci/CompletionTest.hs b/tests/TestPsci/CompletionTest.hs
--- a/tests/TestPsci/CompletionTest.hs
+++ b/tests/TestPsci/CompletionTest.hs
@@ -17,8 +17,9 @@
 
 completionTests :: Spec
 completionTests = context "completionTests" $ do
-  mns <- runIO $ getSupportModuleNames
-  mapM_ assertCompletedOk (completionTestData mns)
+  mns       <- runIO getSupportModuleNames
+  psciState <- runIO getPSCiStateForCompletion
+  mapM_ (assertCompletedOk psciState) (completionTestData mns)
 
 -- If the cursor is at the right end of the line, with the 1st element of the
 -- pair as the text in the line, then pressing tab should offer all the
@@ -33,12 +34,12 @@
   , (":b",  [":browse"])
 
   -- :browse should complete module names
-  , (":b Control.Monad.E",    map (":b Control.Monad.Eff" ++) ["", ".Unsafe", ".Class", ".Console", ".Uncurried"])
-  , (":b Control.Monad.Eff.", map (":b Control.Monad.Eff" ++) [".Unsafe", ".Class", ".Console", ".Uncurried"])
+  , (":b Eff",    map (":b Effect" ++) ["", ".Unsafe", ".Class", ".Console", ".Uncurried", ".Ref"])
+  , (":b Effect.", map (":b Effect" ++) [".Unsafe", ".Class", ".Console", ".Uncurried", ".Ref"])
 
   -- import should complete module names
-  , ("import Control.Monad.E",    map ("import Control.Monad.Eff" ++) ["", ".Unsafe", ".Class", ".Console", ".Uncurried"])
-  , ("import Control.Monad.Eff.", map ("import Control.Monad.Eff" ++) [".Unsafe", ".Class", ".Console", ".Uncurried"])
+  , ("import Eff",    map ("import Effect" ++) ["", ".Unsafe", ".Class", ".Console", ".Uncurried", ".Ref"])
+  , ("import Effect.", map ("import Effect" ++) [".Unsafe", ".Class", ".Console", ".Uncurried", ".Ref"])
 
   -- :quit, :help, :reload, :clear should not complete
   , (":help ", [])
@@ -50,20 +51,27 @@
   , (":show ", [":show import", ":show loaded"])
   , (":show a", [])
 
-  -- :type should complete values and data constructors in scope
-  , (":type Control.Monad.Eff.Console.lo", [":type Control.Monad.Eff.Console.log", ":type Control.Monad.Eff.Console.logShow"])
-  --, (":type uni", [":type unit"])
-  --, (":type E", [":type EQ"])
+  -- :type should complete next word from values and constructors in scope
+  , (":type uni", [":type unit"])
+  , (":type E", [":type EQ"])
+  , (":type P.", map (":type P." ++) ["EQ", "GT", "LT", "unit"]) -- import Prelude (unit, Ordering(..)) as P
+  , (":type Effect.Console.lo", [])
+  , (":type voi", [])
 
-  -- :kind should complete types in scope
-  --, (":kind C", [":kind Control.Monad.Eff.Pure"])
-  --, (":kind O", [":kind Ordering"])
+  -- :kind should complete next word from types in scope
+  , (":kind Str", [":kind String"])
+  , (":kind ST.", [":kind ST.ST"]) -- import Control.Monad.ST as ST
+  , (":kind STRef.", [":kind STRef.STRef"]) -- import Control.Monad.ST.Ref as STRef
+  , (":kind Effect.", [])
 
-  -- Only one argument for directives should be completed
+  -- Only one argument for these directives should be completed
   , (":show import ", [])
-  , (":type EQ ", [])
-  , (":kind Ordering ", [])
+  , (":browse Data.List ", [])
 
+  -- These directives take any number of completable terms
+  , (":type const compa", [":type const compare", ":type const comparing"])
+  , (":kind Array In", [":kind Array Int"])
+
   -- a few other import tests
   , ("impor", ["import"])
   , ("import ", map (T.unpack . mappend "import ") supportModuleNames)
@@ -73,36 +81,57 @@
   , ("\"hi", [])
   , ("34", [])
 
-  -- Identifiers and data constructors should be completed
-  --, ("uni", ["unit"])
-  , ("Control.Monad.Eff.Class.", ["Control.Monad.Eff.Class.liftEff"])
-  --, ("G", ["GT"])
-  , ("Data.Ordering.L", ["Data.Ordering.LT"])
+  -- Identifiers and data constructors in scope should be completed
+  , ("uni", ["unit"])
+  , ("G", ["GT"])
+  , ("P.G", ["P.GT"])
+  , ("P.uni", ["P.unit"])
+  , ("voi", []) -- import Prelude hiding (void)
+  , ("Effect.Class.", [])
 
-  -- if a module is imported qualified, values should complete under the
-  -- qualified name, as well as the original name.
-  , ("ST.new", ["ST.newSTRef"])
-  , ("Control.Monad.ST.new", ["Control.Monad.ST.newSTRef"])
+  -- complete first name after type annotation symbol
+  , ("1 :: I", ["1 :: Int"])
+  , ("1 ::I",  ["1 ::Int"])
+  , ("1:: I",  ["1:: Int"])
+  , ("1::I",   ["1::Int"])
+  , ("(1::Int) uni", ["(1::Int) unit"]) -- back to completing values
+
+  -- Parens and brackets aren't considered part of the current identifier
+  , ("map id [uni", ["map id [unit"])
+  , ("map (cons", ["map (const"])
   ]
 
-assertCompletedOk :: (String, [String]) -> Spec
-assertCompletedOk (line, expecteds) = specify line $ do
-  results <- runCM (completion' (reverse line, ""))
+assertCompletedOk :: PSCiState -> (String, [String]) -> Spec
+assertCompletedOk psciState (line, expecteds) = specify line $ do
+  results <- runCM psciState (completion' (reverse line, ""))
   let actuals = formatCompletions results
   sort actuals `shouldBe` sort expecteds
 
-runCM :: CompletionM a -> IO a
-runCM act = do
-  psciState <- getPSCiStateForCompletion
-  evalStateT (liftCompletionM act) psciState
+runCM :: PSCiState -> CompletionM a -> IO a
+runCM psciState act = evalStateT (liftCompletionM act) psciState
 
 getPSCiStateForCompletion :: IO PSCiState
 getPSCiStateForCompletion = do
-  (PSCiState _ bs es, _) <- initTestPSCiEnv
-  let imports = [controlMonadSTasST, (P.ModuleName [P.ProperName "Prelude"], P.Implicit, Nothing)]
-  return $ PSCiState imports bs es
-
-controlMonadSTasST :: ImportedModule
-controlMonadSTasST = (s "Control.Monad.ST", P.Implicit, Just (s "ST"))
+  (st, _) <- initTestPSCiEnv
+  let imports = [-- import Control.Monad.ST as S
+                 (qualName "Control.Monad.ST"
+                    ,P.Implicit
+                    ,Just (qualName "ST"))
+                , -- import Control.Monad.ST.Ref as STRef
+                 (qualName "Control.Monad.ST.Ref"
+                    ,P.Implicit
+                    ,Just (qualName "STRef"))
+                 -- import Prelude hiding (void)
+                ,(qualName "Prelude"
+                    ,P.Hiding [valName "void"]
+                    ,Nothing)
+                 -- import Prelude (unit, Ordering(..)) as P
+                ,(qualName "Prelude"
+                    ,P.Explicit [valName "unit", typeName "Ordering"]
+                    ,Just (qualName "P"))]
+  return $ updateImportedModules (const imports) st
   where
-  s = P.moduleNameFromString
+    qualName   = P.moduleNameFromString
+    valName    = P.ValueRef srcSpan . P.Ident
+    typeName t = P.TypeRef srcSpan (P.ProperName t) Nothing
+    srcSpan    = P.internalModuleSourceSpan "<internal>"
diff --git a/tests/TestPsci/EvalTest.hs b/tests/TestPsci/EvalTest.hs
--- a/tests/TestPsci/EvalTest.hs
+++ b/tests/TestPsci/EvalTest.hs
@@ -23,7 +23,7 @@
 evalTestFiles :: IO [FilePath]
 evalTestFiles = do
   cwd <- getCurrentDirectory
-  let psciExamples = cwd </> "examples" </> "psci"
+  let psciExamples = cwd </> "tests" </> "purs" </> "psci"
   Glob.globDir1 (Glob.compile "**/*.purs") psciExamples
 
 data EvalLine = Line String
diff --git a/tests/TestPsci/TestEnv.hs b/tests/TestPsci/TestEnv.hs
--- a/tests/TestPsci/TestEnv.hs
+++ b/tests/TestPsci/TestEnv.hs
@@ -3,6 +3,7 @@
 import Prelude ()
 import Prelude.Compat
 
+import           Control.Monad (void)
 import           Control.Monad.IO.Class (liftIO)
 import           Control.Monad.Trans.RWS.Strict (evalRWST, RWST)
 import qualified Language.PureScript as P
@@ -12,7 +13,7 @@
 import           System.FilePath ((</>))
 import qualified System.FilePath.Glob as Glob
 import           System.Process (readProcessWithExitCode)
-import           Test.Hspec (shouldBe)
+import           Test.Hspec (shouldBe, Expectation)
 
 -- | A monad transformer for handle PSCi actions in tests
 type TestPSCi a = RWST PSCiConfig () PSCiState IO a
@@ -35,7 +36,7 @@
       case makeResultOrError of
         Left errs -> putStrLn (P.prettyPrintMultipleErrors P.defaultPPEOptions errs) >> exitFailure
         Right (externs, env) ->
-          return (PSCiState [] [] (zip (map snd modules) externs), PSCiConfig pursFiles env)
+          return (updateLoadedExterns (const (zip (map snd modules) externs)) initialPSCiState, PSCiConfig pursFiles env)
 
 -- | Execute a TestPSCi, returning IO
 execTestPSCi :: TestPSCi a -> IO a
@@ -90,7 +91,7 @@
 
 -- | An assertion to check command PSCi printed output against a given string
 prints :: String -> String -> TestPSCi ()
-prints command expected = runAndEval command evalJsAndIgnore evalPrinted
-  where
-    evalJsAndIgnore = jsEval *> return ()
-    evalPrinted s = s `equalsTo` expected
+prints command expected = printed command (`shouldBe` expected)
+
+printed :: String -> (String -> Expectation) -> TestPSCi ()
+printed command f = runAndEval command (void jsEval) (liftIO . f)
diff --git a/tests/purs/docs/bower.json b/tests/purs/docs/bower.json
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/bower.json
@@ -0,0 +1,21 @@
+{
+  "name": "docs-test-package",
+  "version": "1.0.0",
+  "moduleType": [
+    "node"
+  ],
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/not-real/not-a-real-repo.git"
+  },
+  "ignore": [
+    "**/.*",
+    "node_modules",
+    "bower_components",
+    "output"
+  ],
+  "dependencies": {
+    "purescript-prelude": "./bower_components/purescript-prelude"
+  },
+  "license": "MIT"
+}
diff --git a/tests/purs/docs/bower_components/purescript-prelude/src/Prelude.purs b/tests/purs/docs/bower_components/purescript-prelude/src/Prelude.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/bower_components/purescript-prelude/src/Prelude.purs
@@ -0,0 +1,8 @@
+module Prelude where
+
+newtype Unit = Unit {}
+
+unit :: Unit
+unit = Unit {}
+
+data Boolean2 = True | False
diff --git a/tests/purs/docs/output/ConstrainedArgument/externs.json b/tests/purs/docs/output/ConstrainedArgument/externs.json
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/output/ConstrainedArgument/externs.json
@@ -0,0 +1,1 @@
+{"efVersion":"0.10.7","efModuleName":["ConstrainedArgument"],"efExports":[{"TypeRef":["MultiWithArgs",[]]},{"TypeRef":["MultiWithoutArgs",[]]},{"TypeRef":["WithArgs",[]]},{"TypeRef":["WithoutArgs",[]]},{"TypeClassRef":"Foo"}],"efImports":[{"eiModule":["Prim"],"eiImportType":{"Implicit":[]},"eiImportedAs":null}],"efFixities":[],"efTypeFixities":[],"efDeclarations":[{"EDType":{"edTypeName":"MultiWithArgs","edTypeKind":{"tag":"NamedKind","contents":[["Prim"],"Type"]},"edTypeDeclarationKind":{"TypeSynonym":[]}}},{"EDTypeSynonym":{"edTypeSynonymName":"MultiWithArgs","edTypeSynonymArguments":[],"edTypeSynonymType":{"tag":"ForAll","contents":["b",{"tag":"ForAll","contents":["a",{"tag":"TypeApp","contents":[{"tag":"TypeApp","contents":[{"tag":"TypeConstructor","contents":[["Prim"],"Function"]},{"tag":"ConstrainedType","contents":[[{"constraintClass":[["ConstrainedArgument"],"Foo"],"constraintArgs":[{"tag":"TypeVar","contents":"a"}],"constraintData":null}],{"tag":"ConstrainedType","contents":[[{"constraintClass":[["ConstrainedArgument"],"Foo"],"constraintArgs":[{"tag":"TypeVar","contents":"b"}],"constraintData":null}],{"tag":"TypeVar","contents":"a"}]}]}]},{"tag":"TypeVar","contents":"a"}]},null]},null]}}},{"EDType":{"edTypeName":"MultiWithoutArgs","edTypeKind":{"tag":"NamedKind","contents":[["Prim"],"Type"]},"edTypeDeclarationKind":{"TypeSynonym":[]}}},{"EDTypeSynonym":{"edTypeSynonymName":"MultiWithoutArgs","edTypeSynonymArguments":[],"edTypeSynonymType":{"tag":"ForAll","contents":["a",{"tag":"TypeApp","contents":[{"tag":"TypeApp","contents":[{"tag":"TypeConstructor","contents":[["Prim"],"Function"]},{"tag":"ConstrainedType","contents":[[{"constraintClass":[["Prim"],"Partial"],"constraintArgs":[],"constraintData":null}],{"tag":"ConstrainedType","contents":[[{"constraintClass":[["Prim"],"Partial"],"constraintArgs":[],"constraintData":null}],{"tag":"TypeVar","contents":"a"}]}]}]},{"tag":"TypeVar","contents":"a"}]},null]}}},{"EDType":{"edTypeName":"WithArgs","edTypeKind":{"tag":"NamedKind","contents":[["Prim"],"Type"]},"edTypeDeclarationKind":{"TypeSynonym":[]}}},{"EDTypeSynonym":{"edTypeSynonymName":"WithArgs","edTypeSynonymArguments":[],"edTypeSynonymType":{"tag":"ForAll","contents":["a",{"tag":"TypeApp","contents":[{"tag":"TypeApp","contents":[{"tag":"TypeConstructor","contents":[["Prim"],"Function"]},{"tag":"ConstrainedType","contents":[[{"constraintClass":[["ConstrainedArgument"],"Foo"],"constraintArgs":[{"tag":"TypeVar","contents":"a"}],"constraintData":null}],{"tag":"TypeVar","contents":"a"}]}]},{"tag":"TypeVar","contents":"a"}]},null]}}},{"EDType":{"edTypeName":"WithoutArgs","edTypeKind":{"tag":"NamedKind","contents":[["Prim"],"Type"]},"edTypeDeclarationKind":{"TypeSynonym":[]}}},{"EDTypeSynonym":{"edTypeSynonymName":"WithoutArgs","edTypeSynonymArguments":[],"edTypeSynonymType":{"tag":"ForAll","contents":["a",{"tag":"TypeApp","contents":[{"tag":"TypeApp","contents":[{"tag":"TypeConstructor","contents":[["Prim"],"Function"]},{"tag":"ConstrainedType","contents":[[{"constraintClass":[["Prim"],"Partial"],"constraintArgs":[],"constraintData":null}],{"tag":"TypeVar","contents":"a"}]}]},{"tag":"TypeVar","contents":"a"}]},null]}}},{"EDType":{"edTypeName":"Foo","edTypeKind":{"tag":"FunKind","contents":[{"tag":"NamedKind","contents":[["Prim"],"Type"]},{"tag":"NamedKind","contents":[["Prim"],"Type"]}]},"edTypeDeclarationKind":{"TypeSynonym":[]}}},{"EDTypeSynonym":{"edTypeSynonymName":"Foo","edTypeSynonymArguments":[["t",null]],"edTypeSynonymType":{"tag":"TypeApp","contents":[{"tag":"TypeConstructor","contents":[["Prim"],"Record"]},{"tag":"REmpty","contents":[]}]}}},{"EDClass":{"edClassName":"Foo","edClassTypeArguments":[["t",null]],"edClassMembers":[],"edClassConstraints":[],"edFunctionalDependencies":[]}}]}
diff --git a/tests/purs/docs/output/ConstrainedArgument/index.js b/tests/purs/docs/output/ConstrainedArgument/index.js
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/output/ConstrainedArgument/index.js
@@ -0,0 +1,5 @@
+"use strict";
+var Foo = {};
+module.exports = {
+    Foo: Foo
+};
diff --git a/tests/purs/docs/resolutions.json b/tests/purs/docs/resolutions.json
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/resolutions.json
@@ -0,0 +1,21 @@
+{
+  "canonicalDir": ".",
+  "pkgMeta": {
+    "dependencies": {
+      "purescript-prelude": "./bower_components/purescript-prelude"
+    }
+  },
+  "dependencies": {
+    "purescript-prelude": {
+      "canonicalDir": "bower_components/purescript-prelude",
+      "pkgMeta": {
+        "_resolution": {
+          "type": "version",
+          "tag": "v2.4.0",
+          "commit": "21067a4c782f42d08bc877214f85b92ce6769b21"
+        }
+      },
+      "dependencies": {}
+    }
+  }
+}
diff --git a/tests/purs/docs/src/ChildDeclOrder.purs b/tests/purs/docs/src/ChildDeclOrder.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/ChildDeclOrder.purs
@@ -0,0 +1,27 @@
+-- Tests should ensure that, in the docs:
+--  - First should come before Second
+--  - foo1 should be listed before foo2
+--  - the instances should be listed in the same order as this source file
+module ChildDeclOrder where
+
+data Two
+  = First
+  | Second
+
+class Show a where
+  show :: a -> String
+
+class Foo a where
+  foo1 :: a
+  foo2 :: a
+
+instance showTwo :: Show Two where
+  show _  = ""
+
+instance fooTwo :: Foo Two where
+  foo1 = First
+  foo2 = Second
+
+instance fooInt :: Foo Int where
+  foo1 = 1
+  foo2 = 2
diff --git a/tests/purs/docs/src/Clash.purs b/tests/purs/docs/src/Clash.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/Clash.purs
@@ -0,0 +1,4 @@
+module Clash (module Clash1) where
+
+import Clash1 as Clash1
+import Clash2 as Clash2
diff --git a/tests/purs/docs/src/Clash1.purs b/tests/purs/docs/src/Clash1.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/Clash1.purs
@@ -0,0 +1,3 @@
+module Clash1 (module Clash1a) where
+
+import Clash1a
diff --git a/tests/purs/docs/src/Clash1a.purs b/tests/purs/docs/src/Clash1a.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/Clash1a.purs
@@ -0,0 +1,9 @@
+module Clash1a where
+
+value :: Int
+value = 0
+
+type Type = Int
+
+class TypeClass a where
+  typeClassMember :: a
diff --git a/tests/purs/docs/src/Clash2.purs b/tests/purs/docs/src/Clash2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/Clash2.purs
@@ -0,0 +1,3 @@
+module Clash2 (module Clash2a) where
+
+import Clash2a
diff --git a/tests/purs/docs/src/Clash2a.purs b/tests/purs/docs/src/Clash2a.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/Clash2a.purs
@@ -0,0 +1,9 @@
+module Clash2a where
+
+value :: String
+value = "hello"
+
+type Type = String
+
+class TypeClass a b where
+  typeClassMember :: a -> b
diff --git a/tests/purs/docs/src/ConstrainedArgument.purs b/tests/purs/docs/src/ConstrainedArgument.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/ConstrainedArgument.purs
@@ -0,0 +1,8 @@
+module ConstrainedArgument where
+
+class Foo t
+
+type WithoutArgs      = forall a. (Partial => a) -> a
+type WithArgs         = forall a. (Foo a => a) -> a
+type MultiWithoutArgs = forall a. (Partial => Partial => a) -> a
+type MultiWithArgs    = forall a b. (Foo a => Foo b => a) -> a
diff --git a/tests/purs/docs/src/DeclOrder.purs b/tests/purs/docs/src/DeclOrder.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/DeclOrder.purs
@@ -0,0 +1,17 @@
+module DeclOrder
+  ( class A
+  , x1
+  , X2
+  , x3
+  , X4
+  , class B
+  ) where
+
+x1 = 0
+x3 = 0
+
+data X2
+data X4
+
+class A
+class B
diff --git a/tests/purs/docs/src/DeclOrderNoExportList.purs b/tests/purs/docs/src/DeclOrderNoExportList.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/DeclOrderNoExportList.purs
@@ -0,0 +1,10 @@
+module DeclOrderNoExportList where
+
+x1 = 0
+x3 = 0
+
+data X2
+data X4
+
+class A
+class B
diff --git a/tests/purs/docs/src/Desugar.purs b/tests/purs/docs/src/Desugar.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/Desugar.purs
@@ -0,0 +1,8 @@
+module Desugar where
+
+data X a b = X a b
+
+test :: forall a b. X (a -> b) a -> b
+test x =
+  let X a b = x
+  in a b
diff --git a/tests/purs/docs/src/DocComments.purs b/tests/purs/docs/src/DocComments.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/DocComments.purs
@@ -0,0 +1,11 @@
+module DocComments where
+
+-- | This declaration has a code block:
+-- |
+-- |     example == 0
+-- |
+-- | Here we are really testing that the leading whitespace is not stripped, as
+-- | this ensures that we don't accidentally change code blocks into normal
+-- | paragraphs.
+example :: Int
+example = 0
diff --git a/tests/purs/docs/src/DuplicateNames.purs b/tests/purs/docs/src/DuplicateNames.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/DuplicateNames.purs
@@ -0,0 +1,9 @@
+module DuplicateNames
+  ( module DuplicateNames
+  , module Prelude
+  ) where
+
+import Prelude (Unit)
+
+unit :: Int
+unit = 0
diff --git a/tests/purs/docs/src/Example.purs b/tests/purs/docs/src/Example.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/Example.purs
@@ -0,0 +1,7 @@
+module Example
+  ( module Prelude
+  , module Example2
+  ) where
+
+import Prelude (Unit())
+import Example2 (one)
diff --git a/tests/purs/docs/src/Example2.purs b/tests/purs/docs/src/Example2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/Example2.purs
@@ -0,0 +1,7 @@
+module Example2 where
+
+one :: Int
+one = 1
+
+two :: Int
+two = 2
diff --git a/tests/purs/docs/src/ExplicitExport.purs b/tests/purs/docs/src/ExplicitExport.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/ExplicitExport.purs
@@ -0,0 +1,7 @@
+module ExplicitExport (one) where
+
+one :: Int
+one = 1
+
+two :: Int
+two = 2
diff --git a/tests/purs/docs/src/ExplicitTypeSignatures.purs b/tests/purs/docs/src/ExplicitTypeSignatures.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/ExplicitTypeSignatures.purs
@@ -0,0 +1,16 @@
+
+module ExplicitTypeSignatures where
+
+-- This should use the explicit type signature so that the type variable name
+-- is preserved.
+explicit :: forall something. something -> something
+explicit x
+  | true = x
+  | false = x
+
+-- This should use the inferred type.
+anInt :: _
+anInt = 0
+
+-- This should infer a type.
+aNumber = 1.0
diff --git a/tests/purs/docs/src/ImportedTwice.purs b/tests/purs/docs/src/ImportedTwice.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/ImportedTwice.purs
@@ -0,0 +1,13 @@
+-- See also an example in the wild: purescript-transformers v0.8.4.
+-- Control.Monad.RWS.Trans re-exports `lift` from both Control.Monad.Trans
+-- (where it is originally defined) and Control.Monad.RWS.Class (which
+-- re-exports it from Control.Monad.Trans).
+
+module ImportedTwice
+  ( module ImportedTwiceA
+  , module ImportedTwiceB
+  )
+  where
+
+import ImportedTwiceA
+import ImportedTwiceB
diff --git a/tests/purs/docs/src/ImportedTwiceA.purs b/tests/purs/docs/src/ImportedTwiceA.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/ImportedTwiceA.purs
@@ -0,0 +1,8 @@
+module ImportedTwiceA
+  ( module ImportedTwiceB )
+  where
+
+import ImportedTwiceB
+
+bar :: Int
+bar = 1
diff --git a/tests/purs/docs/src/ImportedTwiceB.purs b/tests/purs/docs/src/ImportedTwiceB.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/ImportedTwiceB.purs
@@ -0,0 +1,4 @@
+module ImportedTwiceB where
+
+foo :: Int
+foo = 0
diff --git a/tests/purs/docs/src/MultiVirtual.purs b/tests/purs/docs/src/MultiVirtual.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/MultiVirtual.purs
@@ -0,0 +1,6 @@
+module MultiVirtual
+  ( module X )
+  where
+
+import MultiVirtual1 as X
+import MultiVirtual2 as X
diff --git a/tests/purs/docs/src/MultiVirtual1.purs b/tests/purs/docs/src/MultiVirtual1.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/MultiVirtual1.purs
@@ -0,0 +1,4 @@
+module MultiVirtual1 where
+
+foo :: Int
+foo = 1
diff --git a/tests/purs/docs/src/MultiVirtual2.purs b/tests/purs/docs/src/MultiVirtual2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/MultiVirtual2.purs
@@ -0,0 +1,9 @@
+module MultiVirtual2
+  ( module MultiVirtual2
+  , module MultiVirtual3
+  ) where
+
+import MultiVirtual3
+
+bar :: Int
+bar = 2
diff --git a/tests/purs/docs/src/MultiVirtual3.purs b/tests/purs/docs/src/MultiVirtual3.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/MultiVirtual3.purs
@@ -0,0 +1,4 @@
+module MultiVirtual3 where
+
+baz :: Int
+baz = 3
diff --git a/tests/purs/docs/src/NewOperators.purs b/tests/purs/docs/src/NewOperators.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/NewOperators.purs
@@ -0,0 +1,5 @@
+module NewOperators
+  ( module NewOperators2 )
+  where
+
+import NewOperators2
diff --git a/tests/purs/docs/src/NewOperators2.purs b/tests/purs/docs/src/NewOperators2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/NewOperators2.purs
@@ -0,0 +1,6 @@
+module NewOperators2 where
+
+infixl 8 _compose as >>>
+
+_compose :: forall a b c. (b -> c) -> (a -> b) -> (a -> c)
+_compose f g x = f (g x)
diff --git a/tests/purs/docs/src/NotAllCtors.purs b/tests/purs/docs/src/NotAllCtors.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/NotAllCtors.purs
@@ -0,0 +1,5 @@
+module NotAllCtors
+  ( module Prelude )
+  where
+
+import Prelude (Boolean2(True))
diff --git a/tests/purs/docs/src/PrimSubmodules.purs b/tests/purs/docs/src/PrimSubmodules.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/PrimSubmodules.purs
@@ -0,0 +1,11 @@
+module PrimSubmodules (Lol(..), x, y, module O) where
+
+import Prim.Ordering (kind Ordering, LT, EQ, GT) as O
+
+data Lol (a :: O.Ordering) = Lol Int
+
+x :: Lol O.LT
+x = Lol 0
+
+y :: Lol O.EQ
+y = Lol 1
diff --git a/tests/purs/docs/src/ReExportedTypeClass.purs b/tests/purs/docs/src/ReExportedTypeClass.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/ReExportedTypeClass.purs
@@ -0,0 +1,5 @@
+module ReExportedTypeClass
+  ( module SomeTypeClass )
+  where
+
+import SomeTypeClass
diff --git a/tests/purs/docs/src/SolitaryTypeClassMember.purs b/tests/purs/docs/src/SolitaryTypeClassMember.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/SolitaryTypeClassMember.purs
@@ -0,0 +1,6 @@
+module SolitaryTypeClassMember
+  ( module SomeTypeClass )
+  where
+
+import SomeTypeClass (member)
+
diff --git a/tests/purs/docs/src/SomeTypeClass.purs b/tests/purs/docs/src/SomeTypeClass.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/SomeTypeClass.purs
@@ -0,0 +1,5 @@
+
+module SomeTypeClass where
+
+class SomeClass a where
+  member :: a
diff --git a/tests/purs/docs/src/Transitive1.purs b/tests/purs/docs/src/Transitive1.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/Transitive1.purs
@@ -0,0 +1,5 @@
+module Transitive1
+  ( module Transitive2 )
+  where
+
+import Transitive2
diff --git a/tests/purs/docs/src/Transitive2.purs b/tests/purs/docs/src/Transitive2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/Transitive2.purs
@@ -0,0 +1,5 @@
+module Transitive2
+  ( module Transitive3 )
+  where
+
+import Transitive3
diff --git a/tests/purs/docs/src/Transitive3.purs b/tests/purs/docs/src/Transitive3.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/Transitive3.purs
@@ -0,0 +1,4 @@
+module Transitive3 where
+
+transitive3 :: Int
+transitive3 = 0
diff --git a/tests/purs/docs/src/TypeClassWithFunDeps.purs b/tests/purs/docs/src/TypeClassWithFunDeps.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/TypeClassWithFunDeps.purs
@@ -0,0 +1,5 @@
+
+module TypeClassWithFunDeps where
+
+class TypeClassWithFunDeps a b c d e | a b -> c, c -> d e where
+  aMember :: a -> b
diff --git a/tests/purs/docs/src/TypeClassWithoutMembers.purs b/tests/purs/docs/src/TypeClassWithoutMembers.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/TypeClassWithoutMembers.purs
@@ -0,0 +1,5 @@
+module TypeClassWithoutMembers
+  ( module TypeClassWithoutMembersIntermediate )
+  where
+
+import TypeClassWithoutMembersIntermediate
diff --git a/tests/purs/docs/src/TypeClassWithoutMembersIntermediate.purs b/tests/purs/docs/src/TypeClassWithoutMembersIntermediate.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/TypeClassWithoutMembersIntermediate.purs
@@ -0,0 +1,5 @@
+module TypeClassWithoutMembersIntermediate
+  ( module SomeTypeClass )
+  where
+
+import SomeTypeClass (class SomeClass)
diff --git a/tests/purs/docs/src/TypeLevelString.purs b/tests/purs/docs/src/TypeLevelString.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/TypeLevelString.purs
@@ -0,0 +1,9 @@
+module TypeLevelString where
+
+import Prim.TypeError (class Fail, Text)
+
+data Foo
+
+class Bar a
+
+instance fooBar :: Fail (Text "oops") => Bar Foo
diff --git a/tests/purs/docs/src/TypeOpAliases.purs b/tests/purs/docs/src/TypeOpAliases.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/TypeOpAliases.purs
@@ -0,0 +1,44 @@
+module TypeOpAliases where
+
+type AltFn a b = a -> b
+
+infixr 6 type AltFn as ~>
+
+foreign import test1 :: forall a b. a ~> b
+foreign import test2 :: forall a b c. a ~> b ~> c
+foreign import test3 :: forall a b c d. a ~> (b ~> c) ~> d
+foreign import test4 :: forall a b c d. ((a ~> b) ~> c) ~> d
+
+data Tuple a b = Tuple a b
+
+infixl 6 Tuple as ×
+infixl 6 type Tuple as ×
+
+data Either a b = Left a | Right b
+
+infixl 5 type Either as ⊕
+
+third ∷ ∀ a b c. a × b × c → c
+third (a × b × c) = c
+
+class Show a where
+  show :: a -> String
+
+instance showTuple :: Show a => Show (a × b) where
+  show (a × _) = show a
+
+-- Test that precedence is taken into account while desugaring type operators
+
+class TestL a where
+  testL :: a
+
+class TestR a where
+  testR :: a
+
+-- Note: this type is Either Int (Tuple Int String)
+instance testLEither :: TestL (Int ⊕ Int × String) where
+  testL = Right (0 × "hi")
+
+-- Note: this type is Either (Tuple Int Int) String
+instance testREither :: TestR (Int × Int ⊕ String) where
+  testR = Left (0 × 1)
diff --git a/tests/purs/docs/src/UTF8.purs b/tests/purs/docs/src/UTF8.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/UTF8.purs
@@ -0,0 +1,7 @@
+module UTF8 where
+
+import Prelude (Unit, unit)
+
+-- | üÜäÄ 😰
+thing :: Unit
+thing = unit
diff --git a/tests/purs/docs/src/Virtual.purs b/tests/purs/docs/src/Virtual.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/Virtual.purs
@@ -0,0 +1,5 @@
+module Virtual
+  ( module VirtualPrelude )
+  where
+
+import Prelude as VirtualPrelude
diff --git a/tests/purs/failing/1071.purs b/tests/purs/failing/1071.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/1071.purs
@@ -0,0 +1,8 @@
+-- @shouldFailWith KindsDoNotUnify
+module Main where
+
+class Foo a b where
+  foo :: a -> b
+
+bar :: forall a. Foo a => a -> a
+bar a = a
diff --git a/tests/purs/failing/1169.purs b/tests/purs/failing/1169.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/1169.purs
@@ -0,0 +1,12 @@
+-- @shouldFailWith IncorrectConstructorArity 
+module Test where
+
+data Outer a = Outer a
+            
+data Inner a b = Inner a b
+
+test1 :: forall a b. Outer (Inner a b) -> Boolean
+test1 (Outer (Inner _)) = true
+
+test2 :: forall a b. Inner a b -> Boolean
+test2 (Inner _) = true
diff --git a/tests/purs/failing/1175.purs b/tests/purs/failing/1175.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/1175.purs
@@ -0,0 +1,11 @@
+-- @shouldFailWith TypesDoNotUnify
+module X where
+
+class Foo where
+  foo :: String
+
+instance f :: Foo where
+  foo = "a"
+    where
+    bar :: String
+    bar = 1
diff --git a/tests/purs/failing/1310.purs b/tests/purs/failing/1310.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/1310.purs
@@ -0,0 +1,18 @@
+-- @shouldFailWith NoInstanceFound
+
+module Issue1310 where
+
+import Prelude
+import Effect
+import Effect.Console
+
+class Inject f g where
+  inj :: forall a. f a -> g a
+
+instance inject :: Inject f f where
+  inj x = x
+
+newtype Oops a = Oops (Effect a)
+
+main :: Effect Unit
+main = inj (Oops (log "Oops"))
diff --git a/tests/purs/failing/1570.purs b/tests/purs/failing/1570.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/1570.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith ExpectedType
+module M where
+
+data F a = F a
+
+test = \(x :: F) -> x
diff --git a/tests/purs/failing/1733.purs b/tests/purs/failing/1733.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/1733.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith UnknownName
+module Main where
+
+import Thingy as Thing
+
+main = Thing.doesntExist "hi"
diff --git a/tests/purs/failing/1733/Thingy.purs b/tests/purs/failing/1733/Thingy.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/1733/Thingy.purs
@@ -0,0 +1,4 @@
+module Thingy where
+
+foo :: Int
+foo = 1
diff --git a/tests/purs/failing/1825.purs b/tests/purs/failing/1825.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/1825.purs
@@ -0,0 +1,9 @@
+-- @shouldFailWith UnknownName
+
+module Main where
+
+data W = X | Y | Z
+
+bad X a = a
+bad Y _ = a
+bad Z a = a
diff --git a/tests/purs/failing/1881.purs b/tests/purs/failing/1881.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/1881.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith ErrorParsingModule
+module Main where
+
+foo =
+bar :: Int
+bar = 3
diff --git a/tests/purs/failing/2128-class.purs b/tests/purs/failing/2128-class.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/2128-class.purs
@@ -0,0 +1,5 @@
+-- @shouldFailWith ErrorParsingModule
+module Main where
+
+class Foo a where
+  foo :: a -> !!!
diff --git a/tests/purs/failing/2128-instance.purs b/tests/purs/failing/2128-instance.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/2128-instance.purs
@@ -0,0 +1,8 @@
+-- @shouldFailWith ErrorParsingModule
+module Main where
+
+class Foo a where
+  foo :: a
+
+instance fooInt :: Foo Int where
+  foo = !!!
diff --git a/tests/purs/failing/2197-shouldFail.purs b/tests/purs/failing/2197-shouldFail.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/2197-shouldFail.purs
@@ -0,0 +1,10 @@
+-- @shouldFailWith ScopeConflict
+module Main where
+
+import Prim as P
+import Prim (Number)
+
+type Number = P.Number
+
+z :: Number
+z = 0.0
diff --git a/tests/purs/failing/2197-shouldFail2.purs b/tests/purs/failing/2197-shouldFail2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/2197-shouldFail2.purs
@@ -0,0 +1,7 @@
+-- @shouldFailWith UnknownName
+module Main where
+
+import Prim (Boolean)
+
+z :: Number
+z = 0.0
diff --git a/tests/purs/failing/2378.purs b/tests/purs/failing/2378.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/2378.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith OrphanInstance
+module Main where
+
+import Lib
+
+instance fooX :: Foo "x"
diff --git a/tests/purs/failing/2378/Lib.purs b/tests/purs/failing/2378/Lib.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/2378/Lib.purs
@@ -0,0 +1,3 @@
+module Lib (class Foo) where
+
+class Foo (a :: Symbol)
diff --git a/tests/purs/failing/2379.purs b/tests/purs/failing/2379.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/2379.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith UnknownClass
+module Main where
+
+import Lib
+
+test = x [1, 2, 3]
diff --git a/tests/purs/failing/2379/Lib.purs b/tests/purs/failing/2379/Lib.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/2379/Lib.purs
@@ -0,0 +1,9 @@
+module Lib (class X, x) where
+
+class X a where
+  x :: a -> String
+
+class Y a
+
+instance xArray :: Y a => X (Array a) where
+  x _ = "[]"
diff --git a/tests/purs/failing/2434.purs b/tests/purs/failing/2434.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/2434.purs
@@ -0,0 +1,5 @@
+-- @shouldFailWith ErrorParsingModule
+module Main where
+
+x :: Char
+x = '\x10000'
diff --git a/tests/purs/failing/2534.purs b/tests/purs/failing/2534.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/2534.purs
@@ -0,0 +1,8 @@
+-- @shouldFailWith InfiniteType
+module Main where
+
+foo :: Array Int -> Int
+foo xs = go xs where
+  go :: Array _ -> Int
+  go [] = 0
+  go xs = go [xs]
diff --git a/tests/purs/failing/2542.purs b/tests/purs/failing/2542.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/2542.purs
@@ -0,0 +1,9 @@
+-- @shouldFailWith UndefinedTypeVariable
+module Main where
+
+type T = forall a. Array a
+
+foo :: T
+foo = bar where
+  bar :: Array a
+  bar = []
diff --git a/tests/purs/failing/2567.purs b/tests/purs/failing/2567.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/2567.purs
@@ -0,0 +1,7 @@
+-- @shouldFailWith NoInstanceFound
+module Main where
+
+import Prim.TypeError
+
+foo :: Int
+foo = (0 :: Fail (Text "This constraint should be checked") => Int)
diff --git a/tests/purs/failing/2601.purs b/tests/purs/failing/2601.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/2601.purs
@@ -0,0 +1,7 @@
+-- @shouldFailWith KindsDoNotUnify
+module Main where
+
+type Syn (a :: Type -> Type) = String
+
+val :: Syn Int
+val = "bad"
diff --git a/tests/purs/failing/2616.purs b/tests/purs/failing/2616.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/2616.purs
@@ -0,0 +1,9 @@
+-- @shouldFailWith NoInstanceFound
+module Main where
+	
+import Prelude
+
+newtype Foo r = Foo { | r }
+
+derive instance eqFoo :: Eq (Foo r)
+derive instance ordFoo :: Ord (Foo r)
diff --git a/tests/purs/failing/2806.purs b/tests/purs/failing/2806.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/2806.purs
@@ -0,0 +1,7 @@
+-- @shouldFailWith NoInstanceFound
+module X where
+
+data E a b = L a | R b
+
+g :: forall a b . E a b -> a
+g e | L x <- e = x
diff --git a/tests/purs/failing/2874-forall.purs b/tests/purs/failing/2874-forall.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/2874-forall.purs
@@ -0,0 +1,8 @@
+-- @shouldFailWith ErrorParsingModule
+module Main where
+
+class T a b | a -> b
+instance tT :: (T Int (forall a. a)) => T Int String
+
+ddd :: Int
+ddd = 0 :: forall t. T Int t => Int
diff --git a/tests/purs/failing/2874-forall2.purs b/tests/purs/failing/2874-forall2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/2874-forall2.purs
@@ -0,0 +1,10 @@
+-- @shouldFailWith ErrorParsingModule
+module Main where
+
+class X a b | a -> b
+class X a (forall t. t) <= Y a b | a -> b
+instance tX :: X Int String
+instance tY :: Y Int Boolean
+
+ggg :: Int
+ggg = 0 :: forall t. Y Int t => Int
diff --git a/tests/purs/failing/2874-wildcard.purs b/tests/purs/failing/2874-wildcard.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/2874-wildcard.purs
@@ -0,0 +1,11 @@
+-- @shouldFailWith ErrorParsingModule
+module Main where
+
+class Foo a where
+  foo :: a
+
+class Baz b where
+  baz :: b
+
+instance bazFoo :: (Baz _) => Foo b where
+  foo = baz
diff --git a/tests/purs/failing/2947.purs b/tests/purs/failing/2947.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/2947.purs
@@ -0,0 +1,10 @@
+-- @shouldFailWith ErrorParsingModule
+
+module Main where
+
+import Prelude
+
+data Foo = Foo
+
+instance eqFoo :: Eq Foo where
+eq _ _ = true
diff --git a/tests/purs/failing/3132.purs b/tests/purs/failing/3132.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/3132.purs
@@ -0,0 +1,18 @@
+-- @shouldFailWith TransitiveExportError
+module Main (class C3) where
+
+import Prelude
+
+import Effect (Effect)
+import Effect.Console (log)
+
+class C1
+instance inst1 :: C1
+
+class C1 <= C2 a
+
+class (C2 a) <= C3 a b
+
+main :: Effect Unit
+main = do
+  log "Done"
diff --git a/tests/purs/failing/3275-BindingGroupErrorPos.purs b/tests/purs/failing/3275-BindingGroupErrorPos.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/3275-BindingGroupErrorPos.purs
@@ -0,0 +1,12 @@
+-- @shouldFailWith KindsDoNotUnify
+module BindingGroupErrorPos where
+
+-- This isn't really about KindsDoNotUnify, it's about positioning errors
+-- that occur in binding groups
+
+import Prelude
+
+type Result = Array Int
+
+wrong :: Int -> Result String
+wrong n = wrong (n - 1)
diff --git a/tests/purs/failing/3275-DataBindingGroupErrorPos.purs b/tests/purs/failing/3275-DataBindingGroupErrorPos.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/3275-DataBindingGroupErrorPos.purs
@@ -0,0 +1,8 @@
+-- @shouldFailWith KindsDoNotUnify
+module DataBindingGroupErrorPos where
+
+-- This isn't really about KindsDoNotUnify, it's about positioning errors
+-- that occur in data binding groups
+
+data Foo a = Foo (Bar a a)
+data Bar a = Bar (Foo a)
diff --git a/tests/purs/failing/3335-TypeOpAssociativityError.purs b/tests/purs/failing/3335-TypeOpAssociativityError.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/3335-TypeOpAssociativityError.purs
@@ -0,0 +1,7 @@
+-- @shouldFailWith NonAssociativeError
+module Main where
+
+infix 6 type Function as >>
+
+const :: forall a b. a >> b >> a
+const a _ = a
diff --git a/tests/purs/failing/365.purs b/tests/purs/failing/365.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/365.purs
@@ -0,0 +1,14 @@
+-- @shouldFailWith CycleInDeclaration
+module Main where
+
+import Prelude
+
+class C a where
+  f :: a -> a
+  g :: a -> a
+
+instance cS :: C String where
+  f s = s
+  g = f
+
+main = g "Done"
diff --git a/tests/purs/failing/438.purs b/tests/purs/failing/438.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/438.purs
@@ -0,0 +1,15 @@
+-- @shouldFailWith PossiblyInfiniteInstance
+
+-- See issue 438 for details: this test is mainly here to test that code like
+-- this doesn't cause the compiler to loop.
+
+module Main where
+
+import Prelude
+
+data Fix f = In (f (Fix f))
+
+instance eqFix :: (Eq (f (Fix f))) => Eq (Fix f) where
+  eq (In f) (In g) = f == g
+
+example = In [] == In []
diff --git a/tests/purs/failing/881.purs b/tests/purs/failing/881.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/881.purs
@@ -0,0 +1,13 @@
+-- @shouldFailWith DuplicateValueDeclaration
+module Main where
+
+data X = X | Y
+
+class Foo a where
+  foo :: a -> a
+  bar :: a
+
+instance fooX :: Foo X where
+  foo X = X
+  bar = X
+  foo Y = Y
diff --git a/tests/purs/failing/AnonArgument1.purs b/tests/purs/failing/AnonArgument1.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/AnonArgument1.purs
@@ -0,0 +1,5 @@
+-- @shouldFailWith IncorrectAnonymousArgument
+module Main where
+
+test :: Int -> Int
+test = _
diff --git a/tests/purs/failing/AnonArgument2.purs b/tests/purs/failing/AnonArgument2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/AnonArgument2.purs
@@ -0,0 +1,7 @@
+-- @shouldFailWith IncorrectAnonymousArgument
+module Main where
+
+import Prelude
+
+test :: Int -> Int
+test = 1 + 2 * _
diff --git a/tests/purs/failing/AnonArgument3.purs b/tests/purs/failing/AnonArgument3.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/AnonArgument3.purs
@@ -0,0 +1,5 @@
+-- @shouldFailWith IncorrectAnonymousArgument
+module Main where
+
+test :: Int -> Int
+test = 1 + _
diff --git a/tests/purs/failing/ArgLengthMismatch.purs b/tests/purs/failing/ArgLengthMismatch.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ArgLengthMismatch.purs
@@ -0,0 +1,7 @@
+-- @shouldFailWith ArgListLengthsDiffer
+module ArgLengthMismatch where
+
+import Prelude
+
+f x y = true
+f = false
diff --git a/tests/purs/failing/ArrayType.purs b/tests/purs/failing/ArrayType.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ArrayType.purs
@@ -0,0 +1,13 @@
+-- @shouldFailWith TypesDoNotUnify
+
+module Main where
+
+import Prelude
+
+bar :: Number -> Number -> Number
+bar n m = n + m
+
+foo = x `bar` y
+  where
+  x = 1
+  y = []
diff --git a/tests/purs/failing/Arrays.purs b/tests/purs/failing/Arrays.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/Arrays.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith TypesDoNotUnify
+module Main where
+
+foreign import ix :: forall a. Array a -> Int -> a
+
+test = \arr -> arr `ix` (0 `ix` 0)
diff --git a/tests/purs/failing/BindInDo-2.purs b/tests/purs/failing/BindInDo-2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/BindInDo-2.purs
@@ -0,0 +1,9 @@
+-- @shouldFailWith CannotUseBindWithDo
+module Main where
+
+import Prelude
+
+foo = do
+  let bind = 42
+  x <- [4, 5, 6]
+  pure x
diff --git a/tests/purs/failing/BindInDo.purs b/tests/purs/failing/BindInDo.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/BindInDo.purs
@@ -0,0 +1,9 @@
+-- @shouldFailWith CannotUseBindWithDo
+module Main where
+
+import Prelude
+
+foo = do
+  bind <- [1,2,3]
+  x <- [4, 5, 6]
+  pure x
diff --git a/tests/purs/failing/CannotDeriveNewtypeForData.purs b/tests/purs/failing/CannotDeriveNewtypeForData.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/CannotDeriveNewtypeForData.purs
@@ -0,0 +1,8 @@
+-- @shouldFailWith CannotDeriveNewtypeForData
+module CannotDeriveNewtypeForData where
+
+import Data.Newtype
+
+data Test = Test String
+
+derive instance newtypeTest :: Newtype Test _
diff --git a/tests/purs/failing/CaseBinderLengthsDiffer.purs b/tests/purs/failing/CaseBinderLengthsDiffer.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/CaseBinderLengthsDiffer.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith CaseBinderLengthDiffers
+module Main where
+
+test = case 1, 2 of
+  1, 2, 3 -> 42
+  _, _    -> 43
diff --git a/tests/purs/failing/CaseDoesNotMatchAllConstructorArgs.purs b/tests/purs/failing/CaseDoesNotMatchAllConstructorArgs.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/CaseDoesNotMatchAllConstructorArgs.purs
@@ -0,0 +1,15 @@
+-- @shouldFailWith IncorrectConstructorArity
+module Main where
+
+import Prelude
+
+data Person = Person String Int
+
+data TwoPeople = Two Person Person
+
+getName p = case p of
+  (Two (Person n) (Person n2 a2)) -> n
+  _ -> "Unknown"
+
+
+name = getName (Two (Person "Jimmy" 20) (Person "" 1))
diff --git a/tests/purs/failing/ConflictingExports.purs b/tests/purs/failing/ConflictingExports.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ConflictingExports.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith ScopeConflict
+-- Fails here because re-exporting forces any scope conflicts to be resolved
+module Main (module A, module B) where
+
+  import A
+  import B
diff --git a/tests/purs/failing/ConflictingExports/A.purs b/tests/purs/failing/ConflictingExports/A.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ConflictingExports/A.purs
@@ -0,0 +1,4 @@
+module A where
+
+thing :: Int
+thing = 1
diff --git a/tests/purs/failing/ConflictingExports/B.purs b/tests/purs/failing/ConflictingExports/B.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ConflictingExports/B.purs
@@ -0,0 +1,4 @@
+module B where
+
+thing :: Int
+thing = 2
diff --git a/tests/purs/failing/ConflictingImports.purs b/tests/purs/failing/ConflictingImports.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ConflictingImports.purs
@@ -0,0 +1,9 @@
+-- @shouldFailWith ScopeConflict
+module Main where
+
+import A
+import B
+
+-- Error due to referencing `thing` which is in scope as A.thing and B.thing
+what :: Int
+what = thing
diff --git a/tests/purs/failing/ConflictingImports/A.purs b/tests/purs/failing/ConflictingImports/A.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ConflictingImports/A.purs
@@ -0,0 +1,4 @@
+module A where
+
+thing :: Int
+thing = 1
diff --git a/tests/purs/failing/ConflictingImports/B.purs b/tests/purs/failing/ConflictingImports/B.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ConflictingImports/B.purs
@@ -0,0 +1,4 @@
+module B where
+
+thing :: Int
+thing = 2
diff --git a/tests/purs/failing/ConflictingImports2.purs b/tests/purs/failing/ConflictingImports2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ConflictingImports2.purs
@@ -0,0 +1,10 @@
+-- @shouldFailWith ScopeConflict
+module Main where
+
+import A (thing)
+import B (thing)
+
+-- Error due to referencing `thing` which is explicitly in scope as A.thing
+-- and B.thing
+what :: Int
+what = thing
diff --git a/tests/purs/failing/ConflictingImports2/A.purs b/tests/purs/failing/ConflictingImports2/A.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ConflictingImports2/A.purs
@@ -0,0 +1,4 @@
+module A where
+
+thing :: Int
+thing = 1
diff --git a/tests/purs/failing/ConflictingImports2/B.purs b/tests/purs/failing/ConflictingImports2/B.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ConflictingImports2/B.purs
@@ -0,0 +1,4 @@
+module B where
+
+thing :: Int
+thing = 2
diff --git a/tests/purs/failing/ConflictingQualifiedImports.purs b/tests/purs/failing/ConflictingQualifiedImports.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ConflictingQualifiedImports.purs
@@ -0,0 +1,7 @@
+-- @shouldFailWith ScopeConflict
+module Main where
+
+import A as X
+import B as X
+
+foo = X.thing
diff --git a/tests/purs/failing/ConflictingQualifiedImports/A.purs b/tests/purs/failing/ConflictingQualifiedImports/A.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ConflictingQualifiedImports/A.purs
@@ -0,0 +1,4 @@
+module A where
+
+thing :: Int
+thing = 1
diff --git a/tests/purs/failing/ConflictingQualifiedImports/B.purs b/tests/purs/failing/ConflictingQualifiedImports/B.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ConflictingQualifiedImports/B.purs
@@ -0,0 +1,4 @@
+module B where
+
+thing :: Int
+thing = 2
diff --git a/tests/purs/failing/ConflictingQualifiedImports2.purs b/tests/purs/failing/ConflictingQualifiedImports2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ConflictingQualifiedImports2.purs
@@ -0,0 +1,5 @@
+-- @shouldFailWith ScopeConflict
+module Main (module X) where
+
+import A as X
+import B as X
diff --git a/tests/purs/failing/ConflictingQualifiedImports2/A.purs b/tests/purs/failing/ConflictingQualifiedImports2/A.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ConflictingQualifiedImports2/A.purs
@@ -0,0 +1,4 @@
+module A where
+
+thing :: Int
+thing = 1
diff --git a/tests/purs/failing/ConflictingQualifiedImports2/B.purs b/tests/purs/failing/ConflictingQualifiedImports2/B.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ConflictingQualifiedImports2/B.purs
@@ -0,0 +1,4 @@
+module B where
+
+thing :: Int
+thing = 2
diff --git a/tests/purs/failing/ConstraintFailure.purs b/tests/purs/failing/ConstraintFailure.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ConstraintFailure.purs
@@ -0,0 +1,13 @@
+-- @shouldFailWith NoInstanceFound
+
+module Main where
+
+import Prelude
+
+data Foo = Bar
+       
+spin :: forall a. a -> Foo
+spin x = Bar
+
+main = show <<< spin
+     
diff --git a/tests/purs/failing/ConstraintInference.purs b/tests/purs/failing/ConstraintInference.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ConstraintInference.purs
@@ -0,0 +1,10 @@
+-- @shouldFailWith AmbiguousTypeVariables
+
+module Main where
+
+import Prelude
+
+spin :: forall a b. a -> b
+spin x = spin x
+
+test = show <<< spin
diff --git a/tests/purs/failing/DctorOperatorAliasExport.purs b/tests/purs/failing/DctorOperatorAliasExport.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/DctorOperatorAliasExport.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith TransitiveDctorExportError
+module Data.List (List, (:)) where
+
+  data List a = Cons a (List a) | Nil
+
+  infixr 6 Cons as :
diff --git a/tests/purs/failing/DeclConflictClassCtor.purs b/tests/purs/failing/DeclConflictClassCtor.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/DeclConflictClassCtor.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith DeclConflict
+module Main where
+
+data T = Fail
+
+class Fail
diff --git a/tests/purs/failing/DeclConflictClassSynonym.purs b/tests/purs/failing/DeclConflictClassSynonym.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/DeclConflictClassSynonym.purs
@@ -0,0 +1,8 @@
+-- @shouldFailWith DeclConflict
+module Main where
+
+import Prelude
+
+type Fail = Unit
+
+class Fail
diff --git a/tests/purs/failing/DeclConflictClassType.purs b/tests/purs/failing/DeclConflictClassType.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/DeclConflictClassType.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith DeclConflict
+module Main where
+
+class Fail
+
+data Fail
diff --git a/tests/purs/failing/DeclConflictCtorClass.purs b/tests/purs/failing/DeclConflictCtorClass.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/DeclConflictCtorClass.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith DeclConflict
+module Main where
+
+class Fail
+
+data T = Fail
diff --git a/tests/purs/failing/DeclConflictCtorCtor.purs b/tests/purs/failing/DeclConflictCtorCtor.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/DeclConflictCtorCtor.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith DeclConflict
+module Main where
+
+data T1 = Fail
+
+data T2 = Fail
diff --git a/tests/purs/failing/DeclConflictDuplicateCtor.purs b/tests/purs/failing/DeclConflictDuplicateCtor.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/DeclConflictDuplicateCtor.purs
@@ -0,0 +1,5 @@
+-- @shouldFailWith DeclConflict
+module Main where
+
+data T = Fail | Fail
+
diff --git a/tests/purs/failing/DeclConflictSynonymClass.purs b/tests/purs/failing/DeclConflictSynonymClass.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/DeclConflictSynonymClass.purs
@@ -0,0 +1,8 @@
+-- @shouldFailWith DeclConflict
+module Main where
+
+import Prelude
+
+class Fail
+
+type Fail = Unit
diff --git a/tests/purs/failing/DeclConflictSynonymType.purs b/tests/purs/failing/DeclConflictSynonymType.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/DeclConflictSynonymType.purs
@@ -0,0 +1,8 @@
+-- @shouldFailWith DeclConflict
+module Main where
+
+import Prelude
+
+data Fail
+
+type Fail = Unit
diff --git a/tests/purs/failing/DeclConflictTypeClass.purs b/tests/purs/failing/DeclConflictTypeClass.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/DeclConflictTypeClass.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith DeclConflict
+module Main where
+
+class Fail
+
+data Fail
diff --git a/tests/purs/failing/DeclConflictTypeSynonym.purs b/tests/purs/failing/DeclConflictTypeSynonym.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/DeclConflictTypeSynonym.purs
@@ -0,0 +1,8 @@
+-- @shouldFailWith DeclConflict
+module Main where
+
+import Prelude
+
+type Fail = Unit
+
+data Fail
diff --git a/tests/purs/failing/DeclConflictTypeType.purs b/tests/purs/failing/DeclConflictTypeType.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/DeclConflictTypeType.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith DeclConflict
+module Main where
+
+data Fail
+
+data Fail
diff --git a/tests/purs/failing/DiffKindsSameName.purs b/tests/purs/failing/DiffKindsSameName.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/DiffKindsSameName.purs
@@ -0,0 +1,15 @@
+-- @shouldFailWith KindsDoNotUnify
+module DiffKindsSameName where
+
+import DiffKindsSameName.LibA as LibA
+import DiffKindsSameName.LibB as LibB
+
+-- both `LibA` and `LibB` define a kind locally called `DemoKind`
+-- `LibB` defines `DemoData :: LibB.DemoKind`
+-- if we try to use `DemoData` in a place where `LibA.DemoKind` is expected, it should fail with `KindsDoNotUnify`
+
+data AProxy (m :: LibA.DemoKind) = AProxy
+
+bProxy :: AProxy LibB.DemoData
+bProxy = AProxy
+
diff --git a/tests/purs/failing/DiffKindsSameName/LibA.purs b/tests/purs/failing/DiffKindsSameName/LibA.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/DiffKindsSameName/LibA.purs
@@ -0,0 +1,4 @@
+module DiffKindsSameName.LibA where
+
+foreign import kind DemoKind
+
diff --git a/tests/purs/failing/DiffKindsSameName/LibB.purs b/tests/purs/failing/DiffKindsSameName/LibB.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/DiffKindsSameName/LibB.purs
@@ -0,0 +1,6 @@
+module DiffKindsSameName.LibB where
+
+foreign import kind DemoKind
+
+foreign import data DemoData :: DemoKind
+
diff --git a/tests/purs/failing/Do.purs b/tests/purs/failing/Do.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/Do.purs
@@ -0,0 +1,12 @@
+-- @shouldFailWith InvalidDoBind
+-- @shouldFailWith InvalidDoLet
+module Main where
+
+import Prelude
+
+test1 = do let x = 1
+
+test2 y = do x <- y
+
+test3 = do pure 1
+           pure 2
diff --git a/tests/purs/failing/DoNotSuggestComposition.purs b/tests/purs/failing/DoNotSuggestComposition.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/DoNotSuggestComposition.purs
@@ -0,0 +1,13 @@
+-- @shouldFailWith TypesDoNotUnify
+-- TODO: Check that this does not produce a "function composition is (<<<)"
+-- suggestion.
+module DoNotSuggestComposition where
+
+import Prelude
+
+x = { y: 3 }
+
+foo :: String -> String
+foo y = y
+
+bar = foo x
diff --git a/tests/purs/failing/DoNotSuggestComposition2.purs b/tests/purs/failing/DoNotSuggestComposition2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/DoNotSuggestComposition2.purs
@@ -0,0 +1,7 @@
+-- @shouldFailWith TypesDoNotUnify
+-- TODO: Check that this does not produce a "function composition is (<<<)"
+-- suggestion.
+
+module DoNotSuggestComposition2 where
+
+foo = let x = { y: 3 } in x 2
diff --git a/tests/purs/failing/DuplicateDeclarationsInLet.purs b/tests/purs/failing/DuplicateDeclarationsInLet.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/DuplicateDeclarationsInLet.purs
@@ -0,0 +1,12 @@
+-- @shouldFailWith OverlappingNamesInLet
+module Main where
+
+import Prelude
+
+foo = a
+  where
+  a :: Number
+  a = 1
+
+  a :: Number
+  a = 2
diff --git a/tests/purs/failing/DuplicateInstance.purs b/tests/purs/failing/DuplicateInstance.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/DuplicateInstance.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith DuplicateInstance
+module Main where
+class X
+class Y
+instance i :: X
+instance i :: Y
diff --git a/tests/purs/failing/DuplicateModule.purs b/tests/purs/failing/DuplicateModule.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/DuplicateModule.purs
@@ -0,0 +1,2 @@
+-- @shouldFailWith DuplicateModule
+module M1 where
diff --git a/tests/purs/failing/DuplicateModule/M1.purs b/tests/purs/failing/DuplicateModule/M1.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/DuplicateModule/M1.purs
@@ -0,0 +1,1 @@
+module M1 where
diff --git a/tests/purs/failing/DuplicateProperties.purs b/tests/purs/failing/DuplicateProperties.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/DuplicateProperties.purs
@@ -0,0 +1,12 @@
+-- @shouldFailWith TypesDoNotUnify
+module DuplicateProperties where
+
+import Prelude
+
+foreign import data Test :: # Type -> Type
+
+foreign import subtractX :: forall r. Test (x :: Unit | r) -> Test r
+
+foreign import hasX :: Test (x :: Unit, y :: Unit)
+
+baz = subtractX (subtractX hasX)
diff --git a/tests/purs/failing/DuplicateTypeClass.purs b/tests/purs/failing/DuplicateTypeClass.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/DuplicateTypeClass.purs
@@ -0,0 +1,4 @@
+-- @shouldFailWith DuplicateTypeClass
+module Main where
+class C
+class C
diff --git a/tests/purs/failing/DuplicateTypeVars.purs b/tests/purs/failing/DuplicateTypeVars.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/DuplicateTypeVars.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith DuplicateTypeArgument
+module Main where
+
+import Prelude
+
+type Foo a a = a
diff --git a/tests/purs/failing/EmptyCase.purs b/tests/purs/failing/EmptyCase.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/EmptyCase.purs
@@ -0,0 +1,4 @@
+-- @shouldFailWith ErrorParsingModule
+module Main where
+
+error err = case err of \_ -> 1
diff --git a/tests/purs/failing/EmptyClass.purs b/tests/purs/failing/EmptyClass.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/EmptyClass.purs
@@ -0,0 +1,7 @@
+-- @shouldFailWith ErrorParsingModule
+module Main where
+
+class Foo x where
+
+bar :: String
+bar = "hello"
diff --git a/tests/purs/failing/EmptyDo.purs b/tests/purs/failing/EmptyDo.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/EmptyDo.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith ErrorParsingModule
+
+module Main where
+
+main = do
+
diff --git a/tests/purs/failing/ExpectedWildcard.purs b/tests/purs/failing/ExpectedWildcard.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ExpectedWildcard.purs
@@ -0,0 +1,8 @@
+-- @shouldFailWith ExpectedWildcard
+module ExpectedWildcard where
+
+import Data.Newtype
+
+data Test = Test String
+
+derive instance newtypeTest :: Newtype Test String
diff --git a/tests/purs/failing/ExportConflictClass.purs b/tests/purs/failing/ExportConflictClass.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ExportConflictClass.purs
@@ -0,0 +1,5 @@
+-- @shouldFailWith ExportConflict
+module C (module A, module B) where
+
+import A as A
+import B as B
diff --git a/tests/purs/failing/ExportConflictClass/A.purs b/tests/purs/failing/ExportConflictClass/A.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ExportConflictClass/A.purs
@@ -0,0 +1,3 @@
+module A where
+
+class X
diff --git a/tests/purs/failing/ExportConflictClass/B.purs b/tests/purs/failing/ExportConflictClass/B.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ExportConflictClass/B.purs
@@ -0,0 +1,3 @@
+module B where
+
+class X
diff --git a/tests/purs/failing/ExportConflictCtor.purs b/tests/purs/failing/ExportConflictCtor.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ExportConflictCtor.purs
@@ -0,0 +1,5 @@
+-- @shouldFailWith ExportConflict
+module C (module A, module B) where
+
+import A as A
+import B as B
diff --git a/tests/purs/failing/ExportConflictCtor/A.purs b/tests/purs/failing/ExportConflictCtor/A.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ExportConflictCtor/A.purs
@@ -0,0 +1,3 @@
+module A where
+
+data T1 = X
diff --git a/tests/purs/failing/ExportConflictCtor/B.purs b/tests/purs/failing/ExportConflictCtor/B.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ExportConflictCtor/B.purs
@@ -0,0 +1,3 @@
+module B where
+
+data T2 = X
diff --git a/tests/purs/failing/ExportConflictType.purs b/tests/purs/failing/ExportConflictType.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ExportConflictType.purs
@@ -0,0 +1,5 @@
+-- @shouldFailWith ExportConflict
+module C (module A, module B) where
+
+import A as A
+import B as B
diff --git a/tests/purs/failing/ExportConflictType/A.purs b/tests/purs/failing/ExportConflictType/A.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ExportConflictType/A.purs
@@ -0,0 +1,3 @@
+module A where
+
+data T
diff --git a/tests/purs/failing/ExportConflictType/B.purs b/tests/purs/failing/ExportConflictType/B.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ExportConflictType/B.purs
@@ -0,0 +1,3 @@
+module B where
+
+data T
diff --git a/tests/purs/failing/ExportConflictTypeOp.purs b/tests/purs/failing/ExportConflictTypeOp.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ExportConflictTypeOp.purs
@@ -0,0 +1,5 @@
+-- @shouldFailWith ExportConflict
+module C (module A, module B) where
+
+import A as A
+import B as B
diff --git a/tests/purs/failing/ExportConflictTypeOp/A.purs b/tests/purs/failing/ExportConflictTypeOp/A.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ExportConflictTypeOp/A.purs
@@ -0,0 +1,5 @@
+module A where
+
+type T1 a b = a -> b
+
+infixr 4 type T1 as ??
diff --git a/tests/purs/failing/ExportConflictTypeOp/B.purs b/tests/purs/failing/ExportConflictTypeOp/B.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ExportConflictTypeOp/B.purs
@@ -0,0 +1,5 @@
+module B where
+
+type T2 a b = a -> b
+
+infixr 4 type T2 as ??
diff --git a/tests/purs/failing/ExportConflictValue.purs b/tests/purs/failing/ExportConflictValue.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ExportConflictValue.purs
@@ -0,0 +1,5 @@
+-- @shouldFailWith ExportConflict
+module C (module A, module B) where
+
+import A as A
+import B as B
diff --git a/tests/purs/failing/ExportConflictValue/A.purs b/tests/purs/failing/ExportConflictValue/A.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ExportConflictValue/A.purs
@@ -0,0 +1,4 @@
+module A where
+
+x :: Boolean
+x = true
diff --git a/tests/purs/failing/ExportConflictValue/B.purs b/tests/purs/failing/ExportConflictValue/B.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ExportConflictValue/B.purs
@@ -0,0 +1,4 @@
+module B where
+
+x :: Boolean
+x = false
diff --git a/tests/purs/failing/ExportConflictValueOp.purs b/tests/purs/failing/ExportConflictValueOp.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ExportConflictValueOp.purs
@@ -0,0 +1,5 @@
+-- @shouldFailWith ExportConflict
+module C (module A, module B) where
+
+import A as A
+import B as B
diff --git a/tests/purs/failing/ExportConflictValueOp/A.purs b/tests/purs/failing/ExportConflictValueOp/A.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ExportConflictValueOp/A.purs
@@ -0,0 +1,6 @@
+module A where
+
+f1 :: forall a b. a -> b -> a
+f1 x _ = x
+
+infix 0 f1 as !!
diff --git a/tests/purs/failing/ExportConflictValueOp/B.purs b/tests/purs/failing/ExportConflictValueOp/B.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ExportConflictValueOp/B.purs
@@ -0,0 +1,6 @@
+module B where
+
+f2 :: forall a b. a -> b -> a
+f2 x _ = x
+
+infix 0 f2 as !!
diff --git a/tests/purs/failing/ExportExplicit.purs b/tests/purs/failing/ExportExplicit.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ExportExplicit.purs
@@ -0,0 +1,8 @@
+-- @shouldFailWith UnknownExport
+-- should fail as z does not exist in the module
+module M1 (x, y, z) where
+
+import Prelude
+
+x = 1
+y = 2
diff --git a/tests/purs/failing/ExportExplicit1.purs b/tests/purs/failing/ExportExplicit1.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ExportExplicit1.purs
@@ -0,0 +1,12 @@
+-- @shouldFailWith UnknownName
+module Main where
+
+import M1
+import Effect.Console (log)
+
+testX = X
+
+-- should fail as Y constructor is not exported from M1
+testY = Y
+
+main = log "Done"
diff --git a/tests/purs/failing/ExportExplicit1/M1.purs b/tests/purs/failing/ExportExplicit1/M1.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ExportExplicit1/M1.purs
@@ -0,0 +1,3 @@
+module M1 (X(X)) where
+
+data X = X | Y
diff --git a/tests/purs/failing/ExportExplicit2.purs b/tests/purs/failing/ExportExplicit2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ExportExplicit2.purs
@@ -0,0 +1,8 @@
+-- @shouldFailWith UnknownExportDataConstructor
+-- should fail as Y is not a data constructor for X
+module M1 (X(Y)) where
+
+import Prelude
+
+data X = X
+data Y = Y
diff --git a/tests/purs/failing/ExportExplicit3.purs b/tests/purs/failing/ExportExplicit3.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ExportExplicit3.purs
@@ -0,0 +1,10 @@
+-- @shouldFailWith UnknownName
+module Main where
+
+import M1 as M
+import Effect.Console (log)
+
+-- should fail as Z is not exported from M1
+testZ = M.Z
+
+main = log "Done"
diff --git a/tests/purs/failing/ExportExplicit3/M1.purs b/tests/purs/failing/ExportExplicit3/M1.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ExportExplicit3/M1.purs
@@ -0,0 +1,4 @@
+module M1 (X(..)) where
+
+data X = X | Y
+data Z = Z
diff --git a/tests/purs/failing/ExtraRecordField.purs b/tests/purs/failing/ExtraRecordField.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ExtraRecordField.purs
@@ -0,0 +1,9 @@
+-- @shouldFailWith AdditionalProperty
+module ExtraRecordField where
+
+import Prelude ((<>))
+
+full :: { first :: String, last :: String } -> String
+full p = p.first <> " " <> p.last
+
+oops = full { first: "Jane", last: "Smith", age: 29 }
diff --git a/tests/purs/failing/ExtraneousClassMember.purs b/tests/purs/failing/ExtraneousClassMember.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ExtraneousClassMember.purs
@@ -0,0 +1,11 @@
+-- @shouldFailWith ExtraneousClassMember
+module Main where
+
+import Prelude
+
+class A a where
+  a :: a -> String
+
+instance aString :: A String where
+  a s = s
+  b x = x
diff --git a/tests/purs/failing/Foldable.purs b/tests/purs/failing/Foldable.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/Foldable.purs
@@ -0,0 +1,17 @@
+-- @shouldFailWith CycleInDeclaration
+module Main where
+
+import Prelude
+
+class Foldable f where
+  fold :: forall a b. (a -> b -> b) -> b -> f a -> b
+  size :: forall a. f a -> Number
+
+data L a = C a (L a) | N
+
+instance foldableL :: Foldable L where
+  fold _ z N = z
+  fold f z (C x xs) = x `f` (fold f z xs)
+  size = fold (const ((+) 1.0)) 0.0
+
+x = size (C 1 (C 2 (C 3 N)))
diff --git a/tests/purs/failing/Generalization1.purs b/tests/purs/failing/Generalization1.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/Generalization1.purs
@@ -0,0 +1,11 @@
+-- @shouldFailWith CannotGeneralizeRecursiveFunction
+module Main where
+
+import Prelude
+
+foo 0 x _ = x
+foo n x y = x <> bar (n - 1) x y
+
+bar 0 x _ = x
+bar n x y = y <> foo (n - 1) x y
+
diff --git a/tests/purs/failing/Generalization2.purs b/tests/purs/failing/Generalization2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/Generalization2.purs
@@ -0,0 +1,8 @@
+-- @shouldFailWith CannotGeneralizeRecursiveFunction
+module Main where
+
+import Prelude
+
+test n m | n <= 1 = m
+         | otherwise = test (n - 1) (m <> m)
+
diff --git a/tests/purs/failing/ImportExplicit.purs b/tests/purs/failing/ImportExplicit.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ImportExplicit.purs
@@ -0,0 +1,4 @@
+-- @shouldFailWith UnknownImport
+module Main where
+
+import M1 (X(..))
diff --git a/tests/purs/failing/ImportExplicit/M1.purs b/tests/purs/failing/ImportExplicit/M1.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ImportExplicit/M1.purs
@@ -0,0 +1,3 @@
+module M1 where
+
+foo = "foo"
diff --git a/tests/purs/failing/ImportExplicit2.purs b/tests/purs/failing/ImportExplicit2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ImportExplicit2.purs
@@ -0,0 +1,4 @@
+-- @shouldFailWith UnknownImportDataConstructor
+module Main where
+
+import M1 (X(Z, Q))
diff --git a/tests/purs/failing/ImportExplicit2/M1.purs b/tests/purs/failing/ImportExplicit2/M1.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ImportExplicit2/M1.purs
@@ -0,0 +1,3 @@
+module M1 where
+
+data X = Y
diff --git a/tests/purs/failing/ImportHidingModule.purs b/tests/purs/failing/ImportHidingModule.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ImportHidingModule.purs
@@ -0,0 +1,4 @@
+-- @shouldFailWith ImportHidingModule
+module Main where
+
+import B hiding (module A)
diff --git a/tests/purs/failing/ImportHidingModule/A.purs b/tests/purs/failing/ImportHidingModule/A.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ImportHidingModule/A.purs
@@ -0,0 +1,2 @@
+module A where
+x = 1
diff --git a/tests/purs/failing/ImportHidingModule/B.purs b/tests/purs/failing/ImportHidingModule/B.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ImportHidingModule/B.purs
@@ -0,0 +1,3 @@
+module B (module B, module A) where
+import A
+y = 1
diff --git a/tests/purs/failing/ImportModule.purs b/tests/purs/failing/ImportModule.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ImportModule.purs
@@ -0,0 +1,4 @@
+-- @shouldFailWith ModuleNotFound
+module Main where
+
+import M1
diff --git a/tests/purs/failing/ImportModule/M2.purs b/tests/purs/failing/ImportModule/M2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ImportModule/M2.purs
@@ -0,0 +1,3 @@
+module M2 where
+
+data X = X
diff --git a/tests/purs/failing/InfiniteKind.purs b/tests/purs/failing/InfiniteKind.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/InfiniteKind.purs
@@ -0,0 +1,5 @@
+-- @shouldFailWith InfiniteKind 
+
+module Main where
+
+data F a = F (a a)
diff --git a/tests/purs/failing/InfiniteKind2.purs b/tests/purs/failing/InfiniteKind2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/InfiniteKind2.purs
@@ -0,0 +1,5 @@
+-- @shouldFailWith InfiniteKind
+
+module InfiniteKind2 where
+
+data Tree m a = Tree a (m (Tree a))
diff --git a/tests/purs/failing/InfiniteType.purs b/tests/purs/failing/InfiniteType.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/InfiniteType.purs
@@ -0,0 +1,5 @@
+-- @shouldFailWith InfiniteType 
+
+module Main where
+
+f a = a a
diff --git a/tests/purs/failing/InstanceChainBothUnknownAndMatch.purs b/tests/purs/failing/InstanceChainBothUnknownAndMatch.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/InstanceChainBothUnknownAndMatch.purs
@@ -0,0 +1,18 @@
+-- @shouldFailWith NoInstanceFound
+module InstanceChains.BothUnknownAndMatch where
+
+import Type.Proxy (Proxy)
+import Type.Row (RProxy(..))
+import Data.Symbol (SProxy(..))
+
+class Same l r (o :: Symbol) | l r -> o
+instance sameY :: Same t t "Y" else instance sameN :: Same l r "N"
+same :: forall l r o. Same l r o => l -> r -> SProxy o
+same _ _ = SProxy
+
+-- for label `u`, `t ~ Int` should be Unknown
+-- for label `m`, `Int ~ Int` should be a match
+-- together they should be Unknown
+example :: forall t. Proxy t -> SProxy _
+example _ = same (RProxy :: RProxy (u :: t, m :: Int))
+                 (RProxy :: RProxy (u :: Int, m :: Int))
diff --git a/tests/purs/failing/InstanceChainSkolemUnknownMatch.purs b/tests/purs/failing/InstanceChainSkolemUnknownMatch.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/InstanceChainSkolemUnknownMatch.purs
@@ -0,0 +1,15 @@
+-- @shouldFailWith NoInstanceFound
+module InstanceChainSkolemUnknownMatch where
+
+import Type.Proxy (Proxy(..))
+import Data.Symbol (SProxy(..))
+
+class Same l r (o :: Symbol) | l r -> o
+instance sameY :: Same t t "Y" else instance sameN :: Same l r "N"
+same :: forall l r o. Same l r o => l -> r -> SProxy o
+same _ _ = SProxy
+
+-- shouldn't discard sameY as Apart
+example :: forall t. Proxy t -> SProxy _
+example _ = same (Proxy :: Proxy t) (Proxy :: Proxy Int)
+
diff --git a/tests/purs/failing/InstanceExport.purs b/tests/purs/failing/InstanceExport.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/InstanceExport.purs
@@ -0,0 +1,7 @@
+-- @shouldFailWith TransitiveExportError
+module Test where
+
+import InstanceExport
+import Prelude
+
+test = f $ S "Test"
diff --git a/tests/purs/failing/InstanceExport/InstanceExport.purs b/tests/purs/failing/InstanceExport/InstanceExport.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/InstanceExport/InstanceExport.purs
@@ -0,0 +1,11 @@
+module InstanceExport (S(..), f) where
+
+import Prelude
+
+newtype S = S String
+
+class F a where
+  f :: a -> String
+
+instance fs :: F S where
+  f (S s) = s
diff --git a/tests/purs/failing/InstanceSigsBodyIncorrect.purs b/tests/purs/failing/InstanceSigsBodyIncorrect.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/InstanceSigsBodyIncorrect.purs
@@ -0,0 +1,10 @@
+-- @shouldFailWith TypesDoNotUnify
+
+module Main where
+
+class Foo a where
+  foo :: a
+
+instance fooNumber :: Foo Number where
+  foo :: Number
+  foo = true
diff --git a/tests/purs/failing/InstanceSigsDifferentTypes.purs b/tests/purs/failing/InstanceSigsDifferentTypes.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/InstanceSigsDifferentTypes.purs
@@ -0,0 +1,10 @@
+-- @shouldFailWith TypesDoNotUnify
+
+module Main where
+
+class Foo a where
+  foo :: a
+
+instance fooNumber :: Foo Number where
+  foo :: Int
+  foo = 0.0
diff --git a/tests/purs/failing/InstanceSigsIncorrectType.purs b/tests/purs/failing/InstanceSigsIncorrectType.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/InstanceSigsIncorrectType.purs
@@ -0,0 +1,10 @@
+-- @shouldFailWith TypesDoNotUnify
+
+module Main where
+
+class Foo a where
+  foo :: a
+
+instance fooNumber :: Foo Number where
+  foo :: Boolean
+  foo = true
diff --git a/tests/purs/failing/InstanceSigsOrphanTypeDeclaration.purs b/tests/purs/failing/InstanceSigsOrphanTypeDeclaration.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/InstanceSigsOrphanTypeDeclaration.purs
@@ -0,0 +1,10 @@
+-- @shouldFailWith OrphanTypeDeclaration
+
+module Main where
+
+class Foo a where
+  foo :: a
+
+instance fooNumber :: Foo Number where
+  bar :: Int
+  foo = 0.0
diff --git a/tests/purs/failing/IntOutOfRange.purs b/tests/purs/failing/IntOutOfRange.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/IntOutOfRange.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith IntOutOfRange
+
+module Main where
+
+n :: Int
+n = 2147483648
diff --git a/tests/purs/failing/InvalidDerivedInstance.purs b/tests/purs/failing/InvalidDerivedInstance.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/InvalidDerivedInstance.purs
@@ -0,0 +1,8 @@
+-- @shouldFailWith InvalidDerivedInstance
+module Main where
+
+import Prelude
+
+data X = X
+
+derive instance eqX :: Eq X X
diff --git a/tests/purs/failing/InvalidDerivedInstance2.purs b/tests/purs/failing/InvalidDerivedInstance2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/InvalidDerivedInstance2.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith ExpectedTypeConstructor
+module Main where
+
+import Prelude
+
+derive instance eqRecord :: Eq {}
diff --git a/tests/purs/failing/InvalidOperatorInBinder.purs b/tests/purs/failing/InvalidOperatorInBinder.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/InvalidOperatorInBinder.purs
@@ -0,0 +1,12 @@
+-- @shouldFailWith InvalidOperatorInBinder
+module Main where
+
+data List a = Cons a (List a) | Nil
+
+cons ∷ ∀ a. a → List a → List a
+cons = Cons
+
+infixl 6 cons as :
+
+get ∷ ∀ a. List a → a
+get (_ : x : _) = x
diff --git a/tests/purs/failing/KindError.purs b/tests/purs/failing/KindError.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/KindError.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith KindsDoNotUnify
+module Main where
+
+import Prelude
+
+data KindError f a = One f | Two (f a)
diff --git a/tests/purs/failing/KindStar.purs b/tests/purs/failing/KindStar.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/KindStar.purs
@@ -0,0 +1,8 @@
+-- @shouldFailWith ExpectedType
+
+module X where
+
+data List a = Nil | Cons a (List a)
+
+test :: List
+test = Nil
diff --git a/tests/purs/failing/LacksWithSubGoal.purs b/tests/purs/failing/LacksWithSubGoal.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/LacksWithSubGoal.purs
@@ -0,0 +1,16 @@
+-- @shouldFailWith NoInstanceFound
+module LacksWithSubGoal where
+
+import Prim.Row (class Lacks)
+
+data S (r :: Symbol) = S
+
+data R (r :: # Type) = R
+
+union :: forall s r. Lacks s r => S s -> R r
+union S = R
+
+example :: forall r. R (k :: Int | r)
+example = union (S :: S "hello")
+
+
diff --git a/tests/purs/failing/LeadingZeros1.purs b/tests/purs/failing/LeadingZeros1.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/LeadingZeros1.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith ErrorParsingModule
+module Main where
+
+import Prelude
+
+x = 01
diff --git a/tests/purs/failing/LeadingZeros2.purs b/tests/purs/failing/LeadingZeros2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/LeadingZeros2.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith ErrorParsingModule
+module Main where
+
+import Prelude
+
+x = 00.1
diff --git a/tests/purs/failing/Let.purs b/tests/purs/failing/Let.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/Let.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith CycleInDeclaration
+module Main where
+
+import Prelude
+
+test = let x = x in x
diff --git a/tests/purs/failing/LetPatterns1.purs b/tests/purs/failing/LetPatterns1.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/LetPatterns1.purs
@@ -0,0 +1,10 @@
+-- @shouldFailWith ErrorParsingModule
+module Main where
+
+import Prelude
+
+-- wrong binders for function, the first one should be VarBinder
+x =
+  let (X a b) x y = hoge
+  in
+   a
diff --git a/tests/purs/failing/LetPatterns2.purs b/tests/purs/failing/LetPatterns2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/LetPatterns2.purs
@@ -0,0 +1,14 @@
+-- @shouldFailWith UnknownName
+module Main where
+
+import Prelude
+
+data X a = X a
+
+-- wrong dependency order
+x =
+  let
+    b = a
+    X a = X 10
+  in
+   b
diff --git a/tests/purs/failing/LetPatterns3.purs b/tests/purs/failing/LetPatterns3.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/LetPatterns3.purs
@@ -0,0 +1,13 @@
+-- @shouldFailWith IncorrectConstructorArity
+module Main where
+
+import Prelude
+
+data X a = X a
+
+-- a parameter binder should be with nullary constructor, or with parens
+x =
+  let
+    a X b = b
+  in
+   a $ X 10
diff --git a/tests/purs/failing/LetPatterns4.purs b/tests/purs/failing/LetPatterns4.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/LetPatterns4.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith ErrorParsingModule
+module Main where
+
+data X a = X a
+
+X a = a
diff --git a/tests/purs/failing/MPTCs.purs b/tests/purs/failing/MPTCs.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/MPTCs.purs
@@ -0,0 +1,10 @@
+-- @shouldFailWith ClassInstanceArityMismatch
+module Main where
+
+import Prelude
+
+class Foo a where
+  f :: a -> a
+
+instance fooStringString :: Foo String String where
+  f a = a
diff --git a/tests/purs/failing/MissingClassExport.purs b/tests/purs/failing/MissingClassExport.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/MissingClassExport.purs
@@ -0,0 +1,7 @@
+-- @shouldFailWith TransitiveExportError
+module Test (bar) where
+
+import Prelude
+
+class Foo a where
+  bar :: a -> a
diff --git a/tests/purs/failing/MissingClassMember.purs b/tests/purs/failing/MissingClassMember.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/MissingClassMember.purs
@@ -0,0 +1,11 @@
+-- @shouldFailWith MissingClassMember
+module Main where
+
+import Prelude
+
+class A a where
+  a :: a -> String
+  b :: a -> Number
+
+instance aString :: A String where
+  a s = s
diff --git a/tests/purs/failing/MissingClassMemberExport.purs b/tests/purs/failing/MissingClassMemberExport.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/MissingClassMemberExport.purs
@@ -0,0 +1,7 @@
+-- @shouldFailWith TransitiveExportError
+module Test (class Foo) where
+
+import Prelude
+
+class Foo a where
+  bar :: a -> a
diff --git a/tests/purs/failing/MissingFFIImplementations.js b/tests/purs/failing/MissingFFIImplementations.js
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/MissingFFIImplementations.js
@@ -0,0 +1,1 @@
+exports.yes = true;
diff --git a/tests/purs/failing/MissingFFIImplementations.purs b/tests/purs/failing/MissingFFIImplementations.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/MissingFFIImplementations.purs
@@ -0,0 +1,5 @@
+-- @shouldFailWith MissingFFIImplementations
+module Main where
+
+foreign import yes :: Boolean
+foreign import no :: Boolean
diff --git a/tests/purs/failing/MissingRecordField.purs b/tests/purs/failing/MissingRecordField.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/MissingRecordField.purs
@@ -0,0 +1,10 @@
+-- @shouldFailWith PropertyIsMissing
+module MissingRecordField where
+
+import Prelude ((>))
+
+john = { first: "John", last: "Smith" }
+
+isOver50 p = p.age > 50.0
+
+result = isOver50 john
diff --git a/tests/purs/failing/MixedAssociativityError.purs b/tests/purs/failing/MixedAssociativityError.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/MixedAssociativityError.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith MixedAssociativityError
+module Main where
+
+import Prelude
+
+feq f x y = f <$> x == f <$> y
diff --git a/tests/purs/failing/MultipleErrors.purs b/tests/purs/failing/MultipleErrors.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/MultipleErrors.purs
@@ -0,0 +1,13 @@
+-- @shouldFailWith TypesDoNotUnify
+-- @shouldFailWith TypesDoNotUnify
+module MultipleErrors where
+
+import Prelude
+
+foo :: Int -> Int
+foo 0 = "Test"
+foo n = bar (n - 1)
+
+bar :: Int -> Int
+bar 0 = "Test"
+bar n = foo (n - 1)
diff --git a/tests/purs/failing/MultipleErrors2.purs b/tests/purs/failing/MultipleErrors2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/MultipleErrors2.purs
@@ -0,0 +1,9 @@
+-- @shouldFailWith UnknownName
+-- @shouldFailWith UnknownName
+module MultipleErrors2 where
+
+import Prelude
+
+foo = itDoesntExist
+
+bar = neitherDoesThis
diff --git a/tests/purs/failing/MultipleTypeOpFixities.purs b/tests/purs/failing/MultipleTypeOpFixities.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/MultipleTypeOpFixities.purs
@@ -0,0 +1,9 @@
+-- @shouldFailWith MultipleTypeOpFixities
+module MultipleTypeOpFixities where
+
+import Prelude
+
+type Op x y = Op x y
+
+infix 2 type Op as !?
+infix 2 type Op as !?
diff --git a/tests/purs/failing/MultipleValueOpFixities.purs b/tests/purs/failing/MultipleValueOpFixities.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/MultipleValueOpFixities.purs
@@ -0,0 +1,9 @@
+-- @shouldFailWith MultipleValueOpFixities
+module MultipleValueOpFixities where
+
+import Prelude
+
+add x y = x + y
+
+infix 2 add as !?
+infix 2 add as !?
diff --git a/tests/purs/failing/MutRec.purs b/tests/purs/failing/MutRec.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/MutRec.purs
@@ -0,0 +1,9 @@
+-- @shouldFailWith CycleInDeclaration
+-- @shouldFailWith CycleInDeclaration
+module MutRec where
+
+import Prelude
+
+x = y
+
+y = x
diff --git a/tests/purs/failing/MutRec2.purs b/tests/purs/failing/MutRec2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/MutRec2.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith CycleInDeclaration
+module Main where
+
+import Prelude
+
+x = x
diff --git a/tests/purs/failing/NewtypeInstance.purs b/tests/purs/failing/NewtypeInstance.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/NewtypeInstance.purs
@@ -0,0 +1,8 @@
+-- @shouldFailWith InvalidNewtypeInstance
+module Main where
+
+import Prelude
+
+data X = X
+
+derive newtype instance showX :: Show X
diff --git a/tests/purs/failing/NewtypeInstance2.purs b/tests/purs/failing/NewtypeInstance2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/NewtypeInstance2.purs
@@ -0,0 +1,8 @@
+-- @shouldFailWith InvalidNewtypeInstance
+module Main where
+
+import Prelude
+
+data X a = X a a
+
+derive newtype instance showX :: Show a => Show (X a)
diff --git a/tests/purs/failing/NewtypeInstance3.purs b/tests/purs/failing/NewtypeInstance3.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/NewtypeInstance3.purs
@@ -0,0 +1,8 @@
+-- @shouldFailWith InvalidNewtypeInstance
+module Main where
+
+import Prelude
+
+class Nullary
+
+derive newtype instance nullary :: Nullary
diff --git a/tests/purs/failing/NewtypeInstance4.purs b/tests/purs/failing/NewtypeInstance4.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/NewtypeInstance4.purs
@@ -0,0 +1,8 @@
+-- @shouldFailWith InvalidNewtypeInstance
+module Main where
+
+import Prelude
+
+data X = X | Y
+
+derive newtype instance showX :: Show X
diff --git a/tests/purs/failing/NewtypeInstance5.purs b/tests/purs/failing/NewtypeInstance5.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/NewtypeInstance5.purs
@@ -0,0 +1,8 @@
+-- @shouldFailWith InvalidNewtypeInstance
+module Main where
+
+import Prelude
+
+newtype X a = X a
+
+derive newtype instance functorX :: Functor X
diff --git a/tests/purs/failing/NewtypeInstance6.purs b/tests/purs/failing/NewtypeInstance6.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/NewtypeInstance6.purs
@@ -0,0 +1,8 @@
+-- @shouldFailWith InvalidNewtypeInstance
+module Main where
+
+import Prelude
+
+newtype X a b = X (Array b)
+
+derive newtype instance functorX :: Functor X
diff --git a/tests/purs/failing/NewtypeMultiArgs.purs b/tests/purs/failing/NewtypeMultiArgs.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/NewtypeMultiArgs.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith InvalidNewtype
+module Main where
+
+import Prelude
+
+newtype Thing = Thing String Boolean
diff --git a/tests/purs/failing/NewtypeMultiCtor.purs b/tests/purs/failing/NewtypeMultiCtor.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/NewtypeMultiCtor.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith InvalidNewtype
+module Main where
+
+import Prelude
+
+newtype Thing = Thing String | Other
diff --git a/tests/purs/failing/NonAssociativeError.purs b/tests/purs/failing/NonAssociativeError.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/NonAssociativeError.purs
@@ -0,0 +1,8 @@
+-- @shouldFailWith NonAssociativeError
+-- @shouldFailWith NonAssociativeError
+module Main where
+
+import Prelude
+
+a = true == true == true
+b = true == false /= true
diff --git a/tests/purs/failing/NonExhaustivePatGuard.purs b/tests/purs/failing/NonExhaustivePatGuard.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/NonExhaustivePatGuard.purs
@@ -0,0 +1,5 @@
+-- @shouldFailWith NoInstanceFound
+module Main where
+
+f :: Int -> Int
+f x | 1 <- x = x
diff --git a/tests/purs/failing/NullaryAbs.purs b/tests/purs/failing/NullaryAbs.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/NullaryAbs.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith ErrorParsingModule
+module Main where
+
+import Prelude
+
+func = \ -> "no"
diff --git a/tests/purs/failing/Object.purs b/tests/purs/failing/Object.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/Object.purs
@@ -0,0 +1,8 @@
+-- @shouldFailWith PropertyIsMissing
+module Main where
+
+import Prelude
+
+test o = o.foo
+
+test1 = test {}
diff --git a/tests/purs/failing/OperatorAliasNoExport.purs b/tests/purs/failing/OperatorAliasNoExport.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/OperatorAliasNoExport.purs
@@ -0,0 +1,7 @@
+-- @shouldFailWith TransitiveExportError
+module Test ((?!)) where
+
+infixl 4 what as ?!
+
+what :: forall a b. a -> b -> a
+what a _ = a
diff --git a/tests/purs/failing/OperatorSections.purs b/tests/purs/failing/OperatorSections.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/OperatorSections.purs
@@ -0,0 +1,7 @@
+-- @shouldFailWith TypesDoNotUnify
+module Main where
+
+import Prelude
+
+main = do
+  (true `not` _)
diff --git a/tests/purs/failing/OrphanInstance.purs b/tests/purs/failing/OrphanInstance.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/OrphanInstance.purs
@@ -0,0 +1,7 @@
+-- @shouldFailWith OrphanInstance
+module Test where
+
+import Class
+
+instance cBoolean :: C Boolean where
+  op a = a
diff --git a/tests/purs/failing/OrphanInstance/Class.purs b/tests/purs/failing/OrphanInstance/Class.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/OrphanInstance/Class.purs
@@ -0,0 +1,4 @@
+module Class where
+
+class C a where
+  op :: a -> a
diff --git a/tests/purs/failing/OrphanInstanceFunDepCycle.purs b/tests/purs/failing/OrphanInstanceFunDepCycle.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/OrphanInstanceFunDepCycle.purs
@@ -0,0 +1,5 @@
+-- @shouldFailWith OrphanInstance
+module Main where
+import Lib
+data L
+instance clr :: C L R
diff --git a/tests/purs/failing/OrphanInstanceFunDepCycle/Lib.purs b/tests/purs/failing/OrphanInstanceFunDepCycle/Lib.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/OrphanInstanceFunDepCycle/Lib.purs
@@ -0,0 +1,4 @@
+module Lib where
+-- covering sets: {{l}, {r}}
+class C l r | l -> r, r -> l
+data R
diff --git a/tests/purs/failing/OrphanInstanceNullary.purs b/tests/purs/failing/OrphanInstanceNullary.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/OrphanInstanceNullary.purs
@@ -0,0 +1,4 @@
+-- @shouldFailWith OrphanInstance
+module Test where
+import Lib
+instance c :: C
diff --git a/tests/purs/failing/OrphanInstanceNullary/Lib.purs b/tests/purs/failing/OrphanInstanceNullary/Lib.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/OrphanInstanceNullary/Lib.purs
@@ -0,0 +1,2 @@
+module Lib where
+class C
diff --git a/tests/purs/failing/OrphanInstanceWithDetermined.purs b/tests/purs/failing/OrphanInstanceWithDetermined.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/OrphanInstanceWithDetermined.purs
@@ -0,0 +1,5 @@
+-- @shouldFailWith OrphanInstance
+module Main where
+import Lib
+data R
+instance cflr :: C F L R
diff --git a/tests/purs/failing/OrphanInstanceWithDetermined/Lib.purs b/tests/purs/failing/OrphanInstanceWithDetermined/Lib.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/OrphanInstanceWithDetermined/Lib.purs
@@ -0,0 +1,5 @@
+module Lib where
+-- covering sets: {{f, l}}
+class C f l r | l -> r
+data F
+data L
diff --git a/tests/purs/failing/OrphanTypeDecl.purs b/tests/purs/failing/OrphanTypeDecl.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/OrphanTypeDecl.purs
@@ -0,0 +1,4 @@
+-- @shouldFailWith OrphanTypeDeclaration
+module OrphanTypeDecl where
+
+fn :: Number -> Boolean
diff --git a/tests/purs/failing/OverlapAcrossModules.purs b/tests/purs/failing/OverlapAcrossModules.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/OverlapAcrossModules.purs
@@ -0,0 +1,7 @@
+-- @shouldFailWith OverlappingInstances
+module OverlapAcrossModules where
+import OverlapAcrossModules.Class
+import OverlapAcrossModules.X
+data Y
+instance cxy :: C X Y
+
diff --git a/tests/purs/failing/OverlapAcrossModules/Class.purs b/tests/purs/failing/OverlapAcrossModules/Class.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/OverlapAcrossModules/Class.purs
@@ -0,0 +1,2 @@
+module OverlapAcrossModules.Class where
+class C x y
diff --git a/tests/purs/failing/OverlapAcrossModules/X.purs b/tests/purs/failing/OverlapAcrossModules/X.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/OverlapAcrossModules/X.purs
@@ -0,0 +1,4 @@
+module OverlapAcrossModules.X where
+import OverlapAcrossModules.Class
+data X
+instance cxy :: C X y
diff --git a/tests/purs/failing/OverlappingArguments.purs b/tests/purs/failing/OverlappingArguments.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/OverlappingArguments.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith OverlappingArgNames
+module OverlappingArguments where
+
+import Prelude
+
+f x x = x
diff --git a/tests/purs/failing/OverlappingBinders.purs b/tests/purs/failing/OverlappingBinders.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/OverlappingBinders.purs
@@ -0,0 +1,9 @@
+-- @shouldFailWith OverlappingArgNames
+module OverlappingBinders where
+
+import Prelude
+
+data S a = S a (S a)
+
+f x = case x of
+  (S y (S y@(S z zs))) -> y
diff --git a/tests/purs/failing/OverlappingInstances.purs b/tests/purs/failing/OverlappingInstances.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/OverlappingInstances.purs
@@ -0,0 +1,17 @@
+-- @shouldFailWith OverlappingInstances
+module Main where
+
+class Test a where
+  test :: a -> a
+
+instance testRefl :: Test a where
+  test x = x
+
+instance testInt :: Test Int where
+  test _ = 0
+
+-- The OverlappingInstances instances error only arises when there are two
+-- choices for a dictionary, not when the instances are defined. So without
+-- `value` this module would not raise a warning.
+value :: Int
+value = test 1
diff --git a/tests/purs/failing/OverlappingVars.purs b/tests/purs/failing/OverlappingVars.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/OverlappingVars.purs
@@ -0,0 +1,14 @@
+-- @shouldFailWith NoInstanceFound
+module Main where
+
+import Prelude
+
+class OverlappingVars a where
+  f :: a -> a
+
+data Foo a b = Foo a b
+
+instance overlappingVarsFoo :: OverlappingVars (Foo a a) where
+  f a = a
+
+test = f (Foo "" 0)
diff --git a/tests/purs/failing/PrimModuleReserved.purs b/tests/purs/failing/PrimModuleReserved.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/PrimModuleReserved.purs
@@ -0,0 +1,4 @@
+-- @shouldFailWith CannotDefinePrimModules
+module Main where
+
+import Prim
diff --git a/tests/purs/failing/PrimModuleReserved/Prim.purs b/tests/purs/failing/PrimModuleReserved/Prim.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/PrimModuleReserved/Prim.purs
@@ -0,0 +1,1 @@
+module Prim where
diff --git a/tests/purs/failing/PrimRow.purs b/tests/purs/failing/PrimRow.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/PrimRow.purs
@@ -0,0 +1,13 @@
+-- @shouldFailWith UnknownName
+module Main where
+
+import Prelude
+
+-- The 'Cons' class is not imported here, so we should not be able to refer to
+-- it in the module.
+import Prim.Row ()
+
+x :: Cons "hello" Int () ("hello" :: Int)
+  => Unit
+x = unit
+
diff --git a/tests/purs/failing/PrimSubModuleReserved.purs b/tests/purs/failing/PrimSubModuleReserved.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/PrimSubModuleReserved.purs
@@ -0,0 +1,4 @@
+-- @shouldFailWith CannotDefinePrimModules
+module Main where
+
+import Prim.Foobar
diff --git a/tests/purs/failing/PrimSubModuleReserved/Prim_Foobar.purs b/tests/purs/failing/PrimSubModuleReserved/Prim_Foobar.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/PrimSubModuleReserved/Prim_Foobar.purs
@@ -0,0 +1,1 @@
+module Prim.Foobar where
diff --git a/tests/purs/failing/ProgrammableTypeErrors.purs b/tests/purs/failing/ProgrammableTypeErrors.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ProgrammableTypeErrors.purs
@@ -0,0 +1,17 @@
+-- @shouldFailWith NoInstanceFound
+
+module Main where
+
+import Prelude
+import Prim.TypeError
+import Effect (Effect)
+import Effect.Console (log)
+
+class MyShow a where
+  myShow :: a -> String
+
+instance cannotShowFunctions :: Fail (Text "Cannot show functions") => MyShow (a -> b) where
+  myShow _ = "unreachable"
+
+main :: Effect Unit
+main = log (myShow (_ + 1))
diff --git a/tests/purs/failing/ProgrammableTypeErrorsTypeString.purs b/tests/purs/failing/ProgrammableTypeErrorsTypeString.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/ProgrammableTypeErrorsTypeString.purs
@@ -0,0 +1,24 @@
+-- @shouldFailWith NoInstanceFound
+
+module Main where
+
+import Prelude
+import Prim.TypeError
+import Effect (Effect)
+import Effect.Console (log)
+
+newtype MyType a = MyType a
+
+instance cannotShowFunctions ::
+  Fail ( Text "Don't want to show " <>
+         Quote (MyType a) <>
+         Text " because."
+       ) => Show (MyType a)
+  where
+    show _ = "unreachable"
+
+infixl 6 type Beside as <>
+
+main :: Effect Unit
+main = do
+  log $ show (MyType 2)
diff --git a/tests/purs/failing/Rank2Types.purs b/tests/purs/failing/Rank2Types.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/Rank2Types.purs
@@ -0,0 +1,8 @@
+-- @shouldFailWith TypesDoNotUnify
+module Main where
+
+import Prelude
+
+foreign import test :: (forall a. a -> a) -> Number
+
+test1 = test (\n -> n + 1)
diff --git a/tests/purs/failing/RequiredHiddenType.purs b/tests/purs/failing/RequiredHiddenType.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/RequiredHiddenType.purs
@@ -0,0 +1,9 @@
+-- @shouldFailWith TransitiveExportError
+-- exporting `a` should fail as `A` is hidden
+module Foo (B(..), a, b) where
+
+data A = A
+data B = B
+
+a = A
+b = B
diff --git a/tests/purs/failing/Reserved.purs b/tests/purs/failing/Reserved.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/Reserved.purs
@@ -0,0 +1,7 @@
+-- @shouldFailWith ErrorParsingModule
+module Main where
+
+import Prelude
+
+(<) :: Number -> Number -> Number
+(<) a b = !(a >= b)
diff --git a/tests/purs/failing/RowConstructors1.purs b/tests/purs/failing/RowConstructors1.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/RowConstructors1.purs
@@ -0,0 +1,9 @@
+-- @shouldFailWith KindsDoNotUnify
+module Main where
+
+import Effect.Console (log)
+
+data Foo = Bar
+type Baz = { | Foo }
+
+main = log "Done"
diff --git a/tests/purs/failing/RowConstructors2.purs b/tests/purs/failing/RowConstructors2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/RowConstructors2.purs
@@ -0,0 +1,9 @@
+-- @shouldFailWith KindsDoNotUnify
+module Main where
+
+import Effect.Console (log)
+
+type Foo r = (x :: Number | r)
+type Bar = { | Foo }
+
+main = log "Done"
diff --git a/tests/purs/failing/RowConstructors3.purs b/tests/purs/failing/RowConstructors3.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/RowConstructors3.purs
@@ -0,0 +1,9 @@
+-- @shouldFailWith KindsDoNotUnify
+module Main where
+
+import Effect.Console (log)
+
+type Foo = { x :: Number }
+type Bar = { | Foo }
+
+main = log "Done"
diff --git a/tests/purs/failing/RowInInstanceNotDetermined0.purs b/tests/purs/failing/RowInInstanceNotDetermined0.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/RowInInstanceNotDetermined0.purs
@@ -0,0 +1,9 @@
+-- @shouldFailWith InvalidInstanceHead
+module Main where
+
+import Prelude
+
+-- no fundeps
+class C a b
+instance c :: C Unit {}
+
diff --git a/tests/purs/failing/RowInInstanceNotDetermined1.purs b/tests/purs/failing/RowInInstanceNotDetermined1.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/RowInInstanceNotDetermined1.purs
@@ -0,0 +1,9 @@
+-- @shouldFailWith InvalidInstanceHead
+module Main where
+
+import Prelude
+
+-- `c` not mentioned in any fundeps
+class C a b c | a -> b
+instance c :: C Unit Unit {}
+
diff --git a/tests/purs/failing/RowInInstanceNotDetermined2.purs b/tests/purs/failing/RowInInstanceNotDetermined2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/RowInInstanceNotDetermined2.purs
@@ -0,0 +1,9 @@
+-- @shouldFailWith InvalidInstanceHead
+module Main where
+
+import Prelude
+
+-- `b` isn't determined by anything that `b` doesn't determine
+class C a b | a -> b, b -> a
+instance c :: C Unit {}
+
diff --git a/tests/purs/failing/RowLacks.purs b/tests/purs/failing/RowLacks.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/RowLacks.purs
@@ -0,0 +1,18 @@
+-- @shouldFailWith NoInstanceFound
+module Main where
+
+import Effect.Console (log)
+import Prim.Row (class Lacks)
+import Type.Row (RProxy(..))
+
+lacksX
+  :: forall r
+   . Lacks "x" r
+  => RProxy r
+  -> RProxy ()
+lacksX _ = RProxy
+
+test1 :: RProxy ()
+test1 = lacksX (RProxy :: RProxy (x :: Int, y :: Int, z :: String))
+
+main = log "Done"
diff --git a/tests/purs/failing/SkolemEscape.purs b/tests/purs/failing/SkolemEscape.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/SkolemEscape.purs
@@ -0,0 +1,8 @@
+-- @shouldFailWith EscapedSkolem
+module Main where
+
+import Prelude
+
+foreign import foo :: (forall a. a -> a) -> Number
+
+test = \x -> foo x
diff --git a/tests/purs/failing/SkolemEscape2.purs b/tests/purs/failing/SkolemEscape2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/SkolemEscape2.purs
@@ -0,0 +1,11 @@
+-- @shouldFailWith EscapedSkolem
+module Main where
+
+import Prelude
+import Effect
+import Control.Monad.ST as ST
+import Control.Monad.ST.Ref as STRef
+
+test _ = do
+  r <- pure (ST.run (STRef.new 0))
+  pure r
diff --git a/tests/purs/failing/SuggestComposition.purs b/tests/purs/failing/SuggestComposition.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/SuggestComposition.purs
@@ -0,0 +1,7 @@
+-- @shouldFailWith TypesDoNotUnify
+-- TODO: Ensure the correct suggestion is produced.
+module SuggestComposition where
+
+import Prelude
+
+f = g . g where g = (_ + 1)
diff --git a/tests/purs/failing/Superclasses1.purs b/tests/purs/failing/Superclasses1.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/Superclasses1.purs
@@ -0,0 +1,14 @@
+-- @shouldFailWith NoInstanceFound
+module Main where
+
+import Prelude
+
+class Su a where
+  su :: a -> a
+
+class (Su a) <= Cl a where
+  cl :: a -> a -> a
+
+instance clNumber :: Cl Number where
+  cl n m = n + m
+
diff --git a/tests/purs/failing/Superclasses2.purs b/tests/purs/failing/Superclasses2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/Superclasses2.purs
@@ -0,0 +1,13 @@
+-- @shouldFailWith CycleInTypeSynonym
+-- TODO: Should this have its own error, perhaps CycleInTypeClassDeclaration?
+module CycleInSuperclasses where
+
+import Prelude
+
+class (Foo a) <= Bar a
+
+class (Bar a) <= Foo a
+
+instance barString :: Bar String
+
+instance fooString :: Foo String
diff --git a/tests/purs/failing/Superclasses3.purs b/tests/purs/failing/Superclasses3.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/Superclasses3.purs
@@ -0,0 +1,8 @@
+-- @shouldFailWith UndefinedTypeVariable
+module UnknownSuperclassTypeVar where
+
+import Prelude
+
+class Foo a
+
+class (Foo b) <= Bar a
diff --git a/tests/purs/failing/Superclasses5.purs b/tests/purs/failing/Superclasses5.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/Superclasses5.purs
@@ -0,0 +1,26 @@
+-- @shouldFailWith NoInstanceFound
+
+module Main where
+
+import Prelude
+import Effect.Console (logShow)
+
+class Su a where
+  su :: a -> a
+
+class Su (Array a) <= Cl a where
+  cl :: a -> a -> a
+
+instance suNumber :: Su Number where
+  su n = n + 1.0
+
+instance suArray :: Su a => Su (Array a) where
+  su [x] = [su x]
+
+instance clNumber :: Cl Number where
+  cl n m = n + m
+
+test :: forall a. Cl a => a -> Array a
+test x = su [cl x x]
+
+main = logShow $ test 10.0
diff --git a/tests/purs/failing/TooFewClassInstanceArgs.purs b/tests/purs/failing/TooFewClassInstanceArgs.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/TooFewClassInstanceArgs.purs
@@ -0,0 +1,8 @@
+-- @shouldFailWith ClassInstanceArityMismatch
+module Main where
+
+import Prelude
+
+class Foo a b
+
+instance fooString :: Foo String
diff --git a/tests/purs/failing/TopLevelCaseNoArgs.purs b/tests/purs/failing/TopLevelCaseNoArgs.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/TopLevelCaseNoArgs.purs
@@ -0,0 +1,8 @@
+-- @shouldFailWith DuplicateValueDeclaration
+module Main where
+
+import Prelude
+
+foo :: Number
+foo = 1
+foo = 2
diff --git a/tests/purs/failing/TransitiveDctorExport.purs b/tests/purs/failing/TransitiveDctorExport.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/TransitiveDctorExport.purs
@@ -0,0 +1,5 @@
+-- @shouldFailWith TransitiveExportError
+module Main (Y(..)) where
+
+type X = Int
+data Y = Y X
diff --git a/tests/purs/failing/TransitiveKindExport.purs b/tests/purs/failing/TransitiveKindExport.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/TransitiveKindExport.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith TransitiveExportError
+module Main (TestProxy(..)) where
+
+foreign import kind Test
+
+data TestProxy (p :: Test) = TestProxy
diff --git a/tests/purs/failing/TransitiveSynonymExport.purs b/tests/purs/failing/TransitiveSynonymExport.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/TransitiveSynonymExport.purs
@@ -0,0 +1,5 @@
+-- @shouldFailWith TransitiveExportError
+module Main (Y()) where
+
+type X = Int
+type Y = X
diff --git a/tests/purs/failing/TypeClasses2.purs b/tests/purs/failing/TypeClasses2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/TypeClasses2.purs
@@ -0,0 +1,9 @@
+-- @shouldFailWith NoInstanceFound
+module Main where
+
+import Prelude ()
+
+class Show a where
+  show :: a -> String
+
+test = show "testing"
diff --git a/tests/purs/failing/TypeError.purs b/tests/purs/failing/TypeError.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/TypeError.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith TypesDoNotUnify
+module Main where
+
+import Prelude
+
+test = 1 <> "A"
diff --git a/tests/purs/failing/TypeOperatorAliasNoExport.purs b/tests/purs/failing/TypeOperatorAliasNoExport.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/TypeOperatorAliasNoExport.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith TransitiveExportError
+module Test (type (×)) where
+
+data Tuple a b = Tuple a b
+
+infixl 6 type Tuple as ×
diff --git a/tests/purs/failing/TypeSynonyms.purs b/tests/purs/failing/TypeSynonyms.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/TypeSynonyms.purs
@@ -0,0 +1,8 @@
+-- @shouldFailWith CycleInTypeSynonym
+module Main where
+
+import Prelude
+
+type T1 = Array T2
+
+type T2 = T1
diff --git a/tests/purs/failing/TypeSynonyms2.purs b/tests/purs/failing/TypeSynonyms2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/TypeSynonyms2.purs
@@ -0,0 +1,12 @@
+-- @shouldFailWith TypeSynonymInstance
+module Main where
+
+import Prelude
+
+class Foo a where
+  foo :: a -> String
+
+type Bar = String
+
+instance fooBar :: Foo Bar where
+  foo s = s
diff --git a/tests/purs/failing/TypeSynonyms3.purs b/tests/purs/failing/TypeSynonyms3.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/TypeSynonyms3.purs
@@ -0,0 +1,12 @@
+-- @shouldFailWith TypeSynonymInstance
+module Main where
+
+import Prelude
+
+class Foo a where
+  foo :: a -> String
+
+type Bar = String
+
+instance fooBar :: Foo Bar where
+  foo s = s
diff --git a/tests/purs/failing/TypeSynonyms4.purs b/tests/purs/failing/TypeSynonyms4.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/TypeSynonyms4.purs
@@ -0,0 +1,11 @@
+-- @shouldFailWith PartiallyAppliedSynonym
+module TypeSynonyms4 where
+
+import Prelude
+
+type F x y = x -> y
+
+type G x = F x
+
+f :: G String String -> String
+f k = k "Done"
diff --git a/tests/purs/failing/TypeSynonyms5.purs b/tests/purs/failing/TypeSynonyms5.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/TypeSynonyms5.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith CycleInTypeSynonym
+module Main where
+
+import Prelude
+
+type T = T
diff --git a/tests/purs/failing/TypeWildcards1.purs b/tests/purs/failing/TypeWildcards1.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/TypeWildcards1.purs
@@ -0,0 +1,7 @@
+-- @shouldFailWith ErrorParsingModule
+module TypeWildcards where
+
+import Prelude
+
+type Test = _
+
diff --git a/tests/purs/failing/TypeWildcards2.purs b/tests/purs/failing/TypeWildcards2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/TypeWildcards2.purs
@@ -0,0 +1,7 @@
+-- @shouldFailWith ErrorParsingModule
+module TypeWildcards where
+
+import Prelude
+
+data Test = Test _
+
diff --git a/tests/purs/failing/TypeWildcards3.purs b/tests/purs/failing/TypeWildcards3.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/TypeWildcards3.purs
@@ -0,0 +1,9 @@
+-- @shouldFailWith InvalidInstanceHead
+module TypeWildcards where
+
+import Prelude
+
+data Foo a = Foo
+
+instance showFoo :: Show (Foo _) where
+  show Foo = "Foo"
diff --git a/tests/purs/failing/TypedBinders.purs b/tests/purs/failing/TypedBinders.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/TypedBinders.purs
@@ -0,0 +1,10 @@
+-- @shouldFailWith ErrorParsingModule
+module Main where
+
+import Effect.Console (log)
+
+test = (\f :: Int -> Int -> f 10) identity
+
+main = do
+  let t1 = test
+  log "Done"
diff --git a/tests/purs/failing/TypedBinders2.purs b/tests/purs/failing/TypedBinders2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/TypedBinders2.purs
@@ -0,0 +1,9 @@
+-- @shouldFailWith TypesDoNotUnify
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+main = do
+  s :: String <- log "Foo"
+  log "Done"
diff --git a/tests/purs/failing/TypedBinders3.purs b/tests/purs/failing/TypedBinders3.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/TypedBinders3.purs
@@ -0,0 +1,13 @@
+-- @shouldFailWith TypesDoNotUnify
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+test = case 1 of
+  (0 :: String) -> true
+  _ -> false
+
+main = do
+  let t = test
+  log "Done"
diff --git a/tests/purs/failing/TypedHole.purs b/tests/purs/failing/TypedHole.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/TypedHole.purs
@@ -0,0 +1,8 @@
+-- @shouldFailWith HoleInferredType
+module Main where
+
+import Prelude
+import Effect (Effect)
+
+main :: Effect Unit
+main = ?ummm
diff --git a/tests/purs/failing/UnderscoreModuleName.purs b/tests/purs/failing/UnderscoreModuleName.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/UnderscoreModuleName.purs
@@ -0,0 +1,6 @@
+-- @shouldFailWith ErrorParsingModule
+module Bad_Module where
+
+import Effect.Console (log)
+
+main = log "Done"
diff --git a/tests/purs/failing/UnknownType.purs b/tests/purs/failing/UnknownType.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/UnknownType.purs
@@ -0,0 +1,7 @@
+-- @shouldFailWith UnknownName
+module Main where
+
+import Prelude
+
+test :: Number -> Something
+test = {}
diff --git a/tests/purs/failing/UnusableTypeClassMethod.purs b/tests/purs/failing/UnusableTypeClassMethod.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/UnusableTypeClassMethod.purs
@@ -0,0 +1,7 @@
+-- @shouldFailWith UnusableDeclaration
+module Main where
+
+class C a b where
+  -- type doesn't contain `a`, which is also required to determine an instance
+  c :: b
+
diff --git a/tests/purs/failing/UnusableTypeClassMethodConflictingIdent.purs b/tests/purs/failing/UnusableTypeClassMethodConflictingIdent.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/UnusableTypeClassMethodConflictingIdent.purs
@@ -0,0 +1,7 @@
+-- @shouldFailWith UnusableDeclaration
+module Main where
+
+class C a where
+  -- type doesn't contain the type class var `a`
+  c :: forall a. a
+
diff --git a/tests/purs/failing/UnusableTypeClassMethodSynonym.purs b/tests/purs/failing/UnusableTypeClassMethodSynonym.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/failing/UnusableTypeClassMethodSynonym.purs
@@ -0,0 +1,9 @@
+-- @shouldFailWith UnusableDeclaration
+module Main where
+
+type M x = forall a. a
+
+class C a where
+  -- after synonym expansion, the type doesn't actually contain an `a`
+  c :: M a
+
diff --git a/tests/purs/passing/1110.purs b/tests/purs/passing/1110.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/1110.purs
@@ -0,0 +1,26 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+data X a = X
+
+x :: forall a. X a
+x = X
+	 
+type Y = { x :: X Int }
+
+test :: forall m. Monad m => m Y
+test = pure { x: x }
+
+type Z t = forall x. t x -> (forall a. t a) -> t x
+
+class C t where c :: Z t
+
+instance cA :: C Array where
+  c x _ = x
+
+test2 :: forall m. Monad m => m { ccc :: Z Array }
+test2 = pure { ccc: (c :: Z Array) }
+
+main = log "Done"
diff --git a/tests/purs/passing/1185.purs b/tests/purs/passing/1185.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/1185.purs
@@ -0,0 +1,15 @@
+module Main where
+
+import Effect.Console (log)
+
+data Person = Person String Boolean
+
+getName :: Person -> String
+getName p = case p of
+              Person name true -> name
+              _ -> "Unknown"
+
+name :: String
+name = getName (Person "John Smith" true)
+
+main = log "Done"
diff --git a/tests/purs/passing/1335.purs b/tests/purs/passing/1335.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/1335.purs
@@ -0,0 +1,14 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+x :: forall a. a -> String
+x a = y "Test"
+  where
+  y :: forall a. Show a => a -> String
+  y a = show (a :: a)
+
+main = do
+  log (x 0)
+  log "Done"
diff --git a/tests/purs/passing/1570.purs b/tests/purs/passing/1570.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/1570.purs
@@ -0,0 +1,8 @@
+module Main where
+
+import Effect.Console (log)
+
+test :: forall a. a -> a
+test = \(x :: a) -> x
+
+main = log "Done"
diff --git a/tests/purs/passing/1664.purs b/tests/purs/passing/1664.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/1664.purs
@@ -0,0 +1,16 @@
+module Main where
+
+import Prelude
+import Effect
+import Effect.Console
+
+data Identity a = Identity a
+
+newtype IdentityEff a = IdentityEff (Effect (Identity a))
+
+test :: forall a. IdentityEff a -> IdentityEff Unit
+test (IdentityEff action) = IdentityEff $ do
+  (Identity x :: Identity _) <- action
+  pure $ Identity unit
+
+main = log "Done"
diff --git a/tests/purs/passing/1697.purs b/tests/purs/passing/1697.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/1697.purs
@@ -0,0 +1,25 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+_2 :: forall a. a -> a
+_2 a = a
+
+x :: forall m. Monad m => m Unit
+x = do
+  _ <- pure unit
+  pure unit
+
+y :: forall m. Monad m => m Unit
+y = do
+  _ <- pure unit
+  pure unit
+
+wtf :: forall m. Monad m => m Unit
+wtf = do
+  _ <- pure unit
+  let tmp = _2 1
+  pure unit
+
+main = log "Done"
diff --git a/tests/purs/passing/1807.purs b/tests/purs/passing/1807.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/1807.purs
@@ -0,0 +1,14 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+fn = _.b.c.d
+a = {b:{c:{d:2}}}
+
+d :: Int
+d = fn a + a.b.c.d
+
+main = if fn a + a.b.c.d == 4
+  then log "Done"
+  else log "Fail"
diff --git a/tests/purs/passing/1881.purs b/tests/purs/passing/1881.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/1881.purs
@@ -0,0 +1,19 @@
+module Main where
+
+import Effect.Console (log)
+
+foo =
+ 1
+
+bar
+ = 2
+
+baz
+ =
+ 3
+
+qux
+  =
+ 3
+
+main = log "Done"
diff --git a/tests/purs/passing/1991.purs b/tests/purs/passing/1991.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/1991.purs
@@ -0,0 +1,22 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+singleton :: forall a. a -> Array a
+singleton x = [x]
+
+empty :: forall a. Array a
+empty = []
+
+foldMap :: forall a m. Semigroup m => (a -> m) -> Array a -> m
+foldMap f [a, b, c, d, e] = f a <> f b <> f c <> f d <> f e
+foldMap f xs = foldMap f xs -- spin, not used
+
+regression :: Array Int
+regression =
+  let as = [1,2,3,4,5]
+      as' = foldMap (\x -> if 1 < x && x < 4 then singleton x else empty) as
+  in as'
+
+main = log "Done"
diff --git a/tests/purs/passing/2018.purs b/tests/purs/passing/2018.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/2018.purs
@@ -0,0 +1,12 @@
+module Main where
+
+import Prelude
+import A (foo)
+import B (Foo(..))
+import Effect (Effect)
+import Effect.Console (log)
+
+main :: Effect Unit
+main = do
+  let tmp = foo X
+  log "Done"
diff --git a/tests/purs/passing/2018/A.purs b/tests/purs/passing/2018/A.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/2018/A.purs
@@ -0,0 +1,7 @@
+module A where
+
+import B as Main
+
+-- Prior to the 2018 fix this would be detected as a cycle between A and Main.
+foo ∷ Main.Foo → Main.Foo
+foo x = x
diff --git a/tests/purs/passing/2018/B.purs b/tests/purs/passing/2018/B.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/2018/B.purs
@@ -0,0 +1,3 @@
+module B where
+
+data Foo = X | Y
diff --git a/tests/purs/passing/2049.purs b/tests/purs/passing/2049.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/2049.purs
@@ -0,0 +1,14 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+data List a = Cons a (List a) | Nil
+
+infixr 6 Cons as :
+
+f :: List { x :: Int, y :: Int } -> Int
+f ( r@{ x } : _) = x + r.y
+f _ = 0
+
+main = log "Done"
diff --git a/tests/purs/passing/2136.purs b/tests/purs/passing/2136.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/2136.purs
@@ -0,0 +1,9 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+main = 
+  if (negate (bottom :: Int) > top)
+    then log "Fail"
+    else log "Done"
diff --git a/tests/purs/passing/2138.purs b/tests/purs/passing/2138.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/2138.purs
@@ -0,0 +1,7 @@
+module Main where
+
+import Effect.Console (log)
+
+import Lib (A(B,C))
+
+main = log "Done"
diff --git a/tests/purs/passing/2138/Lib.purs b/tests/purs/passing/2138/Lib.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/2138/Lib.purs
@@ -0,0 +1,3 @@
+module Lib (A(..), A) where
+
+data A = B | C
diff --git a/tests/purs/passing/2172.js b/tests/purs/passing/2172.js
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/2172.js
@@ -0,0 +1,5 @@
+exports['a\''] = 0;
+exports["\x62\x27"] = 1;
+// NOTE: I wanted to use "\c'" here, but langauge-javascript doesn't support it...
+exports["c'"] = 2;
+exports["\u0064\u0027"] = 3;
diff --git a/tests/purs/passing/2172.purs b/tests/purs/passing/2172.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/2172.purs
@@ -0,0 +1,10 @@
+module Main where
+
+import Effect.Console (log)
+
+foreign import a' :: Number
+foreign import b' :: Number
+foreign import c' :: Number
+foreign import d' :: Number
+
+main = log "Done"
diff --git a/tests/purs/passing/2197-1.purs b/tests/purs/passing/2197-1.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/2197-1.purs
@@ -0,0 +1,12 @@
+module Main where
+
+import Effect.Console
+import Prim as P
+
+type Number = P.Number
+type Test = {}
+
+z :: Number
+z = 0.0
+
+main = log "Done"
diff --git a/tests/purs/passing/2197-2.purs b/tests/purs/passing/2197-2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/2197-2.purs
@@ -0,0 +1,11 @@
+module Main where
+
+import Effect.Console
+import Prim (Int)
+
+type Number = Int
+
+z :: Number
+z = 0
+
+main = log "Done"
diff --git a/tests/purs/passing/2252.purs b/tests/purs/passing/2252.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/2252.purs
@@ -0,0 +1,15 @@
+module Main where
+	
+import Effect.Console (log)
+
+data T a = T
+	 
+ti :: T Int
+ti = T
+
+t :: forall a. T a
+t = T
+
+xs = [ti, t, t]
+
+main = log "Done"
diff --git a/tests/purs/passing/2288.purs b/tests/purs/passing/2288.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/2288.purs
@@ -0,0 +1,19 @@
+module Main where
+
+import Prelude
+import Effect
+import Effect.Console
+import Data.Array
+import Data.Array.Partial as P
+import Partial.Unsafe
+
+length :: forall a. Array a -> Int
+length = go 0 where
+  go acc arr =
+    if null arr
+    then acc
+    else go (acc + 1) (unsafePartial P.tail arr)
+
+main = do
+  logShow (length (1 .. 10000))
+  log "Done"
diff --git a/tests/purs/passing/2378.purs b/tests/purs/passing/2378.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/2378.purs
@@ -0,0 +1,9 @@
+module Main where
+
+import Effect.Console (log)
+
+class Foo (a :: Symbol)
+
+instance fooX :: Foo "x"
+
+main = log "Done"
diff --git a/tests/purs/passing/2438.purs b/tests/purs/passing/2438.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/2438.purs
@@ -0,0 +1,8 @@
+module Main where
+
+import Effect.Console (log)
+
+done :: String
+done = {"𝌆": "Done"}."𝌆"
+
+main = log done
diff --git a/tests/purs/passing/2609.purs b/tests/purs/passing/2609.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/2609.purs
@@ -0,0 +1,12 @@
+module Main where
+
+import Prelude
+import Eg (Foo'(Bar'), (:->))
+import Effect (Effect)
+import Effect.Console (log)
+
+bar' :: Foo'
+bar' = 4 :-> 5
+
+main :: Effect Unit
+main = case bar' of Bar' l r -> log "Done"
diff --git a/tests/purs/passing/2609/Eg.purs b/tests/purs/passing/2609/Eg.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/2609/Eg.purs
@@ -0,0 +1,6 @@
+module Eg (Foo'(Bar'), (:->)) where
+
+data Foo' = Bar' Int Int
+
+infix 4 Bar' as :->
+
diff --git a/tests/purs/passing/2616.purs b/tests/purs/passing/2616.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/2616.purs
@@ -0,0 +1,13 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+newtype F r a = F { x :: a | r }
+
+unF :: forall r a. F r a -> { x :: a | r }
+unF (F x) = x
+
+derive instance functorF :: Functor (F r)
+
+main = log (unF (map identity (F { x: "Done", y: 42 }))).x
diff --git a/tests/purs/passing/2626.purs b/tests/purs/passing/2626.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/2626.purs
@@ -0,0 +1,13 @@
+module Main where
+
+import Effect.Console (log)
+
+f = \(x :: forall a. a -> a) -> x x
+
+test1 = (f \x -> x) 1
+
+g = \(x :: (forall a. a -> a) -> Int) -> x (\y -> y)
+
+test2 = g \f -> if f true then f 0 else f 1
+
+main = log "Done"
diff --git a/tests/purs/passing/2663.purs b/tests/purs/passing/2663.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/2663.purs
@@ -0,0 +1,10 @@
+module Main where
+
+import Prelude
+import Prim.TypeError (class Warn, Text)
+import Effect.Console (log)
+
+foo :: forall t. Warn (Text "Example") => t -> t
+foo x = x
+
+main = when (foo 42 == 42) $ log "Done"
diff --git a/tests/purs/passing/2689.purs b/tests/purs/passing/2689.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/2689.purs
@@ -0,0 +1,36 @@
+module Main where
+
+import Prelude
+import Effect.Console
+import Data.Array.Partial
+import Partial.Unsafe
+
+sumTCObug = go identity where 
+  go f 0 = f 
+  go f n =
+    let
+      f' a = n + a
+    in
+      go f' 0
+
+sumTCObug' = go identity where 
+  go f 0 = f
+  go f n = go (\a -> n + a) 0
+
+count :: forall a. (a -> Boolean) -> Array a -> Int
+count p = count' 0 where
+  count' acc [] = acc
+  count' acc xs =
+    let h = unsafePartial head xs
+    in count' (acc + if p h then 1 else 0) (unsafePartial tail xs)
+
+main = do
+  let x = sumTCObug 7 3
+      y = sumTCObug' 7 3
+      z = count (_ > 0) [-1, 0, 1]
+  logShow x
+  logShow y 
+  logShow z
+  if x == 10 && y == 10 && z == 1
+    then log "Done"
+    else log "Fail"
diff --git a/tests/purs/passing/2756.purs b/tests/purs/passing/2756.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/2756.purs
@@ -0,0 +1,20 @@
+module Main where
+
+import Effect (Effect)
+import Effect.Console (log)
+import Prelude
+
+pu :: forall i. i -> Effect Unit
+pu _ = pure unit
+
+type C i = { pu :: i -> Effect Unit }
+
+sampleC :: C Unit
+sampleC = { pu: pu }
+
+newtype Identity a = Id a
+
+sampleIdC :: Identity (C Unit)
+sampleIdC = Id { pu : pu }
+
+main = log "Done"
diff --git a/tests/purs/passing/2787.purs b/tests/purs/passing/2787.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/2787.purs
@@ -0,0 +1,8 @@
+module Main where
+
+import Prelude
+import Effect.Console
+
+main
+  | between 0 1 2 = log "Fail"
+  | otherwise = log "Done"
diff --git a/tests/purs/passing/2795.purs b/tests/purs/passing/2795.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/2795.purs
@@ -0,0 +1,14 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+data X = X Int | Y
+
+x :: X -> Int
+x = case _ of
+      Y -> 0
+      X n | 1 <- n -> 1
+          | otherwise -> 2
+
+main = log "Done"
diff --git a/tests/purs/passing/2803.purs b/tests/purs/passing/2803.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/2803.purs
@@ -0,0 +1,17 @@
+module Main where
+
+import Prelude ((+), (-), (==))
+import Effect.Console (log)
+
+f :: Int -> Int -> Int
+f = (+)
+
+infixl 6 f as %
+
+g :: Int -> Int -> Int
+g a b = let f = (-) in a % b
+
+main =
+  if g 10 5 == 15
+    then log "Done"
+    else log "Failed"
diff --git a/tests/purs/passing/2806.purs b/tests/purs/passing/2806.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/2806.purs
@@ -0,0 +1,14 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+data Stream a = Cons a (Stream a)
+
+step :: forall a. Stream a -> Stream a
+step (Cons _ xs) = xs
+
+head :: forall a. Stream a -> a
+head xs | Cons x _ <- step xs = x
+
+main = log "Done"
diff --git a/tests/purs/passing/2947.purs b/tests/purs/passing/2947.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/2947.purs
@@ -0,0 +1,11 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+data Foo = Foo
+
+instance eqFoo :: Eq Foo where
+  eq _ _ = true
+
+main = log "Done"
diff --git a/tests/purs/passing/2958.purs b/tests/purs/passing/2958.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/2958.purs
@@ -0,0 +1,14 @@
+module Main where
+
+import Effect.Console
+
+data Nil
+data Snoc xs x
+
+infixl 1 type Snoc as :>
+
+type One = Nil :> Int
+type Two = Nil :> Int :> Int
+type Three = Nil :> Int :> Int :> Int
+
+main = log "Done"
diff --git a/tests/purs/passing/2972.purs b/tests/purs/passing/2972.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/2972.purs
@@ -0,0 +1,13 @@
+module Main where
+
+import Effect.Console (log)
+import Prelude (class Show, show)
+
+type I t = t
+
+newtype Id t = Id t
+
+instance foo :: Show (I t) => Show (Id t) where
+  show (Id t) = "Done"
+
+main = log (show (Id "other"))
diff --git a/tests/purs/passing/3114.purs b/tests/purs/passing/3114.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/3114.purs
@@ -0,0 +1,53 @@
+module Main where
+
+import Prelude
+
+import Data.Either
+import Data.Maybe
+import Data.Tuple
+import Effect
+import Effect.Console (log)
+import VendoredVariant
+import Data.Symbol
+
+type TestVariants =
+  ( foo :: FProxy Maybe
+  , bar :: FProxy (Tuple String)
+  )
+
+_foo :: SProxy "foo"
+_foo = SProxy
+
+_bar :: SProxy "bar"
+_bar = SProxy
+
+main :: Effect Unit
+main = do
+  let
+    -- with the type signatures on `a`, this compiles fine.
+    case1 :: VariantF TestVariants Int → String
+    case1 = case_
+       # on _foo (\a → "foo: " <> show (a :: Maybe Int))
+       # on _bar (\a → "bar: " <> show (a :: Tuple String Int))
+
+    -- without the type signature, this would complain about
+    -- Could not match type 
+    --   Array
+    -- with type
+    --   Tuple String
+    -- while trying to match the type FProxy Array
+    --   with type FProxy (Tuple String)
+    -- while solving type class constraint
+    --   Prim.RowCons "baz"
+    --     (FProxy t0)
+    --     t1
+    --     ( foo :: FProxy Maybe
+    --     , bar :: FProxy (Tuple String)
+    --     )
+    -- while inferring the type of `on _baz`
+    case2 :: VariantF TestVariants Int → String
+    case2 = case_
+       # on _foo (\a → "foo: " <> show a)
+       # on _bar (\a → "bar: " <> show a)
+
+  log "Done"
diff --git a/tests/purs/passing/3114/VendoredVariant.purs b/tests/purs/passing/3114/VendoredVariant.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/3114/VendoredVariant.purs
@@ -0,0 +1,42 @@
+module VendoredVariant where
+
+import Prelude
+
+import Prim.Row as Row
+
+import Unsafe.Coerce (unsafeCoerce)
+import Partial.Unsafe (unsafeCrashWith)
+import Data.Symbol
+
+data FProxy (k :: Type -> Type) = FProxy
+data VariantF (f :: # Type) a
+
+newtype VariantFRep f a = VariantFRep
+  { type :: String
+  , value :: f a
+  , map :: forall x y. (x -> y) -> f x -> f y
+  }
+
+case_ :: forall a b. VariantF () a -> b
+case_ r = unsafeCrashWith case unsafeCoerce r of
+    VariantFRep v -> "failure on " <> v.type
+
+on
+  :: forall sym f a b r1 r2
+  . Row.Cons sym (FProxy f) r1 r2
+  => IsSymbol sym
+  => SProxy sym
+  -> (f a -> b)
+  -> (VariantF r1 a -> b)
+  -> VariantF r2 a
+  -> b
+on p f g r =
+  case coerceY r of
+    VariantFRep v | v.type == reflectSymbol p -> f v.value
+    _ -> g (coerceR r)
+  where
+  coerceY :: VariantF r2 a -> VariantFRep f a
+  coerceY = unsafeCoerce
+
+  coerceR :: VariantF r2 a -> VariantF r1 a
+  coerceR = unsafeCoerce
diff --git a/tests/purs/passing/3125.purs b/tests/purs/passing/3125.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/3125.purs
@@ -0,0 +1,16 @@
+module Main where
+
+import Prelude
+import Data.Monoid (class Monoid, mempty)
+import Effect.Console (log, logShow)
+
+data B a = B a a
+
+memptyB :: forall a b. Monoid b => B (a -> b)
+memptyB = B l r where
+  l _ = mempty
+  r _ = mempty
+
+main = do
+  logShow $ case (memptyB :: B (Int -> Array Unit)) of B l r -> l 0 == r 0
+  log "Done"
diff --git a/tests/purs/passing/3187-UnusedNameClash.purs b/tests/purs/passing/3187-UnusedNameClash.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/3187-UnusedNameClash.purs
@@ -0,0 +1,12 @@
+module Main (main) where
+
+import Prelude ((+))
+import Effect.Console (log)
+
+-- the __unused parameter used to get optimized away
+abuseUnused :: forall a. a -> a
+abuseUnused __unused = __unused
+
+main = do
+  let explode = abuseUnused 0 + abuseUnused 0
+  log "Done"
diff --git a/tests/purs/passing/652.purs b/tests/purs/passing/652.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/652.purs
@@ -0,0 +1,18 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+class Foo a b
+
+class Bar a c
+
+class (Foo a b, Bar a c) <= Baz a b c
+
+instance foo :: Foo (a -> b) a
+
+instance bar :: Bar (a -> b) b
+
+instance baz :: (Eq a) => Baz (a -> b) a b
+
+main = log "Done"
diff --git a/tests/purs/passing/810.purs b/tests/purs/passing/810.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/810.purs
@@ -0,0 +1,14 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+data Maybe a = Nothing | Just a
+
+test :: forall a. Maybe a -> Maybe a
+test m = o.x
+  where
+    o = case m of Nothing -> { x : Nothing }
+                  Just a  -> { x : Just a }
+
+main = log "Done"
diff --git a/tests/purs/passing/862.purs b/tests/purs/passing/862.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/862.purs
@@ -0,0 +1,8 @@
+module Main where
+
+import Prelude
+import Effect.Console
+
+id' = (\x -> x) <$> \y -> y
+
+main = log (id' "Done")
diff --git a/tests/purs/passing/922.purs b/tests/purs/passing/922.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/922.purs
@@ -0,0 +1,20 @@
+module Main where
+
+import Prelude
+
+import Effect.Console
+
+class Default a where
+  def :: a
+
+instance defaultString :: Default String where
+  def = "Done"
+
+data I a = I a
+
+instance defaultI :: (Default a) => Default (I a) where
+  def = I def
+
+main = do
+  case def of
+    I s -> log s
diff --git a/tests/purs/passing/Ado.purs b/tests/purs/passing/Ado.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Ado.purs
@@ -0,0 +1,77 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+import Effect.Ref as Ref
+
+data Maybe a = Nothing | Just a
+
+instance functorMaybe :: Functor Maybe where
+  map f Nothing = Nothing
+  map f (Just x) = Just (f x)
+
+instance applyMaybe :: Apply Maybe where
+  apply (Just f) (Just x) = Just (f x)
+  apply _ _ = Nothing
+
+instance applicativeMaybe :: Applicative Maybe where
+  pure = Just
+
+test1 = \_ -> ado
+  in "abc"
+
+test2 = \_ -> ado
+  x <- Just 1.0
+  y <- Just 2.0
+  in x + y
+
+test3 = \_ -> ado
+  _ <- Just 1.0
+  _ <- Nothing :: Maybe Number
+  in 2.0
+
+test4 mx my = ado
+  x <- mx
+  y <- my
+  in x + y + 1.0
+
+test5 mx my mz = ado
+  x <- mx
+  y <- my
+  let sum = x + y
+  z <- mz
+  in z + sum + 1.0
+
+test6 mx = \_ -> ado
+  let
+    f :: forall a. Maybe a -> a
+    f (Just x) = x
+  in f mx
+
+test8 = \_ -> ado
+  in (ado
+    in 1.0)
+
+test9 = \_ -> (+) <$> Just 1.0 <*> Just 2.0
+
+test10 _ = ado
+  let
+    f x = g x * 3.0
+    g x = f x / 2.0
+  in f 10.0
+
+test11 = \_ -> ado
+  x <- pure 1
+  y <- pure "A"
+  z <- pure []
+  in show (x :: Int) <> y <> show (z :: Array Int)
+
+main = do
+  r <- Ref.new "X"
+  log =<< ado
+    _ <- Ref.write "D" r
+    a <- Ref.read r
+    b <- pure "o"
+    let c = "n"
+    d <- pure "e"
+    in a <> b <> c <> d
diff --git a/tests/purs/passing/AppendInReverse.purs b/tests/purs/passing/AppendInReverse.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/AppendInReverse.purs
@@ -0,0 +1,38 @@
+module Main where
+
+import Prelude
+import Data.Symbol (SProxy(..))
+import Prim.Symbol (class Append)
+import Effect.Console (log)
+
+class Balanced (sym :: Symbol)
+
+instance balanced1 :: Balanced ""
+else
+instance balanced2
+  :: ( Append "(" sym1 sym
+     , Append sym2 ")" sym1
+     , Balanced sym2
+     ) => Balanced sym
+
+balanced :: forall sym. Balanced sym => SProxy sym -> String
+balanced _ = "ok"
+
+b0 :: String
+b0 = balanced (SProxy :: SProxy "")
+
+b1 :: String
+b1 = balanced (SProxy :: SProxy "()")
+
+b2 :: String
+b2 = balanced (SProxy :: SProxy "(())")
+
+b3 :: String
+b3 = balanced (SProxy :: SProxy "((()))")
+
+main = do
+  log b0
+  log b1
+  log b2
+  log b3
+  log "Done"
diff --git a/tests/purs/passing/Applicative.purs b/tests/purs/passing/Applicative.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Applicative.purs
@@ -0,0 +1,16 @@
+module Main where
+
+import Effect.Console (log)
+
+class Applicative f where
+  pure :: forall a. a -> f a
+  apply :: forall a b. f (a -> b) -> f a -> f b
+
+data Maybe a = Nothing | Just a
+
+instance applicativeMaybe :: Applicative Maybe where
+  pure = Just
+  apply (Just f) (Just a) = Just (f a)
+  apply _ _ = Nothing
+
+main = log "Done"
diff --git a/tests/purs/passing/ArrayType.purs b/tests/purs/passing/ArrayType.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ArrayType.purs
@@ -0,0 +1,12 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+class Pointed p where
+  point :: forall a. a -> p a
+
+instance pointedArray :: Pointed Array where
+  point a = [a]
+
+main = log "Done"
diff --git a/tests/purs/passing/Auto.purs b/tests/purs/passing/Auto.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Auto.purs
@@ -0,0 +1,16 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+data Auto s i o = Auto { state :: s, step :: s -> i -> o }
+
+type SomeAuto i o = forall r. (forall s. Auto s i o -> r) -> r
+
+exists :: forall s i o. s -> (s -> i -> o) -> SomeAuto i o
+exists = \state step f -> f (Auto { state: state, step: step })
+
+run :: forall i o. SomeAuto i o -> i -> o
+run = \s i -> s (\a -> case a of Auto a -> a.step a.state i)
+
+main = log "Done"
diff --git a/tests/purs/passing/AutoPrelude.purs b/tests/purs/passing/AutoPrelude.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/AutoPrelude.purs
@@ -0,0 +1,11 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+f x = x * 10.0
+g y = y - 10.0
+
+main = do
+  log $ show $ (f <<< g) 100.0
+  log "Done"
diff --git a/tests/purs/passing/AutoPrelude2.purs b/tests/purs/passing/AutoPrelude2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/AutoPrelude2.purs
@@ -0,0 +1,10 @@
+module Main where
+
+import Prelude
+import Prelude as P
+import Effect.Console
+
+f :: forall a. a -> a
+f = P.identity
+
+main = P.($) log ((f P.<<< f) "Done")
diff --git a/tests/purs/passing/BindersInFunctions.purs b/tests/purs/passing/BindersInFunctions.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/BindersInFunctions.purs
@@ -0,0 +1,16 @@
+module Main where
+
+import Prelude
+import Partial.Unsafe (unsafePartial)
+import Test.Assert (assert')
+import Effect (Effect)
+import Effect.Console (log)
+
+snd :: forall a. Partial => Array a -> a
+snd = \[_, y] -> y
+
+main :: Effect _
+main = do
+  let ts = unsafePartial (snd [1.0, 2.0])
+  assert' "Incorrect result from 'snd'." (ts == 2.0)
+  log "Done"
diff --git a/tests/purs/passing/BindingGroups.purs b/tests/purs/passing/BindingGroups.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/BindingGroups.purs
@@ -0,0 +1,11 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+foo = bar
+  where bar r = r + 1.0
+
+r = foo 2.0
+
+main = log "Done"
diff --git a/tests/purs/passing/BlockString.purs b/tests/purs/passing/BlockString.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/BlockString.purs
@@ -0,0 +1,9 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+foo :: String
+foo = """foo"""
+
+main = log "Done"
diff --git a/tests/purs/passing/CaseInDo.purs b/tests/purs/passing/CaseInDo.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/CaseInDo.purs
@@ -0,0 +1,21 @@
+module Main where
+
+import Prelude
+import Partial.Unsafe (unsafeCrashWith)
+import Effect.Console
+import Effect
+
+doIt :: Effect Boolean
+doIt = pure true
+
+set = do
+  log "Testing..."
+  case 0 of
+    0 -> doIt
+    _ -> pure false
+
+main = do
+  b <- set
+  case b of
+    true -> log "Done"
+    false -> unsafeCrashWith "Failed"
diff --git a/tests/purs/passing/CaseInputWildcard.purs b/tests/purs/passing/CaseInputWildcard.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/CaseInputWildcard.purs
@@ -0,0 +1,18 @@
+module Main where
+
+import Prelude
+import Effect (Effect)
+import Effect.Console (log)
+
+data Foo = X | Y
+
+what ∷ Foo → Int → Boolean → Foo
+what x = case _, x, _ of
+  0, X, true → X
+  0, Y, true → X
+  _, _, _ → Y
+
+main :: Effect Unit
+main = do
+  let tmp = what Y 0 true
+  log "Done"
diff --git a/tests/purs/passing/CaseMultipleExpressions.purs b/tests/purs/passing/CaseMultipleExpressions.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/CaseMultipleExpressions.purs
@@ -0,0 +1,21 @@
+module Main where
+
+import Prelude
+import Partial.Unsafe (unsafeCrashWith)
+import Effect.Console
+import Effect
+
+doIt :: Effect Boolean
+doIt = pure true
+
+set = do
+  log "Testing..."
+  case 42, 10 of
+    42, 10 -> doIt
+    _ , _  -> pure false
+
+main = do
+  b <- set
+  case b of
+    true -> log "Done"
+    false -> unsafeCrashWith "Failed"
diff --git a/tests/purs/passing/CaseStatement.purs b/tests/purs/passing/CaseStatement.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/CaseStatement.purs
@@ -0,0 +1,22 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+data A = A | B | C
+
+f a _ A = a
+f _ a B = a
+f _ _ C = "Done"
+
+g a _ A = a
+g _ b B = b
+g _ _ C = C
+
+data M a = N | J a
+
+h f N a = a
+h f a N = a
+h f (J a) (J b) = J (f a b)
+
+main = log $ f "Done" "Failed" A
diff --git a/tests/purs/passing/CheckFunction.purs b/tests/purs/passing/CheckFunction.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/CheckFunction.purs
@@ -0,0 +1,8 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+test = ((\x -> x+1.0) >>> (\x -> x*2.0)) 4.0
+
+main = log "Done"
diff --git a/tests/purs/passing/CheckSynonymBug.purs b/tests/purs/passing/CheckSynonymBug.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/CheckSynonymBug.purs
@@ -0,0 +1,13 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+length :: forall a. Array a -> Int
+length _ = 0
+
+type Foo a = Array a
+
+foo _ = length ([] :: Foo Number)
+
+main = log "Done"
diff --git a/tests/purs/passing/CheckTypeClass.purs b/tests/purs/passing/CheckTypeClass.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/CheckTypeClass.purs
@@ -0,0 +1,18 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+data Bar a = Bar
+data Baz
+
+class Foo a where
+  foo :: Bar a -> Baz
+
+foo_ :: forall a. Foo a => a -> Baz
+foo_ x = foo ((mkBar :: forall a. Foo a => a -> Bar a) x)
+
+mkBar :: forall a. a -> Bar a
+mkBar _ = Bar
+
+main = log "Done"
diff --git a/tests/purs/passing/Church.purs b/tests/purs/passing/Church.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Church.purs
@@ -0,0 +1,18 @@
+module Main where
+
+import Effect.Console (log)
+
+type List a = forall r. r -> (a -> r -> r) -> r
+
+empty :: forall a. List a
+empty = \r f -> r
+
+cons :: forall a. a -> List a -> List a
+cons = \a l r f -> f a (l r f)
+
+append :: forall a. List a -> List a -> List a
+append = \l1 l2 r f -> l2 (l1 r f) f
+
+test = append (cons 1 empty) (cons 2 empty)
+
+main = log "Done"
diff --git a/tests/purs/passing/ClassRefSyntax.purs b/tests/purs/passing/ClassRefSyntax.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ClassRefSyntax.purs
@@ -0,0 +1,9 @@
+module Main where
+
+import Lib (class X, go)
+import Effect.Console (log)
+
+go' :: forall a. X a => a -> a
+go' = go
+
+main = log "Done"
diff --git a/tests/purs/passing/ClassRefSyntax/Lib.purs b/tests/purs/passing/ClassRefSyntax/Lib.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ClassRefSyntax/Lib.purs
@@ -0,0 +1,4 @@
+module Lib (class X, go) where
+
+class X a where
+  go :: a -> a
diff --git a/tests/purs/passing/Collatz.purs b/tests/purs/passing/Collatz.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Collatz.purs
@@ -0,0 +1,21 @@
+module Main where
+
+import Prelude
+import Effect
+import Control.Monad.ST as ST
+import Control.Monad.ST.Ref as STRef
+import Effect.Console (log, logShow)
+
+collatz :: Int -> Int
+collatz n = ST.run (do
+  r <- STRef.new n
+  count <- STRef.new 0
+  ST.while (map (_ /= 1) (STRef.read r)) do
+    _ <- STRef.modify (_ + 1) count
+    m <- STRef.read r
+    void $ STRef.write (if m `mod` 2 == 0 then m / 2 else 3 * m + 1) r
+  STRef.read count)
+
+main = do
+  logShow $ collatz 1000
+  log "Done"
diff --git a/tests/purs/passing/Comparisons.purs b/tests/purs/passing/Comparisons.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Comparisons.purs
@@ -0,0 +1,15 @@
+module Main where
+
+import Prelude
+import Effect
+import Effect.Console
+import Test.Assert
+
+main = do
+  assert (1.0 < 2.0)
+  assert (2.0 == 2.0)
+  assert (3.0 > 1.0)
+  assert ("a" < "b")
+  assert ("a" == "a")
+  assert ("z" > "a")
+  log "Done"
diff --git a/tests/purs/passing/Conditional.purs b/tests/purs/passing/Conditional.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Conditional.purs
@@ -0,0 +1,9 @@
+module Main where
+
+import Effect.Console (log)
+
+fns = \f -> if f true then f else \x -> x
+
+not = \x -> if x then false else true
+
+main = log "Done"
diff --git a/tests/purs/passing/Console.purs b/tests/purs/passing/Console.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Console.purs
@@ -0,0 +1,15 @@
+module Main where
+
+import Prelude
+import Effect
+import Effect.Console
+
+replicateM_ :: forall m a. Monad m => Number -> m a -> m Unit
+replicateM_ 0.0 _ = pure unit
+replicateM_ n act = do
+  _ <- act
+  replicateM_ (n - 1.0) act
+
+main = do
+  replicateM_ 10.0 (log "Hello World!")
+  log "Done"
diff --git a/tests/purs/passing/ConstraintInference.purs b/tests/purs/passing/ConstraintInference.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ConstraintInference.purs
@@ -0,0 +1,10 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+shout = log <<< (_ <> "!") <<< show
+
+main = do
+  shout "Test"
+  log "Done"
diff --git a/tests/purs/passing/ConstraintParens.purs b/tests/purs/passing/ConstraintParens.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ConstraintParens.purs
@@ -0,0 +1,12 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+class Foo a where
+  foo ∷ a → a
+
+test ∷ ∀ a. (Foo a) ⇒ a → a
+test = foo
+
+main = log "Done"
diff --git a/tests/purs/passing/ConstraintParsingIssue.purs b/tests/purs/passing/ConstraintParsingIssue.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ConstraintParsingIssue.purs
@@ -0,0 +1,9 @@
+module Main where
+
+import Effect.Console
+
+class X a
+
+instance x :: X (Array (Array a)) => X (Array a)
+
+main = log "Done"
diff --git a/tests/purs/passing/ContextSimplification.purs b/tests/purs/passing/ContextSimplification.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ContextSimplification.purs
@@ -0,0 +1,15 @@
+module Main where
+
+import Prelude
+import Effect.Console
+
+shout = log <<< (_ <> "!") <<< show
+
+-- Here, we should simplify the context so that only one Show
+-- constraint is added.
+usesShowTwice true = shout
+usesShowTwice false = logShow
+
+main = do
+  usesShowTwice true "Test"
+  log "Done"
diff --git a/tests/purs/passing/DataAndType.purs b/tests/purs/passing/DataAndType.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/DataAndType.purs
@@ -0,0 +1,10 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+data A = A B
+
+type B = A
+
+main = log "Done"
diff --git a/tests/purs/passing/DataConsClassConsOverlapOk.purs b/tests/purs/passing/DataConsClassConsOverlapOk.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/DataConsClassConsOverlapOk.purs
@@ -0,0 +1,8 @@
+module Main where
+
+import Effect.Console (log)
+import Prim.Row (class Cons)
+
+data Cons = Cons
+
+main = log "Done"
diff --git a/tests/purs/passing/DctorName.purs b/tests/purs/passing/DctorName.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/DctorName.purs
@@ -0,0 +1,33 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+newtype Bar' = Bar' Int
+
+data Foo' = Foo' Bar'
+
+data Baz'' = Baz'' | Baz'
+
+f ∷ Foo' → Boolean
+f a = case a of Foo' b → true
+
+f' ∷ Boolean
+f' = f $ Foo' $ Bar' 0
+
+g ∷ Baz'' → Int
+g Baz'' = 0
+g Baz' = 1
+
+g' ∷ Int
+g' = g Baz''
+
+h ∷ Bar' → Int
+h (Bar' x)
+ | x <= 10 = x * 2 
+ | otherwise = 10
+
+h' ∷ Int
+h' = h $ Bar' 4
+
+main = log "Done"
diff --git a/tests/purs/passing/DctorOperatorAlias.purs b/tests/purs/passing/DctorOperatorAlias.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/DctorOperatorAlias.purs
@@ -0,0 +1,34 @@
+module Main where
+
+  import Prelude (Unit, bind, discard, (==))
+  import Effect (Effect)
+  import Effect.Console (log)
+  import Test.Assert (assert')
+  import List (List(..), (:))
+  import List as L
+
+  -- unqualified
+  infixl 6 Cons as !
+
+  -- qualified
+  infixl 6 L.Cons as !!
+
+  get1 ∷ ∀ a. a → List a → a
+  get1 y xs = case xs of
+    _ : x : _ → x
+    _ → y
+
+  get2 ∷ ∀ a. a → List a → a
+  get2 _ (_ : x : _) = x
+  get2 y _ = y
+
+  get3 ∷ ∀ a. a → List a → a
+  get3 _ (_ ! (x ! _)) = x
+  get3 y _ = y
+
+  main ∷ Effect Unit
+  main = do
+    assert' "Incorrect result!" (get1 0 (1 : 2 : 3 : Nil) == 2)
+    assert' "Incorrect result!" (get2 0 (1 ! (2 ! (3 ! Nil))) == 2)
+    assert' "Incorrect result!" (get3 0.0 (1.0 : 2.0 : (3.0 ! Nil)) == 2.0)
+    log "Done"
diff --git a/tests/purs/passing/DctorOperatorAlias/List.purs b/tests/purs/passing/DctorOperatorAlias/List.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/DctorOperatorAlias/List.purs
@@ -0,0 +1,5 @@
+module List where
+
+data List a = Cons a (List a) | Nil
+
+infixr 6 Cons as :
diff --git a/tests/purs/passing/DeepArrayBinder.purs b/tests/purs/passing/DeepArrayBinder.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/DeepArrayBinder.purs
@@ -0,0 +1,17 @@
+module Main where
+
+import Prelude
+import Effect
+import Effect.Console (log)
+import Test.Assert
+
+data List a = Cons a (List a) | Nil
+
+match2 :: List Number -> Number
+match2 (Cons x (Cons y xs)) = x * y + match2 xs
+match2 _ = 0.0
+
+main = do
+  let result = match2 (Cons 1.0 (Cons 2.0 (Cons 3.0 (Cons 4.0 (Cons 5.0 (Cons 6.0 (Cons 7.0 (Cons 8.0 (Cons 9.0 Nil)))))))))
+  assert' "Incorrect result!" (result == 100.0)
+  log "Done"
diff --git a/tests/purs/passing/DeepCase.purs b/tests/purs/passing/DeepCase.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/DeepCase.purs
@@ -0,0 +1,15 @@
+module Main where
+
+import Prelude
+import Effect.Console (log, logShow)
+
+f x y =
+  let
+    g = case y of
+	  0.0 -> x
+          x -> 1.0 + x * x
+  in g + x + y
+
+main = do
+  logShow $ f 1.0 10.0
+  log "Done"
diff --git a/tests/purs/passing/DeriveNewtype.purs b/tests/purs/passing/DeriveNewtype.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/DeriveNewtype.purs
@@ -0,0 +1,29 @@
+module Main where
+
+import Effect.Console (log)
+
+import Data.Newtype
+
+type MyString = String
+
+newtype Test = Test MyString
+
+derive instance newtypeTest :: Newtype Test _
+
+t :: Test
+t = wrap "hello"
+
+a :: String
+a = unwrap t
+
+newtype First a = First a
+
+derive instance newtypeFirst :: Newtype (First b) _
+
+f :: First Int
+f = wrap 1
+
+i :: Int
+i = unwrap f
+
+main = log "Done"
diff --git a/tests/purs/passing/DeriveWithNestedSynonyms.purs b/tests/purs/passing/DeriveWithNestedSynonyms.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/DeriveWithNestedSynonyms.purs
@@ -0,0 +1,29 @@
+module Main where
+	
+import Prelude
+import Effect.Console (log)
+
+type L = {}
+data X = X L
+derive instance eqX :: Eq X
+
+type M = {}
+data Y = Y {foo :: M}
+derive instance eqY :: Eq Y
+
+type N = {}
+data Z = Z N
+derive instance eqZ :: Eq Z
+
+type Foo = String
+
+type Bar = { foo :: Foo }
+
+type Baz = { baz :: Bar }
+
+newtype T = T Baz
+
+derive instance eqT :: Eq T
+derive instance ordT :: Ord T
+
+main = log "Done"
diff --git a/tests/purs/passing/Deriving.purs b/tests/purs/passing/Deriving.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Deriving.purs
@@ -0,0 +1,36 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+import Test.Assert
+
+data V
+
+derive instance eqV :: Eq V
+
+derive instance ordV :: Ord V
+
+type MyString = String
+
+data X = X Int | Y MyString
+
+derive instance eqX :: Eq X
+
+derive instance ordX :: Ord X
+
+newtype Z = Z { left :: X, right :: X }
+
+derive instance eqZ :: Eq Z
+
+main = do
+  assert $ X 0 == X 0
+  assert $ X 0 /= X 1
+  assert $ Y "Foo" == Y "Foo"
+  assert $ Y "Foo" /= Y "Bar"
+  assert $ X 0 < X 1
+  assert $ X 0 < Y "Foo"
+  assert $ Y "Bar" < Y "Baz"
+  assert $ z == z
+  log "Done"
+  where
+  z = Z { left: X 0, right: Y "Foo" }
diff --git a/tests/purs/passing/DerivingFunctor.purs b/tests/purs/passing/DerivingFunctor.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/DerivingFunctor.purs
@@ -0,0 +1,36 @@
+module Main where
+
+import Prelude
+import Data.Eq (class Eq1)
+import Effect.Console (log)
+import Test.Assert
+
+type MyRecord a = { myField :: a }
+
+data M f a
+  = M0 a (Array a)
+  | M1 Int
+  | M2 (f a)
+  | M3 { foo :: Int, bar :: a, baz :: f a }
+  | M4 (MyRecord a)
+
+derive instance eqM :: (Eq1 f, Eq a) => Eq (M f a)
+derive instance functorM :: Functor f => Functor (M f)
+
+data T a = T (forall t. Show t => t -> a)
+derive instance functorT :: Functor T
+
+type MA = M Array
+
+main = do
+  assert $ map show (M0 0 [1, 2] :: MA Int) == M0 "0" ["1", "2"]
+  assert $ map show (M1 0 :: MA Int) == M1 0
+  assert $ map show (M2 [0, 1] :: MA Int) == M2 ["0", "1"]
+  assert $ map show (M3 {foo: 0, bar: 1, baz: [2, 3]} :: MA Int) == M3 {foo: 0, bar: "1", baz: ["2", "3"]}
+  assert $ map show (M4 { myField: 42 }) == M4 { myField: "42" } :: MA String
+
+  case map show (T \_ -> 42) of
+    T f -> assert $ f "hello" == "42"
+    _   -> assert false
+
+  log "Done"
diff --git a/tests/purs/passing/Do.purs b/tests/purs/passing/Do.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Do.purs
@@ -0,0 +1,68 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+data Maybe a = Nothing | Just a
+
+instance functorMaybe :: Functor Maybe where
+  map f Nothing = Nothing
+  map f (Just x) = Just (f x)
+
+instance applyMaybe :: Apply Maybe where
+  apply (Just f) (Just x) = Just (f x)
+  apply _ _ = Nothing
+
+instance applicativeMaybe :: Applicative Maybe where
+  pure = Just
+
+instance bindMaybe :: Bind Maybe where
+  bind Nothing _ = Nothing
+  bind (Just a) f = f a
+
+instance monadMaybe :: Monad Maybe
+
+test1 = \_ -> do
+  Just "abc"
+
+test2 = \_ -> do
+  x <- Just 1.0
+  y <- Just 2.0
+  Just (x + y)
+
+test3 = \_ -> do
+  _ <- Just 1.0
+  _ <- Nothing :: Maybe Number
+  Just 2.0
+
+test4 mx my = do
+  x <- mx
+  y <- my
+  Just (x + y + 1.0)
+
+test5 mx my mz = do
+  x <- mx
+  y <- my
+  let sum = x + y
+  z <- mz
+  Just (z + sum + 1.0)
+
+test6 mx = \_ -> do
+  let
+    f :: forall a. Maybe a -> a
+    f (Just x) = x
+  Just (f mx)
+
+test8 = \_ -> do
+  Just (do
+    Just 1.0)
+
+test9 = \_ -> (+) <$> Just 1.0 <*> Just 2.0
+
+test10 _ = do
+  let
+    f x = g x * 3.0
+    g x = f x / 2.0
+  Just (f 10.0)
+
+main = log "Done"
diff --git a/tests/purs/passing/Dollar.purs b/tests/purs/passing/Dollar.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Dollar.purs
@@ -0,0 +1,16 @@
+module Main where
+
+import Effect.Console (log)
+
+applyFn :: forall a b. (a -> b) -> a -> b
+applyFn f x = f x
+
+infixr 1000 applyFn as $
+
+id x = x
+
+test1 x = id $ id $ id $ id $ x
+
+test2 x = id id $ id x
+
+main = log "Done"
diff --git a/tests/purs/passing/DuplicateProperties.purs b/tests/purs/passing/DuplicateProperties.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/DuplicateProperties.purs
@@ -0,0 +1,27 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+data RProxy (r :: # Type) = RProxy
+
+data Proxy (a :: Type) = Proxy
+
+subtractX :: forall r a. RProxy (x :: a | r) -> RProxy r
+subtractX RProxy = RProxy
+
+extractX :: forall r a. RProxy (x :: a | r) -> Proxy a
+extractX RProxy = Proxy
+
+hasX :: forall r a b. RProxy (x :: a, y :: b | r)
+hasX = RProxy
+
+test1 = subtractX (subtractX hasX)
+
+test2
+  :: forall r a b
+   . RProxy (x :: a, x :: b, x :: Int | r)
+  -> Proxy Int
+test2 x = extractX (subtractX (subtractX x))
+
+main = log "Done"
diff --git a/tests/purs/passing/EffFn.js b/tests/purs/passing/EffFn.js
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/EffFn.js
@@ -0,0 +1,1 @@
+exports.add3 = function (a,b,c) { return a + b + c; };
diff --git a/tests/purs/passing/EffFn.purs b/tests/purs/passing/EffFn.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/EffFn.purs
@@ -0,0 +1,22 @@
+module Main where
+
+import Prelude
+
+import Effect.Console (log)
+import Effect.Uncurried (EffectFn3, mkEffectFn7, runEffectFn3, runEffectFn7)
+import Test.Assert (assert)
+
+testBothWays = do
+  res <- (runEffectFn7 $ mkEffectFn7 \x1 x2 x3 x4 x5 x6 x7 -> pure 42) 1 2 3 4 5 6 7
+  assert $ res == 42
+
+foreign import add3 :: EffectFn3 String String String String
+
+testRunFn = do
+  str <- runEffectFn3 add3 "a" "b" "c"
+  assert $ str == "abc"
+
+main = do
+  testBothWays
+  testRunFn
+  log "Done"
diff --git a/tests/purs/passing/EmptyDataDecls.purs b/tests/purs/passing/EmptyDataDecls.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/EmptyDataDecls.purs
@@ -0,0 +1,20 @@
+module Main where
+
+import Prelude
+import Test.Assert
+import Effect.Console (log)
+
+data Z
+data S n
+
+data ArrayBox n a = ArrayBox (Array a)
+
+nil :: forall a. ArrayBox Z a
+nil = ArrayBox []
+
+cons' :: forall a n. a -> ArrayBox n a -> ArrayBox (S n) a
+cons' x (ArrayBox xs) = ArrayBox $ append [x] xs
+
+main = case cons' 1 $ cons' 2 $ cons' 3 nil of
+         ArrayBox [1, 2, 3] -> log "Done"
+         _ -> assert' "Failed" false
diff --git a/tests/purs/passing/EmptyRow.purs b/tests/purs/passing/EmptyRow.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/EmptyRow.purs
@@ -0,0 +1,11 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+data Foo r = Foo { | r }
+
+test :: Foo ()
+test = Foo {}
+
+main = log "Done"
diff --git a/tests/purs/passing/EmptyTypeClass.purs b/tests/purs/passing/EmptyTypeClass.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/EmptyTypeClass.purs
@@ -0,0 +1,11 @@
+module Main where
+
+import Prelude
+import Effect
+import Effect.Console
+
+head :: forall a. Partial => Array a -> a
+head [x] = x
+
+main :: Effect _
+main = log "Done"
diff --git a/tests/purs/passing/EntailsKindedType.purs b/tests/purs/passing/EntailsKindedType.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/EntailsKindedType.purs
@@ -0,0 +1,11 @@
+module Main where
+
+import Prelude
+import Effect
+import Effect.Console
+
+test x = show (x :: _ :: Type)
+
+main = do
+  when (show (unit :: Unit :: Type) == "unit") (log "Done")
+  when (test unit == "unit") (log "Done")
diff --git a/tests/purs/passing/Eq1Deriving.purs b/tests/purs/passing/Eq1Deriving.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Eq1Deriving.purs
@@ -0,0 +1,12 @@
+module Main where
+
+import Prelude
+import Data.Eq (class Eq1)
+import Effect.Console (log)
+
+data Product a b = Product a b
+
+derive instance eqMu :: (Eq a, Eq b) => Eq (Product a b)
+derive instance eq1Mu :: Eq a => Eq1 (Product a)
+
+main = log "Done"
diff --git a/tests/purs/passing/Eq1InEqDeriving.purs b/tests/purs/passing/Eq1InEqDeriving.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Eq1InEqDeriving.purs
@@ -0,0 +1,11 @@
+module Main where
+
+import Prelude
+import Data.Eq (class Eq1)
+import Effect.Console (log)
+
+newtype Mu f = In (f (Mu f))
+
+derive instance eqMu :: Eq1 f => Eq (Mu f)
+
+main = log "Done"
diff --git a/tests/purs/passing/EqOrd.purs b/tests/purs/passing/EqOrd.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/EqOrd.purs
@@ -0,0 +1,18 @@
+module Main where
+
+import Prelude
+import Effect.Console (log, logShow)
+
+data Pair a b = Pair a b
+
+instance ordPair :: (Ord a, Ord b) => Ord (Pair a b) where
+  compare (Pair a1 b1) (Pair a2 b2) = case compare a1 a2 of
+    EQ -> compare b1 b2
+    r -> r
+
+instance eqPair :: (Eq a, Eq b) => Eq (Pair a b) where
+  eq (Pair a1 b1) (Pair a2 b2) = a1 == a2 && b1 == b2
+
+main = do
+  logShow $ Pair 1.0 2.0 == Pair 1.0 2.0
+  log "Done"
diff --git a/tests/purs/passing/ExplicitImportReExport.purs b/tests/purs/passing/ExplicitImportReExport.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ExplicitImportReExport.purs
@@ -0,0 +1,11 @@
+-- from #1244
+module Main where
+
+import Prelude
+import Effect.Console (log)
+import Bar (foo)
+
+baz :: Int
+baz = foo
+
+main = log "Done"
diff --git a/tests/purs/passing/ExplicitImportReExport/Bar.purs b/tests/purs/passing/ExplicitImportReExport/Bar.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ExplicitImportReExport/Bar.purs
@@ -0,0 +1,3 @@
+module Bar (module Foo) where
+
+import Foo
diff --git a/tests/purs/passing/ExplicitImportReExport/Foo.purs b/tests/purs/passing/ExplicitImportReExport/Foo.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ExplicitImportReExport/Foo.purs
@@ -0,0 +1,4 @@
+module Foo where
+
+foo :: Int
+foo = 3
diff --git a/tests/purs/passing/ExplicitOperatorSections.purs b/tests/purs/passing/ExplicitOperatorSections.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ExplicitOperatorSections.purs
@@ -0,0 +1,15 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+subtractOne :: Int -> Int
+subtractOne = (_ - 1)
+
+addOne :: Int -> Int
+addOne = (1 + _)
+
+named :: Int -> Int
+named = (_ `sub` 1)
+
+main = log "Done"
diff --git a/tests/purs/passing/ExportExplicit.purs b/tests/purs/passing/ExportExplicit.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ExportExplicit.purs
@@ -0,0 +1,10 @@
+module Main where
+
+import M1
+import Effect.Console (log)
+
+testX = X
+testZ = Z
+testFoo = foo
+
+main = log "Done"
diff --git a/tests/purs/passing/ExportExplicit/M1.purs b/tests/purs/passing/ExportExplicit/M1.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ExportExplicit/M1.purs
@@ -0,0 +1,10 @@
+module M1 (X(X), Z(..), foo) where
+
+data X = X | Y
+data Z = Z
+
+foo :: Int
+foo = 0
+
+bar :: Int
+bar = 1
diff --git a/tests/purs/passing/ExportExplicit2.purs b/tests/purs/passing/ExportExplicit2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ExportExplicit2.purs
@@ -0,0 +1,8 @@
+module Main where
+
+import M1
+import Effect.Console (log)
+
+testBar = bar
+
+main = log "Done"
diff --git a/tests/purs/passing/ExportExplicit2/M1.purs b/tests/purs/passing/ExportExplicit2/M1.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ExportExplicit2/M1.purs
@@ -0,0 +1,7 @@
+module M1 (bar) where
+
+foo :: Int
+foo = 0
+
+bar :: Int
+bar = foo
diff --git a/tests/purs/passing/ExportedInstanceDeclarations.purs b/tests/purs/passing/ExportedInstanceDeclarations.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ExportedInstanceDeclarations.purs
@@ -0,0 +1,45 @@
+-- Tests that instances for non-exported classes / types do not appear in the
+-- result of `exportedDeclarations`.
+module Main
+  ( Const(..)
+  , class Foo
+  , foo
+  , main
+  ) where
+
+import Prelude
+import Effect.Console (log)
+
+data Const a b = Const a
+
+class Foo a where
+  foo :: a
+
+data NonexportedType = NonexportedType
+
+class NonexportedClass a where
+  notExported :: a
+
+-- There are three places that a nonexported type or type class can occur,
+-- leading an instance to count as non-exported:
+--  * The instance types
+--  * Constraints
+--  * The type class itself
+
+-- Case 1: instance types
+instance constFoo :: Foo (Const NonexportedType b) where
+  foo = Const NonexportedType
+else
+-- Case 2: constraints
+instance nonExportedFoo :: (Foo NonexportedType) => Foo (a -> a) where
+  foo = identity
+else
+-- Another instance of case 2:
+instance nonExportedFoo2 :: (NonexportedClass a) => Foo a where
+  foo = notExported
+
+-- Case 3: type class
+instance nonExportedNonexportedType :: NonexportedClass (Const Int a) where
+  notExported = Const 0
+
+main = log "Done"
diff --git a/tests/purs/passing/ExtendedInfixOperators.purs b/tests/purs/passing/ExtendedInfixOperators.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ExtendedInfixOperators.purs
@@ -0,0 +1,17 @@
+module Main where
+
+import Prelude
+import Effect.Console (log, logShow)
+import Data.Function (on)
+
+comparing :: forall a b. Ord b => (a -> b) -> a -> a -> Ordering
+comparing f = compare `on` f
+
+null [] = true
+null _ = false
+
+test = [1.0, 2.0, 3.0] `comparing null` [4.0, 5.0, 6.0]
+
+main = do
+  logShow test
+  log "Done"
diff --git a/tests/purs/passing/Fib.purs b/tests/purs/passing/Fib.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Fib.purs
@@ -0,0 +1,20 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+import Control.Monad.ST as ST
+import Control.Monad.ST.Ref as STRef
+
+fib :: Number
+fib = ST.run do
+    n1 <- STRef.new 1.0
+    n2 <- STRef.new 1.0
+    ST.while ((>) 1000.0 <$> STRef.read n1) do
+      n1' <- STRef.read n1
+      n2' <- STRef.read n2
+      _ <- STRef.write (n1' + n2') n2
+      STRef.write n2' n1
+    STRef.read n2
+
+main = do
+  log "Done"
diff --git a/tests/purs/passing/FieldConsPuns.purs b/tests/purs/passing/FieldConsPuns.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/FieldConsPuns.purs
@@ -0,0 +1,13 @@
+module Main where
+
+import Prelude
+import Effect.Console (log, logShow)
+
+greet { greeting, name } = log $ greeting <> ", " <> name <> "."
+
+main = do
+  greet { greeting, name }
+  log "Done"
+  where
+  greeting = "Hello"
+  name = "World"
diff --git a/tests/purs/passing/FieldPuns.purs b/tests/purs/passing/FieldPuns.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/FieldPuns.purs
@@ -0,0 +1,10 @@
+module Main where
+
+import Prelude
+import Effect.Console
+
+greet { greeting, name } = log $ greeting <> ", " <> name <> "."
+
+main = do
+  greet { greeting: "Hello", name: "World" }
+  log "Done"
diff --git a/tests/purs/passing/FinalTagless.purs b/tests/purs/passing/FinalTagless.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/FinalTagless.purs
@@ -0,0 +1,25 @@
+module Main where
+
+import Prelude hiding (add)
+import Effect.Console (log, logShow)
+
+class E e where
+  num :: Number -> e Number
+  add :: e Number -> e Number -> e Number
+
+type Expr a = forall e. E e => e a
+
+data Id a = Id a
+
+instance exprId :: E Id where
+  num = Id
+  add (Id n) (Id m) = Id (n + m)
+
+runId (Id a) = a
+
+three :: Expr Number
+three = add (num 1.0) (num 2.0)
+
+main = do
+  logShow $ runId three
+  log "Done"
diff --git a/tests/purs/passing/ForeignKind.purs b/tests/purs/passing/ForeignKind.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ForeignKind.purs
@@ -0,0 +1,10 @@
+module Main where
+
+import Prelude
+import ForeignKinds.Lib (kind Nat, Zero, Succ, N3, NatProxy, class AddNat, addNat, proxy1, proxy2)
+import Effect.Console (log)
+
+proxy1Add2Is3 :: NatProxy N3
+proxy1Add2Is3 = addNat proxy1 proxy2
+
+main = log "Done"
diff --git a/tests/purs/passing/ForeignKind/Lib.purs b/tests/purs/passing/ForeignKind/Lib.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ForeignKind/Lib.purs
@@ -0,0 +1,60 @@
+module ForeignKinds.Lib (kind Nat, Kinded, Zero, Succ, N0, N1, N2, N3, NatProxy(..), class AddNat, addNat, proxy1, proxy2) where
+
+-- declaration
+
+foreign import kind Nat
+
+-- use in foreign data
+
+foreign import data Zero :: Nat
+foreign import data Succ :: Nat -> Nat
+
+-- use in data
+
+data NatProxy (t :: Nat) = NatProxy
+
+-- use in type sig
+
+succProxy :: forall n. NatProxy n -> NatProxy (Succ n)
+succProxy _ = NatProxy
+
+-- use in alias
+
+type Kinded f = f :: Nat
+
+type KindedZero = Kinded Zero
+
+type N0 = Zero
+type N1 = Succ N0
+type N2 = Succ N1
+type N3 = Succ N2
+
+-- use of alias
+
+proxy0 :: NatProxy N0
+proxy0 = NatProxy
+
+proxy1 :: NatProxy N1
+proxy1 = NatProxy
+
+proxy2 :: NatProxy N2
+proxy2 = NatProxy
+
+proxy3 :: NatProxy N3
+proxy3 = NatProxy
+
+-- use in class
+
+class AddNat (l :: Nat) (r :: Nat) (o :: Nat) | l -> r o
+
+instance addNatZero
+  :: AddNat Zero r r
+
+instance addNatSucc
+  :: AddNat l r o
+  => AddNat (Succ l) r (Succ o)
+
+-- use of class
+
+addNat :: forall l r o. AddNat l r o => NatProxy l -> NatProxy r -> NatProxy o
+addNat _ _ = NatProxy
diff --git a/tests/purs/passing/FunWithFunDeps.js b/tests/purs/passing/FunWithFunDeps.js
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/FunWithFunDeps.js
@@ -0,0 +1,32 @@
+
+//: forall e. FVect Z e
+exports.fnil = [];
+
+//: forall n e. e -> FVect n e -> FVect (S n) e
+exports.fcons = function (hd) {
+  return function (tl) {
+    return [hd].concat(tl);
+  };
+};
+
+exports.fappend = function (dict) {
+  return function (left) {
+    return function (right) {
+      return left.concat(right);
+    };
+  };
+};
+
+exports.fflatten = function (dict) {
+  return function (v) {
+    var accRef = [];
+    for (var indexRef = 0; indexRef < v.length; indexRef += 1) {
+      accRef = accRef.concat(v[indexRef]);
+    }
+    return accRef;
+  };
+};
+
+exports.ftoArray = function (vect) {
+  return vect;
+};
diff --git a/tests/purs/passing/FunWithFunDeps.purs b/tests/purs/passing/FunWithFunDeps.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/FunWithFunDeps.purs
@@ -0,0 +1,41 @@
+-- Taken from https://github.com/LiamGoodacre/purescript-fun-with-fundeps
+
+module Main where
+
+import Effect.Console (log)
+
+-- Nat : Type
+data Z
+data S n
+
+type S2 n = S (S n)
+type S3 n = S (S2 n)
+type S4 n = S (S3 n)
+type S5 n = S (S4 n)
+type S15 n = S5 (S5 (S5 n))
+
+class NatPlus l r o | l r -> o
+instance natPlusZ :: NatPlus Z r r
+instance natPlusS :: (NatPlus l r o) => NatPlus (S l) r (S o)
+
+class NatMult l r o | l r -> o
+instance natMultZ :: NatMult Z n Z
+instance natMultS :: (NatMult m n r, NatPlus n r s) => NatMult (S m) n s
+
+-- Foreign Vect
+foreign import data FVect :: Type -> Type -> Type
+foreign import fnil :: forall e. FVect Z e
+foreign import fcons :: forall n e. e -> FVect n e -> FVect (S n) e
+foreign import fappend :: forall l r o e. NatPlus l r o => FVect l e -> FVect r e -> FVect o e
+foreign import fflatten :: forall f s t o. NatMult f s o => FVect f (FVect s t) -> FVect o t
+foreign import ftoArray :: forall n e. FVect n e -> Array e
+
+-- should be able to figure these out
+fsingleton x = fcons x fnil
+fexample = fcons 1 (fsingleton 2) `fappend` fsingleton 3 `fappend` fcons 4 (fsingleton 5)
+fexample2 = fexample `fappend` fexample `fappend` fexample
+fexample3 = fsingleton fexample `fappend` fsingleton fexample `fappend` fsingleton fexample
+
+fexample4 = fflatten fexample3
+
+main = log "Done"
diff --git a/tests/purs/passing/FunctionScope.purs b/tests/purs/passing/FunctionScope.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/FunctionScope.purs
@@ -0,0 +1,13 @@
+module Main where
+
+import Prelude
+import Test.Assert
+import Effect.Console (log)
+
+mkValue :: Number -> Number
+mkValue id = id
+
+main = do
+  let value = mkValue 1.0
+  assert $ value == 1.0
+  log "Done"
diff --git a/tests/purs/passing/FunctionalDependencies.purs b/tests/purs/passing/FunctionalDependencies.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/FunctionalDependencies.purs
@@ -0,0 +1,21 @@
+module Main where
+
+import Effect.Console (log)
+
+data Nil
+data Cons x xs
+
+class Append a b c | a b -> c
+
+instance appendNil :: Append Nil b b
+
+instance appendCons :: Append xs b c => Append (Cons x xs) b (Cons x c)
+
+data Proxy a = Proxy
+
+appendProxy :: forall a b c. Append a b c => Proxy a -> Proxy b -> Proxy c
+appendProxy Proxy Proxy = Proxy
+
+test = appendProxy (Proxy :: Proxy (Cons Int Nil)) (Proxy :: Proxy (Cons String Nil))
+
+main = log "Done"
diff --git a/tests/purs/passing/Functions.purs b/tests/purs/passing/Functions.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Functions.purs
@@ -0,0 +1,12 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+test1 = \_ -> 0.0
+
+test2 = \a b -> a + b + 1.0
+
+test3 = \a -> a
+
+main = log "Done"
diff --git a/tests/purs/passing/Functions2.purs b/tests/purs/passing/Functions2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Functions2.purs
@@ -0,0 +1,13 @@
+module Main where
+
+import Prelude
+import Test.Assert
+import Effect.Console (log)
+
+test :: forall a b. a -> b -> a
+test = \const _ -> const
+
+main = do
+  let value = test "Done" {}
+  assert' "Not done" $ value == "Done"
+  log "Done"
diff --git a/tests/purs/passing/Generalization1.purs b/tests/purs/passing/Generalization1.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Generalization1.purs
@@ -0,0 +1,11 @@
+module Main where
+
+import Prelude
+import Effect.Console (logShow, log)
+
+main = do
+  logShow (sum 1.0 2.0)
+  logShow (sum 1 2)
+  log "Done"
+
+sum x y = x + y
diff --git a/tests/purs/passing/GenericsRep.purs b/tests/purs/passing/GenericsRep.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/GenericsRep.purs
@@ -0,0 +1,43 @@
+module Main where
+
+import Prelude
+import Effect (Effect)
+import Effect.Console (log, logShow)
+import Data.Generic.Rep (class Generic)
+import Data.Generic.Rep.Eq (genericEq)
+
+data X a = X a
+
+derive instance genericX :: Generic (X a) _
+
+instance eqX :: Eq a => Eq (X a) where
+  eq xs ys = genericEq xs ys
+
+data Y a = Y | Z a (Y a)
+
+derive instance genericY :: Generic (Y a) _
+
+instance eqY :: Eq a => Eq (Y a) where
+  eq xs ys = genericEq xs ys
+
+data Z
+
+derive instance genericZ :: Generic Z _
+
+instance eqZ :: Eq Z where
+  eq x y = genericEq x y
+
+type MyString = String
+
+newtype W = W { x :: Int, y :: MyString }
+
+derive instance genericW :: Generic W _
+
+main :: Effect Unit
+main = do
+  logShow (X 0 == X 1)
+  logShow (X 1 == X 1)
+  logShow (Z 1 Y == Z 1 Y)
+  logShow (Z 1 Y == Y)
+  logShow (Y == Y :: Y Z)
+  log "Done"
diff --git a/tests/purs/passing/Guards.purs b/tests/purs/passing/Guards.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Guards.purs
@@ -0,0 +1,64 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+collatz = \x -> case x of
+  y | y `mod` 2.0 == 0.0 -> y / 2.0
+  y -> y * 3.0 + 1.0
+
+-- Guards have access to current scope
+collatz2 = \x y -> case x of
+  z | y > 0.0 -> z / 2.0
+  z -> z * 3.0 + 1.0
+
+min :: forall a. Ord a => a -> a -> a
+min n m | n < m     = n
+        | otherwise = m
+
+max :: forall a. Ord a => a -> a -> a
+max n m = case unit of
+  _ | m < n     -> n
+    | otherwise -> m
+
+testIndentation :: Number -> Number -> Number
+testIndentation x y | x > 0.0
+  = x + y
+                    | otherwise
+  = y - x
+
+-- pattern guard example with two clauses
+clunky1 :: Int -> Int -> Int
+clunky1 a b | x <- max a b
+            , x > 5
+            = x
+clunky1 a _ = a
+
+clunky2 :: Int -> Int -> Int
+clunky2 a b | x <- max a b
+            , x > 5
+            = x
+            | otherwise
+            = a + b
+
+-- pattern guards on case epxressions
+clunky_case1 :: Int -> Int -> Int
+clunky_case1 a b =
+  case unit of
+    unit | x <- max a b
+         , x > 5
+         -> x
+         | otherwise -> a + b
+
+-- test indentation
+clunky_case2 :: Int -> Int -> Int
+clunky_case2 a b =
+  case unit of
+    unit
+      | x <- max a b
+      , x > 5
+      -> x
+      | otherwise
+      -> a + b
+
+main = log $ min "Done" "ZZZZ"
diff --git a/tests/purs/passing/HasOwnProperty.purs b/tests/purs/passing/HasOwnProperty.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/HasOwnProperty.purs
@@ -0,0 +1,5 @@
+module Main where
+
+import Effect.Console (log)
+
+main = log ({hasOwnProperty: "Hi"} {hasOwnProperty = "Done"}).hasOwnProperty
diff --git a/tests/purs/passing/HoistError.purs b/tests/purs/passing/HoistError.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/HoistError.purs
@@ -0,0 +1,12 @@
+module Main where
+
+import Prelude
+import Effect
+import Effect.Console
+import Test.Assert
+
+main = do
+  let x = 0.0
+  assert $ x == 0.0
+  let x = 1.0 + 1.0
+  log "Done"
diff --git a/tests/purs/passing/IfThenElseMaybe.purs b/tests/purs/passing/IfThenElseMaybe.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/IfThenElseMaybe.purs
@@ -0,0 +1,12 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+data Maybe a = Nothing | Just a
+
+test1 = if true then Just 10 else Nothing
+
+test2 = if true then Nothing else Just 10
+
+main = log "Done"
diff --git a/tests/purs/passing/IfWildcard.purs b/tests/purs/passing/IfWildcard.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/IfWildcard.purs
@@ -0,0 +1,19 @@
+module Main where
+
+import Prelude
+import Effect (Effect)
+import Effect.Console (log)
+
+data Foo = X | Y
+
+cond ∷ ∀ a. Boolean → a → a → a
+cond = if _ then _ else _
+
+what ∷ Boolean → Foo
+what = if _ then X else Y
+
+main :: Effect Unit
+main = do
+  let tmp1 = what true
+      tmp2 = cond true 0 1
+  log "Done"
diff --git a/tests/purs/passing/ImplicitEmptyImport.purs b/tests/purs/passing/ImplicitEmptyImport.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ImplicitEmptyImport.purs
@@ -0,0 +1,9 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+main = do
+  log "Hello"
+  log "Goodbye"
+  log "Done"
diff --git a/tests/purs/passing/Import.purs b/tests/purs/passing/Import.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Import.purs
@@ -0,0 +1,6 @@
+module Main where
+
+import M2
+import Effect.Console (log)
+
+main = log "Done"
diff --git a/tests/purs/passing/Import/M1.purs b/tests/purs/passing/Import/M1.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Import/M1.purs
@@ -0,0 +1,8 @@
+module M1 where
+
+import Prelude ()
+
+id :: forall a. a -> a
+id = \x -> x
+
+foo = id
diff --git a/tests/purs/passing/Import/M2.purs b/tests/purs/passing/Import/M2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Import/M2.purs
@@ -0,0 +1,6 @@
+module M2 where
+
+import Prelude ()
+import M1
+
+main = \_ -> foo 42
diff --git a/tests/purs/passing/ImportExplicit.purs b/tests/purs/passing/ImportExplicit.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ImportExplicit.purs
@@ -0,0 +1,10 @@
+module Main where
+
+import M1 (X(..))
+import Effect.Console (log)
+
+testX :: X
+testX = X
+testY = Y
+
+main = log "Done"
diff --git a/tests/purs/passing/ImportExplicit/M1.purs b/tests/purs/passing/ImportExplicit/M1.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ImportExplicit/M1.purs
@@ -0,0 +1,4 @@
+module M1 where
+
+data X = X | Y
+data Z = Z
diff --git a/tests/purs/passing/ImportHiding.purs b/tests/purs/passing/ImportHiding.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ImportHiding.purs
@@ -0,0 +1,19 @@
+module Main where
+
+import Effect.Console
+import Prelude hiding (
+  show, -- a value
+  class Show, -- a type class
+  Unit(..)  -- a constructor
+  )
+
+show = 1.0
+
+class Show a where
+  noshow :: a -> a
+
+data Unit = X | Y
+
+main = do
+  logShow show
+  log "Done"
diff --git a/tests/purs/passing/ImportQualified.purs b/tests/purs/passing/ImportQualified.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ImportQualified.purs
@@ -0,0 +1,8 @@
+module Main where
+
+import Prelude
+import Effect
+import M1
+import Effect.Console as C
+
+main = C.log (log "Done")
diff --git a/tests/purs/passing/ImportQualified/M1.purs b/tests/purs/passing/ImportQualified/M1.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ImportQualified/M1.purs
@@ -0,0 +1,3 @@
+module M1 where
+
+log x = x
diff --git a/tests/purs/passing/InferRecFunWithConstrainedArgument.purs b/tests/purs/passing/InferRecFunWithConstrainedArgument.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/InferRecFunWithConstrainedArgument.purs
@@ -0,0 +1,11 @@
+module Main where
+
+import Prelude
+import Effect.Console (log, logShow)
+
+test 100 = 100
+test n = test(1 + n)
+
+main = do
+  logShow (test 0)
+  log "Done"
diff --git a/tests/purs/passing/InstanceBeforeClass.purs b/tests/purs/passing/InstanceBeforeClass.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/InstanceBeforeClass.purs
@@ -0,0 +1,12 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+instance fooNumber :: Foo Number where
+  foo = 0.0
+
+class Foo a where
+  foo :: a
+
+main = log "Done"
diff --git a/tests/purs/passing/InstanceChain.purs b/tests/purs/passing/InstanceChain.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/InstanceChain.purs
@@ -0,0 +1,71 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+class Arg i o | i -> o
+
+data Proxy p = Proxy
+
+arg :: forall i o. Arg i o => Proxy i -> Proxy o
+arg _ = Proxy
+
+instance appArg :: Arg i o => Arg (f i) o
+else instance reflArg :: Arg i i
+
+argEg0 :: Proxy Int
+argEg0 = arg (Proxy :: Proxy Int)
+
+argEg1 :: Proxy Int
+argEg1 = arg (Proxy :: Proxy (Array Int))
+
+argEg2 :: Proxy Int
+argEg2 = arg (Proxy :: Proxy (Boolean -> Array Int))
+
+
+class IsEq l r o | l r -> o
+
+foreign import data True :: Type
+foreign import data False :: Type
+
+isEq :: forall l r o. IsEq l r o => Proxy l -> Proxy r -> Proxy o
+isEq _ _ = Proxy
+
+instance reflIsEq :: IsEq a a True
+else instance notIsEq :: IsEq a b False
+
+isEqEg0 :: Proxy True
+isEqEg0 = isEq (Proxy :: Proxy Int) (Proxy :: Proxy Int)
+
+isEqEg1 :: Proxy True
+isEqEg1 = isEq (Proxy :: Proxy (Array Int)) (Proxy :: Proxy (Array Int))
+
+isEqEg2 :: Proxy False
+isEqEg2 = isEq (Proxy :: Proxy (Array Int)) (Proxy :: Proxy (Array Boolean))
+
+
+-- example chain in which we should only commit to `isStringElse` once we've
+-- learnt that the type param is apart from `String`.
+
+class Learn a b | a -> b
+instance learnInst :: Learn a a
+
+class IsString t o | t -> o
+instance isStringString :: IsString String True
+else instance isStringElse :: IsString t False
+
+learnIsString :: forall a t o.
+  IsString t o =>
+  Learn a t =>
+  Proxy a ->
+  Proxy o
+learnIsString _ = Proxy
+
+isStringEg0 :: Proxy True
+isStringEg0 = learnIsString (Proxy :: Proxy String)
+
+isStringEg1 :: Proxy False
+isStringEg1 = learnIsString (Proxy :: Proxy Int)
+
+
+main = log "Done"
diff --git a/tests/purs/passing/InstanceSigs.purs b/tests/purs/passing/InstanceSigs.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/InstanceSigs.purs
@@ -0,0 +1,12 @@
+module Main where
+
+import Effect.Console (log)
+
+class Foo a where
+  foo :: a
+
+instance fooNumber :: Foo Number where
+  foo :: Number
+  foo = 0.0
+
+main = log "Done"
diff --git a/tests/purs/passing/InstanceSigsGeneral.purs b/tests/purs/passing/InstanceSigsGeneral.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/InstanceSigsGeneral.purs
@@ -0,0 +1,12 @@
+module Main where
+
+import Effect.Console (log)
+
+class Eq a where
+  eq :: a -> a -> Boolean
+
+instance eqNumber :: Eq Number where
+  eq :: forall x y. x -> y -> Boolean
+  eq _ _ = true
+
+main = log "Done"
diff --git a/tests/purs/passing/IntAndChar.purs b/tests/purs/passing/IntAndChar.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/IntAndChar.purs
@@ -0,0 +1,19 @@
+module Main where
+
+import Prelude
+import Effect
+import Effect.Console (log)
+import Test.Assert
+
+f 1 = 1
+f _ = 0
+
+g 'a' = 'a'
+g _ = 'b'
+
+main = do
+  assert $ f 1 == 1
+  assert $ f 0 == 0
+  assert $ g 'a' == 'a'
+  assert $ g 'b' == 'b'
+  log "Done"
diff --git a/tests/purs/passing/JSReserved.purs b/tests/purs/passing/JSReserved.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/JSReserved.purs
@@ -0,0 +1,13 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+yield = 0
+member = 1
+
+public = \return -> return
+
+this catch = catch
+
+main = log "Done"
diff --git a/tests/purs/passing/KindedType.purs b/tests/purs/passing/KindedType.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/KindedType.purs
@@ -0,0 +1,34 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+type Star2Star f = f :: Type -> Type
+
+type Star t = t :: Type
+
+test1 :: Star2Star Array String
+test1 = ["test"]
+
+f :: Star (String -> String)
+f s = s
+
+test2 = f "test"
+
+data Proxy (f :: Type -> Type) = Proxy
+
+test3 :: Proxy Array
+test3 = Proxy
+
+type Test (f :: Type -> Type) = f String
+
+test4 :: Test Array
+test4 = ["test"]
+
+class Clazz (a :: Type) where
+  def :: a
+
+instance clazzString :: Clazz String where
+  def = "test"
+
+main = log "Done"
diff --git a/tests/purs/passing/LargeSumType.purs b/tests/purs/passing/LargeSumType.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/LargeSumType.purs
@@ -0,0 +1,35 @@
+module Main where
+
+import Effect.Console (log)
+
+data Large = A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z
+
+explode A A = "A"
+explode B B = "B"
+explode C C = "C"
+explode D D = "D"
+explode E E = "E"
+explode F F = "F"
+explode G G = "G"
+explode H H = "H"
+explode I I = "I"
+explode J J = "J"
+explode K K = "K"
+explode L L = "L"
+explode M M = "M"
+explode N N = "N"
+explode O O = "O"
+explode P P = "P"
+explode Q Q = "Q"
+explode R R = "R"
+explode S S = "S"
+explode T T = "T"
+explode U U = "U"
+explode V V = "V"
+explode W W = "W"
+explode X X = "X"
+explode Y Y = "Y"
+explode Z Z = "Z"
+explode _ _ = ""
+
+main = log "Done"
diff --git a/tests/purs/passing/Let.purs b/tests/purs/passing/Let.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Let.purs
@@ -0,0 +1,58 @@
+module Main where
+
+import Prelude
+import Partial.Unsafe (unsafePartial)
+import Effect
+import Effect.Console (log, logShow)
+import Control.Monad.ST
+
+test1 x = let
+            y :: Number
+            y = x + 1.0
+          in y
+
+test2 x y =
+  let x' = x + 1.0 in
+  let y' = y + 1.0 in
+  x' + y'
+
+test3 = let f x y z = x + y + z in
+        f 1.0 2.0 3.0
+
+test4 = let
+          f x [y, z] = x y z
+        in f (+) [1.0, 2.0]
+
+test5 = let
+          f x | x > 0.0 = g (x / 2.0) + 1.0
+          f x = 0.0
+          g x = f (x - 1.0) + 1.0
+        in f 10.0
+
+test7 = let
+          f :: forall a. a -> a
+          f x = x
+        in if f true then f 1.0 else f 2.0
+
+test8 :: Number -> Number
+test8 x = let
+            go y | (x - 0.1 < y * y) && (y * y < x + 0.1) = y
+            go y = go $ (y + x / y) / 2.0
+          in go x
+
+test10 _ =
+  let
+    f x = g x * 3.0
+    g x = f x / 2.0
+  in f 10.0
+
+main :: Effect _
+main = do
+  logShow (test1 1.0)
+  logShow (test2 1.0 2.0)
+  logShow test3
+  unsafePartial (logShow test4)
+  logShow test5
+  logShow test7
+  logShow (test8 100.0)
+  log "Done"
diff --git a/tests/purs/passing/Let2.purs b/tests/purs/passing/Let2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Let2.purs
@@ -0,0 +1,20 @@
+module Main where
+
+import Prelude
+import Effect.Console (log, logShow)
+
+test =
+  let f :: Number -> Boolean
+      f 0.0 = false
+      f n = g (n - 1.0)
+
+      g :: Number -> Boolean
+      g 0.0 = true
+      g n = f (n - 1.0)
+
+      x = f 1.0
+  in not x
+
+main = do
+  logShow test
+  log "Done"
diff --git a/tests/purs/passing/LetInInstance.purs b/tests/purs/passing/LetInInstance.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/LetInInstance.purs
@@ -0,0 +1,15 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+class Foo a where
+  foo :: a -> String
+
+instance fooString :: Foo String where
+  foo = go
+    where
+    go :: String -> String
+    go s = s
+
+main = log "Done"
diff --git a/tests/purs/passing/LetPattern.purs b/tests/purs/passing/LetPattern.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/LetPattern.purs
@@ -0,0 +1,196 @@
+module Main where
+
+import Prelude
+import Partial.Unsafe (unsafePartial)
+import Effect (Effect)
+import Effect.Console (log)
+import Test.Assert (assert')
+
+patternSimple :: Boolean
+patternSimple =
+  let x = 25252
+  in
+   x == 25252
+
+patternDoSimple :: Effect Boolean
+patternDoSimple = do
+  let x = 25252
+  pure $ x == 25252
+
+newtype X = X Int
+
+patternNewtype :: Boolean
+patternNewtype =
+  let X a = X 123
+  in
+   a == 123
+
+patternDoNewtype :: Effect Boolean
+patternDoNewtype = do
+  let X a = X 123
+  pure $ a == 123
+
+data Y = Y Int String Boolean
+
+patternData :: Boolean
+patternData =
+  let Y a b c = Y 456 "hello, world" false
+  in
+   a == 456 && b == "hello, world" && not c
+
+patternDataIgnored :: Boolean
+patternDataIgnored =
+  let Y _ x _ = Y 789 "world, hello" true
+  in
+   x == "world, hello"
+
+patternDoData :: Effect Boolean
+patternDoData = do
+  let Y a b c = Y 456 "hello, world" false
+  pure $ a == 456 && b == "hello, world" && not c
+
+patternDoDataIgnored :: Effect Boolean
+patternDoDataIgnored = do
+  let Y _ x _ = Y 789 "world, hello" true
+  pure $ x == "world, hello"
+
+patternArray :: Boolean
+patternArray = unsafePartial $
+  let [a, b] = [1, 2]
+  in
+   a == 1 && b == 2
+
+patternDoArray :: Effect Boolean
+patternDoArray = unsafePartial do
+  let [a, b] = [1, 2]
+  pure $ a == 1 && b == 2
+
+patternMultiple :: Boolean
+patternMultiple = unsafePartial $
+  let
+    x = 25252
+    X a = X x
+    Y b c d = Y x "hello, world" false
+    Y _ e _ = Y 789 "world, hello" true
+    [f, g] = [1, 2]
+  in
+   x == 25252 && a == 25252 && b == 25252 && c == "hello, world" &&
+     not d && e == "world, hello" && f == 1 && g == 2
+
+patternDoMultiple :: Effect Boolean
+patternDoMultiple = unsafePartial do
+  let
+    x = 25252
+    X a = X x
+    Y b c d = Y x "hello, world" false
+    Y _ e _ = Y 789 "world, hello" true
+    [f, g] = [1, 2]
+  pure $ x == 25252 && a == 25252 && b == 25252 && c == "hello, world" &&
+     not d && e == "world, hello" && f == 1 && g == 2
+
+patternMultipleWithNormal :: Boolean
+patternMultipleWithNormal = unsafePartial $
+  let
+    x = 25252
+    X a = X x
+    y = 2525
+    Y b c d = Y y "hello, world" false
+  in
+   x == 25252 && y == 2525 &&
+     a == 25252 && b == 2525 && c == "hello, world" && not d
+
+patternDoMultipleWithNormal :: Effect Boolean
+patternDoMultipleWithNormal = unsafePartial do
+  let
+    x = 25252
+    X a = X x
+    y = 2525
+    Y b c d = Y y "hello, world" false
+  pure $ x == 25252 && y == 2525 &&
+    a == 25252 && b == 2525 && c == "hello, world" && not d
+
+patternWithParens :: Boolean
+patternWithParens = unsafePartial $
+  let
+    (x) = 25252
+    (X a) = X x
+    (Y b c d) = Y x "hello, world" false
+    (Y _ e _) = Y 789 "world, hello" true
+    ([f, g]) = [1, 2]
+  in
+   x == 25252 && a == 25252 && b == 25252 && c == "hello, world" &&
+     not d && e == "world, hello" && f == 1 && g == 2
+
+patternDoWithParens :: Effect Boolean
+patternDoWithParens = unsafePartial do
+  let
+    (x) = 25252
+    (X a) = X x
+    (Y b c d) = Y x "hello, world" false
+    (Y _ e _) = Y 789 "world, hello" true
+    ([f, g]) = [1, 2]
+  pure $ x == 25252 && a == 25252 && b == 25252 && c == "hello, world" &&
+     not d && e == "world, hello" && f == 1 && g == 2
+
+patternWithNamedBinder :: Boolean
+patternWithNamedBinder = unsafePartial $
+  let
+    a@{x, y} = {x: 10, y: 20}
+  in
+   a.x == 10 && x == 10 && a.y == 20 && y == 20
+
+patternDoWithNamedBinder :: Effect Boolean
+patternDoWithNamedBinder = unsafePartial do
+  let
+    a@{x, y} = {x: 10, y: 20}
+  pure $
+    a.x == 10 && x == 10 && a.y == 20 && y == 20
+
+data List a = Nil | Cons a (List a)
+infixr 6 Cons as :
+
+instance eqList :: Eq a => Eq (List a) where
+  eq xs ys = go xs ys true
+    where
+      go _ _ false = false
+      go Nil Nil acc = acc
+      go (x : xs') (y : ys') acc = go xs' ys' $ acc && (y == x)
+      go _ _ _ = false
+
+patternWithInfixOp :: Boolean
+patternWithInfixOp = unsafePartial $
+  let
+    x : xs = 1 : 2 : 3 : 4 : Nil
+  in
+   x == 1 && xs == 2 : 3 : 4 : Nil
+
+patternDoWithInfixOp :: Effect Boolean
+patternDoWithInfixOp = unsafePartial do
+  let
+    x : xs = 1 : 2 : 3 : 4 : Nil
+  pure $
+    x == 1 && xs == 2 : 3 : 4 : Nil
+
+main :: Effect Unit
+main = do
+  assert' "simple variable pattern" patternSimple
+  assert' "simple variable pattern with do" =<< patternDoSimple
+  assert' "constructor pattern (newtype)" patternNewtype
+  assert' "constructor pattern (newtype) with do" =<< patternDoNewtype
+  assert' "constructor pattern (data)" patternData
+  assert' "constructor pattern with ignorances" patternDataIgnored
+  assert' "constructor pattern (data) with do" =<< patternDoData
+  assert' "constructor pattern with ignorances and do" =<< patternDoDataIgnored
+  assert' "array pattern" patternArray
+  assert' "array pattern with do" =<< patternDoArray
+  assert' "multiple patterns" patternMultiple
+  assert' "multiple patterns with do" =<< patternDoMultiple
+  assert' "multiple patterns with normal let's" patternMultipleWithNormal
+  assert' "multiple patterns with normal let's and do" =<< patternDoMultipleWithNormal
+  assert' "multiple patterns with parens" patternWithParens
+  assert' "multiple patterns with parens and do" =<< patternDoWithParens
+  assert' "multiple patterns with named binder" patternWithNamedBinder
+  assert' "multiple patterns with named binder and do" =<< patternDoWithNamedBinder
+  assert' "pattern with infix operator" patternWithInfixOp
+  assert' "pattern with infix operator and do" =<< patternDoWithInfixOp
+  log "Done"
diff --git a/tests/purs/passing/LiberalTypeSynonyms.purs b/tests/purs/passing/LiberalTypeSynonyms.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/LiberalTypeSynonyms.purs
@@ -0,0 +1,22 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+type Reader = (->) String
+
+foo :: Reader String
+foo s = s
+
+type AndFoo r = (foo :: String | r)
+
+getFoo :: forall r. Prim.Record (AndFoo r) -> String
+getFoo o = o.foo
+
+type F r = { | r } -> { | r }
+
+f :: (forall r. F r) -> String
+f g = case g { x: "Hello" } of
+        { x: x } -> x
+
+main = log "Done"
diff --git a/tests/purs/passing/MPTCs.purs b/tests/purs/passing/MPTCs.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/MPTCs.purs
@@ -0,0 +1,21 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+class NullaryTypeClass where
+  greeting :: String
+
+instance nullaryTypeClass :: NullaryTypeClass where
+  greeting = "Hello, World!"
+
+class Coerce a b where
+  coerce :: a -> b
+
+instance coerceShow :: Show a => Coerce a String where
+  coerce = show
+else
+instance coerceRefl :: Coerce a a where
+  coerce a = a
+
+main = log "Done"
diff --git a/tests/purs/passing/Match.purs b/tests/purs/passing/Match.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Match.purs
@@ -0,0 +1,10 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+data Foo a = Foo
+
+foo = \f -> case f of Foo -> "foo"
+
+main = log "Done"
diff --git a/tests/purs/passing/Module.purs b/tests/purs/passing/Module.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Module.purs
@@ -0,0 +1,7 @@
+module Main where
+
+import M1
+import M2
+import Effect.Console (log)
+
+main = log "Done"
diff --git a/tests/purs/passing/Module/M1.purs b/tests/purs/passing/Module/M1.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Module/M1.purs
@@ -0,0 +1,14 @@
+module M1 where
+
+import Prelude
+
+data Foo = Foo String
+
+foo :: Foo -> String
+foo = \f -> case f of Foo s -> s <> "foo"
+
+bar :: Foo -> String
+bar = foo
+
+incr :: Int -> Int
+incr x = x + 1
diff --git a/tests/purs/passing/Module/M2.purs b/tests/purs/passing/Module/M2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Module/M2.purs
@@ -0,0 +1,10 @@
+module M2 where
+
+import Prelude
+import M1 as M1
+
+baz :: M1.Foo -> String
+baz = M1.foo
+
+match :: M1.Foo -> String
+match = \f -> case f of M1.Foo s -> s <> "foo"
diff --git a/tests/purs/passing/ModuleDeps.purs b/tests/purs/passing/ModuleDeps.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ModuleDeps.purs
@@ -0,0 +1,6 @@
+module Main where
+
+import M1
+import Effect.Console (log)
+
+main = log "Done"
diff --git a/tests/purs/passing/ModuleDeps/M1.purs b/tests/purs/passing/ModuleDeps/M1.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ModuleDeps/M1.purs
@@ -0,0 +1,5 @@
+module M1 where
+
+import M2 as M2
+
+foo = M2.bar
diff --git a/tests/purs/passing/ModuleDeps/M2.purs b/tests/purs/passing/ModuleDeps/M2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ModuleDeps/M2.purs
@@ -0,0 +1,5 @@
+module M2 where
+
+import M3 as M3
+
+bar = M3.baz
diff --git a/tests/purs/passing/ModuleDeps/M3.purs b/tests/purs/passing/ModuleDeps/M3.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ModuleDeps/M3.purs
@@ -0,0 +1,3 @@
+module M3 where
+
+baz = 1
diff --git a/tests/purs/passing/ModuleExport.purs b/tests/purs/passing/ModuleExport.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ModuleExport.purs
@@ -0,0 +1,8 @@
+module Main where
+
+import Effect.Console (log, logShow)
+import A
+
+main = do
+  logShow (show 1.0)
+  log "Done"
diff --git a/tests/purs/passing/ModuleExport/A.purs b/tests/purs/passing/ModuleExport/A.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ModuleExport/A.purs
@@ -0,0 +1,3 @@
+module A (module Prelude) where
+
+import Prelude
diff --git a/tests/purs/passing/ModuleExportDupes.purs b/tests/purs/passing/ModuleExportDupes.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ModuleExportDupes.purs
@@ -0,0 +1,11 @@
+module Main where
+
+  import Effect.Console
+  import A
+  import B
+  import C
+  import Prelude
+
+  main = do
+    logShow (show 1.0)
+    log "Done"
diff --git a/tests/purs/passing/ModuleExportDupes/A.purs b/tests/purs/passing/ModuleExportDupes/A.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ModuleExportDupes/A.purs
@@ -0,0 +1,3 @@
+module A (module Prelude) where
+
+import Prelude
diff --git a/tests/purs/passing/ModuleExportDupes/B.purs b/tests/purs/passing/ModuleExportDupes/B.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ModuleExportDupes/B.purs
@@ -0,0 +1,3 @@
+module B (module Prelude) where
+
+import Prelude
diff --git a/tests/purs/passing/ModuleExportDupes/C.purs b/tests/purs/passing/ModuleExportDupes/C.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ModuleExportDupes/C.purs
@@ -0,0 +1,4 @@
+module C (module Prelude, module A) where
+
+import Prelude
+import A
diff --git a/tests/purs/passing/ModuleExportExcluded.purs b/tests/purs/passing/ModuleExportExcluded.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ModuleExportExcluded.purs
@@ -0,0 +1,11 @@
+module Main where
+
+import Prelude
+import Effect.Console (log, logShow)
+import A (foo)
+
+otherwise = false
+
+main = do
+  logShow "1.0"
+  log "Done"
diff --git a/tests/purs/passing/ModuleExportExcluded/A.purs b/tests/purs/passing/ModuleExportExcluded/A.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ModuleExportExcluded/A.purs
@@ -0,0 +1,6 @@
+module A (module Prelude, foo) where
+
+import Prelude
+
+foo :: Number -> Number
+foo _ = 0.0
diff --git a/tests/purs/passing/ModuleExportQualified.purs b/tests/purs/passing/ModuleExportQualified.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ModuleExportQualified.purs
@@ -0,0 +1,9 @@
+module Main where
+
+import Prelude
+import Effect.Console (log, logShow)
+import A as B
+
+main = do
+  logShow (B.show 1.0)
+  log "Done"
diff --git a/tests/purs/passing/ModuleExportQualified/A.purs b/tests/purs/passing/ModuleExportQualified/A.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ModuleExportQualified/A.purs
@@ -0,0 +1,3 @@
+module A (module Prelude) where
+
+import Prelude
diff --git a/tests/purs/passing/ModuleExportSelf.purs b/tests/purs/passing/ModuleExportSelf.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ModuleExportSelf.purs
@@ -0,0 +1,11 @@
+module Main where
+
+import Effect.Console
+import A
+
+bar :: Foo
+bar = true
+
+main = do
+  logShow (show bar)
+  log "Done"
diff --git a/tests/purs/passing/ModuleExportSelf/A.purs b/tests/purs/passing/ModuleExportSelf/A.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ModuleExportSelf/A.purs
@@ -0,0 +1,5 @@
+module A (module A, module Prelude) where
+
+import Prelude
+
+type Foo = Boolean
diff --git a/tests/purs/passing/Monad.purs b/tests/purs/passing/Monad.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Monad.purs
@@ -0,0 +1,32 @@
+module Main where
+
+import Effect.Console (log)
+
+type Monad m = { return :: forall a. a -> m a
+	 , bind :: forall a b. m a -> (a -> m b) -> m b }
+
+data Id a = Id a
+
+id :: Monad Id
+id = { return : Id
+     , bind : \ma f -> case ma of Id a -> f a }
+
+data Maybe a = Nothing | Just a
+
+maybe :: Monad Maybe
+maybe = { return : Just
+  , bind : \ma f -> case ma of
+      Nothing -> Nothing
+      Just a -> f a
+  }
+
+test :: forall m. Monad m -> m Number
+test = \m -> m.bind (m.return 1.0) (\n1 ->
+	 m.bind (m.return "Test") (\n2 ->
+	   m.return n1))
+
+test1 = test id
+
+test2 = test maybe
+
+main = log "Done"
diff --git a/tests/purs/passing/MonadState.purs b/tests/purs/passing/MonadState.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/MonadState.purs
@@ -0,0 +1,63 @@
+module Main where
+
+import Prelude
+import Effect.Console
+
+data Tuple a b = Tuple a b
+
+instance showTuple :: (Show a, Show b) => Show (Tuple a b) where
+  show (Tuple a b) = "(" <> show a <> ", " <> show b <> ")"
+
+class Monad m <= MonadState s m where
+  get :: m s
+  put :: s -> m Unit
+
+data State s a = State (s -> Tuple s a)
+
+runState s (State f) = f s
+
+instance functorState :: Functor (State s) where
+  map = liftM1
+
+instance applyState :: Apply (State s) where
+  apply = ap
+
+instance applicativeState :: Applicative (State s) where
+  pure a = State $ \s -> Tuple s a
+
+instance bindState :: Bind (State s) where
+  bind f g = State $ \s -> case runState s f of
+                              Tuple s1 a -> runState s1 (g a)
+
+instance monadState :: Monad (State s)
+
+instance monadStateState :: MonadState s (State s) where
+  get = State (\s -> Tuple s s)
+  put s = State (\_ -> Tuple s unit)
+
+-- Without the call to same, the following strange (but correct, in the absence of
+-- functional dependencies) type:
+--
+-- forall m t1 t2.
+-- ( Bind m
+-- , MonadState t1 m
+-- , MonadState t2 m
+-- ) => (t1 -> t2) -> m Unit
+--
+-- With the type hint, the inferred type is more sensible:
+--
+-- forall m t.
+-- ( Bind m
+-- , MonadState t m
+-- ) => (t -> t) -> m Unit
+modify f =
+  do
+    s <- get
+    put (same f s)
+  where
+    same :: forall a. (a -> a) -> (a -> a)
+    same = identity
+
+main = do
+  logShow $ runState 0 (modify (_ + 1))
+  log "Done"
diff --git a/tests/purs/passing/MultiArgFunctions.purs b/tests/purs/passing/MultiArgFunctions.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/MultiArgFunctions.purs
@@ -0,0 +1,27 @@
+module Main where
+
+import Prelude
+import Data.Function.Uncurried
+import Effect
+import Effect.Console
+
+f = mkFn2 $ \a b -> runFn2 g a b + runFn2 g b a
+
+g = mkFn2 $ \a b -> case {} of
+  _ | a <= 0.0 || b <= 0.0 -> b
+  _ -> runFn2 f (a - 0.0) (b - 0.0)
+
+main = do
+  runFn0 (mkFn0 $ \_ -> log $ show 0.0)
+  runFn1 (mkFn1 $ \a -> log $ show a) 0.0
+  runFn2 (mkFn2 $ \a b -> log $ show [a, b]) 0.0 0.0
+  runFn3 (mkFn3 $ \a b c -> log $ show [a, b, c]) 0.0 0.0 0.0
+  runFn4 (mkFn4 $ \a b c d -> log $ show [a, b, c, d]) 0.0 0.0 0.0 0.0
+  runFn5 (mkFn5 $ \a b c d e -> log $ show [a, b, c, d, e]) 0.0 0.0 0.0 0.0 0.0
+  runFn6 (mkFn6 $ \a b c d e f -> log $ show [a, b, c, d, e, f]) 0.0 0.0 0.0 0.0 0.0 0.0
+  runFn7 (mkFn7 $ \a b c d e f g -> log $ show [a, b, c, d, e, f, g]) 0.0 0.0 0.0 0.0 0.0 0.0 0.0
+  runFn8 (mkFn8 $ \a b c d e f g h -> log $ show [a, b, c, d, e, f, g, h]) 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
+  runFn9 (mkFn9 $ \a b c d e f g h i -> log $ show [a, b, c, d, e, f, g, h, i]) 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
+  runFn10 (mkFn10 $ \a b c d e f g h i j-> log $ show [a, b, c, d, e, f, g, h, i, j]) 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
+  logShow $ runFn2 g 0.0 0.0
+  log "Done"
diff --git a/tests/purs/passing/MutRec.purs b/tests/purs/passing/MutRec.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/MutRec.purs
@@ -0,0 +1,20 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+f 0.0 = 0.0
+f x = g x + 0.0
+
+g x = f (x / 0.0)
+
+data Even = Zero | Even Odd
+
+data Odd = Odd Even
+
+evenToNumber Zero = 0.0
+evenToNumber (Even n) = oddToNumber n + 0.0
+
+oddToNumber (Odd n) = evenToNumber n + 0.0
+
+main = log "Done"
diff --git a/tests/purs/passing/MutRec2.purs b/tests/purs/passing/MutRec2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/MutRec2.purs
@@ -0,0 +1,20 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+data A = A B
+
+data B = B A
+
+foreign import data S :: Type
+
+f :: A -> S
+f a = case a of A b -> g b
+
+g b = case b of B a -> f a
+
+showN :: A -> S
+showN a = f a
+
+main = log "Done"
diff --git a/tests/purs/passing/MutRec3.purs b/tests/purs/passing/MutRec3.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/MutRec3.purs
@@ -0,0 +1,20 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+data A = A B
+
+data B = B A
+
+foreign import data S :: Type
+
+f a = case a of A b -> g b
+
+g :: B -> S
+g b = case b of B a -> f a
+
+showN :: A -> S
+showN a = f a
+
+main = log "Done"
diff --git a/tests/purs/passing/NakedConstraint.purs b/tests/purs/passing/NakedConstraint.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/NakedConstraint.purs
@@ -0,0 +1,10 @@
+module Main where
+
+import Effect.Console
+
+data List a = Nil | Cons a (List a)
+
+head :: Partial => List Int -> Int
+head (Cons x _) = x
+
+main = log "Done"
diff --git a/tests/purs/passing/NamedPatterns.purs b/tests/purs/passing/NamedPatterns.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/NamedPatterns.purs
@@ -0,0 +1,10 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+foo = \x -> case x of
+  y@{ foo: "Foo" } -> y
+  y -> y
+
+main = log "Done"
diff --git a/tests/purs/passing/NegativeBinder.purs b/tests/purs/passing/NegativeBinder.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/NegativeBinder.purs
@@ -0,0 +1,10 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+test :: Number -> Boolean
+test -1.0 = false
+test _  = true
+
+main = log "Done"
diff --git a/tests/purs/passing/NegativeIntInRange.purs b/tests/purs/passing/NegativeIntInRange.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/NegativeIntInRange.purs
@@ -0,0 +1,9 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+n :: Int
+n = -2147483648
+
+main = log "Done"
diff --git a/tests/purs/passing/Nested.purs b/tests/purs/passing/Nested.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Nested.purs
@@ -0,0 +1,10 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+data Extend r a = Extend { prev :: r a, next :: a }
+
+data Matrix r a = Square (r (r a)) | Bigger (Matrix (Extend r) a)
+
+main = log "Done"
diff --git a/tests/purs/passing/NestedRecordUpdate.purs b/tests/purs/passing/NestedRecordUpdate.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/NestedRecordUpdate.purs
@@ -0,0 +1,24 @@
+module Main where
+
+import Prelude
+import Effect.Console
+
+type T = { foo :: Int, bar :: { baz :: Int, qux :: { lhs :: Int, rhs :: Int } } }
+
+init :: T
+init = { foo: 1, bar: { baz: 2, qux: { lhs: 3, rhs: 4 } } }
+
+updated :: T
+updated = init { foo = 10, bar { baz = 20, qux { lhs = 30, rhs = 40 } } }
+
+expected :: T
+expected = { foo: 10, bar: { baz: 20, qux: { lhs: 30, rhs: 40 } } }
+
+check l r =
+  l.foo == r.foo &&
+  l.bar.baz == r.bar.baz &&
+  l.bar.qux.lhs == r.bar.qux.lhs &&
+  l.bar.qux.rhs == r.bar.qux.rhs
+
+main = do
+  when (check updated expected) $ log "Done"
diff --git a/tests/purs/passing/NestedRecordUpdateWildcards.purs b/tests/purs/passing/NestedRecordUpdateWildcards.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/NestedRecordUpdateWildcards.purs
@@ -0,0 +1,20 @@
+module Main where
+
+import Prelude
+import Effect.Console
+
+update = _ { foo = _, bar { baz = _, qux = _ } }
+
+init = { foo: 1, bar: { baz: 2, qux: 3 } }
+
+after = update init 10 20 30
+
+expected = { foo: 10, bar: { baz: 20, qux: 30 } }
+
+check l r =
+  l.foo == r.foo &&
+  l.bar.baz == r.bar.baz &&
+  l.bar.qux == r.bar.qux
+
+main = do
+  when (check after expected) $ log "Done"
diff --git a/tests/purs/passing/NestedTypeSynonyms.purs b/tests/purs/passing/NestedTypeSynonyms.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/NestedTypeSynonyms.purs
@@ -0,0 +1,12 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+type X = String
+type Y = X -> X
+
+fn :: Y
+fn a = a
+
+main = log (fn "Done")
diff --git a/tests/purs/passing/NestedWhere.purs b/tests/purs/passing/NestedWhere.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/NestedWhere.purs
@@ -0,0 +1,13 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+f x = g x
+  where
+  g x = go x
+    where
+    go x = go1 (x - 1.0)
+    go1 x = go x
+
+main = log "Done"
diff --git a/tests/purs/passing/NewConsClass.purs b/tests/purs/passing/NewConsClass.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/NewConsClass.purs
@@ -0,0 +1,12 @@
+-- This test verifies that we can write a new type class `Cons` without errors
+-- in the presence of the `Cons` class from `Prim.Row`.
+module Main where
+
+import Effect.Console (log)
+import Prim.Row(class Union)
+
+class Cons x xs | xs -> x where
+    cons :: x -> xs -> xs
+
+
+main = log "Done"
diff --git a/tests/purs/passing/Newtype.purs b/tests/purs/passing/Newtype.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Newtype.purs
@@ -0,0 +1,23 @@
+module Main where
+
+import Prelude hiding (apply)
+import Effect
+import Effect.Console
+
+newtype Thing = Thing String
+
+instance showThing :: Show Thing where
+  show (Thing x) = "Thing " <> show x
+
+newtype Box a = Box a
+
+instance showBox :: (Show a) => Show (Box a) where
+  show (Box x) = "Box " <> show x
+
+apply f x = f x
+
+main = do
+  logShow $ Thing "hello"
+  logShow $ Box 42.0
+  logShow $ apply Box 9000.0
+  log "Done"
diff --git a/tests/purs/passing/NewtypeClass.purs b/tests/purs/passing/NewtypeClass.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/NewtypeClass.purs
@@ -0,0 +1,40 @@
+module Main where
+
+import Prelude
+import Effect
+import Effect.Console
+
+class Newtype t a | t -> a where
+  wrap :: a -> t
+  unwrap :: t -> a
+
+instance newtypeMultiplicative :: Newtype (Multiplicative a) a where
+  wrap = Multiplicative
+  unwrap (Multiplicative a) = a
+
+data Multiplicative a = Multiplicative a
+
+instance semiringMultiplicative :: Semiring a => Semigroup (Multiplicative a) where
+  append (Multiplicative a) (Multiplicative b) = Multiplicative (a * b)
+
+data Pair a = Pair a a
+
+foldPair :: forall a s. Semigroup s => (a -> s) -> Pair a -> s
+foldPair f (Pair a b) = f a <> f b
+
+ala
+  :: forall f t a
+   . Functor f
+  => Newtype t a
+  => (a -> t)
+  -> ((a -> t) -> f t)
+  -> f a
+ala _ f = map unwrap (f wrap)
+
+test = ala Multiplicative foldPair
+
+test1 = ala Multiplicative foldPair (Pair 2 3)
+
+main = do
+  logShow (test (Pair 2 3))
+  log "Done"
diff --git a/tests/purs/passing/NewtypeEff.purs b/tests/purs/passing/NewtypeEff.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/NewtypeEff.purs
@@ -0,0 +1,29 @@
+module Main where
+
+import Prelude
+import Effect.Console
+import Effect
+
+newtype T a = T (Effect a)
+
+runT :: forall a. T a -> Effect a
+runT (T t) = t
+
+instance functorT :: Functor T where
+  map f (T t) = T (f <$> t)
+
+instance applyT :: Apply T where
+  apply (T f) (T x) = T (f <*> x)
+
+instance applicativeT :: Applicative T where
+  pure t = T (pure t)
+
+instance bindT :: Bind T where
+  bind (T t) f = T (t >>= \x -> runT (f x))
+
+instance monadT :: Monad T
+
+main = runT do
+  T $ log "Done"
+  T $ log "Done"
+  T $ log "Done"
diff --git a/tests/purs/passing/NewtypeInstance.purs b/tests/purs/passing/NewtypeInstance.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/NewtypeInstance.purs
@@ -0,0 +1,61 @@
+module Main where
+
+import Prelude
+import Effect
+import Effect.Console
+import Data.Monoid
+import Data.Tuple
+
+type MyString = String 
+
+newtype X = X MyString
+
+derive newtype instance showX :: Show X
+derive newtype instance eqX :: Eq X
+derive newtype instance ordX :: Ord X
+
+newtype Y a = Y (Array a)
+
+derive newtype instance showY :: Show (Y String)
+
+class Singleton a b where
+  singleton :: a -> b
+
+instance singletonArray :: Singleton a (Array a) where
+  singleton x = [x]
+
+derive newtype instance singletonY :: Singleton a (Y a)
+
+newtype MyArray a = MyArray (Array a)
+
+derive newtype instance showMyArray :: Show a => Show (MyArray a)
+derive newtype instance functorMyArray :: Functor MyArray
+
+newtype ProxyArray x a = ProxyArray (Array a)
+
+derive newtype instance functorProxyArray :: Functor (ProxyArray x)
+
+class (Monad m, Monoid w) <= MonadWriter w m | m -> w where
+  tell :: w -> m Unit
+
+instance monadWriterTuple :: Monoid w => MonadWriter w (Tuple w) where
+  tell w = Tuple w unit
+
+newtype MyWriter w a = MyWriter (Tuple w a)
+
+derive newtype instance functorMyWriter :: Functor (MyWriter w)
+derive newtype instance applyMyWriter :: Semigroup w => Apply (MyWriter w)
+derive newtype instance applicativeMyWriter :: Monoid w => Applicative (MyWriter w)
+derive newtype instance bindMyWriter :: Semigroup w => Bind (MyWriter w)
+derive newtype instance monadMyWriter :: Monoid w => Monad (MyWriter w)
+derive newtype instance monadWriterMyWriter :: Monoid w => MonadWriter w (MyWriter w)
+
+type Syn' w a = MyWriter w a
+newtype Syn a = Syn (Syn' (MyArray Int) a)
+derive newtype instance functorSyn :: Functor Syn
+
+main = do
+  logShow (X "test")
+  logShow (singleton "test" :: Y String)
+  logShow (map show (MyArray [1, 2, 3]))
+  log "Done"
diff --git a/tests/purs/passing/NewtypeWithRecordUpdate.purs b/tests/purs/passing/NewtypeWithRecordUpdate.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/NewtypeWithRecordUpdate.purs
@@ -0,0 +1,16 @@
+-- https://github.com/purescript/purescript/issues/812.0
+
+module Main where
+
+import Prelude
+import Effect.Console
+
+newtype NewType a = NewType (Record a)
+
+rec1 :: Record (a :: Number, b :: Number, c:: Number)
+rec1 = { a: 0.0, b: 0.0, c: 0.0 }
+
+rec2 :: NewType (a :: Number, b :: Number, c :: Number)
+rec2 = NewType (rec1 { a = 1.0 })
+
+main = log "Done"
diff --git a/tests/purs/passing/NonConflictingExports.purs b/tests/purs/passing/NonConflictingExports.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/NonConflictingExports.purs
@@ -0,0 +1,10 @@
+-- No failure here as the export `thing` only refers to Main.thing
+module Main (thing, main) where
+
+import A
+import Effect.Console (log)
+
+thing :: Int
+thing = 2
+
+main = log "Done"
diff --git a/tests/purs/passing/NonConflictingExports/A.purs b/tests/purs/passing/NonConflictingExports/A.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/NonConflictingExports/A.purs
@@ -0,0 +1,4 @@
+module A where
+
+thing :: Int
+thing = 1
diff --git a/tests/purs/passing/NonOrphanInstanceFunDepExtra.purs b/tests/purs/passing/NonOrphanInstanceFunDepExtra.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/NonOrphanInstanceFunDepExtra.purs
@@ -0,0 +1,8 @@
+-- Both f and l must be known, thus can be in separate modules
+module Main where
+import Effect.Console (log)
+import Lib
+data F
+data R
+instance cflr :: C F L R
+main = log "Done"
diff --git a/tests/purs/passing/NonOrphanInstanceFunDepExtra/Lib.purs b/tests/purs/passing/NonOrphanInstanceFunDepExtra/Lib.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/NonOrphanInstanceFunDepExtra/Lib.purs
@@ -0,0 +1,4 @@
+module Lib where
+-- covering sets: {{f, l}}
+class C f l r | l -> r
+data L
diff --git a/tests/purs/passing/NonOrphanInstanceMulti.purs b/tests/purs/passing/NonOrphanInstanceMulti.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/NonOrphanInstanceMulti.purs
@@ -0,0 +1,7 @@
+-- Both l and r must be known, thus can be in separate modules
+module Main where
+import Effect.Console (log)
+import Lib
+data L
+instance clr :: C L R
+main = log "Done"
diff --git a/tests/purs/passing/NonOrphanInstanceMulti/Lib.purs b/tests/purs/passing/NonOrphanInstanceMulti/Lib.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/NonOrphanInstanceMulti/Lib.purs
@@ -0,0 +1,4 @@
+module Lib where
+-- covering sets: {{l, r}}
+class C l r
+data R
diff --git a/tests/purs/passing/NumberLiterals.purs b/tests/purs/passing/NumberLiterals.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/NumberLiterals.purs
@@ -0,0 +1,39 @@
+module Main where
+
+-- See issue #2115.
+
+import Prelude
+import Test.Assert (assert')
+import Effect.Console (log)
+
+main = do
+  test "0.17" 0.17
+  test "0.25996181067141905" 0.25996181067141905
+  test "0.3572019862807257" 0.3572019862807257
+  test "0.46817723004874223" 0.46817723004874223
+  test "0.9640035681058178" 0.9640035681058178
+  test "4.23808622486133" 4.23808622486133
+  test "4.540362294799751" 4.540362294799751
+  test "5.212384849884261" 5.212384849884261
+  test "13.958257048123212" 13.958257048123212
+  test "32.96176575630599" 32.96176575630599
+  test "38.47735512322269" 38.47735512322269
+
+  test "10000000000.0" 1e10
+  test "10000000000.0" 1.0e10
+  test "0.00001" 1e-5
+  test "0.00001" 1.0e-5
+  test "1.5339794352098402e-118" 1.5339794352098402e-118
+  test "2.108934760892056e-59" 2.108934760892056e-59
+  test "2.250634744599241e-19" 2.250634744599241e-19
+  test "5.960464477539063e-8" 5.960464477539063e-8
+  test "5e-324" 5e-324
+  test "5e-324" 5.0e-324
+
+  log "Done"
+
+test str num =
+  if (show num == str)
+    then pure unit
+    else flip assert' false $
+      "Expected " <> show str <> ", got " <> show (show num) <> "."
diff --git a/tests/purs/passing/ObjectGetter.purs b/tests/purs/passing/ObjectGetter.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ObjectGetter.purs
@@ -0,0 +1,14 @@
+module Main where
+
+import Prelude
+import Effect.Console (log, logShow)
+
+getX = _.x
+
+point = { x: 1.0, y: 0.0 }
+
+main = do
+  logShow $ getX point
+  log $ _." 123 string Prop Name " { " 123 string Prop Name ": "OK" }
+  log $ (_.x >>> _.y) { x: { y: "Nested" } }
+  log $ _.value { value: "Done" }
diff --git a/tests/purs/passing/ObjectSynonym.purs b/tests/purs/passing/ObjectSynonym.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ObjectSynonym.purs
@@ -0,0 +1,16 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+type Inner = Number
+
+inner :: Inner
+inner = 0.0
+
+type Outer = { inner :: Inner }
+
+outer :: Outer
+outer = { inner: inner }
+
+main = log "Done"
diff --git a/tests/purs/passing/ObjectUpdate.purs b/tests/purs/passing/ObjectUpdate.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ObjectUpdate.purs
@@ -0,0 +1,23 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+update1 = \o -> o { foo = "Foo" }
+
+update2 :: forall r. { foo :: String | r } -> { foo :: String | r }
+update2 = \o -> o { foo = "Foo" }
+
+replace = \o -> case o of
+  { foo: "Foo" } -> o { foo = "Bar" }
+  { foo: "Bar" } -> o { bar = "Baz" }
+  o -> o
+
+polyUpdate :: forall a r. { foo :: a | r } -> { foo :: String | r }
+polyUpdate = \o -> o { foo = "Foo" }
+
+inferPolyUpdate = \o -> o { foo = "Foo" }
+
+main = do
+  log ((update1 {foo: ""}).foo)
+  log "Done"
diff --git a/tests/purs/passing/ObjectUpdate2.purs b/tests/purs/passing/ObjectUpdate2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ObjectUpdate2.purs
@@ -0,0 +1,18 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+type X r = { | r }
+
+x :: X (baz :: String)
+x = { baz: "baz" }
+
+blah :: forall r. X r -> X r
+blah x = x
+
+test = blah x
+  { baz = "blah"
+  }
+
+main = log "Done"
diff --git a/tests/purs/passing/ObjectUpdater.purs b/tests/purs/passing/ObjectUpdater.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ObjectUpdater.purs
@@ -0,0 +1,26 @@
+module Main where
+
+import Prelude
+import Effect
+import Effect.Console
+import Test.Assert
+
+getValue :: Effect Boolean
+getValue = pure true
+
+main = do
+  let record = { value: false }
+  record' <- record { value = _ } <$> getValue
+  assert $ record'.value == true
+
+  let point = { x: 1.0, y: 1.0 }
+      x = 10.0
+      point' = (point { x = _, y = x }) 100.0
+
+  assert $ point'.x == 100.0
+  assert $ point'.y == 10.0
+
+  let record2 = (_ { x = _ }) { x: 0.0 } 10.0
+  assert $ record2.x == 10.0
+
+  log "Done"
diff --git a/tests/purs/passing/ObjectWildcards.purs b/tests/purs/passing/ObjectWildcards.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ObjectWildcards.purs
@@ -0,0 +1,20 @@
+module Main where
+
+import Prelude
+import Effect
+import Effect.Console
+import Test.Assert
+
+mkRecord = { foo: _, bar: _, baz: "baz" }
+
+getValue :: Effect Boolean
+getValue = pure true
+
+main = do
+  obj <- { value: _ } <$> getValue
+  logShow obj.value
+  let x = 1.0
+  point <- { x: _, y: x } <$> pure 2.0
+  assert $ point.x == 2.0
+  assert $ point.y == 1.0
+  log (mkRecord 1.0 "Done").bar
diff --git a/tests/purs/passing/Objects.purs b/tests/purs/passing/Objects.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Objects.purs
@@ -0,0 +1,36 @@
+module Main where
+
+import Prelude hiding (append)
+import Effect.Console (log)
+
+test = \x -> x.foo + x.bar + 1.0
+
+append = \o -> { foo: o.foo, bar: 1.0 }
+
+apTest = append({foo : "Foo", baz: "Baz"})
+
+f = (\a -> a.b.c) { b: { c: 1.0, d: "Hello" }, e: "World" }
+
+g = (\a -> a.f { x: 1.0, y: "y" }) { f: \o -> o.x + 1.0 }
+
+typed :: { foo :: Number }
+typed = { foo: 0.0 }
+
+test2 = \x -> x."!@#"
+
+test3 = typed."foo"
+
+test4 = test2 weirdObj
+  where
+  weirdObj :: { "!@#" :: Number }
+  weirdObj = { "!@#": 1.0 }
+
+test5 = case { "***": 1.0 } of
+  { "***": n } -> n
+
+test6 = case { "***": 1.0 } of
+             { "***": n } -> n
+
+test7 {a:    snoog , b     : blah } = blah
+
+main = log "Done"
diff --git a/tests/purs/passing/OneConstructor.purs b/tests/purs/passing/OneConstructor.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/OneConstructor.purs
@@ -0,0 +1,10 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+data One a = One a
+
+one' (One a) = a
+
+main = log "Done"
diff --git a/tests/purs/passing/OperatorAlias.purs b/tests/purs/passing/OperatorAlias.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/OperatorAlias.purs
@@ -0,0 +1,11 @@
+module Main where
+
+import Prelude
+import Effect.Console
+
+infixl 4 what as ?!
+
+what :: forall a b. a -> b -> a
+what a _ = a
+
+main = log $ "Done" ?! true
diff --git a/tests/purs/passing/OperatorAliasElsewhere.purs b/tests/purs/passing/OperatorAliasElsewhere.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/OperatorAliasElsewhere.purs
@@ -0,0 +1,9 @@
+module Main where
+
+import Prelude
+import Def (what)
+import Effect.Console
+
+infixl 4 what as ?!
+
+main = log $ "Done" ?! true
diff --git a/tests/purs/passing/OperatorAliasElsewhere/Def.purs b/tests/purs/passing/OperatorAliasElsewhere/Def.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/OperatorAliasElsewhere/Def.purs
@@ -0,0 +1,4 @@
+module Def where
+
+what :: forall a b. a -> b -> a
+what a _ = a
diff --git a/tests/purs/passing/OperatorAssociativity.purs b/tests/purs/passing/OperatorAssociativity.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/OperatorAssociativity.purs
@@ -0,0 +1,25 @@
+module Main where
+
+import Prelude
+import Effect
+import Effect.Console
+import Test.Assert
+
+bug :: Number -> Number -> Number
+bug a b = 0.0 - (a - b)
+
+main = do
+  assert (bug 0.0 2.0 == 2.0)
+  assert (0.0 - (0.0 - 2.0) == 2.0)
+  assert (0.0 - (0.0 + 2.0) == -2.0)
+  assert (6.0 / (3.0 * 2.0) == 1.0)
+  assert ((6.0 / 3.0) * 2.0 == 4.0)
+  assert (not (1.0 < 0.0) == true)
+  assert (not ((negate 1.0) < 0.0) == false)
+  assert (negate (1.0 + 10.0) == -11.0)
+  assert (2.0 * 3.0 / 4.0 == 1.5)
+  assert (1.0 * 2.0 * 3.0 * 4.0 * 5.0 / 6.0 == 20.0)
+  assert (1.0 + 10.0 - 5.0 == 6.0)
+  assert (1.0 + 10.0 * 5.0 == 51.0)
+  assert (10.0 * 5.0 - 1.0 == 49.0)
+  log "Done"
diff --git a/tests/purs/passing/OperatorInlining.purs b/tests/purs/passing/OperatorInlining.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/OperatorInlining.purs
@@ -0,0 +1,48 @@
+module Main where
+
+import Prelude
+import Effect.Console (logShow, log)
+
+main = do
+
+  -- semiringNumber
+  logShow (1.0 + 2.0)
+  logShow (1.0 * 2.0)
+
+  -- ringNumber
+  logShow (1.0 - 2.0)
+  logShow (negate 1.0)
+
+  -- moduleSemiringNumber
+  logShow (1.0 / 2.0)
+
+  -- ordNumber
+  logShow (1.0 > 2.0)
+  logShow (1.0 < 2.0)
+  logShow (1.0 <= 2.0)
+  logShow (1.0 >= 2.0)
+  logShow (1.0 == 2.0)
+
+  -- eqNumber
+  logShow (1.0 == 2.0)
+  logShow (1.0 /= 2.0)
+
+  -- eqString
+  logShow ("foo" == "bar")
+  logShow ("foo" /= "bar")
+
+  -- eqBoolean
+  logShow (true == false)
+  logShow (true /= false)
+
+  -- semigroupString
+  logShow ("foo" <> "bar")
+
+  -- latticeBoolean
+  logShow (top && true)
+  logShow (bottom || false)
+
+  -- complementedLatticeBoolean
+  logShow (not true)
+
+  log "Done"
diff --git a/tests/purs/passing/OperatorSections.purs b/tests/purs/passing/OperatorSections.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/OperatorSections.purs
@@ -0,0 +1,18 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+import Test.Assert
+
+main = do
+  assert $ (_ / 2.0) 4.0 == 2.0
+  assert $ (2.0 / _) 4.0 == 0.5
+  assert $ (_ `const` 1.0) 2.0 == 2.0
+  assert $ (1.0 `const` _) 2.0 == 1.0
+  let foo = { x: 2.0 }
+  assert $ (_ / foo.x) 4.0 == 2.0
+  assert $ (foo.x / _) 4.0 == 0.5
+  let div x y = x.x / y.x
+  assert $ (_ `div` foo { x = 4.0 }) { x: 4.0 } == 1.0
+  assert $ (foo { x = 4.0 } `div` _) { x: 4.0 } == 1.0
+  log "Done"
diff --git a/tests/purs/passing/Operators.purs b/tests/purs/passing/Operators.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Operators.purs
@@ -0,0 +1,91 @@
+module Main where
+
+import Prelude
+import Other (foo)
+import Other as Other
+import Effect
+import Effect.Console
+
+op1 :: forall a. a -> a -> a
+op1 x _ = x
+
+infix 4 op1 as ?!
+
+test1 :: forall n. Semiring n => n -> n -> (n -> n -> n) -> n
+test1 x y z = x * y + z x y
+
+test2 = (\x -> x.foo false) { foo : \_ -> 1.0 }
+
+test3 = (\x y -> x)(1.0 + 2.0 * (1.0 + 2.0)) (true && (false || false))
+
+k = \x -> \y -> x
+
+test4 = 1 `k` 2
+
+op2 :: Number -> Number -> Number
+op2 x y = x * y + y
+
+infixl 5 op2 as %%
+
+test5 = 1.0 %% 2.0 %% 3.0
+
+test6 = ((\x -> x) `k` 2.0) 3.0
+
+op3 :: String -> String -> String
+op3 = \s1 s2 -> s1 <> s2
+
+infix 4 op3 as <+>
+
+test7 = "Hello" <+> "World!"
+
+op4 :: forall a b. (a -> b) -> a -> b
+op4 = \f x -> f x
+
+infix 4 op4 as @@
+
+test8 = foo @@ "Hello World"
+
+test9 = Other.foo @@ "Hello World"
+
+test10 = "Hello" `Other.baz` "World"
+
+op5 :: forall a. Array a -> Array a -> Array a
+op5 = \as -> \bs -> as
+
+infix 4 op5 as ...
+
+test11 = [1.0, 2.0, 0.0] ... [4.0, 5.0, 6.0]
+
+test14 :: Number -> Number -> Boolean
+test14 a b = a < b
+
+test15 :: Number -> Number -> Boolean
+test15 a b = const false $ a `test14` b
+
+test17 :: Number
+test17 = negate (-1.0)
+
+test18 :: Number
+test18 = negate $ negate 1.0
+
+test19 :: Number
+test19 = negate $ negate (-1.0)
+
+main = do
+  let t1 = test1 1.0 2.0 (\x y -> x + y)
+  let t2 = test2
+  let t3 = test3
+  let t4 = test4
+  let t5 = test5
+  let t6 = test6
+  let t7 = test7
+  let t8 = test8
+  let t9 = test9
+  let t10 = test10
+  let t11 = test11
+  let t14 = test14 1.0 2.0
+  let t15 = test15 1.0 2.0
+  let t17 = test17
+  let t18 = test18
+  let t19 = test19
+  log "Done"
diff --git a/tests/purs/passing/Operators/Other.purs b/tests/purs/passing/Operators/Other.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Operators/Other.purs
@@ -0,0 +1,7 @@
+module Other where
+
+foo :: String -> String
+foo s = s
+
+baz :: String -> String -> String
+baz s _ = s
diff --git a/tests/purs/passing/OptimizerBug.purs b/tests/purs/passing/OptimizerBug.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/OptimizerBug.purs
@@ -0,0 +1,10 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+x a = 1.0 + y a
+
+y a = x a
+
+main = log "Done"
diff --git a/tests/purs/passing/OptionalQualified.purs b/tests/purs/passing/OptionalQualified.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/OptionalQualified.purs
@@ -0,0 +1,12 @@
+module Main where
+
+import Prelude as P
+
+-- qualified import without the "qualified" keyword
+import Effect.Console as Console
+
+bind = P.bind
+
+main = do
+  message <- P.pure "Done"
+  Console.log message
diff --git a/tests/purs/passing/Ord1Deriving.purs b/tests/purs/passing/Ord1Deriving.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Ord1Deriving.purs
@@ -0,0 +1,16 @@
+module Main where
+
+import Prelude
+import Data.Eq (class Eq1)
+import Data.Ord (class Ord1)
+import Effect.Console (log)
+
+data Product a b = Product a b
+
+derive instance eqMu :: (Eq a, Eq b) => Eq (Product a b)
+derive instance eq1Mu :: Eq a => Eq1 (Product a)
+
+derive instance ordMu :: (Ord a, Ord b) => Ord (Product a b)
+derive instance ord1Mu :: Ord a => Ord1 (Product a)
+
+main = log "Done"
diff --git a/tests/purs/passing/Ord1InOrdDeriving.purs b/tests/purs/passing/Ord1InOrdDeriving.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Ord1InOrdDeriving.purs
@@ -0,0 +1,13 @@
+module Main where
+
+import Prelude
+import Data.Eq (class Eq1)
+import Data.Ord (class Ord1)
+import Effect.Console (log)
+
+newtype Mu f = In (f (Mu f))
+
+derive instance eqMu :: Eq1 f => Eq (Mu f)
+derive instance ordMu :: Ord1 f => Ord (Mu f)
+
+main = log "Done"
diff --git a/tests/purs/passing/ParensInType.purs b/tests/purs/passing/ParensInType.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ParensInType.purs
@@ -0,0 +1,14 @@
+module Main where
+
+import Prelude
+import Effect (Effect)
+import Effect.Console (log)
+
+class Foo a where
+  foo :: (String -> a ((Unit)))
+
+instance fooLogEff :: Foo Effect where
+  foo = log
+
+main :: Effect Unit
+main = foo "Done"
diff --git a/tests/purs/passing/ParensInTypedBinder.purs b/tests/purs/passing/ParensInTypedBinder.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ParensInTypedBinder.purs
@@ -0,0 +1,14 @@
+module Main where
+
+import Prelude
+import Effect (Effect)
+import Effect.Console (log)
+
+foo :: Array Int
+foo = do
+  xss :: Array (Array Int) <- [[[1,2,3], [4, 5]], [[6]]]
+  xs :: Array Int <- xss
+  xs
+
+main :: Effect Unit
+main = log "Done"
diff --git a/tests/purs/passing/PartialFunction.purs b/tests/purs/passing/PartialFunction.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/PartialFunction.purs
@@ -0,0 +1,11 @@
+module Main where
+
+import Prelude
+import Effect
+import Effect.Console
+
+fn :: Partial => Number -> Number
+fn 0.0 = 0.0
+fn 1.0 = 2.0
+
+main = log "Done"
diff --git a/tests/purs/passing/Patterns.purs b/tests/purs/passing/Patterns.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Patterns.purs
@@ -0,0 +1,23 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+test = \x -> case x of
+  { str: "Foo", bool: true } -> true
+  { str: "Bar", bool: b } -> b
+  _ -> false
+
+f = \o -> case o of
+  { foo: "Foo" } -> o.bar
+  _ -> 0
+
+h = \o -> case o of
+  a@[_,_,_] -> a
+  _ -> []
+
+isDesc :: Array Number -> Boolean
+isDesc [x, y] | x > y = true
+isDesc _ = false
+
+main = log "Done"
diff --git a/tests/purs/passing/PendingConflictingImports.purs b/tests/purs/passing/PendingConflictingImports.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/PendingConflictingImports.purs
@@ -0,0 +1,8 @@
+module Main where
+
+-- No error as we never force `thing` to be resolved in `Main`
+import A
+import B
+import Effect.Console (log)
+
+main = log "Done"
diff --git a/tests/purs/passing/PendingConflictingImports/A.purs b/tests/purs/passing/PendingConflictingImports/A.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/PendingConflictingImports/A.purs
@@ -0,0 +1,4 @@
+module A where
+
+thing :: Int
+thing = 1
diff --git a/tests/purs/passing/PendingConflictingImports/B.purs b/tests/purs/passing/PendingConflictingImports/B.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/PendingConflictingImports/B.purs
@@ -0,0 +1,4 @@
+module B where
+
+thing :: Int
+thing = 2
diff --git a/tests/purs/passing/PendingConflictingImports2.purs b/tests/purs/passing/PendingConflictingImports2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/PendingConflictingImports2.purs
@@ -0,0 +1,10 @@
+module Main where
+
+import A
+import Effect.Console (log)
+
+-- No error as we never force `thing` to be resolved in `Main`
+thing :: Int
+thing = 2
+
+main = log "Done"
diff --git a/tests/purs/passing/PendingConflictingImports2/A.purs b/tests/purs/passing/PendingConflictingImports2/A.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/PendingConflictingImports2/A.purs
@@ -0,0 +1,4 @@
+module A where
+
+thing :: Int
+thing = 1
diff --git a/tests/purs/passing/Person.purs b/tests/purs/passing/Person.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Person.purs
@@ -0,0 +1,12 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+data Person = Person { name :: String, age :: Number }
+
+showPerson :: Person -> String
+showPerson = \p -> case p of
+  Person o -> o.name <> ", aged " <> show o.age
+
+main = log "Done"
diff --git a/tests/purs/passing/PolyLabels.js b/tests/purs/passing/PolyLabels.js
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/PolyLabels.js
@@ -0,0 +1,17 @@
+"use strict";
+
+exports.unsafeGet = function (s) {
+  return function (o) {
+    return o[s];
+  };
+};
+
+exports.unsafeSet = function(s) {
+  return function(a) {
+    return function (o) {
+      var o1 = {};
+      o1[s] = a;
+      return Object.assign({}, o, o1);
+    };
+  };
+};
diff --git a/tests/purs/passing/PolyLabels.purs b/tests/purs/passing/PolyLabels.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/PolyLabels.purs
@@ -0,0 +1,66 @@
+module Main where
+
+import Prelude
+import Prim.Row
+import Effect
+import Effect.Console
+import Data.Symbol (class IsSymbol, SProxy(..), reflectSymbol)
+
+foreign import unsafeGet
+  :: forall r a
+   . String
+  -> Record r
+  -> a
+
+foreign import unsafeSet
+  :: forall r1 r2 a
+   . String
+  -> a
+  -> Record r1
+  -> Record r2
+
+get
+  :: forall r r' l a
+   . IsSymbol l
+  => Cons l a r' r
+  => SProxy l
+  -> Record r
+  -> a
+get l = unsafeGet (reflectSymbol l)
+
+set
+  :: forall r1 r2 r l a b
+   . IsSymbol l
+  => Cons l a r r1
+  => Cons l b r r2
+  => SProxy l
+  -> b
+  -> Record r1
+  -> Record r2
+set l = unsafeSet (reflectSymbol l)
+
+lens 
+  :: forall l f r1 r2 r a b
+   . IsSymbol l
+  => Cons l a r r1
+  => Cons l b r r2
+  => Functor f
+  => SProxy l
+  -> (a -> f b)
+  -> Record r1
+  -> f (Record r2)
+lens l f r = flip (set l) r <$> f (get l r)
+
+getFoo :: forall a r. { foo :: a | r } -> a
+getFoo = get (SProxy :: SProxy "foo")
+
+setFoo :: forall a b r. b -> { foo :: a | r } -> { foo :: b | r }
+setFoo = set (SProxy :: SProxy "foo")
+
+fooLens :: forall f a b r. Functor f => (a -> f b) -> { foo :: a | r } -> f { foo :: b | r } 
+fooLens = lens (SProxy :: SProxy "foo")
+
+main :: Effect Unit
+main = do
+  _ <- fooLens logShow { foo: 1 }
+  log (getFoo (setFoo "Done" { foo: 1 }))
diff --git a/tests/purs/passing/PrimedTypeName.purs b/tests/purs/passing/PrimedTypeName.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/PrimedTypeName.purs
@@ -0,0 +1,20 @@
+module Main (T, T', T'', T''', main) where
+
+import Prelude
+import Effect.Console (log)
+
+data T a = T
+type T' = T Unit
+
+data T'' = TP
+
+foreign import data T''' ∷ Type
+
+instance eqT ∷ Eq T'' where
+  eq _ _ = true
+
+type A' a b = b → a
+
+infixr 4 type A' as ↫
+
+main = log "Done"
diff --git a/tests/purs/passing/QualifiedNames.purs b/tests/purs/passing/QualifiedNames.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/QualifiedNames.purs
@@ -0,0 +1,11 @@
+module Main where
+
+import Prelude
+import Either as Either
+import Effect.Console (log)
+
+either :: forall a b c. (a -> c) -> (b -> c) -> Either.Either a b -> c
+either f _ (Either.Left x) = f x
+either _ g (Either.Right y) = g y
+
+main = log (either identity identity (Either.Left "Done"))
diff --git a/tests/purs/passing/QualifiedNames/Either.purs b/tests/purs/passing/QualifiedNames/Either.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/QualifiedNames/Either.purs
@@ -0,0 +1,5 @@
+module Either where
+
+import Prelude
+
+data Either a b = Left a | Right b
diff --git a/tests/purs/passing/QualifiedQualifiedImports.purs b/tests/purs/passing/QualifiedQualifiedImports.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/QualifiedQualifiedImports.purs
@@ -0,0 +1,6 @@
+module Main where
+
+-- qualified import with qualified imported names
+import Effect.Console (log) as Console
+
+main = Console.log "Done"
diff --git a/tests/purs/passing/Rank2Data.purs b/tests/purs/passing/Rank2Data.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Rank2Data.purs
@@ -0,0 +1,30 @@
+module Main where
+
+import Prelude hiding (add)
+import Effect.Console (log)
+
+data Id = Id forall a. a -> a
+
+runId = \id a -> case id of
+  Id f -> f a
+
+data Nat = Nat forall r. r -> (r -> r) -> r
+
+runNat = \nat -> case nat of
+  Nat f -> f 0.0 (\n -> n + 1.0)
+
+zero' = Nat (\zero' _ -> zero')
+
+succ = \n -> case n of
+  Nat f -> Nat (\zero' succ -> succ (f zero' succ))
+
+add = \n m -> case n of
+  Nat f -> case m of
+    Nat g -> Nat (\zero' succ -> g (f zero' succ) succ)
+
+one' = succ zero'
+two = succ zero'
+four = add two two
+fourNumber = runNat four
+
+main = log "Done"
diff --git a/tests/purs/passing/Rank2Object.purs b/tests/purs/passing/Rank2Object.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Rank2Object.purs
@@ -0,0 +1,11 @@
+module Main where
+
+import Prelude
+import Effect.Console
+
+data Foo = Foo { id :: forall a. a -> a }
+
+foo :: Foo -> Number
+foo (Foo { id: f }) = f 0.0
+
+main = log "Done"
diff --git a/tests/purs/passing/Rank2TypeSynonym.purs b/tests/purs/passing/Rank2TypeSynonym.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Rank2TypeSynonym.purs
@@ -0,0 +1,17 @@
+module Main where
+
+import Prelude
+import Effect.Console (log, logShow)
+
+type Foo a = forall f. Monad f => f a
+
+foo :: forall a. a -> Foo a
+foo x = pure x
+
+bar :: Foo Number
+bar = foo 3.0
+
+main = do
+  x <- bar
+  logShow x
+  log "Done"
diff --git a/tests/purs/passing/Rank2Types.purs b/tests/purs/passing/Rank2Types.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Rank2Types.purs
@@ -0,0 +1,12 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+test1 :: (forall a. (a -> a)) -> Number
+test1 = \f -> f 0.0
+
+forever :: forall m a b. (forall a b. m a -> (a -> m b) -> m b) -> m a -> m b
+forever = \bind action -> bind action $ \_ -> forever bind action
+
+main = log "Done"
diff --git a/tests/purs/passing/ReExportQualified.purs b/tests/purs/passing/ReExportQualified.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ReExportQualified.purs
@@ -0,0 +1,7 @@
+module Main where
+
+import Prelude
+import C
+import Effect.Console (log)
+
+main = log (x <> y)
diff --git a/tests/purs/passing/ReExportQualified/A.purs b/tests/purs/passing/ReExportQualified/A.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ReExportQualified/A.purs
@@ -0,0 +1,3 @@
+module A where
+
+x = "Do"
diff --git a/tests/purs/passing/ReExportQualified/B.purs b/tests/purs/passing/ReExportQualified/B.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ReExportQualified/B.purs
@@ -0,0 +1,3 @@
+module B where
+
+y = "ne"
diff --git a/tests/purs/passing/ReExportQualified/C.purs b/tests/purs/passing/ReExportQualified/C.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ReExportQualified/C.purs
@@ -0,0 +1,4 @@
+module C (module A, module M2) where
+
+import A
+import B as M2
diff --git a/tests/purs/passing/RebindableSyntax.purs b/tests/purs/passing/RebindableSyntax.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/RebindableSyntax.purs
@@ -0,0 +1,43 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+example1 :: String
+example1 = do
+  "Do"
+  " notation"
+  " for"
+  " Semigroup"
+  where
+  discard x f = x <> f unit
+
+applySecond :: forall f a b. Apply f => f a -> f b -> f b
+applySecond fa fb = const identity <$> fa <*> fb
+
+infixl 4 applySecond as *>
+
+newtype Const a b = Const a
+
+runConst :: forall a b. Const a b -> a
+runConst (Const a) = a
+
+instance functorConst :: Functor (Const a) where
+  map _ (Const a) = Const a
+
+instance applyConst :: Semigroup a => Apply (Const a) where
+  apply (Const a1) (Const a2) = Const (a1 <> a2)
+
+example2 :: Const String Unit
+example2 = do
+  Const "Do"
+  Const " notation"
+  Const " for"
+  Const " Apply"
+  where
+  discard x f = x *> f unit
+
+main = do
+  log example1
+  log $ runConst example2
+  log "Done"
diff --git a/tests/purs/passing/Recursion.purs b/tests/purs/passing/Recursion.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Recursion.purs
@@ -0,0 +1,11 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+fib = \n -> case n of
+  0.0 -> 1.0
+  1.0 -> 1.0
+  n -> fib (n - 1.0) + fib (n - 2.0)
+
+main = log "Done"
diff --git a/tests/purs/passing/RedefinedFixity.purs b/tests/purs/passing/RedefinedFixity.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/RedefinedFixity.purs
@@ -0,0 +1,6 @@
+module Main where
+
+import M3
+import Effect.Console (log)
+
+main = log "Done"
diff --git a/tests/purs/passing/RedefinedFixity/M1.purs b/tests/purs/passing/RedefinedFixity/M1.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/RedefinedFixity/M1.purs
@@ -0,0 +1,6 @@
+module M1 where
+
+applyFn :: forall a b. (forall c d. c -> d) -> a -> b
+applyFn f a = f a
+
+infixr 1000 applyFn as $
diff --git a/tests/purs/passing/RedefinedFixity/M2.purs b/tests/purs/passing/RedefinedFixity/M2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/RedefinedFixity/M2.purs
@@ -0,0 +1,5 @@
+module M2 where
+
+import Prelude ()
+
+import M1
diff --git a/tests/purs/passing/RedefinedFixity/M3.purs b/tests/purs/passing/RedefinedFixity/M3.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/RedefinedFixity/M3.purs
@@ -0,0 +1,6 @@
+module M3 where
+
+import Prelude ()
+
+import M1
+import M2
diff --git a/tests/purs/passing/ReservedWords.purs b/tests/purs/passing/ReservedWords.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ReservedWords.purs
@@ -0,0 +1,19 @@
+-- See https://github.com/purescript/purescript/issues/606
+module Main where
+
+import Prelude
+import Effect
+import Effect.Console (log)
+
+o :: { type :: String }
+o = { type: "o" }
+
+p :: { type :: String }
+p = o { type = "p" }
+
+f :: forall r. { type :: String | r } -> String
+f { type: "p" } = "Done"
+f _ = "Fail"
+
+main :: Effect _
+main = log $ f { type: p.type, foo: "bar" }
diff --git a/tests/purs/passing/ResolvableScopeConflict.purs b/tests/purs/passing/ResolvableScopeConflict.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ResolvableScopeConflict.purs
@@ -0,0 +1,13 @@
+module Main where
+
+import A (thing)
+import B
+import Effect.Console (log)
+
+-- Not an error as although we have `thing` in scope from both A and B, it is
+-- imported explicitly from A, giving it a resolvable solution.
+what :: Boolean -> Int
+what true = thing
+what false = zing
+
+main = log "Done"
diff --git a/tests/purs/passing/ResolvableScopeConflict/A.purs b/tests/purs/passing/ResolvableScopeConflict/A.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ResolvableScopeConflict/A.purs
@@ -0,0 +1,4 @@
+module A where
+
+thing :: Int
+thing = 1
diff --git a/tests/purs/passing/ResolvableScopeConflict/B.purs b/tests/purs/passing/ResolvableScopeConflict/B.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ResolvableScopeConflict/B.purs
@@ -0,0 +1,7 @@
+module B where
+
+thing :: Int
+thing = 2
+
+zing :: Int
+zing = 3
diff --git a/tests/purs/passing/ResolvableScopeConflict2.purs b/tests/purs/passing/ResolvableScopeConflict2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ResolvableScopeConflict2.purs
@@ -0,0 +1,15 @@
+module Main where
+
+import A
+import Effect.Console (log)
+
+thing :: Int
+thing = 1
+
+-- Not an error as although we have `thing` in scope from both Main and A,
+-- as the local declaration takes precedence over the implicit import
+what :: Boolean -> Int
+what true = thing
+what false = zing
+
+main = log "Done"
diff --git a/tests/purs/passing/ResolvableScopeConflict2/A.purs b/tests/purs/passing/ResolvableScopeConflict2/A.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ResolvableScopeConflict2/A.purs
@@ -0,0 +1,7 @@
+module A where
+
+thing :: Int
+thing = 2
+
+zing :: Int
+zing = 3
diff --git a/tests/purs/passing/ResolvableScopeConflict3.purs b/tests/purs/passing/ResolvableScopeConflict3.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ResolvableScopeConflict3.purs
@@ -0,0 +1,9 @@
+module Main (thing, main, module A) where
+
+import A
+import Effect.Console (log)
+
+thing :: Int
+thing = 2
+
+main = log "Done"
diff --git a/tests/purs/passing/ResolvableScopeConflict3/A.purs b/tests/purs/passing/ResolvableScopeConflict3/A.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ResolvableScopeConflict3/A.purs
@@ -0,0 +1,4 @@
+module A where
+
+thing :: Int
+thing = 1
diff --git a/tests/purs/passing/RowConstructors.purs b/tests/purs/passing/RowConstructors.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/RowConstructors.purs
@@ -0,0 +1,43 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+type Foo = (x :: Number | (y :: Number | (z :: Number)))
+type Bar = (x :: Number, y :: Number, z :: Number)
+type Baz = { w :: Number | Bar }
+
+foo :: { | Foo }
+foo = { x: 0.0, y: 0.0, z: 0.0 }
+
+bar :: { | Bar }
+bar = { x: 0.0, y: 0.0, z: 0.0 }
+
+id' :: Record Foo -> Record Bar
+id' = identity
+
+foo' :: { | Foo }
+foo' = id' foo
+
+bar' :: { | Bar }
+bar' = id' bar
+
+baz :: Baz
+baz = { x: 0.0, y: 0.0, z: 0.0, w: 0.0 }
+
+type Quux r = (q :: Number | r)
+type Norf r = (q' :: Number | Quux r)
+
+quux :: { f :: { | Foo } | Quux Bar }
+quux = { f: foo', x: 0.0, y: 0.0, z: 0.0, q: 0.0 }
+
+quux' :: { | Norf Bar }
+quux' = { x: 0.0, y: 0.0, z: 0.0, q: 0.0, q': 0.0 }
+
+wildcard :: { w :: Number | _ } -> Baz
+wildcard { w: w } = { x: w, y: w, z: w, w: w }
+
+wildcard' :: { | Quux _ } -> Number
+wildcard' { q: q } = q
+
+main = log "Done"
diff --git a/tests/purs/passing/RowInInstanceHeadDetermined.purs b/tests/purs/passing/RowInInstanceHeadDetermined.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/RowInInstanceHeadDetermined.purs
@@ -0,0 +1,40 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+data Empty = Empty
+data Cons = Cons
+
+
+-- simple case
+class Simple a b | a -> b where c :: a -> b
+instance simple0 :: Simple Empty {} where c _ = {}
+instance simple1 :: Simple Cons {foo :: Cons} where c cons = {foo: cons}
+
+
+-- simple transitive example
+class Transitive a b c | a -> b, b -> c where d :: a -> c
+instance transitive :: Transitive Empty {} {} where d _ = {}
+
+
+-- transitive example with cycles
+class Cyclic a b c d | a -> b, b -> a
+                     , a -> c
+                     , c -> d, d -> c
+instance cyclic :: Cyclic Empty Empty {} {}
+
+
+-- Determined cycle
+class DeterminedCycle a b c | a -> b
+                            , b -> c, c -> b
+instance determinedCycle :: DeterminedCycle Empty {} {}
+
+
+-- multiple determiners
+class MultipleDeterminers a b c d | a b -> c d
+instance multipleDeterminers :: MultipleDeterminers Empty Empty {} {}
+
+
+main = log "Done"
+
diff --git a/tests/purs/passing/RowLacks.purs b/tests/purs/passing/RowLacks.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/RowLacks.purs
@@ -0,0 +1,23 @@
+module Main where
+
+import Effect.Console (log)
+import Prim.Row (class Lacks)
+import Type.Row (RProxy(..))
+
+lacksX
+  :: forall r
+   . Lacks "x" r
+  => RProxy r
+  -> RProxy ()
+lacksX _ = RProxy
+
+test1 :: RProxy ()
+test1 = lacksX (RProxy :: RProxy (y :: Int, z :: String))
+
+test2 :: forall r. Lacks "x" r => RProxy r -> RProxy ()
+test2 _ = lacksX (RProxy :: RProxy (y :: Int, z :: String | r))
+
+test3 :: RProxy ()
+test3 = test2 (RProxy :: RProxy (a :: String))
+
+main = log "Done"
diff --git a/tests/purs/passing/RowNub.purs b/tests/purs/passing/RowNub.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/RowNub.purs
@@ -0,0 +1,23 @@
+module Main where
+
+import Effect.Console (log)
+import Prim.Row (class Nub, class Union)
+import Type.Row (RProxy(..))
+
+nubUnion
+  :: forall r1 r2 r3 r4
+   . Union r1 r2 r3
+  => Nub r3 r4
+  => RProxy r1
+  -> RProxy r2
+  -> RProxy r4
+nubUnion _ _ = RProxy
+
+type InL = (x :: Int, y :: String)
+type InR = (x :: String, y :: Int, z :: Boolean)
+type Out = (x :: Int, y :: String, z :: Boolean)
+
+test :: RProxy Out
+test = nubUnion (RProxy :: RProxy InL) (RProxy :: RProxy InR)
+
+main = log "Done"
diff --git a/tests/purs/passing/RowPolyInstanceContext.purs b/tests/purs/passing/RowPolyInstanceContext.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/RowPolyInstanceContext.purs
@@ -0,0 +1,23 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+class T s m | m -> s where
+  state :: (s -> s) -> m Unit
+
+data S s a = S (s -> { new :: s, ret :: a })
+
+instance st :: T s (S s) where
+  state f = S $ \s -> { new: f s, ret: unit }
+
+test1 :: forall r . S { foo :: String | r } Unit
+test1 = state $ \o -> o { foo = o.foo <> "!" }
+
+test2 :: forall m r . T { foo :: String | r } m => m Unit
+test2 = state $ \o -> o { foo = o.foo <> "!" }
+
+main = do
+  let t1 = test1
+  let t2 = test2
+  log "Done"
diff --git a/tests/purs/passing/RowUnion.js b/tests/purs/passing/RowUnion.js
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/RowUnion.js
@@ -0,0 +1,10 @@
+"use strict";
+
+exports.merge = function (dict) {
+  return function (l) {
+    return function (r) {
+      var o = {};
+      return Object.assign(o, r, l);
+    };
+  };
+};
diff --git a/tests/purs/passing/RowUnion.purs b/tests/purs/passing/RowUnion.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/RowUnion.purs
@@ -0,0 +1,69 @@
+module Main where
+
+import Prelude
+import Prim.Row
+import Effect
+import Effect.Console
+
+foreign import merge
+  :: forall r1 r2 r3
+   . Union r1 r2 r3
+  => Record r1
+  -> Record r2
+  -> Record r3
+
+test1 = merge { x: 1 } { y: true }
+
+test2 = merge { x: 1 } { x: true }
+
+mergeWithExtras
+ :: forall r1 r2 r3
+  . Union r1 (y :: Boolean | r2) (y :: Boolean | r3)
+ => { x :: Int | r1 }
+ -> { y :: Boolean | r2 }
+ -> { x :: Int, y :: Boolean | r3}
+mergeWithExtras = merge
+
+test3 x = merge { x: 1 } x
+test3' x = merge x { x: 1 }
+
+type Mandatory r = (x :: Int | r)
+type Optional r = (x :: Int, y :: Int, z :: Int | r)
+
+withDefaults
+  :: forall r s
+   . Union r (y :: Int, z :: Int) (y :: Int, z :: Int | s)
+  => Record (Mandatory r)
+  -> Record (Optional s)
+withDefaults p = merge p { y: 1, z: 1 }
+
+withDefaultsClosed
+  :: forall r s
+   . Union r (y :: Int, z :: Int) (y :: Int, z :: Int | s)
+  => Subrow s (y :: Int, z :: Int)
+  => Record (Mandatory r)
+  -> Record (Optional s)
+withDefaultsClosed p = merge p { y: 1, z: 1 }
+
+test4 = withDefaults { x: 1, y: 2 }
+
+-- r is a subrow of s if Union r t s for some t.
+class Subrow (r :: # Type) (s :: # Type)
+instance subrow :: Union r t s => Subrow r s
+
+main :: Effect Unit
+main = do
+  logShow test1.x
+  logShow test1.y
+  logShow (test1.x == 1)
+  logShow (mergeWithExtras { x: 1 } { x: 0, y: true, z: 42.0 }).x
+  logShow (withDefaults { x: 1 }).x
+  logShow (withDefaults { x: 1 }).y
+  logShow (withDefaults { x: 1 }).z
+  logShow (withDefaults { x: 1, y: 2 }).x
+  logShow (withDefaults { x: 1, y: 2 }).y
+  logShow (withDefaults { x: 1, y: 2 }).z
+  logShow (withDefaultsClosed { x: 1, y: 2 }).x
+  logShow (withDefaultsClosed { x: 1, y: 2 }).y
+  logShow (withDefaultsClosed { x: 1, y: 2 }).z
+  log "Done"
diff --git a/tests/purs/passing/RowsInInstanceContext.purs b/tests/purs/passing/RowsInInstanceContext.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/RowsInInstanceContext.purs
@@ -0,0 +1,25 @@
+module Main where
+
+import Prelude
+import Effect (Effect)
+import Effect.Console (log)
+import Data.Newtype (class Newtype, unwrap)
+
+class TypeEquals a b | a -> b, b -> a where
+  coerce :: a -> b
+  coerceBack :: b -> a
+
+instance refl :: TypeEquals a a where
+  coerce = identity
+  coerceBack = identity
+
+newtype RecordNewtype = RecordNewtype { x :: String }
+
+instance newtypeRecordNewtype ::
+  TypeEquals inner { x :: String }
+    => Newtype RecordNewtype inner where
+  wrap = RecordNewtype <<< coerce
+  unwrap (RecordNewtype rec) = coerceBack rec
+
+main :: Effect Unit
+main = log (unwrap (RecordNewtype { x: "Done" })).x
diff --git a/tests/purs/passing/RunFnInline.purs b/tests/purs/passing/RunFnInline.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/RunFnInline.purs
@@ -0,0 +1,11 @@
+module Main where
+
+import Prelude
+
+import Effect.Console (log)
+
+runFn3 :: forall a b c d. (a -> b -> c -> d) -> a -> b -> c -> d
+runFn3 f a b c = f a b c
+
+main = do
+  log $ runFn3 (\a b c -> c) 1 2 "Done"
diff --git a/tests/purs/passing/RuntimeScopeIssue.purs b/tests/purs/passing/RuntimeScopeIssue.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/RuntimeScopeIssue.purs
@@ -0,0 +1,22 @@
+module Main where
+
+import Prelude
+import Effect.Console (log, logShow)
+
+class A a where
+  a :: a -> Boolean
+
+class B a where
+  b :: a -> Boolean
+
+instance aNumber :: A Number where
+  a 0.0 = true
+  a n = b (n - 1.0)
+
+instance bNumber :: B Number where
+  b 0.0 = false
+  b n = a (n - 1.0)
+
+main = do
+  logShow $ a 10.0
+  log "Done"
diff --git a/tests/purs/passing/ScopedTypeVariables.purs b/tests/purs/passing/ScopedTypeVariables.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ScopedTypeVariables.purs
@@ -0,0 +1,37 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+test1 :: forall a. (a -> a) -> a -> a
+test1 f x = g (g x)
+  where
+  g :: a -> a
+  g y = f (f y)
+
+test2 :: forall a. (a -> a) -> a -> a
+test2 = h
+  where
+  h :: forall b. (b -> b) -> b -> b
+  h f x = g (g x)
+    where
+    g :: b -> b
+    g y = f (f y)
+
+test3 :: Number
+test3 = ((\b -> b :: b) :: forall b. b -> b) 0.0
+
+test4 :: forall a. (a -> a) -> a -> a
+test4 = h
+  where
+  h :: forall b. (b -> b) -> b -> b
+  h f x = g (g x)
+    where
+    g :: b -> b
+    g y = j (f (f y))
+      where
+      j :: forall b. b -> b
+      j x = x
+
+
+main = log "Done"
diff --git a/tests/purs/passing/Sequence.purs b/tests/purs/passing/Sequence.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Sequence.purs
@@ -0,0 +1,16 @@
+module Main where
+
+import Prelude
+import Effect
+import Effect.Console (log)
+
+data List a = Cons a (List a) | Nil
+
+class Sequence t where
+  sequence :: forall m a. Monad m => t (m a) -> m (t a)
+
+instance sequenceList :: Sequence List where
+  sequence Nil = pure Nil
+  sequence (Cons x xs) = Cons <$> x <*> sequence xs
+
+main = sequence $ Cons (log "Done") Nil
diff --git a/tests/purs/passing/SequenceDesugared.purs b/tests/purs/passing/SequenceDesugared.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/SequenceDesugared.purs
@@ -0,0 +1,38 @@
+module Main where
+
+import Prelude
+import Effect
+import Effect.Console (log)
+
+data List a = Cons a (List a) | Nil
+
+data Sequence t = Sequence (forall m a. Monad m => t (m a) -> m (t a))
+
+sequence :: forall t. Sequence t -> (forall m a. Monad m => t (m a) -> m (t a))
+sequence (Sequence s) = s
+
+sequenceListSeq :: forall m a. Monad m => List (m a) -> m (List a)
+sequenceListSeq Nil = pure Nil
+sequenceListSeq (Cons x xs) = Cons <$> x <*> sequenceListSeq xs
+
+sequenceList :: Sequence List
+sequenceList = Sequence (sequenceListSeq)
+
+sequenceList' :: Sequence List
+sequenceList' = Sequence ((\val -> case val of
+  Nil -> pure Nil
+  Cons x xs -> Cons <$> x <*> sequence sequenceList' xs))
+
+sequenceList'' :: Sequence List
+sequenceList'' = Sequence (sequenceListSeq :: forall m a. Monad m => List (m a) -> m (List a))
+
+sequenceList''' :: Sequence List
+sequenceList''' = Sequence ((\val -> case val of
+  Nil -> pure Nil
+  Cons x xs -> Cons <$> x <*> sequence sequenceList''' xs) :: forall m a. Monad m => List (m a) -> m (List a))
+
+main = do
+  void $ sequence sequenceList $ Cons (log "Done") Nil
+  void $ sequence sequenceList' $ Cons (log "Done") Nil
+  void $ sequence sequenceList'' $ Cons (log "Done") Nil
+  void $ sequence sequenceList''' $ Cons (log "Done") Nil
diff --git a/tests/purs/passing/ShadowedModuleName.purs b/tests/purs/passing/ShadowedModuleName.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ShadowedModuleName.purs
@@ -0,0 +1,8 @@
+module Main where
+
+import Test
+import Effect.Console
+
+data Test = Test
+
+main = log (runZ (Z "Done"))
diff --git a/tests/purs/passing/ShadowedModuleName/Test.purs b/tests/purs/passing/ShadowedModuleName/Test.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ShadowedModuleName/Test.purs
@@ -0,0 +1,6 @@
+module Test where
+
+data Z = Z String
+
+runZ :: Z -> String
+runZ (Z s) = s
diff --git a/tests/purs/passing/ShadowedName.purs b/tests/purs/passing/ShadowedName.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ShadowedName.purs
@@ -0,0 +1,11 @@
+module Main where
+
+import Prelude
+import Effect.Console
+import Effect.Console (log)
+
+done :: String
+done = let str = "Not yet done" in
+        let str = "Done" in str
+
+main = log done
diff --git a/tests/purs/passing/ShadowedRename.purs b/tests/purs/passing/ShadowedRename.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ShadowedRename.purs
@@ -0,0 +1,14 @@
+module Main where
+
+import Prelude
+import Effect
+import Effect.Console
+import Test.Assert
+
+foo foo = let foo_1 = \_ -> foo
+              foo_2 = foo_1 unit + 1.0
+          in foo_2
+
+main = do
+  assert $ foo 1.0 == 2.0
+  log "Done"
diff --git a/tests/purs/passing/ShadowedTCO.purs b/tests/purs/passing/ShadowedTCO.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ShadowedTCO.purs
@@ -0,0 +1,21 @@
+module Main where
+
+import Prelude hiding (add)
+import Effect.Console (log)
+
+runNat f = f 0.0 (\n -> n + 1.0)
+
+zero' z _ = z
+
+succ f zero' succ = succ (f zero' succ)
+
+add f g zero' succ = g (f zero' succ) succ
+
+one' = succ zero'
+two = succ one'
+four = add two two
+fourNumber = runNat four
+
+main = do
+  log $ show fourNumber
+  log "Done"
diff --git a/tests/purs/passing/ShadowedTCOLet.purs b/tests/purs/passing/ShadowedTCOLet.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/ShadowedTCOLet.purs
@@ -0,0 +1,15 @@
+module Main where
+
+import Prelude
+import Partial.Unsafe (unsafePartial)
+import Effect
+import Effect.Console (log)
+
+f x y z =
+  let f 1.0 2.0 3.0 = 1.0
+  in f x z y
+
+main :: Effect _
+main = do
+  log $ show $ unsafePartial f 1.0 3.0 2.0
+  log "Done"
diff --git a/tests/purs/passing/SignedNumericLiterals.purs b/tests/purs/passing/SignedNumericLiterals.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/SignedNumericLiterals.purs
@@ -0,0 +1,18 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+p = 0.5
+q = 1.0
+x = -1.0
+y = -0.5
+z = 0.5
+w = 1.0
+
+f :: Number -> Number
+f x = -x
+
+test1 = 2.0 - 1.0
+
+main = log "Done"
diff --git a/tests/purs/passing/SolvingAppendSymbol.purs b/tests/purs/passing/SolvingAppendSymbol.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/SolvingAppendSymbol.purs
@@ -0,0 +1,34 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+import Prim.Symbol (class Append)
+import Type.Data.Symbol (SProxy(..), reflectSymbol)
+import Type.Data.Symbol (append) as Symbol
+
+sym :: SProxy ""
+sym = SProxy
+
+symA :: SProxy "A"
+symA = SProxy
+
+symB :: SProxy "B"
+symB = SProxy
+
+egAB :: SProxy "AB"
+egAB = Symbol.append symA symB
+
+egBA :: SProxy "BA"
+egBA = Symbol.append symB symA
+
+egA' :: SProxy "A"
+egA' = Symbol.append sym (Symbol.append symA sym)
+
+main = do
+  let gotAB = reflectSymbol egAB == "AB"
+      gotBA = reflectSymbol egBA == "BA"
+      gotA' = reflectSymbol egA' == "A"
+  when (not gotAB) $ log "Did not get AB"
+  when (not gotBA) $ log "Did not get BA"
+  when (not gotA') $ log "Did not get A"
+  when (gotAB && gotBA && gotA') $ log "Done"
diff --git a/tests/purs/passing/SolvingCompareSymbol.purs b/tests/purs/passing/SolvingCompareSymbol.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/SolvingCompareSymbol.purs
@@ -0,0 +1,33 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+import Prim.Symbol (class Compare)
+import Prim.Ordering (kind Ordering, LT, EQ, GT)
+import Type.Data.Symbol (SProxy(..))
+import Type.Data.Symbol (compare) as Symbol
+import Type.Data.Ordering (OProxy(..), reflectOrdering)
+
+symA :: SProxy "A"
+symA = SProxy
+
+symB :: SProxy "B"
+symB = SProxy
+
+egLT :: OProxy LT
+egLT = Symbol.compare symA symB
+
+egEQ :: OProxy EQ
+egEQ = Symbol.compare symA symA
+
+egGT :: OProxy GT
+egGT = Symbol.compare symB symA
+
+main = do
+  let gotLT = reflectOrdering egLT == LT
+      gotEQ = reflectOrdering egEQ == EQ
+      gotGT = reflectOrdering egGT == GT
+  when (not gotLT) $ log "Did not get LT"
+  when (not gotEQ) $ log "Did not get EQ"
+  when (not gotGT) $ log "Did not get GT"
+  when (gotLT && gotEQ && gotGT) $ log "Done"
diff --git a/tests/purs/passing/SolvingIsSymbol.purs b/tests/purs/passing/SolvingIsSymbol.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/SolvingIsSymbol.purs
@@ -0,0 +1,13 @@
+module Main where
+
+import Prelude
+import Effect
+import Effect.Console
+
+-- Here we import as alias of reflectSymbol without importing Data.Symbol. However,
+-- Data.Symbol should be implicitly imported as we have an instance of IsSymbol solved.
+import SolvingIsSymbol.Lib (literalSymbol, libReflectSymbol)
+
+main = do
+  let lit = libReflectSymbol literalSymbol
+  when (lit == "literal") (log "Done")
diff --git a/tests/purs/passing/SolvingIsSymbol/Lib.purs b/tests/purs/passing/SolvingIsSymbol/Lib.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/SolvingIsSymbol/Lib.purs
@@ -0,0 +1,10 @@
+module SolvingIsSymbol.Lib where
+
+import Data.Symbol
+
+literalSymbol :: SProxy "literal"
+literalSymbol = SProxy
+
+libReflectSymbol :: forall s. IsSymbol s => SProxy s -> String
+libReflectSymbol = reflectSymbol
+
diff --git a/tests/purs/passing/Stream.purs b/tests/purs/passing/Stream.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Stream.purs
@@ -0,0 +1,26 @@
+module Main where
+
+import Prelude
+
+import Effect (Effect)
+import Effect.Console (log)
+
+class IsStream el s | s -> el where
+  cons :: el -> (Unit -> s) -> s
+  uncons :: s -> { head :: el, tail :: s }
+
+data Stream a = Stream a (Unit -> Stream a)
+
+instance streamIsStream :: IsStream a (Stream a) where
+  cons x xs = Stream x xs
+  uncons (Stream x f) = { head: x, tail: f unit }
+
+test :: forall el s. IsStream el s => s -> s
+test s = case uncons s of
+           { head, tail } -> cons head \_ -> tail
+
+main :: Effect Unit
+main = do
+  let dones :: Stream String
+      dones = cons "Done" \_ -> dones
+  log (uncons (test dones)).head
diff --git a/tests/purs/passing/StringEdgeCases.purs b/tests/purs/passing/StringEdgeCases.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/StringEdgeCases.purs
@@ -0,0 +1,9 @@
+module Main where
+
+import Prelude
+import Records as Records
+import Symbols as Symbols
+
+main = do
+  Records.main
+  Symbols.main
diff --git a/tests/purs/passing/StringEdgeCases/Records.purs b/tests/purs/passing/StringEdgeCases/Records.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/StringEdgeCases/Records.purs
@@ -0,0 +1,39 @@
+module Records where
+
+import Prelude
+import Effect.Console (log)
+import Test.Assert (assert')
+
+newtype AstralKeys = AstralKeys { "💡" :: Int, "💢" :: Int }
+newtype LoneSurrogateKeys = LoneSurrogateKeys { "\xdf06" :: Int, "\xd834" :: Int }
+
+testLoneSurrogateKeys =
+  let
+    expected = 5
+    actual = (_."\xd801" <<< helper) { "\xd800": 5 }
+  in
+    assert' ("lone surrogate keys: " <> show actual) (expected == actual)
+
+  where
+  helper :: { "\xd800" :: Int } -> { "\xd801" :: Int }
+  helper o =
+    case o."\xd800" of
+      x -> { "\xd801": x }
+
+testAstralKeys =
+  let
+    expected = 5
+    actual = (_."💢" <<< helper) { "💡": 5 }
+  in
+    assert' ("astral keys: " <> show actual) (expected == actual)
+
+  where
+  helper :: { "💡" :: Int } -> { "💢" :: Int }
+  helper o =
+    case o."💡" of
+      x -> { "💢": x }
+
+main = do
+  testLoneSurrogateKeys
+  testAstralKeys
+  log "Done"
diff --git a/tests/purs/passing/StringEdgeCases/Symbols.purs b/tests/purs/passing/StringEdgeCases/Symbols.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/StringEdgeCases/Symbols.purs
@@ -0,0 +1,32 @@
+-- This is similar to StringEscapes except we are performing the same tests
+-- with Symbols (at the type level).
+
+module Symbols where
+
+import Prelude
+import Effect.Console (log)
+import Prim.Symbol (class Append)
+import Type.Data.Symbol (SProxy(..), reflectSymbol)
+import Type.Data.Symbol (append) as Symbol
+import Test.Assert (assert')
+
+highS :: SProxy "\xd834"
+highS = SProxy
+
+lowS :: SProxy "\xdf06"
+lowS = SProxy
+
+loneSurrogates :: Boolean
+loneSurrogates = reflectSymbol (Symbol.append highS lowS) == "\x1d306"
+
+outOfOrderSurrogates :: Boolean
+outOfOrderSurrogates = reflectSymbol (Symbol.append lowS highS) == "\xdf06\xd834"
+
+notReplacing :: Boolean
+notReplacing = reflectSymbol lowS /= "\xfffd"
+
+main = do
+  assert' "lone surrogates may be combined into a surrogate pair" loneSurrogates
+  assert' "lone surrogates may be combined out of order to remain lone surrogates" outOfOrderSurrogates
+  assert' "lone surrogates are not replaced with the Unicode replacement character U+FFFD" notReplacing
+  log "Done"
diff --git a/tests/purs/passing/StringEscapes.purs b/tests/purs/passing/StringEscapes.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/StringEscapes.purs
@@ -0,0 +1,26 @@
+module Main where
+
+import Prelude ((==), (/=), (<>), discard)
+import Test.Assert (assert, assert')
+import Effect.Console (log)
+
+singleCharacter = "\0\b\t\n\v\f\r\"\\" == "\x0\x8\x9\xA\xB\xC\xD\x22\x5C"
+hex = "\x1D306\x2603\x3C6\xE0\x0" == "𝌆☃φà\0"
+decimal  = "\119558\9731\966\224\0" == "𝌆☃φà\0"
+surrogatePair = "\xD834\xDF06" == "\x1D306"
+highSurrogate = "\xD834"
+lowSurrogate = "\xDF06"
+loneSurrogates = (highSurrogate <> lowSurrogate) == "\x1D306"
+outOfOrderSurrogates = (lowSurrogate <> highSurrogate) == "\xDF06\xD834"
+replacement = "\xFFFD"
+notReplacing = replacement /= highSurrogate
+
+main = do
+  assert' "single-character escape sequences" singleCharacter
+  assert' "hex escape sequences" hex
+  assert' "decimal escape sequences" decimal
+  assert' "astral code points are represented as a UTF-16 surrogate pair" surrogatePair
+  assert' "lone surrogates may be combined into a surrogate pair" loneSurrogates
+  assert' "lone surrogates may be combined out of order to remain lone surrogates" outOfOrderSurrogates
+  assert' "lone surrogates are not replaced with the Unicode replacement character U+FFFD" notReplacing
+  log "Done"
diff --git a/tests/purs/passing/Superclasses1.purs b/tests/purs/passing/Superclasses1.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Superclasses1.purs
@@ -0,0 +1,23 @@
+module Main where
+
+import Prelude
+import Effect.Console (log, logShow)
+
+class Su a where
+  su :: a -> a
+
+class (Su a) <= Cl a where
+  cl :: a -> a -> a
+
+instance suNumber :: Su Number where
+  su n = n + 1.0
+
+instance clNumber :: Cl Number where
+  cl n m = n + m
+
+test :: forall a. Cl a => a -> a
+test a = su (cl a a)
+
+main = do
+  logShow $ test 10.0
+  log "Done"
diff --git a/tests/purs/passing/Superclasses3.purs b/tests/purs/passing/Superclasses3.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Superclasses3.purs
@@ -0,0 +1,41 @@
+module Main where
+
+import Prelude
+import Effect.Console
+import Effect
+
+class Monad m <= MonadWriter w m where
+  tell :: w -> m Unit
+
+testFunctor :: forall m. Monad m => m Number -> m Number
+testFunctor n = (+) 1.0 <$> n
+
+test :: forall w m. Monad m => MonadWriter w m => w -> m Unit
+test w = do
+  tell w
+  tell w
+  tell w
+
+data MTrace a = MTrace (Effect a)
+
+runMTrace :: forall a. MTrace a -> Effect a
+runMTrace (MTrace a) = a
+
+instance functorMTrace :: Functor MTrace where
+  map = liftM1
+
+instance applyMTrace :: Apply MTrace where
+  apply = ap
+
+instance applicativeMTrace :: Applicative MTrace where
+  pure = MTrace <<< pure
+
+instance bindMTrace :: Bind MTrace where
+  bind m f = MTrace (runMTrace m >>= (runMTrace <<< f))
+
+instance monadMTrace :: Monad MTrace
+
+instance writerMTrace :: MonadWriter String MTrace where
+  tell s = MTrace (log s)
+
+main = runMTrace $ test "Done"
diff --git a/tests/purs/passing/TCO.purs b/tests/purs/passing/TCO.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/TCO.purs
@@ -0,0 +1,28 @@
+module Main where
+
+import Prelude
+import Effect.Console (log, logShow)
+import Control.Monad.Rec.Class
+import Data.Array ((..), span, length)
+
+main = do
+  let f x = x + 1
+  let v = 0
+  logShow (applyN 0 f v)
+  logShow (applyN 1 f v)
+  logShow (applyN 2 f v)
+  logShow (applyN 3 f v)
+  logShow (applyN 4 f v)
+
+  let largeArray = 1..10000
+  logShow (length (span (\_ -> true) largeArray).init)
+
+  logShow (tailRec (\n -> if n < 10000 then Loop (n + 1) else Done 42) 0)
+
+  log "Done"
+
+applyN :: forall a. Int -> (a -> a) -> a -> a
+applyN = go identity
+  where
+  go f n _ | n <= 0 = f
+  go f n g = go (f >>> g) (n - 1) g
diff --git a/tests/purs/passing/TCOCase.purs b/tests/purs/passing/TCOCase.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/TCOCase.purs
@@ -0,0 +1,13 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+data Data = One | More Data
+
+main = log (from (to 10000.0 One))
+  where
+  to 0.0 a = a
+  to n a = to (n - 1.0) (More a)
+  from One = "Done"
+  from (More d) = from d
diff --git a/tests/purs/passing/TailCall.purs b/tests/purs/passing/TailCall.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/TailCall.purs
@@ -0,0 +1,20 @@
+module Main where
+
+import Prelude
+import Effect.Console (log, logShow)
+
+data L a = C a (L a) | N
+
+test :: Number -> L Number -> Number
+test n N = n
+test n (C x xs) = test (n + x) xs
+
+loop :: forall a. Number -> a
+loop x = loop (x + 1.0)
+
+notATailCall = \x ->
+  (\notATailCall -> notATailCall x) (\x -> x)
+
+main = do
+  logShow (test 0.0 (1.0 `C` (2.0 `C` (3.0 `C` N))))
+  log "Done"
diff --git a/tests/purs/passing/Tick.purs b/tests/purs/passing/Tick.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Tick.purs
@@ -0,0 +1,8 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+test' x = x
+
+main = log "Done"
diff --git a/tests/purs/passing/TopLevelCase.purs b/tests/purs/passing/TopLevelCase.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/TopLevelCase.purs
@@ -0,0 +1,19 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+gcd :: Number -> Number -> Number
+gcd 0.0 x = x
+gcd x 0.0 = x
+gcd x y | x > y = gcd (x `mod` y) y
+gcd x y = gcd (y `mod` x) x
+
+guardsTest [x] | x > 0.0 = []
+guardsTest xs = xs
+
+data A = A
+
+parseTest A 0.0 = 0.0
+
+main = log "Done"
diff --git a/tests/purs/passing/TransitiveImport.purs b/tests/purs/passing/TransitiveImport.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/TransitiveImport.purs
@@ -0,0 +1,9 @@
+module Main where
+
+  import Prelude
+  import Middle
+  import Effect.Console
+
+  main = do
+    logShow (middle unit)
+    log "Done"
diff --git a/tests/purs/passing/TransitiveImport/Middle.purs b/tests/purs/passing/TransitiveImport/Middle.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/TransitiveImport/Middle.purs
@@ -0,0 +1,5 @@
+module Middle where
+
+import Test (test)
+
+middle = test
diff --git a/tests/purs/passing/TransitiveImport/Test.purs b/tests/purs/passing/TransitiveImport/Test.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/TransitiveImport/Test.purs
@@ -0,0 +1,9 @@
+module Test where
+
+import Prelude
+
+class TestCls a where
+  test :: a -> a
+
+instance unitTestCls :: TestCls Unit where
+  test _ = unit
diff --git a/tests/purs/passing/TypeClassMemberOrderChange.purs b/tests/purs/passing/TypeClassMemberOrderChange.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/TypeClassMemberOrderChange.purs
@@ -0,0 +1,16 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+class Test a where
+  fn :: a -> a -> a
+  val :: a
+
+instance testBoolean :: Test Boolean where
+  val = true
+  fn x y = y
+
+main = do
+  log (show (fn true val))
+  log "Done"
diff --git a/tests/purs/passing/TypeClasses.purs b/tests/purs/passing/TypeClasses.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/TypeClasses.purs
@@ -0,0 +1,71 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+test1 = \_ -> show "testing"
+
+f :: forall a. Show a => a -> String
+f x = show x
+
+test2 = \_ -> f "testing"
+
+test7 :: forall a. Show a => a -> String
+test7 = show
+
+test8 = \_ -> show $ "testing"
+
+data Data a = Data a
+
+instance showData :: Show a => Show (Data a) where
+  show (Data a) = "Data (" <> show a <> ")"
+
+test3 = \_ -> show (Data "testing")
+
+instance functorData :: Functor Data where
+  map = liftM1
+
+instance applyData :: Apply Data where
+  apply = ap
+
+instance applicativeData :: Applicative Data where
+  pure = Data
+
+instance bindData :: Bind Data where
+  bind (Data a) f = f a
+
+instance monadData :: Monad Data
+
+data Maybe a = Nothing | Just a
+
+instance functorMaybe :: Functor Maybe where
+  map = liftM1
+
+instance applyMaybe :: Apply Maybe where
+  apply = ap
+
+instance applicativeMaybe :: Applicative Maybe where
+  pure = Just
+
+instance bindMaybe :: Bind Maybe where
+  bind Nothing _ = Nothing
+  bind (Just a) f = f a
+
+instance monadMaybe :: Monad Maybe
+
+test4 :: forall a m. Monad m => a -> m Number
+test4 = \_ -> pure 1.0
+
+test5 = \_ -> Just 1.0 >>= \n -> pure (n + 1.0)
+
+ask r = r
+
+runReader r f = f r
+
+test9 _ = runReader 0.0 $ do
+  n <- ask
+  pure $ n + 1.0
+
+main = do
+  log (test7 "Hello")
+  log "Done"
diff --git a/tests/purs/passing/TypeClassesInOrder.purs b/tests/purs/passing/TypeClassesInOrder.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/TypeClassesInOrder.purs
@@ -0,0 +1,12 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+class Foo a where
+  foo :: a -> String
+
+instance fooString :: Foo String where
+  foo s = s
+
+main = log $ foo "Done"
diff --git a/tests/purs/passing/TypeClassesWithOverlappingTypeVariables.purs b/tests/purs/passing/TypeClassesWithOverlappingTypeVariables.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/TypeClassesWithOverlappingTypeVariables.purs
@@ -0,0 +1,12 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+data Either a b = Left a | Right b
+
+instance functorEither :: Functor (Either a) where
+  map _ (Left x) = Left x
+  map f (Right y) = Right (f y)
+
+main = log "Done"
diff --git a/tests/purs/passing/TypeDecl.purs b/tests/purs/passing/TypeDecl.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/TypeDecl.purs
@@ -0,0 +1,13 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+k :: String -> Number -> String
+k x y = x
+
+iterate :: forall a. Number -> (a -> a) -> a -> a
+iterate 0.0 f a = a
+iterate n f a = iterate (n - 1.0) f (f a)
+
+main = log "Done"
diff --git a/tests/purs/passing/TypeOperators.purs b/tests/purs/passing/TypeOperators.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/TypeOperators.purs
@@ -0,0 +1,20 @@
+module Main where
+
+import A (type (~>), type (/\), (/\))
+import Effect.Console (log)
+
+natty ∷ ∀ f. f ~> f
+natty x = x
+
+data Compose f g a = Compose (f (g a))
+
+testPrecedence1 ∷ ∀ f g. Compose f g ~> Compose f g
+testPrecedence1 x = x
+
+testPrecedence2 ∷ ∀ f g. f ~> g → f ~> g
+testPrecedence2 nat fx = nat fx
+
+swap ∷ ∀ a b. a /\ b → b /\ a
+swap (a /\ b) = b /\ a
+
+main = log "Done"
diff --git a/tests/purs/passing/TypeOperators/A.purs b/tests/purs/passing/TypeOperators/A.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/TypeOperators/A.purs
@@ -0,0 +1,22 @@
+module A
+( Tuple(..)
+, type (/\)
+, (/\)
+, Natural
+, type (~>)
+) where
+
+data Tuple a b = Tuple a b
+
+infixl 6 Tuple as /\
+infixl 6 type Tuple as /\
+
+type Natural f g = ∀ a. f a → g a
+
+infixr 0 type Natural as ~>
+
+tup ∷ ∀ a b. a → b → b /\ a
+tup a b = b /\ a
+
+tupX ∷ ∀ a b c. a /\ b /\ c → c
+tupX (a /\ b /\ c) = c
diff --git a/tests/purs/passing/TypeSynonymInData.purs b/tests/purs/passing/TypeSynonymInData.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/TypeSynonymInData.purs
@@ -0,0 +1,12 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+type A a = Array a
+
+data Foo a = Foo (A a) | Bar
+
+foo (Foo []) = Bar
+
+main = log "Done"
diff --git a/tests/purs/passing/TypeSynonyms.purs b/tests/purs/passing/TypeSynonyms.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/TypeSynonyms.purs
@@ -0,0 +1,28 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+type Lens a b =
+  { get :: a -> b
+  , set :: a -> b -> a
+  }
+
+composeLenses :: forall a b c. Lens a b -> Lens b c -> Lens a c
+composeLenses = \l1 -> \l2 ->
+  { get: \a -> l2.get (l1.get a)
+  , set: \a c -> l1.set a (l2.set (l1.get a) c)
+  }
+
+type Pair a b = { fst :: a, snd :: b }
+
+fst :: forall a b. Lens (Pair a b) a
+fst =
+  { get: \p -> p.fst
+  , set: \p a -> { fst: a, snd: p.snd }
+  }
+
+test1 :: forall a b c. Lens (Pair (Pair a b) c) a
+test1 = composeLenses fst fst
+
+main = log "Done"
diff --git a/tests/purs/passing/TypeWildcards.purs b/tests/purs/passing/TypeWildcards.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/TypeWildcards.purs
@@ -0,0 +1,16 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+testTopLevel :: _ -> _
+testTopLevel n = n + 1.0
+
+test :: forall a. Eq a => (a -> a) -> a -> a
+test f a = go (f a) a
+  where
+  go :: _ -> _ -> _
+  go a1 a2 | a1 == a2 = a1
+  go a1 _ = go (f a1) a1
+
+main = log "Done"
diff --git a/tests/purs/passing/TypeWildcardsRecordExtension.purs b/tests/purs/passing/TypeWildcardsRecordExtension.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/TypeWildcardsRecordExtension.purs
@@ -0,0 +1,9 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+foo :: forall a. {b :: Number | a} -> {b :: Number | _}
+foo f = f
+
+main = log "Done"
diff --git a/tests/purs/passing/TypeWithoutParens.purs b/tests/purs/passing/TypeWithoutParens.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/TypeWithoutParens.purs
@@ -0,0 +1,12 @@
+module Main where
+
+import Lib (X, Y)
+import Effect.Console (log)
+
+idX :: X -> X
+idX x = x
+
+idY :: Y -> Y
+idY y = y
+
+main = log "Done"
diff --git a/tests/purs/passing/TypeWithoutParens/Lib.purs b/tests/purs/passing/TypeWithoutParens/Lib.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/TypeWithoutParens/Lib.purs
@@ -0,0 +1,4 @@
+module Lib (X, Y) where
+
+data X = X
+type Y = X
diff --git a/tests/purs/passing/TypedBinders.purs b/tests/purs/passing/TypedBinders.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/TypedBinders.purs
@@ -0,0 +1,68 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+data Tuple a b = Tuple a b
+
+class MonadState s m where
+  get :: m s
+  put :: s -> m Unit
+
+data State s a = State (s -> Tuple s a)
+
+runState s (State f) = f s
+
+instance functorState :: Functor (State s) where
+  map = liftM1
+
+instance applyState :: Apply (State s) where
+  apply = ap
+
+instance applicativeState :: Applicative (State s) where
+  pure a = State $ \s -> Tuple s a
+
+instance bindState :: Bind (State s) where
+  bind f g = State $ \s -> case runState s f of
+                              Tuple s1 a -> runState s1 (g a)
+
+instance monadState :: Monad (State s)
+
+instance monadStateState :: MonadState s (State s) where
+  get = State (\s -> Tuple s s)
+  put s = State (\_ -> Tuple s unit)
+
+modify :: forall m s. Monad m => MonadState s m => (s -> s) -> m Unit
+modify f = do
+  s <- get
+  put (f s)
+
+test :: Tuple String String
+test = runState "" $ do
+  modify $ (<>) "World!"
+  modify $ (<>) "Hello, "
+  str :: String <- get
+  pure str
+
+test2 :: (Int -> Int) -> Int
+test2 = (\(f :: Int -> Int) -> f 10)
+
+test3 :: Int -> Boolean
+test3 n = case n of
+  (0 :: Int) -> true
+  _ -> false
+
+test4 :: Tuple Int Int -> Tuple Int Int
+test4 = (\(Tuple a b :: Tuple Int Int) -> Tuple b a)
+
+type Int1 = Int
+
+test5 :: Int1 -> Int1
+test5 = \(x :: Int1) -> x
+
+main = do
+  let t1 = test
+      t2 = test2 identity
+      t3 = test3 1
+      t4 = test4 (Tuple 1 0)
+  log "Done"
diff --git a/tests/purs/passing/TypedWhere.purs b/tests/purs/passing/TypedWhere.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/TypedWhere.purs
@@ -0,0 +1,18 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+data E a b = L a | R b
+
+data L a = C a (L a) | N
+
+lefts :: forall a b. L (E a b) -> L a
+lefts = go N
+  where
+  go :: forall a b. L a -> L (E a b) -> L a
+  go ls N = ls
+  go ls (C (L a) rest) = go (C a ls) rest
+  go ls (C _ rest) = go ls rest
+
+main = log "Done"
diff --git a/tests/purs/passing/UTF8Sourcefile.purs b/tests/purs/passing/UTF8Sourcefile.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/UTF8Sourcefile.purs
@@ -0,0 +1,8 @@
+module Main where
+
+import Effect.Console
+
+-- '→' is multibyte sequence \u2192.
+utf8multibyte = "Hello λ→ world!!"
+
+main = log "Done"
diff --git a/tests/purs/passing/UnderscoreIdent.purs b/tests/purs/passing/UnderscoreIdent.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/UnderscoreIdent.purs
@@ -0,0 +1,13 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+data Data_type = Con_Structor | Con_2 String
+
+type Type_name = Data_type
+
+done (Con_2 s) = s
+done _ = "Failed"
+
+main = log (done (Con_2 "Done"))
diff --git a/tests/purs/passing/UnicodeIdentifier.purs b/tests/purs/passing/UnicodeIdentifier.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/UnicodeIdentifier.purs
@@ -0,0 +1,7 @@
+module Main where
+
+import Effect.Console (log)
+
+f asgård = asgård
+
+main = log (f "Done")
diff --git a/tests/purs/passing/UnicodeOperators.purs b/tests/purs/passing/UnicodeOperators.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/UnicodeOperators.purs
@@ -0,0 +1,22 @@
+module Main where
+
+import Effect.Console (log)
+
+compose :: forall a b c. (b -> c) -> (a -> b) -> a -> c
+compose f g a = f (g a)
+
+infixr 9 compose as ∘
+
+test1 = (\x -> x) ∘ \y -> y
+
+elem :: forall a b. a -> (a -> Boolean) -> Boolean
+elem x f = f x
+
+infixl 1 elem as ∈
+
+emptySet :: forall a. a -> Boolean
+emptySet _ = true
+
+test2 = 1 ∈ emptySet
+
+main = log "Done"
diff --git a/tests/purs/passing/UnicodeType.purs b/tests/purs/passing/UnicodeType.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/UnicodeType.purs
@@ -0,0 +1,22 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+class Monad m ⇐ Monad1 m where
+  f1 :: m Int
+
+class Monad m <= Monad2 m where
+  f2 :: m Int
+
+f ∷ ∀ m. Monad m ⇒ Int → m Int
+f n = do
+  n' ← pure n
+  pure n'
+
+f' :: forall m. Monad m => Int -> m Int
+f' n = do
+  n' <- pure n
+  pure n'
+
+main = log "Done"
diff --git a/tests/purs/passing/UnifyInTypeInstanceLookup.purs b/tests/purs/passing/UnifyInTypeInstanceLookup.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/UnifyInTypeInstanceLookup.purs
@@ -0,0 +1,25 @@
+module Main where
+
+import Effect.Console (log)
+
+data Z = Z
+data S n = S n
+
+data T
+data F
+
+class EQ x y b
+instance eqT :: EQ x x T
+instance eqF :: EQ x y F
+
+test :: forall a b. EQ a b T => a -> b -> a
+test a _ = a
+
+spin :: forall a b. a -> b
+spin a = spin a
+
+-- Expected type:
+-- forall t. (EQ t (S Z) T) => t
+test1 = test (spin 1) (S Z)
+
+main = log "Done"
diff --git a/tests/purs/passing/Unit.purs b/tests/purs/passing/Unit.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Unit.purs
@@ -0,0 +1,8 @@
+module Main where
+
+import Prelude
+import Effect.Console (logShow, log)
+
+main = do
+  logShow (const unit $ "Hello world")
+  log "Done"
diff --git a/tests/purs/passing/UnknownInTypeClassLookup.purs b/tests/purs/passing/UnknownInTypeClassLookup.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/UnknownInTypeClassLookup.purs
@@ -0,0 +1,15 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+class EQ a b
+
+instance eqAA :: EQ a a
+
+test :: forall a b. EQ a b => a -> b -> String
+test _ _ = "Done"
+
+runTest a = test a a
+
+main = log $ runTest 0.0
diff --git a/tests/purs/passing/UnsafeCoerce.purs b/tests/purs/passing/UnsafeCoerce.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/UnsafeCoerce.purs
@@ -0,0 +1,16 @@
+module Main where
+
+import Prelude (Unit)
+import Unsafe.Coerce (unsafeCoerce)
+import Effect (Effect)
+import Effect.Console (log)
+
+x :: Number
+x = unsafeCoerce 1
+
+y :: Number
+y = case unsafeCoerce 1 of
+  z -> unsafeCoerce z
+
+main :: Effect Unit
+main = log "Done"
diff --git a/tests/purs/passing/UntupledConstraints.purs b/tests/purs/passing/UntupledConstraints.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/UntupledConstraints.purs
@@ -0,0 +1,17 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+class Show a <= Nonsense a where
+  method :: a -> a
+
+data Box a = Box a
+
+instance showBox :: Show a => Show (Box a) where
+  show (Box a) = "Box " <> show a
+
+strangeThing :: forall m. Semigroup (m Unit) => m Unit -> m Unit -> m Unit
+strangeThing x y = x <> y
+
+main = log "Done"
diff --git a/tests/purs/passing/UsableTypeClassMethods.purs b/tests/purs/passing/UsableTypeClassMethods.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/UsableTypeClassMethods.purs
@@ -0,0 +1,35 @@
+-- this is testing that we don't see an `UnusableDeclaration` error for type
+-- class methods that should be valid based on various configurations of fundeps
+module Main where
+
+import Effect.Console (log)
+
+-- no fundeps
+class C0 a b where
+  c0 :: a -> b
+
+-- simple fundep
+class C1 a b | a -> b where
+  c1 :: a
+  c1' :: a -> b
+
+-- transitive
+class C2 a b c | a -> b, b -> c where
+  c2 :: a
+  c2' :: a -> b
+  c2'' :: a -> c
+  c2''' :: a -> b -> c
+
+-- with cycles
+class C3 a b c | a -> b, b -> a, b -> c where
+  c3 :: a
+  c3' :: b
+  c3'' :: a -> c
+  c3''' :: b -> c
+  c3'''' :: a -> b -> c
+
+-- nullary class
+class C4 where
+  c4 :: forall a. a
+
+main = log "Done"
diff --git a/tests/purs/passing/Where.purs b/tests/purs/passing/Where.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/Where.purs
@@ -0,0 +1,49 @@
+module Main where
+
+import Prelude
+import Partial.Unsafe (unsafePartial)
+import Effect
+import Effect.Console (logShow, log)
+
+test1 x = y
+  where
+  y :: Number
+  y = x + 1.0
+
+test2 x y = x' + y'
+  where
+  x' = x + 1.0
+  y' = y + 1.0
+
+test3 = f 1.0 2.0 3.0
+  where f x y z = x + y + z
+
+test4 = f (+) [1.0, 2.0]
+  where f x [y, z] = x y z
+
+test5 = g 10.0
+  where
+  f x | x > 0.0 = g (x / 2.0) + 1.0
+  f x = 0.0
+  g x = f (x - 1.0) + 1.0
+
+test6 = if f true then f 1.0 else f 2.0
+  where f :: forall a. a -> a
+        f x = x
+
+test7 :: Number -> Number
+test7 x = go x
+  where
+  go y | (x - 0.1 < y * y) && (y * y < x + 0.1) = y
+  go y = go $ (y + x / y) / 2.0
+
+main :: Effect _
+main = do
+  logShow (test1 1.0)
+  logShow (test2 1.0 2.0)
+  logShow test3
+  unsafePartial (logShow test4)
+  logShow test5
+  logShow test6
+  logShow (test7 100.0)
+  log "Done"
diff --git a/tests/purs/passing/WildcardInInstance.purs b/tests/purs/passing/WildcardInInstance.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/WildcardInInstance.purs
@@ -0,0 +1,21 @@
+module Main where
+
+import Prelude
+import Effect
+import Effect.Console
+
+class Monad m <= MonadAsk r m | m -> r where
+  ask :: m r
+
+instance monadAskFun :: MonadAsk r ((->) r) where
+  ask = identity
+
+-- This should generate a warning with the correct inferred type.
+test :: forall m. MonadAsk _ m  => m Int
+test = do
+  x <- ask
+  pure (x + 1)
+
+main :: Effect Unit
+main = do
+  log "Done"
diff --git a/tests/purs/passing/WildcardType.purs b/tests/purs/passing/WildcardType.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/WildcardType.purs
@@ -0,0 +1,12 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+f1 :: (_ -> _) -> _
+f1 g = g 1
+
+f2 :: _ -> _
+f2 _ = "Done"
+
+main = log $ f1 f2
diff --git a/tests/purs/passing/iota.purs b/tests/purs/passing/iota.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/iota.purs
@@ -0,0 +1,11 @@
+module Main where
+
+import Effect.Console (log)
+
+s = \x -> \y -> \z -> x z (y z)
+
+k = \x -> \y -> x
+
+iota = \x -> x s k
+
+main = log "Done"
diff --git a/tests/purs/passing/s.purs b/tests/purs/passing/s.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/passing/s.purs
@@ -0,0 +1,8 @@
+module Main where
+
+import Prelude
+import Effect.Console (log)
+
+s = \x y z -> x z (y z)
+
+main = log "Done"
diff --git a/tests/purs/psci/BasicEval.purs b/tests/purs/psci/BasicEval.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/psci/BasicEval.purs
@@ -0,0 +1,10 @@
+import Prelude
+import Data.Array
+
+-- @shouldEvaluateTo 3628800
+let fac n = foldl mul 1 (1..n) in fac 10
+
+fac n = foldl mul 1 (1..n)
+
+-- @shouldEvaluateTo 3628800
+fac 10
diff --git a/tests/purs/psci/Multiline.purs b/tests/purs/psci/Multiline.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/psci/Multiline.purs
@@ -0,0 +1,10 @@
+import Prelude
+import Data.Array
+
+-- @paste
+fac :: Int -> Int
+fac n = foldl mul 1 (1..n)
+-- @paste
+
+-- @shouldEvaluateTo 3628800
+fac 10
diff --git a/tests/purs/warning/2140.purs b/tests/purs/warning/2140.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/2140.purs
@@ -0,0 +1,5 @@
+-- @shouldWarnWith ShadowedTypeVar
+module Main where
+
+class Test a where
+  f :: (forall a. a -> a) -> a -> a
diff --git a/tests/purs/warning/2383.purs b/tests/purs/warning/2383.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/2383.purs
@@ -0,0 +1,12 @@
+-- | This specifically shouldn't warn about `x` being shadowed in `main`
+-- | See https://github.com/purescript/purescript/issues/2383
+module Main where
+
+import Prelude
+
+import Effect (Effect)
+
+main :: Effect Unit
+main = do
+  x <- let x = pure unit in x
+  pure unit
diff --git a/tests/purs/warning/2411.purs b/tests/purs/warning/2411.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/2411.purs
@@ -0,0 +1,15 @@
+-- @shouldWarnWith ShadowedName
+module Main where
+
+import Prelude
+
+import Effect (Effect)
+
+test :: forall m. Monad m => Int -> m Unit
+test x =
+  let x = unit
+  in pure x
+
+main :: Effect Unit
+main = test 42
+
diff --git a/tests/purs/warning/2542.purs b/tests/purs/warning/2542.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/2542.purs
@@ -0,0 +1,16 @@
+-- @shouldWarnWith MissingTypeDeclaration
+module Main where
+
+import Effect.Console
+
+type T = forall a. Array a
+
+-- | Note: This should not raise a `ShadowedTypeVar` warning as the 
+-- | type `a` introduced in `T` should not be in scope 
+-- | in the definition of `bar`.
+foo :: T
+foo = bar where
+  bar :: forall a. Array a
+  bar = []
+
+main = log "Done"
diff --git a/tests/purs/warning/CustomWarning.purs b/tests/purs/warning/CustomWarning.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/CustomWarning.purs
@@ -0,0 +1,11 @@
+-- @shouldWarnWith UserDefinedWarning
+module Main where
+
+import Prim.TypeError
+
+foo :: forall t. Warn (Beside (Text "Custom warning ") (Quote t)) => t -> t
+foo x = x
+
+bar :: Int
+bar = foo 42
+
diff --git a/tests/purs/warning/CustomWarning2.purs b/tests/purs/warning/CustomWarning2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/CustomWarning2.purs
@@ -0,0 +1,13 @@
+-- @shouldWarnWith UserDefinedWarning
+module Main where
+
+import Prim.TypeError
+
+foo :: Warn (Text "foo") => Int -> Int
+foo x = x
+
+bar :: Warn (Text "foo") => Int
+bar = foo 42
+
+baz :: Int
+baz = bar
diff --git a/tests/purs/warning/CustomWarning3.purs b/tests/purs/warning/CustomWarning3.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/CustomWarning3.purs
@@ -0,0 +1,15 @@
+-- @shouldWarnWith UserDefinedWarning
+-- @shouldWarnWith UserDefinedWarning
+module Main where
+
+import Prim.TypeError
+
+foo :: Warn (Text "foo") => Int -> Int
+foo x = x
+
+-- Defer the "foo" warning and warn with "bar" as well
+bar :: Warn (Text "foo") => Warn (Text "bar") => Int
+bar = foo 42
+
+baz :: Int
+baz = bar
diff --git a/tests/purs/warning/DuplicateExportRef.purs b/tests/purs/warning/DuplicateExportRef.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/DuplicateExportRef.purs
@@ -0,0 +1,30 @@
+-- @shouldWarnWith DuplicateExportRef
+-- @shouldWarnWith DuplicateExportRef
+-- @shouldWarnWith DuplicateExportRef
+-- @shouldWarnWith DuplicateExportRef
+-- @shouldWarnWith DuplicateExportRef
+-- @shouldWarnWith DuplicateExportRef
+-- @shouldWarnWith DuplicateExportRef
+module Main
+  ( X(X, X), X
+  , fn, fn
+  , (!), (!)
+  , class Y, class Y
+  , Natural, type (~>), type (~>)
+  , module Prelude, module Prelude
+  ) where
+
+import Prelude (Unit)
+
+data X = X
+
+fn :: X -> X -> X
+fn _ _ = X
+
+infix 2 fn as !
+
+class Y a
+
+type Natural f g = forall a. f a -> g a
+
+infixl 1 type Natural as ~>
diff --git a/tests/purs/warning/DuplicateImport.purs b/tests/purs/warning/DuplicateImport.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/DuplicateImport.purs
@@ -0,0 +1,10 @@
+-- @shouldWarnWith DuplicateImport
+module Main where
+
+import Prelude (Unit, unit, pure)
+import Prelude (Unit, unit, pure)
+
+import Effect (Effect)
+
+main :: Effect Unit
+main = pure unit
diff --git a/tests/purs/warning/DuplicateImportRef.purs b/tests/purs/warning/DuplicateImportRef.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/DuplicateImportRef.purs
@@ -0,0 +1,18 @@
+-- @shouldWarnWith DuplicateImportRef
+-- @shouldWarnWith DuplicateImportRef
+-- @shouldWarnWith DuplicateImportRef
+-- @shouldWarnWith DuplicateImportRef
+module Main where
+
+import Prelude
+  ( Unit, Unit
+  , unit, unit
+  , class Functor, class Functor
+  , (<>), (<>)
+  )
+
+u :: Unit
+u = unit <> unit
+
+fid :: forall f a. Functor f => f a -> f a
+fid fa = fa
diff --git a/tests/purs/warning/DuplicateSelectiveImport.purs b/tests/purs/warning/DuplicateSelectiveImport.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/DuplicateSelectiveImport.purs
@@ -0,0 +1,10 @@
+-- @shouldWarnWith DuplicateSelectiveImport
+module Main where
+
+import Prelude (Unit, unit)
+import Prelude (pure)
+
+import Effect (Effect)
+
+main :: Effect Unit
+main = pure unit
diff --git a/tests/purs/warning/HidingImport.purs b/tests/purs/warning/HidingImport.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/HidingImport.purs
@@ -0,0 +1,9 @@
+-- @shouldWarnWith HidingImport
+-- @shouldWarnWith HidingImport
+module Main where
+
+import Prelude hiding (one)
+import Effect hiding (untilE)
+
+main :: Effect Unit
+main = pure unit
diff --git a/tests/purs/warning/ImplicitImport.purs b/tests/purs/warning/ImplicitImport.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/ImplicitImport.purs
@@ -0,0 +1,9 @@
+-- @shouldWarnWith ImplicitImport
+-- @shouldWarnWith ImplicitImport
+module Main where
+
+import Prelude
+import Effect
+
+main :: Effect Unit
+main = pure unit
diff --git a/tests/purs/warning/ImplicitQualifiedImport.purs b/tests/purs/warning/ImplicitQualifiedImport.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/ImplicitQualifiedImport.purs
@@ -0,0 +1,11 @@
+-- @shouldWarnWith ImplicitQualifiedImport
+-- @shouldWarnWith ImplicitQualifiedImport
+module Main where
+
+import Data.Unit
+
+import Effect as E
+import Effect.Console as E
+
+main :: E.Effect Unit
+main = E.log "test"
diff --git a/tests/purs/warning/ImplicitQualifiedImportReExport.purs b/tests/purs/warning/ImplicitQualifiedImportReExport.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/ImplicitQualifiedImportReExport.purs
@@ -0,0 +1,13 @@
+-- @shouldWarnWith ImplicitQualifiedImportReExport
+-- @shouldWarnWith ImplicitQualifiedImportReExport
+module Main (module X, module Y, main) where
+
+import Prelude
+
+import Effect (Effect)
+import Effect.Console (log)
+import Data.Maybe as X
+import Data.Either as Y
+
+main :: Effect Unit
+main = log "test"
diff --git a/tests/purs/warning/MissingTypeDeclaration.purs b/tests/purs/warning/MissingTypeDeclaration.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/MissingTypeDeclaration.purs
@@ -0,0 +1,4 @@
+-- @shouldWarnWith MissingTypeDeclaration
+module Main where
+
+x = 0
diff --git a/tests/purs/warning/NewtypeInstance.purs b/tests/purs/warning/NewtypeInstance.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/NewtypeInstance.purs
@@ -0,0 +1,8 @@
+-- @shouldWarnWith MissingNewtypeSuperclassInstance
+module Main where
+
+import Prelude
+
+newtype X = X String
+
+derive newtype instance ordX :: Ord X
diff --git a/tests/purs/warning/NewtypeInstance2.purs b/tests/purs/warning/NewtypeInstance2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/NewtypeInstance2.purs
@@ -0,0 +1,15 @@
+-- @shouldWarnWith MissingNewtypeSuperclassInstance
+module Main where
+
+import Prelude
+import Data.Tuple (Tuple(..))
+
+class (Monad m, Monoid w) <= MonadWriter w m | m -> w where
+  tell :: w -> m Unit
+
+instance monadWriterTuple :: Monoid w => MonadWriter w (Tuple w) where
+  tell w = Tuple w unit
+
+newtype MyWriter w a = MyWriter (Tuple w a)
+
+derive newtype instance monadWriterMyWriter :: Monoid w => MonadWriter w (MyWriter w)
diff --git a/tests/purs/warning/NewtypeInstance3.purs b/tests/purs/warning/NewtypeInstance3.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/NewtypeInstance3.purs
@@ -0,0 +1,21 @@
+-- @shouldWarnWith MissingNewtypeSuperclassInstance
+module Main where
+
+import Prelude
+import Data.Tuple (Tuple(..))
+
+class (Monad m, Monoid w) <= MonadTell w m | m -> w where
+  tell :: w -> m Unit
+
+class (MonadTell w m) <= MonadWriter w m | m -> w where
+  listen :: forall a. m a -> m (Tuple w a)
+
+instance monadTellTuple :: Monoid w => MonadTell w (Tuple w) where
+  tell w = Tuple w unit
+
+instance monadWriterTuple :: Monoid w => MonadWriter w (Tuple w) where
+  listen (Tuple w a) = Tuple w (Tuple w a)
+
+newtype MyWriter w a = MyWriter (Tuple w a)
+
+derive newtype instance monadWriterMyWriter :: Monoid w => MonadWriter w (MyWriter w)
diff --git a/tests/purs/warning/NewtypeInstance4.purs b/tests/purs/warning/NewtypeInstance4.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/NewtypeInstance4.purs
@@ -0,0 +1,23 @@
+-- @shouldWarnWith UnverifiableSuperclassInstance
+module Main where
+
+import Prelude
+import Data.Tuple (Tuple(..))
+
+class Monoid w <= MonadTell w m where
+  tell :: w -> m Unit
+
+class (MonadTell w m) <= MonadWriter w m where
+  listen :: forall a. m a -> m (Tuple w a)
+
+instance monadTellTuple :: Monoid w => MonadTell w (Tuple w) where
+  tell w = Tuple w unit
+
+instance monadWriterTuple :: Monoid w => MonadWriter w (Tuple w) where
+  listen (Tuple w a) = Tuple w (Tuple w a)
+
+newtype MyWriter w a = MyWriter (Tuple w a)
+
+-- No fundep means this is unverifiable
+derive newtype instance monadTellMyWriter :: Monoid w => MonadTell w (MyWriter w)
+derive newtype instance monadWriterMyWriter :: Monoid w => MonadWriter w (MyWriter w)
diff --git a/tests/purs/warning/OverlappingPattern.purs b/tests/purs/warning/OverlappingPattern.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/OverlappingPattern.purs
@@ -0,0 +1,15 @@
+-- @shouldWarnWith OverlappingPattern
+-- @shouldWarnWith OverlappingPattern
+module Main where
+
+data X = A | B
+
+pat1 :: X -> Boolean
+pat1 A = true
+pat1 A = true
+pat1 B = false
+
+pat2 :: X -> Boolean
+pat2 A = true
+pat2 _ = false
+pat2 B = false
diff --git a/tests/purs/warning/ScopeShadowing.purs b/tests/purs/warning/ScopeShadowing.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/ScopeShadowing.purs
@@ -0,0 +1,13 @@
+-- @shouldWarnWith ScopeShadowing
+module Main where
+
+import Prelude
+
+-- No warning at the definition, only when the name is later resolved
+data Unit = Unit
+
+-- This is only a warning as the `Prelude` import is implicit. If `Unit` was
+-- named explicitly in an import list, then this refernce to `Unit`
+-- would be a `ScopeConflict` error instead.
+test :: Unit
+test = const Unit unit
diff --git a/tests/purs/warning/ScopeShadowing2.purs b/tests/purs/warning/ScopeShadowing2.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/ScopeShadowing2.purs
@@ -0,0 +1,10 @@
+-- @shouldWarnWith ScopeShadowing
+module Main
+  ( append
+  , module Data.Semigroup
+  ) where
+
+import Data.Semigroup
+
+append :: forall a. a -> a -> a
+append x _ = x
diff --git a/tests/purs/warning/ShadowedBinderPatternGuard.purs b/tests/purs/warning/ShadowedBinderPatternGuard.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/ShadowedBinderPatternGuard.purs
@@ -0,0 +1,7 @@
+-- @shouldWarnWith ShadowedName
+module Main where
+
+f :: Int -> Int
+f n | i <- true -- this i is shadowed
+	, i <- 1234
+	= i
diff --git a/tests/purs/warning/ShadowedNameParens.purs b/tests/purs/warning/ShadowedNameParens.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/ShadowedNameParens.purs
@@ -0,0 +1,5 @@
+-- @shouldWarnWith ShadowedName
+module Main where
+
+f :: Int -> Int -> Int
+f n = \(n) -> 1
diff --git a/tests/purs/warning/ShadowedTypeVar.purs b/tests/purs/warning/ShadowedTypeVar.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/ShadowedTypeVar.purs
@@ -0,0 +1,5 @@
+-- @shouldWarnWith ShadowedTypeVar
+module Main where
+
+f :: forall a. (forall a. a -> a) -> a -> a
+f g x = g x
diff --git a/tests/purs/warning/UnnecessaryFFIModule.js b/tests/purs/warning/UnnecessaryFFIModule.js
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/UnnecessaryFFIModule.js
@@ -0,0 +1,1 @@
+exports.out = null;
diff --git a/tests/purs/warning/UnnecessaryFFIModule.purs b/tests/purs/warning/UnnecessaryFFIModule.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/UnnecessaryFFIModule.purs
@@ -0,0 +1,5 @@
+-- @shouldWarnWith UnnecessaryFFIModule
+module Main where
+
+t :: Boolean
+t = true
diff --git a/tests/purs/warning/UnusedDctorExplicitImport.purs b/tests/purs/warning/UnusedDctorExplicitImport.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/UnusedDctorExplicitImport.purs
@@ -0,0 +1,8 @@
+-- @shouldWarnWith UnusedDctorExplicitImport
+module Main where
+
+import Data.Ordering (Ordering(EQ, LT))
+
+f :: Ordering -> Ordering
+f EQ = EQ
+f x = x
diff --git a/tests/purs/warning/UnusedDctorImportAll.purs b/tests/purs/warning/UnusedDctorImportAll.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/UnusedDctorImportAll.purs
@@ -0,0 +1,7 @@
+-- @shouldWarnWith UnusedDctorImport
+module Main where
+
+import Data.Ordering (Ordering(..))
+
+f :: Ordering -> Ordering
+f x = x
diff --git a/tests/purs/warning/UnusedDctorImportExplicit.purs b/tests/purs/warning/UnusedDctorImportExplicit.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/UnusedDctorImportExplicit.purs
@@ -0,0 +1,7 @@
+-- @shouldWarnWith UnusedDctorImport
+module Main where
+
+import Data.Ordering (Ordering(EQ))
+
+f :: Ordering -> Ordering
+f x = x
diff --git a/tests/purs/warning/UnusedExplicitImport.purs b/tests/purs/warning/UnusedExplicitImport.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/UnusedExplicitImport.purs
@@ -0,0 +1,8 @@
+-- @shouldWarnWith UnusedExplicitImport
+module Main where
+
+import Prelude (Unit, unit, pure, bind)
+import Effect (Effect)
+
+main :: Effect Unit
+main = pure unit
diff --git a/tests/purs/warning/UnusedExplicitImportTypeOp.purs b/tests/purs/warning/UnusedExplicitImportTypeOp.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/UnusedExplicitImportTypeOp.purs
@@ -0,0 +1,9 @@
+-- @shouldWarnWith UnusedExplicitImport
+module Main where
+
+import Prelude (Unit, unit, pure)
+import Effect (Effect)
+import Lib (type (~>), natId)
+
+main :: Effect Unit
+main = natId (pure unit)
diff --git a/tests/purs/warning/UnusedExplicitImportTypeOp/Lib.purs b/tests/purs/warning/UnusedExplicitImportTypeOp/Lib.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/UnusedExplicitImportTypeOp/Lib.purs
@@ -0,0 +1,8 @@
+module Lib where
+
+type Nat f g = ∀ x. f x → g x
+
+infixr 4 type Nat as ~>
+
+natId ∷ ∀ f. f ~> f
+natId x = x
diff --git a/tests/purs/warning/UnusedExplicitImportValOp.purs b/tests/purs/warning/UnusedExplicitImportValOp.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/UnusedExplicitImportValOp.purs
@@ -0,0 +1,8 @@
+-- @shouldWarnWith UnusedExplicitImport
+module Main where
+
+import Prelude (Unit, unit, pure, (+))
+import Effect (Effect)
+
+main :: Effect Unit
+main = pure unit
diff --git a/tests/purs/warning/UnusedFFIImplementations.js b/tests/purs/warning/UnusedFFIImplementations.js
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/UnusedFFIImplementations.js
@@ -0,0 +1,2 @@
+exports.yes = true;
+exports.no = false;
diff --git a/tests/purs/warning/UnusedFFIImplementations.purs b/tests/purs/warning/UnusedFFIImplementations.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/UnusedFFIImplementations.purs
@@ -0,0 +1,4 @@
+-- @shouldWarnWith UnusedFFIImplementations
+module Main where
+
+foreign import yes :: Boolean
diff --git a/tests/purs/warning/UnusedImport.purs b/tests/purs/warning/UnusedImport.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/UnusedImport.purs
@@ -0,0 +1,14 @@
+-- @shouldWarnWith UnusedImport
+-- @shouldWarnWith UnusedImport
+-- @shouldWarnWith UnusedImport
+module Main where
+
+import Data.Unit (Unit, unit)
+
+-- All of the below are unused
+import Effect
+import Effect.Console as Console
+import Test.Assert ()
+
+main :: Unit
+main = unit
diff --git a/tests/purs/warning/UnusedTypeVar.purs b/tests/purs/warning/UnusedTypeVar.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/UnusedTypeVar.purs
@@ -0,0 +1,5 @@
+-- @shouldWarnWith UnusedTypeVar
+module Main where
+
+f :: forall a b. a -> a
+f x = x
diff --git a/tests/purs/warning/WildcardInferredType.purs b/tests/purs/warning/WildcardInferredType.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/warning/WildcardInferredType.purs
@@ -0,0 +1,23 @@
+-- @shouldWarnWith WildcardInferredType
+-- @shouldWarnWith WildcardInferredType
+-- @shouldWarnWith WildcardInferredType
+-- @shouldWarnWith WildcardInferredType
+module Main where
+
+x :: Int
+x = 0 :: _
+
+y :: _
+y = 0
+
+z :: Int
+z =
+  let n :: _
+      n = 0
+  in n
+
+w :: Int
+w = n
+  where
+  n :: _
+  n = 0
diff --git a/tests/support/bower.json b/tests/support/bower.json
--- a/tests/support/bower.json
+++ b/tests/support/bower.json
@@ -1,42 +1,77 @@
 {
   "name": "purescript-test-suite-support",
   "dependencies": {
-    "purescript-arrays": "4.1.2",
-    "purescript-assert": "3.0.0",
-    "purescript-bifunctors": "3.0.0",
-    "purescript-console": "3.0.0",
-    "purescript-control": "3.3.0",
-    "purescript-distributive": "3.0.0",
-    "purescript-eff": "3.1.0",
-    "purescript-either": "3.1.0",
-    "purescript-foldable-traversable": "3.4.0",
-    "purescript-functions": "3.0.0",
-    "purescript-gen": "1.1.0",
-    "purescript-generics": "4.0.0",
-    "purescript-generics-rep": "5.1.0",
-    "purescript-globals": "3.0.0",
-    "purescript-identity": "3.1.0",
-    "purescript-integers": "3.1.0",
-    "purescript-invariant": "3.0.0",
-    "purescript-lazy": "3.0.0",
-    "purescript-lists": "4.9.0",
-    "purescript-math": "2.1.0",
-    "purescript-maybe": "3.0.0",
-    "purescript-monoid": "3.1.0",
-    "purescript-newtype": "2.0.0",
-    "purescript-nonempty": "4.0.0",
-    "purescript-partial": "1.2.1",
-    "purescript-prelude": "3.1.0",
-    "purescript-proxy": "2.1.0",
-    "purescript-psci-support": "3.0.0",
-    "purescript-st": "3.0.0",
-    "purescript-strings": "3.3.0",
-    "purescript-symbols": "3.0.0",
-    "purescript-tailrec": "3.3.0",
-    "purescript-tuples": "4.1.0",
-    "purescript-type-equality": "2.1.0",
-    "purescript-typelevel-prelude": "2.3.0",
-    "purescript-unfoldable": "3.0.0",
-    "purescript-unsafe-coerce": "3.0.0"
+    "purescript-arrays": "purescript/purescript-arrays#compiler/0.12",
+    "purescript-assert": "purescript/purescript-assert#compiler/0.12",
+    "purescript-bifunctors": "purescript/purescript-bifunctors#compiler/0.12",
+    "purescript-console": "purescript/purescript-console#compiler/0.12",
+    "purescript-control": "purescript/purescript-control#compiler/0.12",
+    "purescript-distributive": "purescript/purescript-distributive#compiler/0.12",
+    "purescript-effect": "purescript/purescript-effect#compiler/0.12",
+    "purescript-either": "purescript/purescript-either#compiler/0.12",
+    "purescript-foldable-traversable": "purescript/purescript-foldable-traversable#compiler/0.12",
+    "purescript-functions": "purescript/purescript-functions#compiler/0.12",
+    "purescript-gen": "purescript/purescript-gen#compiler/0.12",
+    "purescript-generics-rep": "purescript/purescript-generics-rep#compiler/0.12",
+    "purescript-globals": "purescript/purescript-globals#compiler/0.12",
+    "purescript-identity": "purescript/purescript-identity#compiler/0.12",
+    "purescript-integers": "purescript/purescript-integers#compiler/0.12",
+    "purescript-invariant": "purescript/purescript-invariant#compiler/0.12",
+    "purescript-lazy": "purescript/purescript-lazy#compiler/0.12",
+    "purescript-lists": "purescript/purescript-lists#compiler/0.12",
+    "purescript-math": "purescript/purescript-math#compiler/0.12",
+    "purescript-maybe": "purescript/purescript-maybe#compiler/0.12",
+    "purescript-newtype": "purescript/purescript-newtype#compiler/0.12",
+    "purescript-nonempty": "purescript/purescript-nonempty#compiler/0.12",
+    "purescript-partial": "purescript/purescript-partial#compiler/0.12",
+    "purescript-prelude": "purescript/purescript-prelude#compiler/0.12",
+    "purescript-proxy": "purescript/purescript-proxy#compiler/0.12",
+    "purescript-psci-support": "purescript/purescript-psci-support#compiler/0.12",
+    "purescript-refs": "purescript/purescript-refs#compiler/0.12",
+    "purescript-st": "purescript/purescript-st#compiler/0.12",
+    "purescript-strings": "purescript/purescript-strings#compiler/0.12",
+    "purescript-tailrec": "purescript/purescript-tailrec#compiler/0.12",
+    "purescript-tuples": "purescript/purescript-tuples#compiler/0.12",
+    "purescript-type-equality": "purescript/purescript-type-equality#compiler/0.12",
+    "purescript-typelevel-prelude": "purescript/purescript-typelevel-prelude#compiler/0.12",
+    "purescript-unfoldable": "purescript/purescript-unfoldable#compiler/0.12",
+    "purescript-unsafe-coerce": "purescript/purescript-unsafe-coerce#compiler/0.12"
+  },
+  "resolutions": {
+    "purescript-arrays": "compiler/0.12",
+    "purescript-assert": "compiler/0.12",
+    "purescript-bifunctors": "compiler/0.12",
+    "purescript-console": "compiler/0.12",
+    "purescript-control": "compiler/0.12",
+    "purescript-distributive": "compiler/0.12",
+    "purescript-effect": "compiler/0.12",
+    "purescript-either": "compiler/0.12",
+    "purescript-foldable-traversable": "compiler/0.12",
+    "purescript-functions": "compiler/0.12",
+    "purescript-gen": "compiler/0.12",
+    "purescript-generics-rep": "compiler/0.12",
+    "purescript-globals": "compiler/0.12",
+    "purescript-identity": "compiler/0.12",
+    "purescript-integers": "compiler/0.12",
+    "purescript-invariant": "compiler/0.12",
+    "purescript-lazy": "compiler/0.12",
+    "purescript-lists": "compiler/0.12",
+    "purescript-math": "compiler/0.12",
+    "purescript-maybe": "compiler/0.12",
+    "purescript-newtype": "compiler/0.12",
+    "purescript-nonempty": "compiler/0.12",
+    "purescript-partial": "compiler/0.12",
+    "purescript-prelude": "compiler/0.12",
+    "purescript-proxy": "compiler/0.12",
+    "purescript-psci-support": "compiler/0.12",
+    "purescript-refs": "compiler/0.12",
+    "purescript-st": "compiler/0.12",
+    "purescript-strings": "compiler/0.12",
+    "purescript-tailrec": "compiler/0.12",
+    "purescript-tuples": "compiler/0.12",
+    "purescript-type-equality": "compiler/0.12",
+    "purescript-typelevel-prelude": "compiler/0.12",
+    "purescript-unfoldable": "compiler/0.12",
+    "purescript-unsafe-coerce": "compiler/0.12"
   }
 }
diff --git a/tests/support/package-lock.json b/tests/support/package-lock.json
new file mode 100644
--- /dev/null
+++ b/tests/support/package-lock.json
@@ -0,0 +1,171 @@
+{
+  "requires": true,
+  "lockfileVersion": 1,
+  "dependencies": {
+    "bower": {
+      "version": "1.8.2",
+      "resolved": "https://registry.npmjs.org/bower/-/bower-1.8.2.tgz",
+      "integrity": "sha1-rfU1KcjUrwLvJPuNU0HBQZ0z4vc="
+    },
+    "fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
+    },
+    "glob": {
+      "version": "5.0.15",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz",
+      "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=",
+      "requires": {
+        "inflight": "1.0.6",
+        "inherits": "2.0.3",
+        "minimatch": "3.0.4",
+        "once": "1.4.0",
+        "path-is-absolute": "1.0.1"
+      },
+      "dependencies": {
+        "balanced-match": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+          "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
+        },
+        "brace-expansion": {
+          "version": "1.1.11",
+          "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+          "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+          "requires": {
+            "balanced-match": "1.0.0",
+            "concat-map": "0.0.1"
+          }
+        },
+        "concat-map": {
+          "version": "0.0.1",
+          "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+          "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+        },
+        "inflight": {
+          "version": "1.0.6",
+          "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+          "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+          "requires": {
+            "once": "1.4.0",
+            "wrappy": "1.0.2"
+          }
+        },
+        "inherits": {
+          "version": "2.0.3",
+          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+          "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+        },
+        "minimatch": {
+          "version": "3.0.4",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+          "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+          "requires": {
+            "brace-expansion": "1.1.11"
+          }
+        },
+        "once": {
+          "version": "1.4.0",
+          "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+          "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+          "requires": {
+            "wrappy": "1.0.2"
+          }
+        },
+        "path-is-absolute": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+          "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
+        },
+        "wrappy": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+          "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+        }
+      }
+    },
+    "rimraf": {
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
+      "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
+      "requires": {
+        "glob": "7.1.2"
+      },
+      "dependencies": {
+        "balanced-match": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+          "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
+        },
+        "brace-expansion": {
+          "version": "1.1.11",
+          "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+          "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+          "requires": {
+            "balanced-match": "1.0.0",
+            "concat-map": "0.0.1"
+          }
+        },
+        "concat-map": {
+          "version": "0.0.1",
+          "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+          "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+        },
+        "glob": {
+          "version": "7.1.2",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
+          "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
+          "requires": {
+            "fs.realpath": "1.0.0",
+            "inflight": "1.0.6",
+            "inherits": "2.0.3",
+            "minimatch": "3.0.4",
+            "once": "1.4.0",
+            "path-is-absolute": "1.0.1"
+          }
+        },
+        "inflight": {
+          "version": "1.0.6",
+          "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+          "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+          "requires": {
+            "once": "1.4.0",
+            "wrappy": "1.0.2"
+          }
+        },
+        "inherits": {
+          "version": "2.0.3",
+          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+          "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+        },
+        "minimatch": {
+          "version": "3.0.4",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+          "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+          "requires": {
+            "brace-expansion": "1.1.11"
+          }
+        },
+        "once": {
+          "version": "1.4.0",
+          "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+          "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+          "requires": {
+            "wrappy": "1.0.2"
+          }
+        },
+        "path-is-absolute": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+          "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
+        },
+        "wrappy": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+          "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+        }
+      }
+    }
+  }
+}
diff --git a/tests/support/pscide/src/FindUsage.purs b/tests/support/pscide/src/FindUsage.purs
new file mode 100644
--- /dev/null
+++ b/tests/support/pscide/src/FindUsage.purs
@@ -0,0 +1,12 @@
+module FindUsage where
+
+import FindUsage.Definition (usageId, ($%), Usage(..))
+import FindUsage.Reexport (toBeReexported)
+
+usagePatternMatch ∷ Usage → Usage
+usagePatternMatch x = case x of
+  Used _ → x
+  _ $% _ → x
+
+usageFn ∷ ∀ a. a → a
+usageFn = usageId toBeReexported
diff --git a/tests/support/pscide/src/FindUsage/Definition.purs b/tests/support/pscide/src/FindUsage/Definition.purs
new file mode 100644
--- /dev/null
+++ b/tests/support/pscide/src/FindUsage/Definition.purs
@@ -0,0 +1,13 @@
+module FindUsage.Definition (Usage(..), ($%), usageId, toBeReexported) where
+
+data Usage
+  = Used Int
+  | Usage Int Int
+
+infixl 2 Usage as $%
+
+usageId ∷ ∀ a. a → a
+usageId x = x
+
+toBeReexported ∷ ∀ a. a → a
+toBeReexported = usageId
diff --git a/tests/support/pscide/src/FindUsage/Recursive.purs b/tests/support/pscide/src/FindUsage/Recursive.purs
new file mode 100644
--- /dev/null
+++ b/tests/support/pscide/src/FindUsage/Recursive.purs
@@ -0,0 +1,8 @@
+module FindUsage.Recursive where
+
+data Nat = Suc Nat | Z
+
+recursiveUsage :: Nat -> Int
+recursiveUsage = case _ of
+  Suc x -> recursiveUsage x
+  Z -> 0
diff --git a/tests/support/pscide/src/FindUsage/RecursiveShadowed.purs b/tests/support/pscide/src/FindUsage/RecursiveShadowed.purs
new file mode 100644
--- /dev/null
+++ b/tests/support/pscide/src/FindUsage/RecursiveShadowed.purs
@@ -0,0 +1,10 @@
+module FindUsage.RecursiveShadowed where
+
+data Nat = Suc Nat | Z
+
+recursiveUsage :: Nat -> Int
+recursiveUsage = case _ of
+  Suc x ->
+    let recursiveUsage = 3
+    in recursiveUsage
+  Z -> 0
diff --git a/tests/support/pscide/src/FindUsage/Reexport.purs b/tests/support/pscide/src/FindUsage/Reexport.purs
new file mode 100644
--- /dev/null
+++ b/tests/support/pscide/src/FindUsage/Reexport.purs
@@ -0,0 +1,3 @@
+module FindUsage.Reexport (module X) where
+
+import FindUsage.Definition (toBeReexported) as X
