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 Canonicalize.Effects as Effects
15import qualified Canonicalize.Environment as Env
16import qualified Canonicalize.Environment.Dups as Dups
17import qualified Canonicalize.Environment.Foreign as Foreign
18import qualified Canonicalize.Environment.Local as Local
19import qualified Canonicalize.Expression as Expr
20import qualified Canonicalize.Pattern as Pattern
21import qualified Canonicalize.Type as Type
22import qualified Data.Index as Index
23import qualified Elm.Interface as I
24import qualified Elm.ModuleName as ModuleName
25import qualified Elm.Package as Pkg
26import qualified Reporting.Annotation as A
27import qualified Reporting.Error.Canonicalize as Error
28import qualified Reporting.Result as Result
29import qualified Reporting.Warning as W
37 Result.Result i w Error.Error a
44canonicalize :: Pkg.Name -> Map.Map ModuleName.Raw I.Interface -> Src.Module -> Result i [W.Warning] Can.Module
45canonicalize pkg ifaces modul@(Src.Module _ exports docs imports values _ _ binops effects) =
46 do let home = ModuleName.Canonical pkg (Src.getName modul)
47 let cbinops = Map.fromList (map canonicalizeBinop binops)
49 (env, cunions, caliases) <-
51 Foreign.createInitialEnv home ifaces imports
53 cvalues <- canonicalizeValues env values
54 ceffects <- Effects.canonicalize env values cunions effects
55 cexports <- canonicalizeExports values cunions caliases cbinops ceffects exports
57 return $ Can.Module home cexports docs cvalues cunions caliases cbinops ceffects
64canonicalizeBinop :: A.Located Src.Infix -> ( Name.Name, Can.Binop )
65canonicalizeBinop (A.At _ (Src.Infix op associativity precedence func)) =
66 ( op, Can.Binop_ associativity precedence func )
70-- DECLARATIONS / CYCLE DETECTION
72-- There are two phases of cycle detection:
74-- 1. Detect cycles using ALL dependencies => needed for type inference
75-- 2. Detect cycles using DIRECT dependencies => nonterminating recursion
79canonicalizeValues :: Env.Env -> [A.Located Src.Value] -> Result i [W.Warning] Can.Decls
80canonicalizeValues env values =
81 do nodes <- traverse (toNodeOne env) values
82 detectCycles (Graph.stronglyConnComp nodes)
85detectCycles :: [Graph.SCC NodeTwo] -> Result i w Can.Decls
89 Result.ok Can.SaveTheEnvironment
93 Graph.AcyclicSCC (def, _, _) ->
94 Can.Declare def <$> detectCycles otherSccs
96 Graph.CyclicSCC subNodes ->
97 do defs <- traverse detectBadCycles (Graph.stronglyConnComp subNodes)
99 [] -> detectCycles otherSccs
100 d:ds -> Can.DeclareRec d ds <$> detectCycles otherSccs
103detectBadCycles :: Graph.SCC Can.Def -> Result i w Can.Def
106 Graph.AcyclicSCC def ->
109 Graph.CyclicSCC [] ->
110 error "The definition of Data.Graph.SCC should not allow empty CyclicSCC!"
112 Graph.CyclicSCC (def:defs) ->
114 (A.At region name) = extractDefName def
115 names = map (A.toValue . extractDefName) defs
117 Result.throw (Error.RecursiveDecl region name names)
120extractDefName :: Can.Def -> A.Located Name.Name
123 Can.Def name _ _ -> name
124 Can.TypedDef name _ _ _ _ -> name
128-- DECLARATIONS / CYCLE DETECTION SETUP
130-- toNodeOne and toNodeTwo set up nodes for the two cycle detection phases.
133-- Phase one nodes track ALL dependencies.
134-- This allows us to find cyclic values for type inference.
136 (NodeTwo, Name.Name, [Name.Name])
139-- Phase two nodes track DIRECT dependencies.
140-- This allows us to detect cycles that definitely do not terminate.
142 (Can.Def, Name.Name, [Name.Name])
145toNodeOne :: Env.Env -> A.Located Src.Value -> Result i [W.Warning] NodeOne
146toNodeOne env (A.At _ (Src.Value aname@(A.At _ name) srcArgs body maybeType)) =
149 do (args, argBindings) <-
150 Pattern.verify (Error.DPFuncArgs name) $
151 traverse (Pattern.canonicalize env) srcArgs
154 Env.addLocals argBindings env
156 (cbody, freeLocals) <-
157 Expr.verifyBindings W.Pattern argBindings (Expr.canonicalize newEnv body)
159 let def = Can.Def aname args cbody
161 ( toNodeTwo name srcArgs def freeLocals
163 , Map.keys freeLocals
167 do (Can.Forall freeVars tipe) <- Type.toAnnotation env srcType
169 ((args,resultType), argBindings) <-
170 Pattern.verify (Error.DPFuncArgs name) $
171 Expr.gatherTypedArgs env name srcArgs tipe Index.first []
174 Env.addLocals argBindings env
176 (cbody, freeLocals) <-
177 Expr.verifyBindings W.Pattern argBindings (Expr.canonicalize newEnv body)
179 let def = Can.TypedDef aname freeVars args cbody resultType
181 ( toNodeTwo name srcArgs def freeLocals
183 , Map.keys freeLocals
187toNodeTwo :: Name.Name -> [arg] -> Can.Def -> Expr.FreeLocals -> NodeTwo
188toNodeTwo name args def freeLocals =
191 (def, name, Map.foldrWithKey addDirects [] freeLocals)
197addDirects :: Name.Name -> Expr.Uses -> [Name.Name] -> [Name.Name]
198addDirects name (Expr.Uses directUses _) directDeps =
199 if directUses > 0 then
206-- CANONICALIZE EXPORTS
210 :: [A.Located Src.Value]
211 -> Map.Map Name.Name union
212 -> Map.Map Name.Name alias
213 -> Map.Map Name.Name binop
215 -> A.Located Src.Exposing
216 -> Result i w Can.Exports
217canonicalizeExports values unions aliases binops effects (A.At region exposing) =
220 Result.ok (Can.ExportEverything region)
222 Src.Explicit exposeds ->
223 do let names = Map.fromList (map valueToName values)
224 infos <- traverse (checkExposed names unions aliases binops effects) exposeds
225 Can.Export <$> Dups.detect Error.ExportDuplicate (Dups.unions infos)
228valueToName :: A.Located Src.Value -> ( Name.Name, () )
229valueToName (A.At _ (Src.Value (A.At _ name) _ _ _)) =
234 :: Map.Map Name.Name value
235 -> Map.Map Name.Name union
236 -> Map.Map Name.Name alias
237 -> Map.Map Name.Name binop
240 -> Result i w (Dups.Dict (A.Located Can.Export))
241checkExposed values unions aliases binops effects exposed =
243 Src.Lower (A.At region name) ->
244 if Map.member name values then
245 ok name region Can.ExportValue
247 case checkPorts effects name of
249 ok name region Can.ExportPort
252 Result.throw $ Error.ExportNotFound region Error.BadVar name $
253 ports ++ Map.keys values
255 Src.Operator region name ->
256 if Map.member name binops then
257 ok name region Can.ExportBinop
259 Result.throw $ Error.ExportNotFound region Error.BadOp name $
262 Src.Upper (A.At region name) (Src.Public dotDotRegion) ->
263 if Map.member name unions then
264 ok name region Can.ExportUnionOpen
265 else if Map.member name aliases then
266 Result.throw $ Error.ExportOpenAlias dotDotRegion name
268 Result.throw $ Error.ExportNotFound region Error.BadType name $
269 Map.keys unions ++ Map.keys aliases
271 Src.Upper (A.At region name) Src.Private ->
272 if Map.member name unions then
273 ok name region Can.ExportUnionClosed
274 else if Map.member name aliases then
275 ok name region Can.ExportAlias
277 Result.throw $ Error.ExportNotFound region Error.BadType name $
278 Map.keys unions ++ Map.keys aliases
281checkPorts :: Can.Effects -> Name.Name -> Maybe [Name.Name]
282checkPorts effects name =
288 if Map.member name ports then Nothing else Just (Map.keys ports)
290 Can.Manager _ _ _ _ ->
294ok :: Name.Name -> A.Region -> Can.Export -> Result i w (Dups.Dict (A.Located Can.Export))
295ok name region export =
296 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