git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
Require dependencies to exist during sorting phase (#2570)

* Fix #1921, require dependencies to exist during sorting phase * Fix test * Fix tests * Use ordNub

commit94710ed1972fa9b53e8bb978095d81d831dde7c3 authorPhil Freeman <paf31@cantab.net> dateFri 20 Jan 2017, 09:40 (10 years ago) parentae3aa4d
6 files changed+188−249
examples/failing/ImportModule.purs+1−1 src/Language/PureScript/AST/Declarations.hs+2−1 src/Language/PureScript/Errors.hs+63−82 src/Language/PureScript/Make.hs+80−87 src/Language/PureScript/ModuleDependencies.hs+41−77 tests/Language/PureScript/Ide/Integration.hs+1−1
examples/failing/ImportModule.purs+1−1
@@ -1,4 +1,4 @@
1−-- @shouldFailWith UnknownName
1+-- @shouldFailWith ModuleNotFound
22module Main where
33
44import M1
src/Language/PureScript/AST/Declarations.hs+2−1
@@ -44,7 +44,8 @@ data TypeSearch
4444
4545-- | A type of error messages
4646data SimpleErrorMessage
47− = ErrorParsingFFIModule FilePath (Maybe Bundle.ErrorMessage)
47+ = ModuleNotFound ModuleName
48+ | ErrorParsingFFIModule FilePath (Maybe Bundle.ErrorMessage)
4849 | ErrorParsingModule P.ParseError
4950 | MissingFFIModule ModuleName
5051 | MultipleFFIModules ModuleName [FilePath]
src/Language/PureScript/Errors.hs+63−82
@@ -6,44 +6,40 @@ module Language.PureScript.Errors
66 , module Language.PureScript.Errors
77 ) where
88
9−import Prelude.Compat
10−
11−import Control.Arrow ((&&&))
12−import Control.Monad
13−import Control.Monad.Error.Class (MonadError(..))
14−import Control.Monad.Trans.State.Lazy
15−import Control.Monad.Writer
16−
17−import Data.Char (isSpace)
18−import Data.Either (lefts, rights)
19−import Data.Foldable (fold)
20−import Data.Functor.Identity (Identity(..))
21−import Data.List (transpose, nub, nubBy, sortBy, partition)
22−import Data.Maybe (maybeToList, fromMaybe, mapMaybe)
23−import Data.Ord (comparing)
9+import Prelude.Compat
10+
11+import Control.Arrow ((&&&))
12+import Control.Monad
13+import Control.Monad.Error.Class (MonadError(..))
14+import Control.Monad.Trans.State.Lazy
15+import Control.Monad.Writer
16+import Data.Char (isSpace)
17+import Data.Either (lefts, rights)
18+import Data.Foldable (fold)
19+import Data.Functor.Identity (Identity(..))
20+import Data.List (transpose, nub, nubBy, sortBy, partition)
21+import Data.Maybe (maybeToList, fromMaybe, mapMaybe)
22+import Data.Ord (comparing)
2423import qualified Data.Map as M
2524import qualified Data.Text as T
26−import Data.Text (Text)
27−
28−import Language.PureScript.AST
29−import Language.PureScript.Crash
30−import Language.PureScript.Environment
31−import Language.PureScript.Names
32−import Language.PureScript.Pretty
33−import Language.PureScript.Traversals
34−import Language.PureScript.Types
35−import Language.PureScript.Label (Label(..))
36−import Language.PureScript.Pretty.Common (before, endWith)
25+import Data.Text (Text)
26+import Language.PureScript.AST
3727import qualified Language.PureScript.Bundle as Bundle
3828import qualified Language.PureScript.Constants as C
39−
29+import Language.PureScript.Crash
30+import Language.PureScript.Environment
31+import Language.PureScript.Label (Label(..))
32+import Language.PureScript.Names
33+import Language.PureScript.Pretty
34+import Language.PureScript.Pretty.Common (before, endWith)
35+import Language.PureScript.Traversals
36+import Language.PureScript.Types
37+import qualified Language.PureScript.Publish.BoxesHelpers as BoxHelpers
4038import qualified System.Console.ANSI as ANSI
41−
4239import qualified Text.Parsec as P
4340import qualified Text.Parsec.Error as PE
41+import Text.Parsec.Error (Message(..))
4442import qualified Text.PrettyPrint.Boxes as Box
45−import qualified Language.PureScript.Publish.BoxesHelpers as BoxHelpers
46−import Text.Parsec.Error (Message(..))
4743
4844newtype ErrorSuggestion = ErrorSuggestion Text
4945
@@ -72,11 +68,10 @@ stripModuleAndSpan (ErrorMessage hints e) = ErrorMessage (filter (not . shouldSt
7268 shouldStrip (PositionedError _) = True
7369 shouldStrip _ = False
7470
75−-- |
76−-- Get the error code for a particular error type
77−--
71+-- | Get the error code for a particular error type
7872errorCode :: ErrorMessage -> Text
7973errorCode em = case unwrapErrorMessage em of
74+ ModuleNotFound{} -> "ModuleNotFound"
8075 ErrorParsingFFIModule{} -> "ErrorParsingFFIModule"
8176 ErrorParsingModule{} -> "ErrorParsingModule"
8277 MissingFFIModule{} -> "MissingFFIModule"
@@ -175,25 +170,20 @@ errorCode em = case unwrapErrorMessage em of
175170 ClassInstanceArityMismatch{} -> "ClassInstanceArityMismatch"
176171 UserDefinedWarning{} -> "UserDefinedWarning"
177172
178−-- |
179−-- A stack trace for an error
180−--
173+-- | A stack trace for an error
181174newtype MultipleErrors = MultipleErrors
182− { runMultipleErrors :: [ErrorMessage] } deriving (Show, Monoid)
175+ { runMultipleErrors :: [ErrorMessage]
176+ } deriving (Show, Monoid)
183177
184178-- | Check whether a collection of errors is empty or not.
185179nonEmpty :: MultipleErrors -> Bool
186180nonEmpty = not . null . runMultipleErrors
187181
188−-- |
189−-- Create an error set from a single simple error message
190−--
182+-- | Create an error set from a single simple error message
191183errorMessage :: SimpleErrorMessage -> MultipleErrors
192184errorMessage err = MultipleErrors [ErrorMessage [] err]
193185
194−-- |
195−-- Create an error set from a single error message
196−--
186+-- | Create an error set from a single error message
197187singleError :: ErrorMessage -> MultipleErrors
198188singleError = MultipleErrors . pure
199189
@@ -226,15 +216,12 @@ defaultUnknownMap = TypeMap M.empty M.empty 0
226216-- | How critical the issue is
227217data Level = Error | Warning deriving Show
228218
229−-- |
230−-- Extract nested error messages from wrapper errors
231−--
219+-- | Extract nested error messages from wrapper errors
232220unwrapErrorMessage :: ErrorMessage -> SimpleErrorMessage
233221unwrapErrorMessage (ErrorMessage _ se) = se
234222
235223replaceUnknowns :: Type -> State TypeMap Type
236−replaceUnknowns = everywhereOnTypesM replaceTypes
237− where
224+replaceUnknowns = everywhereOnTypesM replaceTypes where
238225 replaceTypes :: Type -> State TypeMap Type
239226 replaceTypes (TUnknown u) = do
240227 m <- get
@@ -387,10 +374,7 @@ defaultPPEOptions = PPEOptions
387374 , ppeShowDocs = True
388375 }
389376
390−
391−-- |
392−-- Pretty print a single error, simplifying if necessary
393−--
377+-- | Pretty print a single error, simplifying if necessary
394378prettyPrintSingleError :: PPEOptions -> ErrorMessage -> Box.Box
395379prettyPrintSingleError (PPEOptions codeColor full level showDocs) e = flip evalState defaultUnknownMap $ do
396380 em <- onTypesInErrorMessageM replaceUnknowns (if full then e else simplifyErrorMessage e)
@@ -431,6 +415,10 @@ prettyPrintSingleError (PPEOptions codeColor full level showDocs) e = flip evalS
431415 unknownInfo u = line $ markCode ("t" <> T.pack (show u)) <> " is an unknown type"
432416
433417 renderSimpleErrorMessage :: SimpleErrorMessage -> Box.Box
418+ renderSimpleErrorMessage (ModuleNotFound mn) =
419+ paras [ line $ "Module " <> markCode (runModuleName mn) <> " was not found."
420+ , line "Make sure the source file exists, and that it has been provided as an input to psc."
421+ ]
434422 renderSimpleErrorMessage (CannotGetFileInfo path) =
435423 paras [ line "Unable to read file info: "
436424 , indent . lineS $ path
@@ -1176,15 +1164,11 @@ prettyPrintRef (ReExportRef _ _) =
11761164prettyPrintRef (PositionedDeclarationRef _ _ ref) =
11771165 prettyPrintRef ref
11781166
1179−-- |
1180−-- Pretty print multiple errors
1181−--
1167+-- | Pretty print multiple errors
11821168prettyPrintMultipleErrors :: PPEOptions -> MultipleErrors -> String
11831169prettyPrintMultipleErrors ppeOptions = unlines . map renderBox . prettyPrintMultipleErrorsBox ppeOptions
11841170
1185−-- |
1186−-- Pretty print multiple warnings
1187−--
1171+-- | Pretty print multiple warnings
11881172prettyPrintMultipleWarnings :: PPEOptions -> MultipleErrors -> String
11891173prettyPrintMultipleWarnings ppeOptions = unlines . map renderBox . prettyPrintMultipleWarningsBox ppeOptions
11901174
@@ -1215,11 +1199,10 @@ prettyPrintMultipleErrorsWith ppeOptions _ intro (MultipleErrors es) =
12151199prettyPrintParseError :: P.ParseError -> Box.Box
12161200prettyPrintParseError = prettyPrintParseErrorMessages "or" "unknown parse error" "expecting" "unexpected" "end of input" . PE.errorMessages
12171201
1218−-- |
1219−-- Pretty print ParseError detail messages.
1220−--
1221−-- Adapted from 'Text.Parsec.Error.showErrorMessages', see <https://github.com/aslatter/parsec/blob/v3.1.9/Text/Parsec/Error.hs#L173>.
1202+-- | Pretty print 'ParseError' detail messages.
12221203--
1204+-- Adapted from 'Text.Parsec.Error.showErrorMessages'.
1205+-- See <https://github.com/aslatter/parsec/blob/v3.1.9/Text/Parsec/Error.hs#L173>.
12231206prettyPrintParseErrorMessages :: String -> String -> String -> String -> String -> [Message] -> Box.Box
12241207prettyPrintParseErrorMessages msgOr msgUnknown msgExpecting msgUnExpected msgEndOfInput msgs
12251208 | null msgs = Box.text msgUnknown
@@ -1288,9 +1271,7 @@ toTypelevelString (TypeApp (TypeApp (TypeConstructor f) x) ret)
12881271 | f == primName "TypeConcat" = before <$> (toTypelevelString x) <*> (toTypelevelString ret)
12891272toTypelevelString _ = Nothing
12901273
1291−-- |
1292−-- Rethrow an error with a more detailed error message in the case of failure
1293−--
1274+-- | Rethrow an error with a more detailed error message in the case of failure
12941275rethrow :: (MonadError e m) => (e -> e) -> m a -> m a
12951276rethrow f = flip catchError $ \e -> throwError (f e)
12961277
@@ -1303,9 +1284,7 @@ reflectErrors ma = ma >>= either throwError return
13031284warnAndRethrow :: (MonadError e m, MonadWriter e m) => (e -> e) -> m a -> m a
13041285warnAndRethrow f = rethrow f . censor f
13051286
1306−-- |
1307−-- Rethrow an error with source position information
1308−--
1287+-- | Rethrow an error with source position information
13091288rethrowWithPosition :: (MonadError MultipleErrors m) => SourceSpan -> m a -> m a
13101289rethrowWithPosition pos = rethrow (onErrorMessages (withPosition pos))
13111290
@@ -1318,10 +1297,8 @@ warnAndRethrowWithPosition pos = rethrowWithPosition pos . warnWithPosition pos
13181297withPosition :: SourceSpan -> ErrorMessage -> ErrorMessage
13191298withPosition pos (ErrorMessage hints se) = ErrorMessage (PositionedError pos : hints) se
13201299
1321−-- |
1322−-- Runs a computation listening for warnings and then escalating any warnings
1300+-- | Runs a computation listening for warnings and then escalating any warnings
13231301-- that match the predicate to error status.
1324−--
13251302escalateWarningWhen
13261303 :: (MonadWriter MultipleErrors m, MonadError MultipleErrors m)
13271304 => (ErrorMessage -> Bool)
@@ -1334,16 +1311,20 @@ escalateWarningWhen isError ma = do
13341311 unless (null errors) $ throwError $ MultipleErrors errors
13351312 return a
13361313
1337−-- |
1338−-- Collect errors in in parallel
1339−--
1340−parU :: (MonadError MultipleErrors m) => [a] -> (a -> m b) -> m [b]
1341−parU xs f = forM xs (withError . f) >>= collectErrors
1314+-- | Collect errors in in parallel
1315+parU
1316+ :: forall m a b
1317+ . MonadError MultipleErrors m
1318+ => [a]
1319+ -> (a -> m b)
1320+ -> m [b]
1321+parU xs f =
1322+ forM xs (withError . f) >>= collectErrors
13421323 where
1343− withError :: (MonadError MultipleErrors m) => m a -> m (Either MultipleErrors a)
1344− withError u = catchError (Right <$> u) (return . Left)
1324+ withError :: m b -> m (Either MultipleErrors b)
1325+ withError u = catchError (Right <$> u) (return . Left)
13451326
1346− collectErrors :: (MonadError MultipleErrors m) => [Either MultipleErrors a] -> m [a]
1347− collectErrors es = case lefts es of
1348− [] -> return $ rights es
1349− errs -> throwError $ fold errs
1327+ collectErrors :: [Either MultipleErrors b] -> m [b]
1328+ collectErrors es = case lefts es of
1329+ [] -> return $ rights es
1330+ errs -> throwError $ fold errs
src/Language/PureScript/Make.hs+80−87
@@ -20,53 +20,51 @@ module Language.PureScript.Make
2020 , inferForeignModules
2121 ) where
2222
23−import Prelude.Compat
24−
25−import Control.Concurrent.Lifted as C
26−import Control.Monad hiding (sequence)
27−import Control.Monad.Base (MonadBase(..))
28−import Control.Monad.Error.Class (MonadError(..))
29−import Control.Monad.IO.Class
30−import Control.Monad.Logger
31−import Control.Monad.Reader (MonadReader(..), ReaderT(..), asks)
32−import Control.Monad.Supply
33−import Control.Monad.Trans.Class (MonadTrans(..))
34−import Control.Monad.Trans.Control (MonadBaseControl(..))
35−import Control.Monad.Trans.Except
36−import Control.Monad.Writer.Class (MonadWriter(..))
37−
38−import Data.Aeson (encode, decode)
23+import Prelude.Compat
24+
25+import Control.Concurrent.Lifted as C
26+import Control.Monad hiding (sequence)
27+import Control.Monad.Base (MonadBase(..))
28+import Control.Monad.Error.Class (MonadError(..))
29+import Control.Monad.IO.Class
30+import Control.Monad.Logger
31+import Control.Monad.Reader (MonadReader(..), ReaderT(..), asks)
32+import Control.Monad.Supply
33+import Control.Monad.Trans.Class (MonadTrans(..))
34+import Control.Monad.Trans.Control (MonadBaseControl(..))
35+import Control.Monad.Trans.Except
36+import Control.Monad.Writer.Class (MonadWriter(..))
37+import Data.Aeson (encode, decode)
3938import qualified Data.Aeson as Aeson
40−import Data.Either (partitionEithers)
41−import Data.Function (on)
42−import Data.Foldable (for_)
43−import Data.List (foldl', sortBy, groupBy)
44−import Data.Maybe (fromMaybe, catMaybes)
45−import Data.Monoid ((<>))
46−import Data.Time.Clock
47−import Data.Traversable (for)
48−import Data.Version (showVersion)
39+import Data.Either (partitionEithers)
40+import Data.Function (on)
41+import Data.Foldable (for_)
42+import Data.List (foldl', sortBy, groupBy)
43+import Data.Maybe (fromMaybe, catMaybes)
44+import Data.Monoid ((<>))
45+import Data.Time.Clock
46+import Data.Traversable (for)
47+import Data.Version (showVersion)
4948import qualified Data.ByteString.Lazy as B
5049import qualified Data.ByteString.UTF8 as BU8
5150import qualified Data.Map as M
5251import qualified Data.Set as S
5352import qualified Data.Text as T
5453import qualified Data.Text.Encoding as TE
55−
56−import Language.PureScript.AST
57−import Language.PureScript.Crash
58−import Language.PureScript.Environment
59−import Language.PureScript.Errors
60−import Language.PureScript.Externs
61−import Language.PureScript.Linter
62−import Language.PureScript.ModuleDependencies
63−import Language.PureScript.Names
64−import Language.PureScript.Options
65−import Language.PureScript.Pretty
66−import Language.PureScript.Pretty.Common(SMap(..))
67−import Language.PureScript.Renamer
68−import Language.PureScript.Sugar
69−import Language.PureScript.TypeChecker
54+import Language.PureScript.AST
55+import Language.PureScript.Crash
56+import Language.PureScript.Environment
57+import Language.PureScript.Errors
58+import Language.PureScript.Externs
59+import Language.PureScript.Linter
60+import Language.PureScript.ModuleDependencies
61+import Language.PureScript.Names
62+import Language.PureScript.Options
63+import Language.PureScript.Pretty
64+import Language.PureScript.Pretty.Common(SMap(..))
65+import Language.PureScript.Renamer
66+import Language.PureScript.Sugar
67+import Language.PureScript.TypeChecker
7068import qualified Language.JavaScript.Parser as JS
7169import qualified Language.PureScript.Bundle as Bundle
7270import qualified Language.PureScript.CodeGen.JS as J
@@ -74,21 +72,18 @@ import qualified Language.PureScript.Constants as C
7472import qualified Language.PureScript.CoreFn as CF
7573import qualified Language.PureScript.CoreFn.ToJSON as CFJ
7674import qualified Language.PureScript.Parser as PSParser
77−
7875import qualified Paths_purescript as Paths
79−
80−import SourceMap
81−import SourceMap.Types
82−
83−import System.Directory (doesFileExist, getModificationTime, createDirectoryIfMissing, getCurrentDirectory)
84−import System.FilePath ((</>), takeDirectory, makeRelative, splitPath, normalise, replaceExtension)
85−import System.IO.Error (tryIOError)
86−
76+import SourceMap
77+import SourceMap.Types
78+import System.Directory (doesFileExist, getModificationTime, createDirectoryIfMissing, getCurrentDirectory)
79+import System.FilePath ((</>), takeDirectory, makeRelative, splitPath, normalise, replaceExtension)
80+import System.IO.Error (tryIOError)
8781import qualified Text.Parsec as Parsec
8882
8983-- | Progress messages from the make process
9084data ProgressMessage
9185 = CompilingModule ModuleName
86+ -- ^ Compilation started for the specified module
9287 deriving (Show, Eq, Ord)
9388
9489-- | Render a progress message
@@ -102,7 +97,6 @@ renderProgressMessage (CompilingModule mn) = "Compiling " ++ T.unpack (runModule
10297-- * The particular backend being used (Javascript, C++11, etc.)
10398--
10499-- * The details of how files are read/written etc.
105−--
106100data MakeActions m = MakeActions
107101 { getInputTimestamp :: ModuleName -> m (Either RebuildPolicy (Maybe UTCTime))
108102 -- ^ Get the timestamp for the input file(s) for a module. If there are multiple
@@ -121,26 +115,26 @@ data MakeActions m = MakeActions
121115 -- ^ Respond to a progress update.
122116 }
123117
124−-- |
125−-- Generated code for an externs file.
126−--
118+-- | Generated code for an externs file.
127119type Externs = B.ByteString
128120
129−-- |
130−-- Determines when to rebuild a module
131−--
121+-- | Determines when to rebuild a module
132122data RebuildPolicy
133123 -- | Never rebuild this module
134124 = RebuildNever
135125 -- | Always rebuild this module
136126 | RebuildAlways deriving (Show, Eq, Ord)
137127
138−-- | Rebuild a single module
139−rebuildModule :: forall m. (Monad m, MonadBaseControl IO m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
140− => MakeActions m
141− -> [ExternsFile]
142− -> Module
143− -> m ExternsFile
128+-- | Rebuild a single module.
129+--
130+-- This function is used for fast-rebuild workflows (PSCi and psc-ide are examples).
131+rebuildModule
132+ :: forall m
133+ . (Monad m, MonadBaseControl IO m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
134+ => MakeActions m
135+ -> [ExternsFile]
136+ -> Module
137+ -> m ExternsFile
144138rebuildModule MakeActions{..} externs m@(Module _ _ moduleName _ _) = do
145139 progress $ CompilingModule moduleName
146140 let env = foldl' (flip applyExternsFileToEnvironment) initEnvironment externs
@@ -157,12 +151,10 @@ rebuildModule MakeActions{..} externs m@(Module _ _ moduleName _ _) = do
157151 evalSupplyT nextVar . codegen renamed env' . encode $ exts
158152 return exts
159153
160−-- |
161−-- Compiles in "make" mode, compiling each module separately to a js files and an externs file
154+-- | Compiles in "make" mode, compiling each module separately to a @.js@ file and an @externs.json@ file.
162155--
163156-- If timestamps have not changed, the externs file can be used to provide the module's types without
164157-- having to typecheck the module again.
165−--
166158make :: forall m. (Monad m, MonadBaseControl IO m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
167159 => MakeActions m
168160 -> [Module]
@@ -244,7 +236,7 @@ make ma@MakeActions{..} ms = do
244236 putMVar (fst $ fromMaybe (internalError "make: no barrier") $ lookup moduleName barriers) externs
245237 putMVar (snd $ fromMaybe (internalError "make: no barrier") $ lookup moduleName barriers) errors
246238
247− maximumMaybe :: (Ord a) => [a] -> Maybe a
239+ maximumMaybe :: Ord a => [a] -> Maybe a
248240 maximumMaybe [] = Nothing
249241 maximumMaybe xs = Just $ maximum xs
250242
@@ -262,11 +254,10 @@ make ma@MakeActions{..} ms = do
262254importPrim :: Module -> Module
263255importPrim = addDefaultImport (ModuleName [ProperName C.prim])
264256
265−-- |
266−-- A monad for running make actions
267−--
268−newtype Make a = Make { unMake :: ReaderT Options (ExceptT MultipleErrors (Logger MultipleErrors)) a }
269− deriving (Functor, Applicative, Monad, MonadIO, MonadError MultipleErrors, MonadWriter MultipleErrors, MonadReader Options)
257+-- | A monad for running make actions
258+newtype Make a = Make
259+ { unMake :: ReaderT Options (ExceptT MultipleErrors (Logger MultipleErrors)) a
260+ } deriving (Functor, Applicative, Monad, MonadIO, MonadError MultipleErrors, MonadWriter MultipleErrors, MonadReader Options)
270261
271262instance MonadBase IO Make where
272263 liftBase = liftIO
@@ -276,12 +267,12 @@ instance MonadBaseControl IO Make where
276267 liftBaseWith f = Make $ liftBaseWith $ \q -> f (q . unMake)
277268 restoreM = Make . restoreM
278269
279−-- |
280−-- Execute a 'Make' monad, returning either errors, or the result of the compile plus any warnings.
281−--
270+-- | Execute a 'Make' monad, returning either errors, or the result of the compile plus any warnings.
282271runMake :: Options -> Make a -> IO (Either MultipleErrors a, MultipleErrors)
283272runMake opts = runLogger' . runExceptT . flip runReaderT opts . unMake
284273
274+-- | Run an 'IO' action in the 'Make' monad, by specifying how IO errors should
275+-- be rendered as 'ErrorMessage' values.
285276makeIO :: (IOError -> ErrorMessage) -> IO a -> Make a
286277makeIO f io = do
287278 e <- liftIO $ tryIOError io
@@ -299,7 +290,8 @@ inferForeignModules
299290 . MonadIO m
300291 => M.Map ModuleName (Either RebuildPolicy FilePath)
301292 -> m (M.Map ModuleName FilePath)
302−inferForeignModules = fmap (M.mapMaybe id) . traverse inferForeignModule
293+inferForeignModules =
294+ fmap (M.mapMaybe id) . traverse inferForeignModule
303295 where
304296 inferForeignModule :: Either RebuildPolicy FilePath -> m (Maybe FilePath)
305297 inferForeignModule (Left _) = return Nothing
@@ -310,16 +302,19 @@ inferForeignModules = fmap (M.mapMaybe id) . traverse inferForeignModule
310302 then return (Just jsFile)
311303 else return Nothing
312304
313−-- |
314−-- A set of make actions that read and write modules from the given directory.
315−--
316−buildMakeActions :: FilePath -- ^ the output directory
317− -> M.Map ModuleName (Either RebuildPolicy FilePath) -- ^ a map between module names and paths to the file containing the PureScript module
318− -> M.Map ModuleName FilePath -- ^ a map between module name and the file containing the foreign javascript for the module
319− -> Bool -- ^ Generate a prefix comment?
320− -> MakeActions Make
305+-- | A set of make actions that read and write modules from the given directory.
306+buildMakeActions
307+ :: FilePath
308+ -- ^ the output directory
309+ -> M.Map ModuleName (Either RebuildPolicy FilePath)
310+ -- ^ a map between module names and paths to the file containing the PureScript module
311+ -> M.Map ModuleName FilePath
312+ -- ^ a map between module name and the file containing the foreign javascript for the module
313+ -> Bool
314+ -- ^ Generate a prefix comment?
315+ -> MakeActions Make
321316buildMakeActions outputDir filePathMap foreigns usePrefix =
322− MakeActions getInputTimestamp getOutputTimestamp readExterns codegen progress
317+ MakeActions getInputTimestamp getOutputTimestamp readExterns codegen progress
323318 where
324319
325320 getInputTimestamp :: ModuleName -> Make (Either RebuildPolicy (Maybe UTCTime))
@@ -421,10 +416,8 @@ buildMakeActions outputDir filePathMap foreigns usePrefix =
421416 progress :: ProgressMessage -> Make ()
422417 progress = liftIO . putStrLn . renderProgressMessage
423418
424−-- |
425−-- Check that the declarations in a given PureScript module match with those
419+-- | Check that the declarations in a given PureScript module match with those
426420-- in its corresponding foreign module.
427−--
428421checkForeignDecls :: CF.Module ann -> FilePath -> SupplyT Make ()
429422checkForeignDecls m path = do
430423 jsStr <- lift $ readTextFile path
src/Language/PureScript/ModuleDependencies.hs+41−77
@@ -1,24 +1,18 @@
1−-- |
2−-- Provides the ability to sort modules based on module dependencies
3−--
1+-- | Provides the ability to sort modules based on module dependencies
42module Language.PureScript.ModuleDependencies
53 ( sortModules
64 , ModuleGraph
75 ) where
86
9−import Prelude.Compat
10−
11−import Control.Monad.Error.Class (MonadError(..))
12−
13−import Data.Graph
14−import Data.List (nub)
15−import Data.Maybe (fromMaybe)
7+import Protolude
168
17−import Language.PureScript.AST
18−import Language.PureScript.Crash
19−import Language.PureScript.Errors
20−import Language.PureScript.Names
21−import Language.PureScript.Types
9+import Data.Graph
10+import qualified Data.Set as S
11+import Language.PureScript.AST
12+import qualified Language.PureScript.Constants as C
13+import Language.PureScript.Crash
14+import Language.PureScript.Errors
15+import Language.PureScript.Names
2216
2317-- | A list of modules with their transitive dependencies
2418type ModuleGraph = [(ModuleName, [ModuleName])]
@@ -26,75 +20,45 @@ type ModuleGraph = [(ModuleName, [ModuleName])]
2620-- | Sort a collection of modules based on module dependencies.
2721--
2822-- Reports an error if the module graph contains a cycle.
29−--
30−sortModules :: (MonadError MultipleErrors m) => [Module] -> m ([Module], ModuleGraph)
23+sortModules
24+ :: forall m
25+ . MonadError MultipleErrors m
26+ => [Module]
27+ -> m ([Module], ModuleGraph)
3128sortModules ms = do
32− let verts = map goModule ms
33− ms' <- mapM toModule $ stronglyConnComp verts
34− let (graph, fromVertex, toVertex) = graphFromEdges verts
35− moduleGraph = do (_, mn, _) <- verts
36− let v = fromMaybe (internalError "sortModules: vertex not found") (toVertex mn)
37− deps = reachable graph v
38− toKey i = case fromVertex i of (_, key, _) -> key
39− return (mn, filter (/= mn) (map toKey deps))
40− return (ms', moduleGraph)
29+ let mns = S.fromList $ map getModuleName ms
30+ verts <- mapM (toGraphNode mns) ms
31+ ms' <- mapM toModule $ stronglyConnComp verts
32+ let (graph, fromVertex, toVertex) = graphFromEdges verts
33+ moduleGraph = do (_, mn, _) <- verts
34+ let v = fromMaybe (internalError "sortModules: vertex not found") (toVertex mn)
35+ deps = reachable graph v
36+ toKey i = case fromVertex i of (_, key, _) -> key
37+ return (mn, filter (/= mn) (map toKey deps))
38+ return (ms', moduleGraph)
4139 where
42− goModule :: Module -> (Module, ModuleName, [ModuleName])
43− goModule m@(Module _ _ _ ds _) =
44− let ams = concatMap extractQualAs ds
45− in (m, getModuleName m, nub (concatMap (usedModules ams) ds))
40+ toGraphNode :: S.Set ModuleName -> Module -> m (Module, ModuleName, [ModuleName])
41+ toGraphNode mns m@(Module _ _ mn ds _) = do
42+ let deps = ordNub (concatMap usedModules ds)
43+ forM_ deps $ \dep ->
44+ when (dep /= C.Prim && S.notMember dep mns) $
45+ throwError . addHint (ErrorInModule mn) . errorMessage $ ModuleNotFound dep
46+ pure (m, getModuleName m, deps)
4647
47− -- Extract module names that have been brought into scope by an `as` import.
48− extractQualAs :: Declaration -> [ModuleName]
49− extractQualAs (PositionedDeclaration _ _ d) = extractQualAs d
50− extractQualAs (ImportDeclaration _ _ (Just am)) = [am]
51− extractQualAs _ = []
52−
53−-- |
54−-- Calculate a list of used modules based on explicit imports and qualified
55−-- names. `ams` is a list of `ModuleNames` that refer to names brought into
56−-- scope by importing with `as` - this ensures that when building the list we
57−-- don't inadvertantly assume a dependency on an actual module, if there is a
58−-- module that has the same name as the qualified import.
59−--
60−usedModules :: [ModuleName] -> Declaration -> [ModuleName]
61−usedModules ams d =
62− let (f, _, _, _, _) = everythingOnValues (++) forDecls forValues (const []) (const []) (const [])
63− (g, _, _, _, _) = accumTypes (everythingOnTypes (++) forTypes)
64− in nub (f d ++ g d)
65− where
48+-- | Calculate a list of used modules based on explicit imports and qualified names.
49+usedModules :: Declaration -> [ModuleName]
50+usedModules d = f d where
51+ f :: Declaration -> [ModuleName]
52+ (f, _, _, _, _) = everythingOnValues (++) forDecls (const []) (const []) (const []) (const [])
6653
6754 forDecls :: Declaration -> [ModuleName]
68− forDecls (ImportDeclaration mn _ _) =
69− -- Regardless of whether an imported module is qualified we still need to
70− -- take into account its import to build an accurate list of dependencies.
71− [mn]
72− forDecls (FixityDeclaration fd)
73− | Just mn <- extractQualFixity fd, mn `notElem` ams = [mn]
74− forDecls (TypeInstanceDeclaration _ _ (Qualified (Just mn) _) _ _)
75− | mn `notElem` ams = [mn]
55+ -- Regardless of whether an imported module is qualified we still need to
56+ -- take into account its import to build an accurate list of dependencies.
57+ forDecls (ImportDeclaration mn _ _) = [mn]
7658 forDecls _ = []
7759
78− forValues :: Expr -> [ModuleName]
79− forValues (Var (Qualified (Just mn) _))
80− | mn `notElem` ams = [mn]
81− forValues (Constructor (Qualified (Just mn) _))
82− | mn `notElem` ams = [mn]
83− forValues _ = []
84−
85− forTypes :: Type -> [ModuleName]
86− forTypes (TypeConstructor (Qualified (Just mn) _))
87− | mn `notElem` ams = [mn]
88− forTypes _ = []
89−
90− extractQualFixity :: Either ValueFixity TypeFixity -> Maybe ModuleName
91− extractQualFixity (Left (ValueFixity _ (Qualified mn _) _)) = mn
92− extractQualFixity (Right (TypeFixity _ (Qualified mn _) _)) = mn
93−
94−-- |
95−-- Convert a strongly connected component of the module graph to a module
96−--
97−toModule :: (MonadError MultipleErrors m) => SCC Module -> m Module
60+-- | Convert a strongly connected component of the module graph to a module
61+toModule :: MonadError MultipleErrors m => SCC Module -> m Module
9862toModule (AcyclicSCC m) = return m
9963toModule (CyclicSCC [m]) = return m
10064toModule (CyclicSCC ms) = throwError . errorMessage $ CycleInModules (map getModuleName ms)
tests/Language/PureScript/Ide/Integration.hs+1−1
@@ -243,7 +243,7 @@ unwrapResult = withObject "result" $ \o -> do
243243 case rt of
244244 "error" -> do
245245 res <- o .: "result"
246− pure (Left res)
246+ withArray "errors" (fmap (Left . fold) . traverse (withObject "error" (.: "message"))) res
247247 "success" -> do
248248 res <- o .: "result"
249249 pure (Right res)