git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
Merge pull request #2022 from purescript/2018-fix-incorrect-cycle-detection

Fix cycles being detected incorrectly with qualified imports

commit419d90ea7cee4afd95d1f16fb90264cb39b301ac authorGary Burgess <gary.burgess@gmail.com> dateSat 16 Apr 2016, 22:14 (11 years ago) parent17764559a6bcb3
2 files changed+62−24
examples/passing/2018.purs+25 src/Language/PureScript/ModuleDependencies.hs+37−24
examples/passing/2018.pursnew file+25
@@ -0,0 +1,25 @@
1+module B where
2+
3+ data Foo = X | Y
4+
5+module A where
6+
7+ import B as Main
8+
9+ -- Prior to the 2018 fix this would be detected as a cycle between A and Main.
10+ foo ∷ Main.Foo → Main.Foo
11+ foo x = x
12+
13+module Main where
14+
15+import Prelude
16+import A (foo)
17+import B (Foo(..))
18+import Control.Monad.Eff (Eff)
19+import Control.Monad.Eff.Console (CONSOLE, log)
20+
21+main :: forall e. Eff (console :: CONSOLE | e) Unit
22+main = do
23+ let tmp = foo X
24+ log "Done"
25+
src/Language/PureScript/ModuleDependencies.hs+37−24
@@ -1,19 +1,8 @@
1−-----------------------------------------------------------------------------
2−--
3−-- Module : Language.PureScript.ModuleDependencies
4−-- Copyright : (c) 2013-15 Phil Freeman, (c) 2014-15 Gary Burgess
5−-- License : MIT (http://opensource.org/licenses/MIT)
6−--
7−-- Maintainer : Phil Freeman <paf31@cantab.net>
8−-- Stability : experimental
9−-- Portability :
10−--
11−-- | Provides the ability to sort modules based on module dependencies
12−--
13−-----------------------------------------------------------------------------
14−
151{-# LANGUAGE FlexibleContexts #-}
162
3+-- |
4+-- Provides the ability to sort modules based on module dependencies
5+--
176module Language.PureScript.ModuleDependencies (
187 sortModules,
198 ModuleGraph
@@ -40,7 +29,7 @@ type ModuleGraph = [(ModuleName, [ModuleName])]
4029--
4130sortModules :: (MonadError MultipleErrors m) => [Module] -> m ([Module], ModuleGraph)
4231sortModules ms = do
43− let verts = map (\m@(Module _ _ _ ds _) -> (m, getModuleName m, nub (concatMap usedModules ds))) ms
32+ let verts = map goModule ms
4433 ms' <- mapM toModule $ stronglyConnComp verts
4534 let (graph, fromVertex, toVertex) = graphFromEdges verts
4635 moduleGraph = do (_, mn, _) <- verts
@@ -49,29 +38,53 @@ sortModules ms = do
4938 toKey i = case fromVertex i of (_, key, _) -> key
5039 return (mn, filter (/= mn) (map toKey deps))
5140 return (ms', moduleGraph)
41+ 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))
46+
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 _ = []
5252
5353-- |
54−-- Calculate a list of used modules based on explicit imports and qualified names
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.
5559--
56−usedModules :: Declaration -> [ModuleName]
57−usedModules d =
60+usedModules :: [ModuleName] -> Declaration -> [ModuleName]
61+usedModules ams d =
5862 let (f, _, _, _, _) = everythingOnValues (++) forDecls forValues (const []) (const []) (const [])
5963 (g, _, _, _, _) = accumTypes (everythingOnTypes (++) forTypes)
6064 in nub (f d ++ g d)
6165 where
66+
6267 forDecls :: Declaration -> [ModuleName]
63− forDecls (ImportDeclaration mn _ _ _) = [mn]
64− forDecls (FixityDeclaration _ _ (Just (Qualified (Just mn) _))) = [mn]
65− forDecls (TypeInstanceDeclaration _ _ (Qualified (Just mn) _) _ _) = [mn]
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 _ _ (Just (Qualified (Just mn) _)))
73+ | mn `notElem` ams = [mn]
74+ forDecls (TypeInstanceDeclaration _ _ (Qualified (Just mn) _) _ _)
75+ | mn `notElem` ams = [mn]
6676 forDecls _ = []
6777
6878 forValues :: Expr -> [ModuleName]
69− forValues (Var (Qualified (Just mn) _)) = [mn]
70− forValues (Constructor (Qualified (Just mn) _)) = [mn]
79+ forValues (Var (Qualified (Just mn) _))
80+ | mn `notElem` ams = [mn]
81+ forValues (Constructor (Qualified (Just mn) _))
82+ | mn `notElem` ams = [mn]
7183 forValues _ = []
7284
7385 forTypes :: Type -> [ModuleName]
74− forTypes (TypeConstructor (Qualified (Just mn) _)) = [mn]
86+ forTypes (TypeConstructor (Qualified (Just mn) _))
87+ | mn `notElem` ams = [mn]
7588 forTypes _ = []
7689
7790-- |