diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -19,6 +19,7 @@
   SHA
   aeson
   aeson-better-errors
+  alex
   ansi-terminal
   ansi-wl-pprint
   appar
@@ -42,12 +43,12 @@
   bytestring
   bytestring-builder
   case-insensitive
-  cereal
   cheapskate
   clock
   colour
   conduit
   conduit-extra
+  constraints
   containers
   cookie
   cryptonite
@@ -63,6 +64,7 @@
   dlist
   easy-file
   edit-distance
+  enclosed-exceptions
   entropy
   exceptions
   fast-logger
@@ -72,9 +74,10 @@
   fsnotify
   ghc-boot-th
   ghc-prim
+  happy
   hashable
   haskeline
-  hfsevents
+  hinotify
   http-date
   http-types
   http2
@@ -82,6 +85,7 @@
   integer-logarithms
   iproute
   language-javascript
+  lifted-async
   lifted-base
   memory
   microlens
@@ -113,10 +117,10 @@
   regex-base
   regex-tdfa
   resourcet
-  rts
   safe
   scientific
   semigroups
+  shelly
   simple-sendfile
   sourcemap
   split
@@ -125,6 +129,8 @@
   streaming-commons
   stringsearch
   syb
+  system-fileio
+  system-filepath
   tagged
   tagsoup
   template-haskell
@@ -313,6 +319,39 @@
   TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
+alex LICENSE file:
+
+  Copyright (c) 1995-2011, Chris Dornan and Simon Marlow
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are
+  met:
+
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+
+      * Redistributions in binary form must reproduce the above
+        copyright notice, this list of conditions and the following
+        disclaimer in the documentation and/or other materials provided
+        with the distribution.
+
+      * Neither the name of the copyright holders, nor the names of the
+        contributors may be used to endorse or promote products derived
+        from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 ansi-terminal LICENSE file:
 
   Copyright (c) 2008, Maximilian Bolingbroke
@@ -1119,39 +1158,6 @@
   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-cereal LICENSE file:
-
-  Copyright (c) Lennart Kolmodin, Galois, Inc.
-
-  All rights reserved.
-
-  Redistribution and use in source and binary forms, with or without
-  modification, are permitted provided that the following conditions
-  are met:
-
-  1. Redistributions of source code must retain the above copyright
-     notice, this list of conditions and the following disclaimer.
-
-  2. Redistributions in binary form must reproduce the above copyright
-     notice, this list of conditions and the following disclaimer in the
-     documentation and/or other materials provided with the distribution.
-
-  3. Neither the name of the author nor the names of his contributors
-     may be used to endorse or promote products derived from this software
-     without specific prior written permission.
-
-  THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
-  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-  DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
-  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
-  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-  POSSIBILITY OF SUCH DAMAGE.
-
 cheapskate LICENSE file:
 
   Copyright (c) 2013, John MacFarlane
@@ -1289,6 +1295,35 @@
   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
+constraints LICENSE file:
+
+  Copyright 2011-2015 Edward Kmett
+
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+
+  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
+  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+  POSSIBILITY OF SUCH DAMAGE.
+
 containers LICENSE file:
 
   The Glasgow Haskell Compiler License
@@ -1757,6 +1792,29 @@
   IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+enclosed-exceptions LICENSE file:
+
+  Copyright (c) 2012 Michael Snoyman, http://www.yesodweb.com/
+
+  Permission is hereby granted, free of charge, to any person obtaining
+  a copy of this software and associated documentation files (the
+  "Software"), to deal in the Software without restriction, including
+  without limitation the rights to use, copy, modify, merge, publish,
+  distribute, sublicense, and/or sell copies of the Software, and to
+  permit persons to whom the Software is furnished to do so, subject to
+  the following conditions:
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
 entropy LICENSE file:
 
   Copyright (c) Thomas DuBuisson
@@ -2080,6 +2138,39 @@
     be a definition of the Haskell 98 Language.
 
 
+happy LICENSE file:
+
+  The Happy License
+  -----------------
+
+  Copyright 2001, Simon Marlow and Andy Gill.  All rights reserved.
+
+  Extensions to implement Tomita's Generalized LR parsing:
+    Copyright 2004, University of Durham, Paul Callaghan and Ben Medlock.
+    All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+
+  - Redistributions of source code must retain the above copyright notice,
+  this list of conditions and the following disclaimer.
+
+  - Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "AS IS" AND ANY
+  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 hashable LICENSE file:
 
   Copyright Milan Straka 2010
@@ -2139,38 +2230,38 @@
   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
   USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-hfsevents LICENSE file:
+hinotify LICENSE file:
 
-  Copyright (c) 2012, Luite Stegeman
+  Copyright (c) Lennart Kolmodin
 
   All rights reserved.
 
   Redistribution and use in source and binary forms, with or without
-  modification, are permitted provided that the following conditions are met:
+  modification, are permitted provided that the following conditions
+  are met:
 
-      * Redistributions of source code must retain the above copyright
-        notice, this list of conditions and the following disclaimer.
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
 
-      * Redistributions in binary form must reproduce the above
-        copyright notice, this list of conditions and the following
-        disclaimer in the documentation and/or other materials provided
-        with the distribution.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
 
-      * Neither the name of Luite Stegeman nor the names of other
-        contributors may be used to endorse or promote products derived
-        from this software without specific prior written permission.
+  3. Neither the name of the author nor the names of his contributors
+     may be used to endorse or promote products derived from this software
+     without specific prior written permission.
 
-  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
+  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+  POSSIBILITY OF SUCH DAMAGE.
 
 http-date LICENSE file:
 
@@ -2387,6 +2478,39 @@
   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+lifted-async LICENSE file:
+
+  Copyright (c) 2012-2017, Mitsutoshi Aoe
+
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+
+      * Redistributions in binary form must reproduce the above
+        copyright notice, this list of conditions and the following
+        disclaimer in the documentation and/or other materials provided
+        with the distribution.
+
+      * Neither the name of Mitsutoshi Aoe nor the names of other
+        contributors may be used to endorse or promote products derived
+        from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 lifted-base LICENSE file:
 
   Copyright © 2010-2012, Bas van Dijk, Anders Kaseorg
@@ -3526,6 +3650,39 @@
   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   POSSIBILITY OF SUCH DAMAGE.
 
+shelly LICENSE file:
+
+  Copyright (c) 2017, Petr Rockai <me@mornfall.net>
+
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+
+      * Redistributions in binary form must reproduce the above
+        copyright notice, this list of conditions and the following
+        disclaimer in the documentation and/or other materials provided
+        with the distribution.
+
+      * Neither the name of Petr Rockai nor the names of other
+        contributors may be used to endorse or promote products derived
+        from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 simple-sendfile LICENSE file:
 
   Copyright (c) 2009, IIJ Innovation Institute Inc.
@@ -3835,6 +3992,56 @@
     be a definition of the Haskell 98 Foreign Function Interface.
 
   -----------------------------------------------------------------------------
+
+system-fileio LICENSE file:
+
+  Copyright (c) 2011 John Millikin
+
+  Permission is hereby granted, free of charge, to any person
+  obtaining a copy of this software and associated documentation
+  files (the "Software"), to deal in the Software without
+  restriction, including without limitation the rights to use,
+  copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the
+  Software is furnished to do so, subject to the following
+  conditions:
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+  OTHER DEALINGS IN THE SOFTWARE.
+
+system-filepath LICENSE file:
+
+  Copyright (c) 2010 John Millikin
+
+  Permission is hereby granted, free of charge, to any person
+  obtaining a copy of this software and associated documentation
+  files (the "Software"), to deal in the Software without
+  restriction, including without limitation the rights to use,
+  copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the
+  Software is furnished to do so, subject to the following
+  conditions:
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+  OTHER DEALINGS IN THE SOFTWARE.
 
 tagged LICENSE file:
 
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
 
 A small strongly typed programming language with expressive types that compiles to JavaScript, written in and inspired by Haskell.
 
-[![Hackage](https://img.shields.io/hackage/v/purescript.svg)](http://hackage.haskell.org/package/purescript) [![Build Status](https://api.travis-ci.org/purescript/purescript.svg?branch=master)](http://travis-ci.org/purescript/purescript)
+[![Hackage](https://img.shields.io/hackage/v/purescript.svg)](http://hackage.haskell.org/package/purescript) [![Build Status](https://api.travis-ci.org/purescript/purescript.svg?branch=master)](http://travis-ci.org/purescript/purescript) [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/purescript/purescript?branch=master&svg=true)](https://ci.appveyor.com/project/hdgarrood/purescript-lfgff/history)
 
 ## Language info
 
diff --git a/app/static/index.js b/app/static/index.js
--- a/app/static/index.js
+++ b/app/static/index.js
@@ -18,7 +18,7 @@
     };
     // Replace any require(...) statements with lookups on the PSCI object.
     var replaced = js.replace(/require\("[^"]*"\)/g, function(s) {
-        return "PSCI['" + s.substring(12, s.length - 2) + "']";
+        return "PSCI['" + s.split('/')[1] + "']";
     });
     // Wrap the module and evaluate it.
     var wrapped =
diff --git a/purescript.cabal b/purescript.cabal
--- a/purescript.cabal
+++ b/purescript.cabal
@@ -1,11 +1,13 @@
--- This file has been generated from package.yaml by hpack version 0.28.2.
+cabal-version: 1.12
+
+-- This file has been generated from package.yaml by hpack version 0.31.1.
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 41d1259da9e21e4b7e604e45d306d0a5b69939ff6ef1dc59b410a7d51ea3f7f9
+-- hash: 5d1735c5c26a07ecb7e0a4d8033e3083d74c2f22263e67ada418c4e61cae4d3e
 
 name:           purescript
-version:        0.12.2
+version:        0.12.3
 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
@@ -19,26 +21,22 @@
 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/json-compat/v0.11.3/generics-4.0.0.json
-    tests/json-compat/v0.11.3/symbols-3.0.0.json
-    tests/json-compat/v0.12.1/typelevel-prelude-3.0.0.json
-    tests/purs/docs/bower.json
+    tests/purs/failing/MissingFFIImplementations.js
+    tests/purs/passing/2172.js
+    tests/purs/passing/EffFn.js
+    tests/purs/passing/FunWithFunDeps.js
+    tests/purs/passing/PolyLabels.js
+    tests/purs/passing/RowUnion.js
+    tests/purs/warning/UnnecessaryFFIModule.js
+    tests/purs/warning/UnusedFFIImplementations.js
     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/Ado.purs
     tests/purs/docs/src/ChildDeclOrder.purs
     tests/purs/docs/src/Clash.purs
     tests/purs/docs/src/Clash1.purs
@@ -238,7 +236,6 @@
     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
@@ -345,7 +342,6 @@
     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
@@ -420,7 +416,6 @@
     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
@@ -449,7 +444,6 @@
     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
@@ -563,7 +557,6 @@
     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/QualifiedAdo.purs
@@ -601,7 +594,6 @@
     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
@@ -693,7 +685,6 @@
     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
@@ -702,18 +693,24 @@
     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/purs/warning/WildcardInferredType2.purs
+    tests/purs/docs/bower.json
+    tests/purs/docs/resolutions.json
+    tests/json-compat/v0.11.3/generics-4.0.0.json
+    tests/json-compat/v0.11.3/symbols-3.0.0.json
+    tests/json-compat/v0.12.1/typelevel-prelude-3.0.0.json
     tests/support/bower.json
+    tests/support/package-lock.json
     tests/support/package.json
     tests/support/prelude-resolutions.json
+    tests/support/setup-win.cmd
     tests/support/psci/InteractivePrint.purs
-    tests/support/psci/Reload.edit
     tests/support/psci/Reload.purs
+    tests/support/psci/Reload.edit
     tests/support/pscide/src/CompletionSpecDocs.purs
     tests/support/pscide/src/FindUsage.purs
     tests/support/pscide/src/FindUsage/Definition.purs
@@ -724,14 +721,18 @@
     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/RebuildSpecWithForeign.js
+    tests/support/pscide/src/RebuildSpecSingleModule.fail
     tests/support/pscide/src/RebuildSpecWithMissingForeign.fail
-    tests/support/setup-win.cmd
+    stack.yaml
+    README.md
+    INSTALL.md
+    CONTRIBUTORS.md
+    CONTRIBUTING.md
 
 source-repository head
   type: git
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
@@ -308,7 +308,7 @@
   -- A value re-exported from another module. These will be inserted during
   -- elaboration in name desugaring.
   --
-  | ReExportRef SourceSpan ModuleName DeclarationRef
+  | ReExportRef SourceSpan ExportSource DeclarationRef
   deriving (Show, Generic, NFData)
 
 instance Eq DeclarationRef where
@@ -323,6 +323,13 @@
   (ReExportRef _ mn ref) == (ReExportRef _ mn' ref') = mn == mn' && ref == ref'
   _ == _ = False
 
+data ExportSource =
+  ExportSource
+  { exportSourceImportedFrom :: Maybe ModuleName
+  , exportSourceDefinedIn :: ModuleName
+  }
+  deriving (Eq, Ord, Show, Generic, NFData)
+
 -- enable sorting lists of explicitly imported refs when suggesting imports in linting, IDE, etc.
 -- not an Ord because this implementation is not consistent with its Eq instance.
 -- think of it as a notion of contextual, not inherent, ordering.
@@ -902,6 +909,7 @@
 
 $(deriveJSON (defaultOptions { sumEncoding = ObjectWithSingleField }) ''DeclarationRef)
 $(deriveJSON (defaultOptions { sumEncoding = ObjectWithSingleField }) ''ImportDeclarationType)
+$(deriveJSON (defaultOptions { sumEncoding = ObjectWithSingleField }) ''ExportSource)
 
 isTrueExpr :: Expr -> Bool
 isTrueExpr (Literal _ (BooleanLiteral True)) = True
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
@@ -249,6 +249,7 @@
   where
   desugar' =
     traverse P.desugarDoModule
+      >=> traverse P.desugarAdoModule
       >=> map P.desugarLetPatternModule
       >>> traverse P.desugarCasesModule
       >=> traverse P.desugarTypeDeclarationsModule
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
@@ -72,8 +72,8 @@
   case Map.lookup mn env of
     Nothing ->
       internalError ("Module missing: " ++ T.unpack (P.runModuleName mn))
-    Just (_, imports, exports) -> do
-      allExports <- runReaderT (collectDeclarations imports exports) mn
+    Just (_, _, exports) -> do
+      allExports <- runReaderT (collectDeclarations exports) mn
       pure (filter notLocal allExports)
 
   where
@@ -100,16 +100,15 @@
 --
 collectDeclarations :: forall m.
   (MonadState (Map P.ModuleName Module) m, MonadReader P.ModuleName m) =>
-  P.Imports ->
   P.Exports ->
   m [(P.ModuleName, [Declaration])]
-collectDeclarations imports exports = do
-  valsAndMembers <- collect lookupValueDeclaration impVals expVals
-  valOps <- collect lookupValueOpDeclaration impValOps expValOps
-  typeClasses <- collect lookupTypeClassDeclaration impTCs expTCs
-  types <- collect lookupTypeDeclaration impTypes expTypes
-  typeOps <- collect lookupTypeOpDeclaration impTypeOps expTypeOps
-  kinds <- collect lookupKindDeclaration impKinds expKinds
+collectDeclarations exports = do
+  valsAndMembers <- collect lookupValueDeclaration expVals
+  valOps <- collect lookupValueOpDeclaration expValOps
+  typeClasses <- collect lookupTypeClassDeclaration expTCs
+  types <- collect lookupTypeDeclaration expTypes
+  typeOps <- collect lookupTypeOpDeclaration expTypeOps
+  kinds <- collect lookupKindDeclaration expKinds
 
   (vals, classes) <- handleTypeClassMembers valsAndMembers typeClasses
 
@@ -123,72 +122,20 @@
   collect
     :: (Eq a, Show a)
     => (P.ModuleName -> a -> m (P.ModuleName, [b]))
-    -> [P.ImportRecord a]
-    -> Map a P.ModuleName
+    -> Map a P.ExportSource
     -> m (Map P.ModuleName [b])
-  collect lookup' imps exps = do
-    imps' <- traverse (findImport imps) $ Map.toList exps
-    Map.fromListWith (<>) <$> traverse (uncurry lookup') imps'
+  collect lookup' exps = do
+    let reExps = Map.toList $ Map.mapMaybe P.exportSourceImportedFrom exps
+    decls <- traverse (uncurry (flip lookup')) reExps
+    return $ Map.fromListWith (<>) decls
 
   expVals = P.exportedValues exports
-  impVals = concat (Map.elems (P.importedValues imports))
-
   expValOps = P.exportedValueOps exports
-  impValOps = concat (Map.elems (P.importedValueOps imports))
-
   expTypes = Map.map snd (P.exportedTypes exports)
-  impTypes = concat (Map.elems (P.importedTypes imports))
-
   expTypeOps = P.exportedTypeOps exports
-  impTypeOps = concat (Map.elems (P.importedTypeOps imports))
-
   expCtors = concatMap fst (Map.elems (P.exportedTypes exports))
-
   expTCs = P.exportedTypeClasses exports
-  impTCs = concat (Map.elems (P.importedTypeClasses imports))
-
   expKinds = P.exportedKinds exports
-  impKinds = concat (Map.elems (P.importedKinds imports))
-
--- |
--- Given a list of imported declarations (of a particular kind, ie. type, data,
--- class, value, etc), and the name of an exported declaration of the same
--- kind, together with the module it was originally defined in, return a tuple
--- of:
---
---      * the module that exported declaration was imported from (note that
---      this can be different from the module it was originally defined in, if
---      it is a re-export),
---      * that same declaration's name.
---
--- This function uses a type variable for names because we want to be able to
--- instantiate @name@ as both 'P.Ident' and 'P.ProperName'.
---
-findImport ::
-  (Show name, Eq name, MonadReader P.ModuleName m) =>
-  [P.ImportRecord name] ->
-  (name, P.ModuleName) ->
-  m (P.ModuleName, name)
-findImport imps (name, orig) =
-  let
-    matches (P.ImportRecord qual mn _ _) = P.disqualify qual == name && mn == orig
-    matching = filter matches imps
-    getQualified (P.Qualified mname _) = mname
-  in
-    case mapMaybe (getQualified . P.importName) matching of
-      -- A value can occur more than once if it is imported twice (eg, if it is
-      -- exported by A, re-exported from A by B, and C imports it from both A
-      -- 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))
 
 lookupValueDeclaration ::
   (MonadState (Map P.ModuleName Module) m,
diff --git a/src/Language/PureScript/Ide/Externs.hs b/src/Language/PureScript/Ide/Externs.hs
--- a/src/Language/PureScript/Ide/Externs.hs
+++ b/src/Language/PureScript/Ide/Externs.hs
@@ -119,7 +119,7 @@
   | SynonymToResolve (P.ProperName 'P.TypeName) P.SourceType
 
 convertExport :: P.DeclarationRef -> Maybe (P.ModuleName, P.DeclarationRef)
-convertExport (P.ReExportRef _ m r) = Just (m, r)
+convertExport (P.ReExportRef _ src r) = Just (P.exportSourceDefinedIn src, r)
 convertExport _ = Nothing
 
 convertDecl :: P.ExternsDeclaration -> Either ToResolve (Maybe IdeDeclaration)
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
@@ -299,7 +299,7 @@
 
   dtys
     :: ModuleName
-    -> M.Map (ProperName 'TypeName) ([ProperName 'ConstructorName], ModuleName)
+    -> M.Map (ProperName 'TypeName) ([ProperName 'ConstructorName], ExportSource)
   dtys mn = maybe M.empty exportedTypes $ envModuleExports <$> mn `M.lookup` env
 
   dctorsForType
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
@@ -73,34 +73,42 @@
     return $ M.insert efModuleName (efSourceSpan, imps, exps) env
     where
 
-    exportedTypes :: M.Map (ProperName 'TypeName) ([ProperName 'ConstructorName], ModuleName)
+    -- An ExportSource for declarations local to the module which the given
+    -- ExternsFile corresponds to.
+    localExportSource =
+      ExportSource { exportSourceDefinedIn = efModuleName
+                   , exportSourceImportedFrom = Nothing
+                   }
+
+    exportedTypes :: M.Map (ProperName 'TypeName) ([ProperName 'ConstructorName], ExportSource)
     exportedTypes = M.fromList $ mapMaybe toExportedType efExports
       where
-      toExportedType (TypeRef _ tyCon dctors) = Just (tyCon, (fromMaybe (mapMaybe forTyCon efDeclarations) dctors, efModuleName))
+      toExportedType (TypeRef _ tyCon dctors) = Just (tyCon, (fromMaybe (mapMaybe forTyCon efDeclarations) dctors, localExportSource))
         where
         forTyCon :: ExternsDeclaration -> Maybe (ProperName 'ConstructorName)
         forTyCon (EDDataConstructor pn _ tNm _ _) | tNm == tyCon = Just pn
         forTyCon _ = Nothing
       toExportedType _ = Nothing
 
-    exportedTypeOps :: M.Map (OpName 'TypeOpName) ModuleName
+    exportedTypeOps :: M.Map (OpName 'TypeOpName) ExportSource
     exportedTypeOps = exportedRefs getTypeOpRef
 
-    exportedTypeClasses :: M.Map (ProperName 'ClassName) ModuleName
+    exportedTypeClasses :: M.Map (ProperName 'ClassName) ExportSource
     exportedTypeClasses = exportedRefs getTypeClassRef
 
-    exportedValues :: M.Map Ident ModuleName
+    exportedValues :: M.Map Ident ExportSource
     exportedValues = exportedRefs getValueRef
 
-    exportedValueOps :: M.Map (OpName 'ValueOpName) ModuleName
+    exportedValueOps :: M.Map (OpName 'ValueOpName) ExportSource
     exportedValueOps = exportedRefs getValueOpRef
 
-    exportedRefs :: Ord a => (DeclarationRef -> Maybe a) -> M.Map a ModuleName
-    exportedRefs f = M.fromList $ (, efModuleName) <$> mapMaybe f efExports
-
-    exportedKinds :: M.Map (ProperName 'KindName) ModuleName
+    exportedKinds :: M.Map (ProperName 'KindName) ExportSource
     exportedKinds = exportedRefs getKindRef
 
+    exportedRefs :: Ord a => (DeclarationRef -> Maybe a) -> M.Map a ExportSource
+    exportedRefs f =
+      M.fromList $ (, localExportSource) <$> mapMaybe f efExports
+
   updateEnv :: ([Module], Env) -> Module -> m ([Module], Env)
   updateEnv (ms, env) m@(Module ss _ mn _ refs) = do
     members <- findExportable m
@@ -141,14 +149,14 @@
 
   elaboratedTypeRefs :: [DeclarationRef]
   elaboratedTypeRefs =
-    flip map (M.toList (exportedTypes exps)) $ \(tctor, (dctors, mn')) ->
+    flip map (M.toList (exportedTypes exps)) $ \(tctor, (dctors, src)) ->
       let ref = TypeRef ss tctor (Just dctors)
-      in if mn == mn' then ref else ReExportRef ss mn' ref
+      in if mn == exportSourceDefinedIn src then ref else ReExportRef ss src ref
 
-  go :: (a -> DeclarationRef) -> (Exports -> M.Map a ModuleName) -> [DeclarationRef]
+  go :: (a -> DeclarationRef) -> (Exports -> M.Map a ExportSource) -> [DeclarationRef]
   go toRef select =
-    flip map (M.toList (select exps)) $ \(export, mn') ->
-      if mn == mn' then toRef export else ReExportRef ss mn' (toRef export)
+    flip map (M.toList (select exps)) $ \(export, src) ->
+      if mn == exportSourceDefinedIn src then toRef export else ReExportRef ss src (toRef export)
 
 -- |
 -- Given a list of declarations, an original exports list, and an elaborated
@@ -193,20 +201,20 @@
     :: [Ident]
     -> Declaration
     -> m ([Ident], Declaration)
-  updateDecl bound (DataDeclaration sa@(ss, _) dtype name args dctors) =
+  updateDecl bound (DataDeclaration sa dtype name args dctors) =
     fmap (bound,) $
       DataDeclaration sa dtype name
-        <$> updateTypeArguments ss args
-        <*> traverse (sndM (traverse (updateTypesEverywhere ss))) dctors
-  updateDecl bound (TypeSynonymDeclaration sa@(ss, _) name ps ty) =
+        <$> updateTypeArguments args
+        <*> traverse (sndM (traverse updateTypesEverywhere)) dctors
+  updateDecl bound (TypeSynonymDeclaration sa name ps ty) =
     fmap (bound,) $
       TypeSynonymDeclaration sa name
-        <$> updateTypeArguments ss ps
-        <*> updateTypesEverywhere ss ty
+        <$> updateTypeArguments ps
+        <*> updateTypesEverywhere ty
   updateDecl bound (TypeClassDeclaration sa@(ss, _) className args implies deps ds) =
     fmap (bound,) $
       TypeClassDeclaration sa className
-        <$> updateTypeArguments ss args
+        <$> updateTypeArguments args
         <*> updateConstraints ss implies
         <*> pure deps
         <*> pure ds
@@ -215,20 +223,20 @@
       TypeInstanceDeclaration sa ch idx name
         <$> updateConstraints ss cs
         <*> updateClassName cn ss
-        <*> traverse (updateTypesEverywhere ss) ts
+        <*> traverse updateTypesEverywhere ts
         <*> pure ds
-  updateDecl bound (TypeDeclaration (TypeDeclarationData sa@(ss, _) name ty)) =
+  updateDecl bound (TypeDeclaration (TypeDeclarationData sa name ty)) =
     fmap (bound,) $
       TypeDeclaration . TypeDeclarationData sa name
-        <$> updateTypesEverywhere ss ty
-  updateDecl bound (ExternDeclaration sa@(ss, _) name ty) =
+        <$> updateTypesEverywhere ty
+  updateDecl bound (ExternDeclaration sa name ty) =
     fmap (name : bound,) $
       ExternDeclaration sa name
-        <$> updateTypesEverywhere ss ty
-  updateDecl bound (ExternDataDeclaration sa@(ss, _) name ki) =
+        <$> updateTypesEverywhere ty
+  updateDecl bound (ExternDataDeclaration sa name ki) =
     fmap (bound,) $
       ExternDataDeclaration sa name
-        <$> updateKindsEverywhere ss ki
+        <$> updateKindsEverywhere ki
   updateDecl bound (TypeFixityDeclaration sa@(ss, _) fixity alias op) =
     fmap (bound,) $
       TypeFixityDeclaration sa fixity
@@ -268,8 +276,8 @@
     (,) (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 (TypedValue check val ty) =
+    (,) s <$> (TypedValue check val <$> updateTypesEverywhere ty)
   updateValue s v = return (s, v)
 
   updateBinder
@@ -282,8 +290,8 @@
     (,) (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
+  updateBinder s (TypedBinder t b) = do
+    t' <- updateTypesEverywhere t
     return (s, TypedBinder t' b)
   updateBinder s v =
     return (s, v)
@@ -306,37 +314,36 @@
   letBoundVariable :: Declaration -> Maybe Ident
   letBoundVariable = fmap valdeclIdent . getValueDeclaration
 
-  updateKindsEverywhere :: SourceSpan -> Kind a -> m (Kind a)
-  updateKindsEverywhere pos = everywhereOnKindsM updateKind
+  updateKindsEverywhere :: SourceKind -> m SourceKind
+  updateKindsEverywhere = everywhereOnKindsM updateKind
     where
-    updateKind :: Kind a -> m (Kind a)
-    updateKind (NamedKind ann name) = NamedKind ann <$> updateKindName name pos
+    updateKind :: SourceKind -> m SourceKind
+    updateKind (NamedKind ann@(ss, _) name) = NamedKind ann <$> updateKindName name ss
     updateKind k = return k
 
   updateTypeArguments
     :: (Traversable f, Traversable g)
-    => SourceSpan
-    -> f (a, g (Kind ann)) -> m (f (a, g (Kind ann)))
-  updateTypeArguments pos = traverse (sndM (traverse (updateKindsEverywhere pos)))
+    => f (a, g SourceKind) -> m (f (a, g SourceKind))
+  updateTypeArguments = traverse (sndM (traverse updateKindsEverywhere))
 
-  updateTypesEverywhere :: SourceSpan -> Type a -> m (Type a)
-  updateTypesEverywhere pos = everywhereOnTypesM updateType
+  updateTypesEverywhere :: SourceType -> m SourceType
+  updateTypesEverywhere = everywhereOnTypesM updateType
     where
-    updateType :: Type a -> m (Type a)
-    updateType (TypeOp ann name) = TypeOp ann <$> updateTypeOpName name pos
-    updateType (TypeConstructor ann name) = TypeConstructor ann <$> updateTypeName name pos
+    updateType :: SourceType -> m SourceType
+    updateType (TypeOp ann@(ss, _) name) = TypeOp ann <$> updateTypeOpName name ss
+    updateType (TypeConstructor ann@(ss, _) name) = TypeConstructor ann <$> updateTypeName name ss
     updateType (ConstrainedType ann c t) = ConstrainedType ann <$> updateInConstraint c <*> pure t
-    updateType (KindedType ann t k) = KindedType ann t <$> updateKindsEverywhere pos k
+    updateType (KindedType ann t k) = KindedType ann t <$> updateKindsEverywhere k
     updateType t = return t
-    updateInConstraint :: Constraint a -> m (Constraint a)
-    updateInConstraint (Constraint ann name ts info) =
-      Constraint ann <$> updateClassName name pos <*> pure ts <*> pure info
+    updateInConstraint :: SourceConstraint -> m SourceConstraint
+    updateInConstraint (Constraint ann@(ss, _) name ts info) =
+      Constraint ann <$> updateClassName name ss <*> pure ts <*> pure info
 
-  updateConstraints :: SourceSpan -> [Constraint a] -> m [Constraint a]
+  updateConstraints :: SourceSpan -> [SourceConstraint] -> m [SourceConstraint]
   updateConstraints pos = traverse $ \(Constraint ann name ts info) ->
     Constraint ann
       <$> updateClassName name pos
-      <*> traverse (updateTypesEverywhere pos) ts
+      <*> traverse updateTypesEverywhere ts
       <*> pure info
 
   updateTypeName
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
@@ -126,29 +126,29 @@
   -- |
   -- The exported types along with the module they originally came from.
   --
-    exportedTypes :: M.Map (ProperName 'TypeName) ([ProperName 'ConstructorName], ModuleName)
+    exportedTypes :: M.Map (ProperName 'TypeName) ([ProperName 'ConstructorName], ExportSource)
   -- |
   -- The exported type operators along with the module they originally came
   -- from.
   --
-  , exportedTypeOps :: M.Map (OpName 'TypeOpName) ModuleName
+  , exportedTypeOps :: M.Map (OpName 'TypeOpName) ExportSource
   -- |
   -- The exported classes along with the module they originally came from.
   --
-  , exportedTypeClasses :: M.Map (ProperName 'ClassName) ModuleName
+  , exportedTypeClasses :: M.Map (ProperName 'ClassName) ExportSource
   -- |
   -- The exported values along with the module they originally came from.
   --
-  , exportedValues :: M.Map Ident ModuleName
+  , exportedValues :: M.Map Ident ExportSource
   -- |
   -- The exported value operators along with the module they originally came
   -- from.
   --
-  , exportedValueOps :: M.Map (OpName 'ValueOpName) ModuleName
+  , exportedValueOps :: M.Map (OpName 'ValueOpName) ExportSource
   -- |
   -- The exported kinds along with the module they originally came from.
   --
-  , exportedKinds :: M.Map (ProperName 'KindName) ModuleName
+  , exportedKinds :: M.Map (ProperName 'KindName) ExportSource
   } deriving (Show)
 
 -- |
@@ -239,10 +239,16 @@
     , 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)
+  mkTypeEntry (Qualified mn name) = (name, ([], primExportSource mn))
+  mkClassEntry (Qualified mn name) = (name, primExportSource mn)
+  mkKindEntry (Qualified mn name) = (name, primExportSource mn)
 
+  primExportSource mn =
+    ExportSource
+      { exportSourceImportedFrom = Nothing
+      , exportSourceDefinedIn = fromJust mn
+      }
+
 -- | Environment which only contains the Prim modules.
 primEnv :: Env
 primEnv = M.fromList
@@ -289,9 +295,9 @@
   -> Exports
   -> ProperName 'TypeName
   -> [ProperName 'ConstructorName]
-  -> ModuleName
+  -> ExportSource
   -> m Exports
-exportType ss exportMode exps name dctors mn = do
+exportType ss exportMode exps name dctors src = do
   let exTypes = exportedTypes exps
       exClasses = exportedTypeClasses exps
       dctorNameCounts :: [(ProperName 'ConstructorName, Int)]
@@ -311,17 +317,20 @@
         when (coerceProperName dctor `M.member` exClasses) $
           throwDeclConflict (DctorName dctor) (TyClassName (coerceProperName dctor))
     ReExport -> do
-      forM_ (name `M.lookup` exTypes) $ \(_, mn') ->
+      let mn = exportSourceDefinedIn src
+      forM_ (name `M.lookup` exTypes) $ \(_, src') ->
+        let mn' = exportSourceDefinedIn src' in
         when (mn /= mn') $
           throwExportConflict ss mn mn' (TyName name)
       forM_ dctors $ \dctor ->
-        forM_ ((elem dctor . fst) `find` exTypes) $ \(_, mn') ->
+        forM_ ((elem dctor . fst) `find` exTypes) $ \(_, src') ->
+          let mn' = exportSourceDefinedIn src' in
           when (mn /= mn') $
             throwExportConflict ss mn mn' (DctorName dctor)
   return $ exps { exportedTypes = M.alter updateOrInsert name exTypes }
   where
-  updateOrInsert Nothing = Just (dctors, mn)
-  updateOrInsert (Just (dctors', _)) = Just (dctors ++ dctors', mn)
+  updateOrInsert Nothing = Just (dctors, src)
+  updateOrInsert (Just (dctors', _)) = Just (dctors ++ dctors', src)
 
 -- |
 -- Safely adds a type operator to some exports, returning an error if a
@@ -332,10 +341,10 @@
   => SourceSpan
   -> Exports
   -> OpName 'TypeOpName
-  -> ModuleName
+  -> ExportSource
   -> m Exports
-exportTypeOp ss exps op mn = do
-  typeOps <- addExport ss TyOpName op mn (exportedTypeOps exps)
+exportTypeOp ss exps op src = do
+  typeOps <- addExport ss TyOpName op src (exportedTypeOps exps)
   return $ exps { exportedTypeOps = typeOps }
 
 -- |
@@ -347,16 +356,16 @@
   -> ExportMode
   -> Exports
   -> ProperName 'ClassName
-  -> ModuleName
+  -> ExportSource
   -> m Exports
-exportTypeClass ss exportMode exps name mn = do
+exportTypeClass ss exportMode exps name src = 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 ss TyClassName name mn (exportedTypeClasses exps)
+  classes <- addExport ss TyClassName name src (exportedTypeClasses exps)
   return $ exps { exportedTypeClasses = classes }
 
 -- |
@@ -367,10 +376,10 @@
   => SourceSpan
   -> Exports
   -> Ident
-  -> ModuleName
+  -> ExportSource
   -> m Exports
-exportValue ss exps name mn = do
-  values <- addExport ss IdentName name mn (exportedValues exps)
+exportValue ss exps name src = do
+  values <- addExport ss IdentName name src (exportedValues exps)
   return $ exps { exportedValues = values }
 
 -- |
@@ -382,10 +391,10 @@
   => SourceSpan
   -> Exports
   -> OpName 'ValueOpName
-  -> ModuleName
+  -> ExportSource
   -> m Exports
-exportValueOp ss exps op mn = do
-  valueOps <- addExport ss ValOpName op mn (exportedValueOps exps)
+exportValueOp ss exps op src = do
+  valueOps <- addExport ss ValOpName op src (exportedValueOps exps)
   return $ exps { exportedValueOps = valueOps }
 
 -- |
@@ -396,10 +405,10 @@
   => SourceSpan
   -> Exports
   -> ProperName 'KindName
-  -> ModuleName
+  -> ExportSource
   -> m Exports
-exportKind ss exps name mn = do
-  kinds <- addExport ss KiName name mn (exportedKinds exps)
+exportKind ss exps name src = do
+  kinds <- addExport ss KiName name src (exportedKinds exps)
   return $ exps { exportedKinds = kinds }
 
 -- |
@@ -411,16 +420,21 @@
   => SourceSpan
   -> (a -> Name)
   -> a
-  -> ModuleName
-  -> M.Map a ModuleName
-  -> m (M.Map a ModuleName)
-addExport ss toName name mn exports =
+  -> ExportSource
+  -> M.Map a ExportSource
+  -> m (M.Map a ExportSource)
+addExport ss toName name src exports =
   case M.lookup name exports of
-    Just mn'
-      | mn == mn' -> return exports
-      | otherwise -> throwExportConflict ss mn mn' (toName name)
+    Just src' ->
+      let
+        mn = exportSourceDefinedIn src
+        mn' = exportSourceDefinedIn src'
+      in
+        if mn == mn'
+          then return exports
+          else throwExportConflict ss mn mn' (toName name)
     Nothing ->
-      return $ M.insert name mn exports
+      return $ M.insert name src exports
 
 -- |
 -- Raises an error for when there is more than one definition for something.
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
@@ -32,29 +32,35 @@
   updateExports' :: Exports -> Declaration -> m Exports
   updateExports' exps decl = rethrowWithPosition (declSourceSpan decl) $ updateExports exps decl
 
+  source =
+    ExportSource
+    { exportSourceDefinedIn = mn
+    , exportSourceImportedFrom = Nothing
+    }
+
   updateExports :: Exports -> Declaration -> m Exports
   updateExports exps (TypeClassDeclaration (ss, _) tcn _ _ _ ds') = do
-    exps' <- rethrowWithPosition ss $ exportTypeClass ss Internal exps tcn mn
+    exps' <- rethrowWithPosition ss $ exportTypeClass ss Internal exps tcn source
     foldM go exps' ds'
     where
-    go exps'' (TypeDeclaration (TypeDeclarationData (ss', _) name _)) = exportValue ss' exps'' name mn
+    go exps'' (TypeDeclaration (TypeDeclarationData (ss', _) name _)) = exportValue ss' exps'' name source
     go _ _ = internalError "Invalid declaration in TypeClassDeclaration"
   updateExports exps (DataDeclaration (ss, _) _ tn _ dcs) =
-    exportType ss Internal exps tn (map fst dcs) mn
+    exportType ss Internal exps tn (map fst dcs) source
   updateExports exps (TypeSynonymDeclaration (ss, _) tn _ _) =
-    exportType ss Internal exps tn [] mn
+    exportType ss Internal exps tn [] source
   updateExports exps (ExternDataDeclaration (ss, _) tn _) =
-    exportType ss Internal exps tn [] mn
+    exportType ss Internal exps tn [] source
   updateExports exps (ValueDeclaration vd) =
-    exportValue (fst (valdeclSourceAnn vd)) exps (valdeclIdent vd) mn
+    exportValue (fst (valdeclSourceAnn vd)) exps (valdeclIdent vd) source
   updateExports exps (ValueFixityDeclaration (ss, _) _ _ op) =
-    exportValueOp ss exps op mn
+    exportValueOp ss exps op source
   updateExports exps (TypeFixityDeclaration (ss, _) _ _ op) =
-    exportTypeOp ss exps op mn
+    exportTypeOp ss exps op source
   updateExports exps (ExternDeclaration (ss, _) name _) =
-    exportValue ss exps name mn
+    exportValue ss exps name source
   updateExports exps (ExternKindDeclaration (ss, _) pn) =
-    exportKind ss exps pn mn
+    exportKind ss exps pn source
   updateExports exps _ = return exps
 
 -- |
@@ -110,7 +116,7 @@
     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)
+    foldM (\exps' ((tctor, dctors), src) -> exportType ss' ReExport exps' tctor dctors src) 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)
@@ -164,77 +170,69 @@
   resolveTypeExports
     :: [Qualified (ProperName 'TypeName)]
     -> [Qualified (ProperName 'ConstructorName)]
-    -> [((ProperName 'TypeName, [ProperName 'ConstructorName]), ModuleName)]
+    -> [((ProperName 'TypeName, [ProperName 'ConstructorName]), ExportSource)]
   resolveTypeExports tctors dctors = map go tctors
     where
     go
       :: Qualified (ProperName 'TypeName)
-      -> ((ProperName 'TypeName, [ProperName 'ConstructorName]), ModuleName)
+      -> ((ProperName 'TypeName, [ProperName 'ConstructorName]), ExportSource)
     go (Qualified (Just mn'') name) =
       fromMaybe (internalError "Missing value in resolveTypeExports") $ do
         exps' <- envModuleExports <$> mn'' `M.lookup` env
-        (dctors', mnOrig) <- name `M.lookup` exportedTypes exps'
+        (dctors', src) <- name `M.lookup` exportedTypes exps'
         let relevantDctors = mapMaybe (disqualifyFor (Just mn'')) dctors
-        return ((name, relevantDctors `intersect` dctors'), mnOrig)
+        return
+          ( (name, relevantDctors `intersect` dctors')
+          , src { exportSourceImportedFrom = Just mn'' }
+          )
     go (Qualified Nothing _) = internalError "Unqualified value in resolveTypeExports"
 
   -- Looks up an imported type operator and re-qualifies it with the original
   -- module it came from.
-  resolveTypeOp :: Qualified (OpName 'TypeOpName) -> (OpName 'TypeOpName, ModuleName)
+  resolveTypeOp :: Qualified (OpName 'TypeOpName) -> (OpName 'TypeOpName, ExportSource)
   resolveTypeOp op
-    = splitQual
-    . fromMaybe (internalError "Missing value in resolveValue")
+    = fromMaybe (internalError "Missing value in resolveValue")
     $ resolve exportedTypeOps op
 
   -- Looks up an imported class and re-qualifies it with the original module it
   -- came from.
-  resolveClass :: Qualified (ProperName 'ClassName) -> (ProperName 'ClassName, ModuleName)
+  resolveClass :: Qualified (ProperName 'ClassName) -> (ProperName 'ClassName, ExportSource)
   resolveClass className
-    = splitQual
-    . fromMaybe (internalError "Missing value in resolveClass")
+    = fromMaybe (internalError "Missing value in resolveClass")
     $ resolve exportedTypeClasses className
 
   -- Looks up an imported value and re-qualifies it with the original module it
   -- came from.
-  resolveValue :: Qualified Ident -> (Ident, ModuleName)
+  resolveValue :: Qualified Ident -> (Ident, ExportSource)
   resolveValue ident
-    = splitQual
-    . fromMaybe (internalError "Missing value in resolveValue")
+    = fromMaybe (internalError "Missing value in resolveValue")
     $ resolve exportedValues ident
 
   -- Looks up an imported operator and re-qualifies it with the original
   -- module it came from.
-  resolveValueOp :: Qualified (OpName 'ValueOpName) -> (OpName 'ValueOpName, ModuleName)
+  resolveValueOp :: Qualified (OpName 'ValueOpName) -> (OpName 'ValueOpName, ExportSource)
   resolveValueOp op
-    = splitQual
-    . fromMaybe (internalError "Missing value in resolveValueOp")
+    = fromMaybe (internalError "Missing value in resolveValueOp")
     $ resolve exportedValueOps op
 
   -- Looks up an imported kind and re-qualifies it with the original
   -- module it came from.
-  resolveKind :: Qualified (ProperName 'KindName) -> (ProperName 'KindName, ModuleName)
+  resolveKind :: Qualified (ProperName 'KindName) -> (ProperName 'KindName, ExportSource)
   resolveKind kind
-    = splitQual
-    . fromMaybe (internalError "Missing value in resolveKind")
+    = fromMaybe (internalError "Missing value in resolveKind")
     $ resolve exportedKinds kind
 
   resolve
     :: Ord a
-    => (Exports -> M.Map a ModuleName)
+    => (Exports -> M.Map a ExportSource)
     -> Qualified a
-    -> Maybe (Qualified a)
+    -> Maybe (a, ExportSource)
   resolve f (Qualified (Just mn'') a) = do
     exps' <- envModuleExports <$> mn'' `M.lookup` env
-    mn''' <- a `M.lookup` f exps'
-    return $ Qualified (Just mn''') a
+    src <- a `M.lookup` f exps'
+    return $ (a, src { exportSourceImportedFrom = Just mn'' })
   resolve _ _ = internalError "Unqualified value in resolve"
 
-  -- A partial function that takes a qualified value and extracts the value and
-  -- qualified module components.
-  splitQual :: Qualified a -> (a, ModuleName)
-  splitQual (Qualified (Just mn'') a) = (a, mn'')
-  splitQual _ = internalError "Unqualified value in splitQual"
-
 -- |
 -- Filters the full list of exportable values, types, and classes for a module
 -- based on a list of export declaration references.
@@ -277,16 +275,16 @@
     . mapMaybe (\ref -> (declRefSourceSpan ref,) <$> getTypeRef ref)
 
   filterTypes
-    :: M.Map (ProperName 'TypeName) ([ProperName 'ConstructorName], ModuleName)
+    :: M.Map (ProperName 'TypeName) ([ProperName 'ConstructorName], ExportSource)
     -> DeclarationRef
-    -> m (M.Map (ProperName 'TypeName) ([ProperName 'ConstructorName], ModuleName))
+    -> m (M.Map (ProperName 'TypeName) ([ProperName 'ConstructorName], ExportSource))
   filterTypes result (TypeRef ss name expDcons) =
     case name `M.lookup` exportedTypes exps of
       Nothing -> throwError . errorMessage' ss . UnknownExport $ TyName name
-      Just (dcons, _) -> do
+      Just (dcons, src) -> do
         let expDcons' = fromMaybe dcons expDcons
         traverse_ (checkDcon name dcons) expDcons'
-        return $ M.insert name (expDcons', mn) result
+        return $ M.insert name (expDcons', src) result
     where
     -- Ensures a data constructor is exportable for a given type. Takes a type
     -- name, a list of exportable data constructors for the type, and the name of
@@ -305,14 +303,17 @@
     :: Ord a
     => (a -> Name)
     -> (DeclarationRef -> Maybe a)
-    -> (Exports -> M.Map a ModuleName)
-    -> M.Map a ModuleName
+    -> (Exports -> M.Map a ExportSource)
+    -> M.Map a ExportSource
     -> DeclarationRef
-    -> m (M.Map a ModuleName)
+    -> m (M.Map a ExportSource)
   filterExport toName get fromExps result ref
     | Just name <- get ref =
         case name `M.lookup` fromExps exps of
-          -- TODO: I'm not sure if we actually need to check mn == mn' here -gb
-          Just mn' | mn == mn' -> return $ M.insert name mn result
-          _ -> throwError . errorMessage' (declRefSourceSpan ref) . UnknownExport $ toName name
+          -- TODO: I'm not sure if we actually need to check that these modules
+          -- are the same here -gb
+          Just source' | mn == exportSourceDefinedIn source' ->
+            return $ M.insert name source' result
+          _ ->
+            throwError . errorMessage' (declRefSourceSpan ref) . UnknownExport $ toName name
   filterExport _ _ _ result _ = return result
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
@@ -188,9 +188,9 @@
     return $ imp { importedValueOps = valueOps' }
   importRef prov imp (TypeRef ss name dctors) = do
     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
+    let (dctorNames, src) = allExportedDataConstructors name
+        dctorLookup :: M.Map (ProperName 'ConstructorName) ExportSource
+        dctorLookup = M.fromList $ map (, src) dctorNames
     traverse_ (traverse_ $ checkDctorExists ss name 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' }
@@ -210,7 +210,7 @@
   -- Find all exported data constructors for a given type
   allExportedDataConstructors
     :: ProperName 'TypeName
-    -> ([ProperName 'ConstructorName], ModuleName)
+    -> ([ProperName 'ConstructorName], ExportSource)
   allExportedDataConstructors name =
     fromMaybe (internalError "Invalid state in allExportedDataConstructors")
       $ name `M.lookup` exportedTypes exps
@@ -220,15 +220,15 @@
     :: Ord a
     => M.Map (Qualified a) [ImportRecord a]
     -> M.Map a b
-    -> (b -> ModuleName)
+    -> (b -> ExportSource)
     -> a
     -> SourceSpan
     -> ImportProvenance
     -> M.Map (Qualified a) [ImportRecord a]
   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 ss prov
+      src = maybe (internalError "Invalid state in updateImports") expName (name `M.lookup` exps')
+      rec = ImportRecord (Qualified (Just importModule) name) (exportSourceDefinedIn src) ss prov
     in
       M.alter
         (\currNames -> Just $ rec : fromMaybe [] currNames)
diff --git a/tests/TestDocs.hs b/tests/TestDocs.hs
--- a/tests/TestDocs.hs
+++ b/tests/TestDocs.hs
@@ -643,6 +643,11 @@
   , ("DeclOrderNoExportList",
       shouldBeOrdered (n "DeclOrderNoExportList")
         [ "x1", "x3", "X2", "X4", "A", "B" ])
+
+  , ("Ado",
+      [ ValueShouldHaveTypeSignature (n "Ado") "test" (renderedType "Int")
+      ]
+    )
   ]
 
   where
diff --git a/tests/purs/docs/output/ConstrainedArgument/externs.json b/tests/purs/docs/output/ConstrainedArgument/externs.json
deleted file mode 100644
--- a/tests/purs/docs/output/ConstrainedArgument/externs.json
+++ /dev/null
@@ -1,1 +0,0 @@
-{"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
deleted file mode 100644
--- a/tests/purs/docs/output/ConstrainedArgument/index.js
+++ /dev/null
@@ -1,5 +0,0 @@
-"use strict";
-var Foo = {};
-module.exports = {
-    Foo: Foo
-};
diff --git a/tests/purs/docs/src/Ado.purs b/tests/purs/docs/src/Ado.purs
new file mode 100644
--- /dev/null
+++ b/tests/purs/docs/src/Ado.purs
@@ -0,0 +1,9 @@
+-- See https://github.com/purescript/purescript/issues/3414 
+module Ado where
+  
+test = 
+  ado x <- 1
+   in x
+
+  where
+  map f x = f x
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,110 @@
+{
+  "requires": true,
+  "lockfileVersion": 1,
+  "dependencies": {
+    "balanced-match": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
+    },
+    "bower": {
+      "version": "1.8.4",
+      "resolved": "http://registry.npmjs.org/bower/-/bower-1.8.4.tgz",
+      "integrity": "sha1-54dqB23rgTf30GUl3F6MZtuC8oo="
+    },
+    "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="
+    },
+    "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.4",
+        "inherits": "2",
+        "minimatch": "2 || 3",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      }
+    },
+    "inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+      "requires": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "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.7"
+      }
+    },
+    "once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+      "requires": {
+        "wrappy": "1"
+      }
+    },
+    "path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
+    },
+    "rimraf": {
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
+      "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
+      "requires": {
+        "glob": "^7.0.5"
+      },
+      "dependencies": {
+        "glob": {
+          "version": "7.1.3",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
+          "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
+          "requires": {
+            "fs.realpath": "^1.0.0",
+            "inflight": "^1.0.4",
+            "inherits": "2",
+            "minimatch": "^3.0.4",
+            "once": "^1.3.0",
+            "path-is-absolute": "^1.0.0"
+          }
+        }
+      }
+    },
+    "wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+    }
+  }
+}
