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.Result as Result
30import qualified Reporting.Warning as W
38 Result.Result i w Error.Error a
47 -> Map.Map N.Name ModuleName.Canonical
50 -> Result i [W.Warning] Can.Module
51canonicalize pkg importDict interfaces module_@(Valid.Module name _ _ exports imports decls unions aliases binops effects) =
52 do let home = ModuleName.Canonical pkg name
54 startEnv <- Local.addVarsAndTypes module_ =<<
55 Foreign.createInitialEnv home importDict interfaces imports
57 (cunions, caliases) <-
59 <$> (Map.fromList <$> traverse (canonicalizeUnion startEnv) unions)
60 <*> (Map.fromList <$> traverse (canonicalizeAlias startEnv) aliases)
62 let finalEnv = Local.addPatterns cunions startEnv
63 let cbinops = Map.fromList (map canonicalizeBinop binops)
67 <$> canonicalizeDecls finalEnv decls
68 <*> Effects.canonicalize finalEnv decls cunions effects
70 cexports <- canonicalizeExports decls cunions caliases cbinops ceffects exports
72 let docs = toDocs module_
73 return $ Can.Module home docs cexports cdecls cunions caliases cbinops ceffects
80toDocs :: Valid.Module -> A.Located (Maybe Can.Docs)
81toDocs (Valid.Module _ (A.At region maybeOverview) comments _ _ _ _ _ _ _) =
87 A.At region (Just (Can.Docs overview comments))
94canonicalizeAlias :: Env.Env -> Valid.Alias -> Result i w ( N.Name, Can.Alias )
95canonicalizeAlias env (Valid.Alias (A.At _ name) args tipe) =
96 do ctipe <- Type.canonicalize env tipe
97 return (name, Can.Alias (map A.toValue args) ctipe (toRecordCtorInfo tipe))
100toRecordCtorInfo :: Src.Type -> Maybe [N.Name]
101toRecordCtorInfo (A.At _ tipe) =
103 Src.TRecord fields Nothing ->
104 Just (map (A.toValue . fst) fields)
114canonicalizeUnion :: Env.Env -> Valid.Union -> Result i w ( N.Name, Can.Union )
115canonicalizeUnion env (Valid.Union (A.At _ name) args ctors) =
117 canonicalizeCtor (A.At _ ctor, tipes) =
118 do ctipes <- traverse (Type.canonicalize env) tipes
119 return (ctor, ctipes)
121 do cctors <- traverse canonicalizeCtor ctors
122 return ( name, Can.Union (map A.toValue args) cctors )
129canonicalizeBinop :: Valid.Binop -> ( N.Name, Can.Binop )
130canonicalizeBinop (Valid.Binop (A.At _ op) associativity precedence func) =
131 ( op, Can.Binop_ associativity precedence func )
135-- DECLARATIONS / CYCLE DETECTION
137-- There are two phases of cycle detection:
139-- 1. Detect cycles using ALL dependencies => needed for type inference
140-- 2. Detect cycles using DIRECT dependencies => nonterminating recursion
144canonicalizeDecls :: Env.Env -> [A.Located Valid.Decl] -> Result i [W.Warning] Can.Decls
145canonicalizeDecls env decls =
146 do nodes <- traverse (toNodeOne env) decls
147 detectCycles (Graph.stronglyConnComp nodes)
150detectCycles :: [Graph.SCC NodeTwo] -> Result i w Can.Decls
154 Result.ok Can.SaveTheEnvironment
158 Graph.AcyclicSCC (def, _, _) ->
159 Can.Declare def <$> detectCycles otherSccs
161 Graph.CyclicSCC [] ->
162 detectCycles otherSccs
164 Graph.CyclicSCC subNodes ->
166 <$> traverse detectBadCycles (Graph.stronglyConnComp subNodes)
167 <*> detectCycles otherSccs
170detectBadCycles :: Graph.SCC Can.Def -> Result i w Can.Def
173 Graph.AcyclicSCC def ->
176 Graph.CyclicSCC cyclicValueDefs ->
177 Result.throw (Error.RecursiveDecl cyclicValueDefs)
181-- DECLARATIONS / CYCLE DETECTION SETUP
183-- toNodeOne and toNodeTwo set up nodes for the two cycle detection phases.
186-- Phase one nodes track ALL dependencies.
187-- This allows us to find cyclic values for type inference.
189 (NodeTwo, N.Name, [N.Name])
192-- Phase two nodes track DIRECT dependencies.
193-- This allows us to detect cycles that definitely do not terminate.
195 (Can.Def, N.Name, [N.Name])
198toNodeOne :: Env.Env -> A.Located Valid.Decl -> Result i [W.Warning] NodeOne
199toNodeOne env (A.At _ (Valid.Decl aname@(A.At _ name) srcArgs body maybeType)) =
202 do (args, argBindings) <-
203 Pattern.verify (Error.DPFuncArgs name) $
204 traverse (Pattern.canonicalize env) srcArgs
207 Env.addLocals argBindings env
209 (cbody, freeLocals) <-
210 Expr.verifyBindings W.Pattern argBindings (Expr.canonicalize newEnv body)
212 let def = Can.Def aname args cbody
214 ( toNodeTwo name srcArgs def freeLocals
216 , Map.keys freeLocals
220 do (Can.Forall freeVars tipe) <- Type.toAnnotation env srcType
222 ((args,resultType), argBindings) <-
223 Pattern.verify (Error.DPFuncArgs name) $
224 Expr.gatherTypedArgs env name srcArgs tipe Index.first []
227 Env.addLocals argBindings env
229 (cbody, freeLocals) <-
230 Expr.verifyBindings W.Pattern argBindings (Expr.canonicalize newEnv body)
232 let def = Can.TypedDef aname freeVars args cbody resultType
234 ( toNodeTwo name srcArgs def freeLocals
236 , Map.keys freeLocals
240toNodeTwo :: N.Name -> [arg] -> Can.Def -> Expr.FreeLocals -> NodeTwo
241toNodeTwo name args def freeLocals =
244 (def, name, Map.foldrWithKey addDirects [] freeLocals)
250addDirects :: N.Name -> Expr.Uses -> [N.Name] -> [N.Name]
251addDirects name (Expr.Uses directUses _) directDeps =
252 if directUses > 0 then
259-- CANONICALIZE EXPORTS
263 :: [A.Located Valid.Decl]
264 -> Map.Map N.Name union
265 -> Map.Map N.Name alias
266 -> Map.Map N.Name binop
269 -> Result i w Can.Exports
270canonicalizeExports decls unions aliases binops effects exposing =
273 Result.ok Can.ExportEverything
275 Src.Explicit exposeds ->
276 do let names = Map.fromList (map declToName decls)
277 infos <- traverse (checkExposed names unions aliases binops effects) exposeds
278 Can.Export <$> Dups.detect Error.ExportDuplicate (Dups.unions infos)
281declToName :: A.Located Valid.Decl -> ( N.Name, () )
282declToName (A.At _ (Valid.Decl (A.At _ name) _ _ _)) =
287 :: Map.Map N.Name decl
288 -> Map.Map N.Name union
289 -> Map.Map N.Name alias
290 -> Map.Map N.Name binop
292 -> A.Located Src.Exposed
293 -> Result i w (Dups.Dict () Can.Export)
294checkExposed decls unions aliases binops effects (A.At region exposed) =
297 if Map.member name decls then
298 Result.ok (Dups.one name region () Can.ExportValue)
300 case checkPorts effects name of
302 Result.ok (Dups.one name region () Can.ExportPort)
305 Result.throw $ Error.ExportNotFound region Error.BadVar name $
306 ports ++ Map.keys decls
309 if Map.member name binops then
310 Result.ok (Dups.one name region () Can.ExportBinop)
312 Result.throw $ Error.ExportNotFound region Error.BadOp name $
315 Src.Upper name Src.Public ->
316 if Map.member name unions then
317 Result.ok (Dups.one name region () Can.ExportUnionOpen)
318 else if Map.member name aliases then
319 Result.throw $ Error.ExportOpenAlias region name
321 Result.throw $ Error.ExportNotFound region Error.BadType name $
322 Map.keys unions ++ Map.keys aliases
324 Src.Upper name Src.Private ->
325 if Map.member name unions then
326 Result.ok (Dups.one name region () Can.ExportUnionClosed)
327 else if Map.member name aliases then
328 Result.ok (Dups.one name region () Can.ExportAlias)
330 Result.throw $ Error.ExportNotFound region Error.BadType name $
331 Map.keys unions ++ Map.keys aliases
334checkPorts :: Can.Effects -> N.Name -> Maybe [N.Name]
335checkPorts effects name =
341 if Map.member name ports then Nothing else Just (Map.keys ports)
343 Can.Manager _ _ _ _ ->
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