1{-# OPTIONS_GHC -Wall #-}
2module Canonicalize.Module
8import qualified Data.Graph as Graph
9import qualified Data.Map as Map
11import qualified AST.Canonical as Can
12import qualified AST.Source as Src
13import qualified AST.Valid as Valid
14import qualified AST.Module.Name as ModuleName
15import qualified Canonicalize.Effects as Effects
16import qualified Canonicalize.Environment as Env
17import qualified Canonicalize.Environment.Dups as Dups
18import qualified Canonicalize.Environment.Foreign as Foreign
19import qualified Canonicalize.Environment.Local as Local
20import qualified Canonicalize.Expression as Expr
21import qualified Canonicalize.Pattern as Pattern
22import qualified Canonicalize.Type as Type
23import qualified Data.Index as Index
24import qualified Elm.Interface as I
25import qualified Elm.Name as N
26import qualified Elm.Package as Pkg
27import qualified Reporting.Annotation as A
28import qualified Reporting.Error.Canonicalize as Error
29import qualified Reporting.Region as R
30import qualified Reporting.Result as Result
31import qualified Reporting.Warning as W
39 Result.Result i w Error.Error a
48 -> Map.Map N.Name ModuleName.Canonical
51 -> Result i [W.Warning] Can.Module
52canonicalize pkg importDict interfaces module_@(Valid.Module name _ _ exports imports decls _ _ binops effects) =
53 do let home = ModuleName.Canonical pkg name
54 let cbinops = Map.fromList (map canonicalizeBinop binops)
56 (env, cunions, caliases) <-
58 Foreign.createInitialEnv home importDict interfaces imports
60 cdecls <- canonicalizeDecls env decls
61 ceffects <- Effects.canonicalize env decls cunions effects
62 cexports <- canonicalizeExports decls cunions caliases cbinops ceffects exports
64 return $ Can.Module home (toDocs module_) cexports cdecls cunions caliases cbinops ceffects
71toDocs :: Valid.Module -> Can.Docs
72toDocs (Valid.Module _ docs comments _ _ _ _ _ _ _) =
77 Src.YesDocs region overview ->
78 Can.YesDocs region overview comments
85canonicalizeBinop :: Valid.Binop -> ( N.Name, Can.Binop )
86canonicalizeBinop (Valid.Binop op associativity precedence func) =
87 ( op, Can.Binop_ associativity precedence func )
91-- DECLARATIONS / CYCLE DETECTION
93-- There are two phases of cycle detection:
95-- 1. Detect cycles using ALL dependencies => needed for type inference
96-- 2. Detect cycles using DIRECT dependencies => nonterminating recursion
100canonicalizeDecls :: Env.Env -> [A.Located Valid.Decl] -> Result i [W.Warning] Can.Decls
101canonicalizeDecls env decls =
102 do nodes <- traverse (toNodeOne env) decls
103 detectCycles (Graph.stronglyConnComp nodes)
106detectCycles :: [Graph.SCC NodeTwo] -> Result i w Can.Decls
110 Result.ok Can.SaveTheEnvironment
114 Graph.AcyclicSCC (def, _, _) ->
115 Can.Declare def <$> detectCycles otherSccs
117 Graph.CyclicSCC [] ->
118 detectCycles otherSccs
120 Graph.CyclicSCC subNodes ->
122 <$> traverse detectBadCycles (Graph.stronglyConnComp subNodes)
123 <*> detectCycles otherSccs
126detectBadCycles :: Graph.SCC Can.Def -> Result i w Can.Def
129 Graph.AcyclicSCC def ->
132 Graph.CyclicSCC cyclicValueDefs ->
133 Result.throw (Error.RecursiveDecl cyclicValueDefs)
137-- DECLARATIONS / CYCLE DETECTION SETUP
139-- toNodeOne and toNodeTwo set up nodes for the two cycle detection phases.
142-- Phase one nodes track ALL dependencies.
143-- This allows us to find cyclic values for type inference.
145 (NodeTwo, N.Name, [N.Name])
148-- Phase two nodes track DIRECT dependencies.
149-- This allows us to detect cycles that definitely do not terminate.
151 (Can.Def, N.Name, [N.Name])
154toNodeOne :: Env.Env -> A.Located Valid.Decl -> Result i [W.Warning] NodeOne
155toNodeOne env (A.At _ (Valid.Decl aname@(A.At _ name) srcArgs body maybeType)) =
158 do (args, argBindings) <-
159 Pattern.verify (Error.DPFuncArgs name) $
160 traverse (Pattern.canonicalize env) srcArgs
163 Env.addLocals argBindings env
165 (cbody, freeLocals) <-
166 Expr.verifyBindings W.Pattern argBindings (Expr.canonicalize newEnv body)
168 let def = Can.Def aname args cbody
170 ( toNodeTwo name srcArgs def freeLocals
172 , Map.keys freeLocals
176 do (Can.Forall freeVars tipe) <- Type.toAnnotation env srcType
178 ((args,resultType), argBindings) <-
179 Pattern.verify (Error.DPFuncArgs name) $
180 Expr.gatherTypedArgs env name srcArgs tipe Index.first []
183 Env.addLocals argBindings env
185 (cbody, freeLocals) <-
186 Expr.verifyBindings W.Pattern argBindings (Expr.canonicalize newEnv body)
188 let def = Can.TypedDef aname freeVars args cbody resultType
190 ( toNodeTwo name srcArgs def freeLocals
192 , Map.keys freeLocals
196toNodeTwo :: N.Name -> [arg] -> Can.Def -> Expr.FreeLocals -> NodeTwo
197toNodeTwo name args def freeLocals =
200 (def, name, Map.foldrWithKey addDirects [] freeLocals)
206addDirects :: N.Name -> Expr.Uses -> [N.Name] -> [N.Name]
207addDirects name (Expr.Uses directUses _) directDeps =
208 if directUses > 0 then
215-- CANONICALIZE EXPORTS
219 :: [A.Located Valid.Decl]
220 -> Map.Map N.Name union
221 -> Map.Map N.Name alias
222 -> Map.Map N.Name binop
224 -> A.Located Src.Exposing
225 -> Result i w Can.Exports
226canonicalizeExports decls unions aliases binops effects (A.At region exposing) =
229 Result.ok (Can.ExportEverything region)
231 Src.Explicit exposeds ->
232 do let names = Map.fromList (map declToName decls)
233 infos <- traverse (checkExposed names unions aliases binops effects) exposeds
234 Can.Export <$> Dups.detect Error.ExportDuplicate (Dups.unions infos)
237declToName :: A.Located Valid.Decl -> ( N.Name, () )
238declToName (A.At _ (Valid.Decl (A.At _ name) _ _ _)) =
243 :: Map.Map N.Name decl
244 -> Map.Map N.Name union
245 -> Map.Map N.Name alias
246 -> Map.Map N.Name binop
248 -> A.Located Src.Exposed
249 -> Result i w (Dups.Dict (A.Located Can.Export))
250checkExposed decls unions aliases binops effects (A.At region exposed) =
253 if Map.member name decls then
254 ok name region Can.ExportValue
256 case checkPorts effects name of
258 ok name region Can.ExportPort
261 Result.throw $ Error.ExportNotFound region Error.BadVar name $
262 ports ++ Map.keys decls
265 if Map.member name binops then
266 ok name region Can.ExportBinop
268 Result.throw $ Error.ExportNotFound region Error.BadOp name $
271 Src.Upper name Src.Public ->
272 if Map.member name unions then
273 ok name region Can.ExportUnionOpen
274 else if Map.member name aliases then
275 Result.throw $ Error.ExportOpenAlias region name
277 Result.throw $ Error.ExportNotFound region Error.BadType name $
278 Map.keys unions ++ Map.keys aliases
280 Src.Upper name Src.Private ->
281 if Map.member name unions then
282 ok name region Can.ExportUnionClosed
283 else if Map.member name aliases then
284 ok name region Can.ExportAlias
286 Result.throw $ Error.ExportNotFound region Error.BadType name $
287 Map.keys unions ++ Map.keys aliases
290checkPorts :: Can.Effects -> N.Name -> Maybe [N.Name]
291checkPorts effects name =
297 if Map.member name ports then Nothing else Just (Map.keys ports)
299 Can.Manager _ _ _ _ ->
303ok :: N.Name -> R.Region -> Can.Export -> Result i w (Dups.Dict (A.Located Can.Export))
304ok name region export =
305 Result.ok $ Dups.one name region (A.At region export)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list