1{-# OPTIONS_GHC -Wall #-}
2module Canonicalize.Module
8import qualified Data.Graph as Graph
9import qualified Data.Map as Map
10import qualified Data.Name as Name
12import qualified AST.Canonical as Can
13import qualified AST.Source as Src
14import qualified AST.Valid as Valid
15import qualified AST.Module.Name as ModuleName
16import qualified Canonicalize.Effects as Effects
17import qualified Canonicalize.Environment as Env
18import qualified Canonicalize.Environment.Dups as Dups
19import qualified Canonicalize.Environment.Foreign as Foreign
20import qualified Canonicalize.Environment.Local as Local
21import qualified Canonicalize.Expression as Expr
22import qualified Canonicalize.Pattern as Pattern
23import qualified Canonicalize.Type as Type
24import qualified Data.Index as Index
25import qualified Elm.Interface as I
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 Name.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 -> ( Name.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, Name.Name, [Name.Name])
148-- Phase two nodes track DIRECT dependencies.
149-- This allows us to detect cycles that definitely do not terminate.
151 (Can.Def, Name.Name, [Name.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 :: Name.Name -> [arg] -> Can.Def -> Expr.FreeLocals -> NodeTwo
197toNodeTwo name args def freeLocals =
200 (def, name, Map.foldrWithKey addDirects [] freeLocals)
206addDirects :: Name.Name -> Expr.Uses -> [Name.Name] -> [Name.Name]
207addDirects name (Expr.Uses directUses _) directDeps =
208 if directUses > 0 then
215-- CANONICALIZE EXPORTS
219 :: [A.Located Valid.Decl]
220 -> Map.Map Name.Name union
221 -> Map.Map Name.Name alias
222 -> Map.Map Name.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 -> ( Name.Name, () )
238declToName (A.At _ (Valid.Decl (A.At _ name) _ _ _)) =
243 :: Map.Map Name.Name decl
244 -> Map.Map Name.Name union
245 -> Map.Map Name.Name alias
246 -> Map.Map Name.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 -> Name.Name -> Maybe [Name.Name]
291checkPorts effects name =
297 if Map.member name ports then Nothing else Just (Map.keys ports)
299 Can.Manager _ _ _ _ ->
303ok :: Name.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