@@ -24,6 +24,7 @@ module Language.PureScript.Sugar.BindingGroups (
2424import Data.Graph
2525import Data.List (nub, intersect)
2626import Data.Maybe (isJust, mapMaybe)
27+import Data.Monoid ((<>))
2728import Control.Applicative ((<$>), (<*>), pure)
2829
2930import qualified Data.Set as S
@@ -58,7 +59,7 @@ createBindingGroups moduleName ds = do
5859 dataBindingGroupDecls <- mapM toDataBindingGroup $ stronglyConnComp dataVerts
5960 let allIdents = map getIdent values
6061 valueVerts = map (\d -> (d, getIdent d, usedIdents moduleName d `intersect` allIdents)) values
61− bindingGroupDecls = map toBindingGroup $ stronglyConnComp valueVerts
62+ bindingGroupDecls <- mapM (toBindingGroup moduleName) $ stronglyConnComp valueVerts
6263 return $ filter isImportDecl ds ++
6364 filter isExternDataDecl ds ++
6465 filter isExternInstanceDecl ds ++
@@ -107,6 +108,19 @@ usedIdents moduleName =
107108 usedNamesB :: S.Set Ident -> Binder -> (S.Set Ident, [Ident])
108109 usedNamesB scope binder = (scope `S.union` S.fromList (binderNames binder), [])
109110
111+usedImmediateIdents :: ModuleName -> Declaration -> [Ident]
112+usedImmediateIdents moduleName =
113+ let (f, _, _, _, _) = everythingWithContextOnValues True [] (++) def usedNamesE def def def
114+ in nub . f
115+ where
116+ def s _ = (s, [])
117+
118+ usedNamesE :: Bool -> Expr -> (Bool, [Ident])
119+ usedNamesE True (Var (Qualified Nothing name)) = (True, [name])
120+ usedNamesE True (Var (Qualified (Just moduleName') name)) | moduleName == moduleName' = (True, [name])
121+ usedNamesE True (Abs _ _) = (False, [])
122+ usedNamesE scope _ = (scope, [])
123+
110124usedProperNames :: ModuleName -> Declaration -> [ProperName]
111125usedProperNames moduleName =
112126 let (f, _, _, _, _) = accumTypes (everythingOnTypes (++) usedNames)
@@ -131,10 +145,42 @@ getProperName (TypeSynonymDeclaration pn _ _) = pn
131145getProperName (PositionedDeclaration _ d) = getProperName d
132146getProperName _ = error "Expected DataDeclaration"
133147
134−toBindingGroup :: SCC Declaration -> Declaration
135−toBindingGroup (AcyclicSCC d) = d
136−toBindingGroup (CyclicSCC [d]) = d
137−toBindingGroup (CyclicSCC ds') = BindingGroupDeclaration $ map fromValueDecl ds'
148+-- |
149+-- Convert a group of mutually-recursive dependencies into a BindingGroupDeclaration (or simple ValueDeclaration).
150+--
151+--
152+toBindingGroup :: ModuleName -> SCC Declaration -> Either ErrorStack Declaration
153+toBindingGroup _ (AcyclicSCC d) = return d
154+toBindingGroup _ (CyclicSCC [d]) = return d
155+toBindingGroup moduleName (CyclicSCC ds') =
156+ -- Once we have a mutually-recursive group of declarations, we need to sort
157+ -- them further by their immediate dependencies (those outside function
158+ -- bodies). In particular, this is relevant for type instance dictionaries
159+ -- whose members require other type instances (for example, functorEff
160+ -- defines (<$>) = liftA1, which depends on applicativeEff). Note that
161+ -- superclass references are still inside functions, so don't count here.
162+ -- If we discover declarations that still contain mutually-recursive
163+ -- immediate references, we're guaranteed to get an undefined reference at
164+ -- runtime, so treat this as an error. See also github issue #365.
165+ BindingGroupDeclaration <$> mapM toBinding (stronglyConnComp valueVerts)
166+ where
167+ idents :: [Ident]
168+ idents = map (\(_, i, _) -> i) valueVerts
169+
170+ valueVerts :: [(Declaration, Ident, [Ident])]
171+ valueVerts = map (\d -> (d, getIdent d, usedImmediateIdents moduleName d `intersect` idents)) ds'
172+
173+ toBinding :: SCC Declaration -> Either ErrorStack (Ident, NameKind, Expr)
174+ toBinding (AcyclicSCC d) = return $ fromValueDecl d
175+ toBinding (CyclicSCC ~(d:ds)) = cycleError d ds
176+
177+ cycleError :: Declaration -> [Declaration] -> Either ErrorStack a
178+ cycleError (PositionedDeclaration p d) ds = rethrowWithPosition p $ cycleError d ds
179+ cycleError (ValueDeclaration n _ _ _ e) [] = Left $
180+ mkErrorStack ("Cycle in definition of " ++ show n) (Just (ExprError e))
181+ cycleError d ds@(_:_) = rethrow (<> mkErrorStack ("The following are not yet defined here: " ++ unwords (map (show . getIdent) ds)) Nothing) $ cycleError d []
182+ cycleError _ _ = error "Expected ValueDeclaration"
183+
138184
139185toDataBindingGroup :: SCC Declaration -> Either ErrorStack Declaration
140186toDataBindingGroup (AcyclicSCC d) = return d