1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Canonicalize.Environment.Local
10import Control.Applicative (liftA2)
11import Control.Monad (foldM)
12import qualified Data.Graph as Graph
13import qualified Data.Map.Strict as Map
14import qualified Data.Map.Merge.Strict as Map
16import qualified AST.Canonical as Can
17import qualified AST.Source as Src
18import qualified AST.Valid as Valid
19import qualified Canonicalize.Environment as Env
20import qualified Canonicalize.Environment.Dups as Dups
21import qualified Canonicalize.Type as Type
22import qualified Data.Bag as Bag
23import qualified Data.Index as Index
24import qualified Elm.Name as N
25import qualified Reporting.Annotation as A
26import qualified Reporting.Error.Canonicalize as Error
27import qualified Reporting.Region as R
28import qualified Reporting.Result as Result
29import qualified Reporting.Warning as Warning
37 Result.Result i [Warning.Warning] Error.Error a
41-- ADD VARS, TYPES, AND OPS
43-- We can add names for local definitions, unions, aliases, and operators.
44-- These are basically just names. We CANNOT add patterns though. Those must
45-- be added by `addPatterns` after some canonicalization has occurred.
47-- This code checks for (1) duplicate names and (2) cycles in type aliases.
50addVarsAndTypes :: Valid.Module -> Env.Env -> Result i Env.Env
51addVarsAndTypes module_ env =
52 addVars module_ =<< addTypes module_ env
56 :: (N.Name -> a -> homes)
57 -> (N.Name -> a -> homes -> homes)
59 -> Map.Map N.Name homes
60 -> Map.Map N.Name homes
61merge addLeft addBoth locals foreigns =
62 let addRight _ homes = homes in
64 (Map.mapMissing addLeft)
65 (Map.mapMissing addRight)
66 (Map.zipWithMatched addBoth)
74-- Local patterns are added to the environment later such that we can have
75-- canonical union types. This way we can avoid looking up the types during
76-- type constraint generation.
78-- This function does not return a Result because Dups.detect is already called
79-- in collectUpperVars. This will detect all local pattern clashes. We skip it
80-- here to avoid a second version of the same error.
83addPatterns :: Map.Map N.Name Can.Union -> Env.Env -> Env.Env
84addPatterns unions (Env.Env home vars types patterns binops) =
87 Map.fromList $ concatMap toPatterns (Map.toList unions)
89 toPatterns (tipe, Can.Union tvars ctors) =
90 Index.indexedMap (ctorToPattern tipe tvars (Can.ctorsToAlts ctors)) ctors
92 ctorToPattern tipe tvars alts index (name, args) =
93 ( name, Env.Pattern home tipe tvars alts index args )
97 merge addLeft addBoth localPatterns patterns
99 addLeft _ localPattern =
100 Env.Homes (Bag.one localPattern) Map.empty
102 addBoth _ localPattern (Env.Homes _ qualified) =
103 Env.Homes (Bag.one localPattern) qualified
105 Env.Env home vars types newPatterns binops
112addVars :: Valid.Module -> Env.Env -> Result i Env.Env
113addVars module_ (Env.Env home vars types patterns binops) =
114 do upperDict <- collectUpperVars module_
115 lowerDict <- collectLowerVars module_
116 let varDict = Map.union upperDict lowerDict
117 let newVars = addVarsHelp varDict vars
118 return $ Env.Env home newVars types patterns binops
121addVarsHelp :: Map.Map N.Name () -> Map.Map N.Name Env.VarHomes -> Map.Map N.Name Env.VarHomes
122addVarsHelp localVars vars =
125 Env.VarHomes Env.TopLevel Map.empty
130 addBoth _ _ (Env.VarHomes _ qualified) =
131 Env.VarHomes Env.TopLevel qualified
133 merge addLeft addBoth localVars vars
136collectLowerVars :: Valid.Module -> Result i (Map.Map N.Name ())
137collectLowerVars (Valid.Module _ _ _ _ _ decls _ _ _ effects) =
139 addDecl (A.At _ (Valid.Decl (A.At region name) _ _ _)) dict =
140 Dups.insert name region () () dict
142 addPort (Valid.Port (A.At region name) _) dict =
143 Dups.insert name region () () dict
151 foldr addPort Dups.none ports
153 Valid.Manager _ manager ->
155 Valid.Cmd (A.At region _) ->
156 Dups.one "command" region () ()
158 Valid.Sub (A.At region _) ->
159 Dups.one "subscription" region () ()
161 Valid.Fx (A.At regionCmd _) (A.At regionSub _) ->
163 (Dups.one "command" regionCmd () ())
164 (Dups.one "subscription" regionSub () ())
166 Dups.detect Error.DuplicateDecl $ foldr addDecl effectDict decls
169collectUpperVars :: Valid.Module -> Result i (Map.Map N.Name ())
170collectUpperVars (Valid.Module _ _ _ _ _ _ unions aliases _ _) =
172 addUnion (Valid.Union (A.At _ name) _ ctors) dict =
173 foldr (addCtor name) dict ctors
175 addCtor tipe (A.At region name, _args) dict =
176 Dups.insert name region (Error.UnionCtor tipe) () dict
178 addAlias (Valid.Alias (A.At region name) _ (A.At _ tipe)) dict =
180 Src.TRecord _ Nothing ->
181 Dups.insert name region Error.RecordCtor () dict
186 Dups.detect Error.DuplicateCtor $
187 foldr addAlias (foldr addUnion Dups.none unions) aliases
194addTypes :: Valid.Module -> Env.Env -> Result i Env.Env
195addTypes (Valid.Module _ _ _ _ _ _ unions aliases _ _) env =
197 aliasToDict alias@(Valid.Alias (A.At region name) _ tipe) =
198 do args <- checkAliasFreeVars alias
199 return $ Dups.one name region () (Left (Alias region name args tipe))
201 unionToDict union@(Valid.Union (A.At region name) _ _) =
202 do arity <- checkUnionFreeVars union
203 return $ Dups.one name region () (Right arity)
205 combineDicts dicts1 dicts2 =
206 Dups.union (Dups.unions dicts1) (Dups.unions dicts2)
210 (traverse aliasToDict aliases)
211 (traverse unionToDict unions)
212 types <- Dups.detect Error.DuplicateType dict
213 let (aliasDict, unionDict) = Map.mapEither id types
214 addTypeAliases aliasDict (addUnionTypes unionDict env)
217addUnionTypes :: Map.Map N.Name Int -> Env.Env -> Env.Env
218addUnionTypes unions (Env.Env home vars types patterns binops) =
221 Env.Homes (Bag.one (Env.Union arity home)) Map.empty
223 addBoth _ arity (Env.Homes _ qualified) =
224 Env.Homes (Bag.one (Env.Union arity home)) qualified
227 merge addLeft addBoth unions types
229 Env.Env home vars newTypes patterns binops
238 { _region :: R.Region
245addTypeAliases :: Map.Map N.Name Alias -> Env.Env -> Result i Env.Env
246addTypeAliases aliases env =
247 do let nodes = map toNode (Map.elems aliases)
248 let sccs = Graph.stronglyConnComp nodes
249 foldM addTypeAlias env sccs
252addTypeAlias :: Env.Env -> Graph.SCC Alias -> Result i Env.Env
253addTypeAlias env@(Env.Env home vars types patterns binops) scc =
255 Graph.AcyclicSCC (Alias _ name args tipe) ->
256 do ctype <- Type.canonicalize env tipe
257 let info = Env.Alias (length args) home args ctype
258 let newTypes = Map.alter (addAliasInfo info) name types
259 return $ Env.Env home vars newTypes patterns binops
261 Graph.CyclicSCC [] ->
264 Graph.CyclicSCC (Alias region name1 args tipe : others) ->
265 let toName (Alias _ name _ _) = name in
266 Result.throw (Error.RecursiveAlias region name1 args tipe (map toName others))
269addAliasInfo :: a -> Maybe (Env.Homes a) -> Maybe (Env.Homes a)
270addAliasInfo info maybeHomes =
274 Env.Homes (Bag.one info) Map.empty
276 Just (Env.Homes _ qualified) ->
277 Env.Homes (Bag.one info) qualified
281-- DETECT TYPE ALIAS CYCLES
284toNode :: Alias -> ( Alias, N.Name, [N.Name] )
285toNode alias@(Alias _ name _ tipe) =
286 ( alias, name, Bag.toList (getEdges tipe) )
289getEdges :: Src.Type -> Bag.Bag N.Name
290getEdges (A.At _ tipe) =
292 Src.TLambda arg result ->
293 Bag.append (getEdges arg) (getEdges result)
298 Src.TType _ Nothing name args ->
299 foldr Bag.append (Bag.one name) (map getEdges args)
301 Src.TType _ (Just _) _ args ->
302 foldr Bag.append Bag.empty (map getEdges args)
304 Src.TRecord fields ext ->
306 (maybe Bag.empty getEdges ext)
307 (map (getEdges . snd) fields)
315 (getEdges b : map getEdges cs)
319-- CHECK FREE VARIABLES
322checkUnionFreeVars :: Valid.Union -> Result i Int
323checkUnionFreeVars (Valid.Union (A.At unionRegion name) args ctors) =
325 addUnion (A.At region arg) dict =
326 Dups.insert arg region () region dict
329 Error.DuplicateUnionArg name (map A.toValue args)
331 addCtorFreeVars (_, tipes) freeVars =
332 foldr addFreeVars freeVars tipes
334 do boundVars <- Dups.detect toError (foldr addUnion Dups.none args)
335 let freeVars = foldr addCtorFreeVars Map.empty ctors
336 case Map.toList (Map.difference freeVars boundVars) of
338 Result.ok (length args)
341 let toLoc (arg, region) = A.At region arg in
343 Error.TypeVarsUnboundInUnion unionRegion name (map A.toValue args) (map toLoc unbound)
347checkAliasFreeVars :: Valid.Alias -> Result i [N.Name]
348checkAliasFreeVars (Valid.Alias (A.At aliasRegion name) args tipe) =
350 addAlias (A.At region arg) dict =
351 Dups.insert arg region () region dict
354 Error.DuplicateAliasArg name (map A.toValue args)
356 do boundVars <- Dups.detect toError (foldr addAlias Dups.none args)
357 let freeVars = addFreeVars tipe Map.empty
358 let overlap = Map.size (Map.intersection boundVars freeVars)
359 if Map.size boundVars == overlap && Map.size freeVars == overlap
360 then Result.ok (map A.toValue args)
362 let toLoc (arg, region) = A.At region arg in
364 Error.TypeVarsMessedUpInAlias aliasRegion name
366 (map toLoc (Map.toList (Map.difference boundVars freeVars)))
367 (map toLoc (Map.toList (Map.difference freeVars boundVars)))
370addFreeVars :: Src.Type -> Map.Map N.Name R.Region -> Map.Map N.Name R.Region
371addFreeVars (A.At region tipe) freeVars =
373 Src.TLambda arg result ->
374 addFreeVars arg (addFreeVars result freeVars)
377 Map.insert name region freeVars
379 Src.TType _ _ _ args ->
380 foldr addFreeVars freeVars args
382 Src.TRecord fields Nothing ->
383 foldr addFreeVars freeVars (map snd fields)
385 Src.TRecord fields (Just ext) ->
386 foldr addFreeVars (addFreeVars ext freeVars) (map snd fields)
392 foldr addFreeVars freeVars (a:b:cs)
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