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 unions aliases binops effects) =
53 do let home = ModuleName.Canonical pkg name
55 startEnv <- Local.addVarsAndTypes module_ =<<
56 Foreign.createInitialEnv home importDict interfaces imports
58 (cunions, caliases) <-
60 <$> (Map.fromList <$> traverse (canonicalizeUnion startEnv) unions)
61 <*> (Map.fromList <$> traverse (canonicalizeAlias startEnv) aliases)
63 let finalEnv = Local.addPatterns cunions startEnv
64 let cbinops = Map.fromList (map canonicalizeBinop binops)
68 <$> canonicalizeDecls finalEnv decls
69 <*> Effects.canonicalize finalEnv decls cunions effects
71 cexports <- canonicalizeExports decls cunions caliases cbinops ceffects exports
73 let docs = toDocs module_
74 return $ Can.Module home docs cexports cdecls cunions caliases cbinops ceffects
81toDocs :: Valid.Module -> Maybe (A.Located Can.Docs)
82toDocs (Valid.Module _ docs comments _ _ _ _ _ _ _) =
87 Just (A.At region overview) ->
88 Just (A.At region (Can.Docs overview comments))
95canonicalizeAlias :: Env.Env -> Valid.Alias -> Result i w ( N.Name, Can.Alias )
96canonicalizeAlias env (Valid.Alias (A.At _ name) args tipe) =
97 do ctipe <- Type.canonicalize env tipe
98 return (name, Can.Alias (map A.toValue args) ctipe (toRecordCtorInfo tipe))
101toRecordCtorInfo :: Src.Type -> Maybe [N.Name]
102toRecordCtorInfo (A.At _ tipe) =
104 Src.TRecord fields Nothing ->
105 Just (map (A.toValue . fst) fields)
115canonicalizeUnion :: Env.Env -> Valid.Union -> Result i w ( N.Name, Can.Union )
116canonicalizeUnion env (Valid.Union (A.At _ name) args ctors) =
118 canonicalizeCtor (A.At _ ctor, tipes) =
119 do ctipes <- traverse (Type.canonicalize env) tipes
120 return (ctor, ctipes)
122 do cctors <- traverse canonicalizeCtor ctors
123 return ( name, Can.Union (map A.toValue args) cctors )
130canonicalizeBinop :: Valid.Binop -> ( N.Name, Can.Binop )
131canonicalizeBinop (Valid.Binop op associativity precedence func) =
132 ( op, Can.Binop_ associativity precedence func )
136-- DECLARATIONS / CYCLE DETECTION
138-- There are two phases of cycle detection:
140-- 1. Detect cycles using ALL dependencies => needed for type inference
141-- 2. Detect cycles using DIRECT dependencies => nonterminating recursion
145canonicalizeDecls :: Env.Env -> [A.Located Valid.Decl] -> Result i [W.Warning] Can.Decls
146canonicalizeDecls env decls =
147 do nodes <- traverse (toNodeOne env) decls
148 detectCycles (Graph.stronglyConnComp nodes)
151detectCycles :: [Graph.SCC NodeTwo] -> Result i w Can.Decls
155 Result.ok Can.SaveTheEnvironment
159 Graph.AcyclicSCC (def, _, _) ->
160 Can.Declare def <$> detectCycles otherSccs
162 Graph.CyclicSCC [] ->
163 detectCycles otherSccs
165 Graph.CyclicSCC subNodes ->
167 <$> traverse detectBadCycles (Graph.stronglyConnComp subNodes)
168 <*> detectCycles otherSccs
171detectBadCycles :: Graph.SCC Can.Def -> Result i w Can.Def
174 Graph.AcyclicSCC def ->
177 Graph.CyclicSCC cyclicValueDefs ->
178 Result.throw (Error.RecursiveDecl cyclicValueDefs)
182-- DECLARATIONS / CYCLE DETECTION SETUP
184-- toNodeOne and toNodeTwo set up nodes for the two cycle detection phases.
187-- Phase one nodes track ALL dependencies.
188-- This allows us to find cyclic values for type inference.
190 (NodeTwo, N.Name, [N.Name])
193-- Phase two nodes track DIRECT dependencies.
194-- This allows us to detect cycles that definitely do not terminate.
196 (Can.Def, N.Name, [N.Name])
199toNodeOne :: Env.Env -> A.Located Valid.Decl -> Result i [W.Warning] NodeOne
200toNodeOne env (A.At _ (Valid.Decl aname@(A.At _ name) srcArgs body maybeType)) =
203 do (args, argBindings) <-
204 Pattern.verify (Error.DPFuncArgs name) $
205 traverse (Pattern.canonicalize env) srcArgs
208 Env.addLocals argBindings env
210 (cbody, freeLocals) <-
211 Expr.verifyBindings W.Pattern argBindings (Expr.canonicalize newEnv body)
213 let def = Can.Def aname args cbody
215 ( toNodeTwo name srcArgs def freeLocals
217 , Map.keys freeLocals
221 do (Can.Forall freeVars tipe) <- Type.toAnnotation env srcType
223 ((args,resultType), argBindings) <-
224 Pattern.verify (Error.DPFuncArgs name) $
225 Expr.gatherTypedArgs env name srcArgs tipe Index.first []
228 Env.addLocals argBindings env
230 (cbody, freeLocals) <-
231 Expr.verifyBindings W.Pattern argBindings (Expr.canonicalize newEnv body)
233 let def = Can.TypedDef aname freeVars args cbody resultType
235 ( toNodeTwo name srcArgs def freeLocals
237 , Map.keys freeLocals
241toNodeTwo :: N.Name -> [arg] -> Can.Def -> Expr.FreeLocals -> NodeTwo
242toNodeTwo name args def freeLocals =
245 (def, name, Map.foldrWithKey addDirects [] freeLocals)
251addDirects :: N.Name -> Expr.Uses -> [N.Name] -> [N.Name]
252addDirects name (Expr.Uses directUses _) directDeps =
253 if directUses > 0 then
260-- CANONICALIZE EXPORTS
264 :: [A.Located Valid.Decl]
265 -> Map.Map N.Name union
266 -> Map.Map N.Name alias
267 -> Map.Map N.Name binop
270 -> Result i w Can.Exports
271canonicalizeExports decls unions aliases binops effects exposing =
274 Result.ok Can.ExportEverything
276 Src.Explicit exposeds ->
277 do let names = Map.fromList (map declToName decls)
278 infos <- traverse (checkExposed names unions aliases binops effects) exposeds
279 Can.Export <$> Dups.detect Error.ExportDuplicate (Dups.unions infos)
282declToName :: A.Located Valid.Decl -> ( N.Name, () )
283declToName (A.At _ (Valid.Decl (A.At _ name) _ _ _)) =
288 :: Map.Map N.Name decl
289 -> Map.Map N.Name union
290 -> Map.Map N.Name alias
291 -> Map.Map N.Name binop
293 -> A.Located Src.Exposed
294 -> Result i w (Dups.Dict (A.Located Can.Export))
295checkExposed decls unions aliases binops effects (A.At region exposed) =
298 if Map.member name decls then
299 ok name region Can.ExportValue
301 case checkPorts effects name of
303 ok name region Can.ExportPort
306 Result.throw $ Error.ExportNotFound region Error.BadVar name $
307 ports ++ Map.keys decls
310 if Map.member name binops then
311 ok name region Can.ExportBinop
313 Result.throw $ Error.ExportNotFound region Error.BadOp name $
316 Src.Upper name Src.Public ->
317 if Map.member name unions then
318 ok name region Can.ExportUnionOpen
319 else if Map.member name aliases then
320 Result.throw $ Error.ExportOpenAlias region name
322 Result.throw $ Error.ExportNotFound region Error.BadType name $
323 Map.keys unions ++ Map.keys aliases
325 Src.Upper name Src.Private ->
326 if Map.member name unions then
327 ok name region Can.ExportUnionClosed
328 else if Map.member name aliases then
329 ok name region Can.ExportAlias
331 Result.throw $ Error.ExportNotFound region Error.BadType name $
332 Map.keys unions ++ Map.keys aliases
335checkPorts :: Can.Effects -> N.Name -> Maybe [N.Name]
336checkPorts effects name =
342 if Map.member name ports then Nothing else Just (Map.keys ports)
344 Can.Manager _ _ _ _ ->
348ok :: N.Name -> R.Region -> Can.Export -> Result i w (Dups.Dict (A.Located Can.Export))
349ok name region export =
350 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