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 R.Region -> Map.Map N.Name Env.VarHomes -> Map.Map N.Name Env.VarHomes
122addVarsHelp localVars vars =
125 Env.VarHomes (Env.TopLevel region) Map.empty
127 addBoth _ region (Env.VarHomes _ qualified) =
128 Env.VarHomes (Env.TopLevel region) qualified
130 merge addLeft addBoth localVars vars
133collectLowerVars :: Valid.Module -> Result i (Map.Map N.Name R.Region)
134collectLowerVars (Valid.Module _ _ _ _ _ decls _ _ _ effects) =
136 addDecl (A.At _ (Valid.Decl (A.At region name) _ _ _)) dict =
137 Dups.insert name region region dict
139 addPort (Valid.Port (A.At region name) _) dict =
140 Dups.insert name region region dict
148 foldr addPort Dups.none ports
150 Valid.Manager _ manager ->
152 Valid.Cmd (A.At region _) ->
153 Dups.one "command" region region
155 Valid.Sub (A.At region _) ->
156 Dups.one "subscription" region region
158 Valid.Fx (A.At regionCmd _) (A.At regionSub _) ->
160 (Dups.one "command" regionCmd regionCmd)
161 (Dups.one "subscription" regionSub regionSub)
163 Dups.detect Error.DuplicateDecl $ foldr addDecl effectDict decls
166collectUpperVars :: Valid.Module -> Result i (Map.Map N.Name R.Region)
167collectUpperVars (Valid.Module _ _ _ _ _ _ unions aliases _ _) =
169 addUnion (Valid.Union _ _ ctors) dict =
170 foldr addCtor dict ctors
172 addCtor (A.At region name, _args) dict =
173 Dups.insert name region region dict
175 addAlias (Valid.Alias (A.At region name) _ (A.At _ tipe)) dict =
177 Src.TRecord _ Nothing ->
178 Dups.insert name region region dict
183 Dups.detect Error.DuplicateCtor $
184 foldr addAlias (foldr addUnion Dups.none unions) aliases
191addTypes :: Valid.Module -> Env.Env -> Result i Env.Env
192addTypes (Valid.Module _ _ _ _ _ _ unions aliases _ _) env =
194 aliasToDict alias@(Valid.Alias (A.At region name) _ tipe) =
195 do args <- checkAliasFreeVars alias
196 return $ Dups.one name region (Left (Alias region name args tipe))
198 unionToDict union@(Valid.Union (A.At region name) _ _) =
199 do arity <- checkUnionFreeVars union
200 return $ Dups.one name region (Right arity)
202 combineDicts dicts1 dicts2 =
203 Dups.union (Dups.unions dicts1) (Dups.unions dicts2)
207 (traverse aliasToDict aliases)
208 (traverse unionToDict unions)
209 types <- Dups.detect Error.DuplicateType dict
210 let (aliasDict, unionDict) = Map.mapEither id types
211 addTypeAliases aliasDict (addUnionTypes unionDict env)
214addUnionTypes :: Map.Map N.Name Int -> Env.Env -> Env.Env
215addUnionTypes unions (Env.Env home vars types patterns binops) =
218 Env.Homes (Bag.one (Env.Union arity home)) Map.empty
220 addBoth _ arity (Env.Homes _ qualified) =
221 Env.Homes (Bag.one (Env.Union arity home)) qualified
224 merge addLeft addBoth unions types
226 Env.Env home vars newTypes patterns binops
235 { _region :: R.Region
242addTypeAliases :: Map.Map N.Name Alias -> Env.Env -> Result i Env.Env
243addTypeAliases aliases env =
244 do let nodes = map toNode (Map.elems aliases)
245 let sccs = Graph.stronglyConnComp nodes
246 foldM addTypeAlias env sccs
249addTypeAlias :: Env.Env -> Graph.SCC Alias -> Result i Env.Env
250addTypeAlias env@(Env.Env home vars types patterns binops) scc =
252 Graph.AcyclicSCC (Alias _ name args tipe) ->
253 do ctype <- Type.canonicalize env tipe
254 let info = Env.Alias (length args) home args ctype
255 let newTypes = Map.alter (addAliasInfo info) name types
256 return $ Env.Env home vars newTypes patterns binops
258 Graph.CyclicSCC [] ->
261 Graph.CyclicSCC (Alias region name1 args tipe : others) ->
262 let toName (Alias _ name _ _) = name in
263 Result.throw (Error.RecursiveAlias region name1 args tipe (map toName others))
266addAliasInfo :: a -> Maybe (Env.Homes a) -> Maybe (Env.Homes a)
267addAliasInfo info maybeHomes =
271 Env.Homes (Bag.one info) Map.empty
273 Just (Env.Homes _ qualified) ->
274 Env.Homes (Bag.one info) qualified
278-- DETECT TYPE ALIAS CYCLES
281toNode :: Alias -> ( Alias, N.Name, [N.Name] )
282toNode alias@(Alias _ name _ tipe) =
283 ( alias, name, Bag.toList (getEdges tipe) )
286getEdges :: Src.Type -> Bag.Bag N.Name
287getEdges (A.At _ tipe) =
289 Src.TLambda arg result ->
290 Bag.append (getEdges arg) (getEdges result)
295 Src.TType _ Nothing name args ->
296 foldr Bag.append (Bag.one name) (map getEdges args)
298 Src.TType _ (Just _) _ args ->
299 foldr Bag.append Bag.empty (map getEdges args)
301 Src.TRecord fields ext ->
303 (maybe Bag.empty getEdges ext)
304 (map (getEdges . snd) fields)
312 (getEdges b : map getEdges cs)
316-- CHECK FREE VARIABLES
319checkUnionFreeVars :: Valid.Union -> Result i Int
320checkUnionFreeVars (Valid.Union (A.At unionRegion name) args ctors) =
322 addUnion (A.At region arg) dict =
323 Dups.insert arg region region dict
325 addCtorFreeVars (_, tipes) freeVars =
326 foldr addFreeVars freeVars tipes
328 do boundVars <- Dups.detect (Error.DuplicateUnionArg name) (foldr addUnion Dups.none args)
329 let freeVars = foldr addCtorFreeVars Map.empty ctors
330 case Map.toList (Map.difference freeVars boundVars) of
332 Result.ok (length args)
335 let toLoc (arg, region) = A.At region arg in
337 Error.TypeVarsUnboundInUnion unionRegion name (map A.toValue args) (map toLoc unbound)
341checkAliasFreeVars :: Valid.Alias -> Result i [N.Name]
342checkAliasFreeVars (Valid.Alias (A.At aliasRegion name) args tipe) =
344 addAlias (A.At region arg) dict =
345 Dups.insert arg region region dict
347 do boundVars <- Dups.detect (Error.DuplicateAliasArg name) (foldr addAlias Dups.none args)
348 let freeVars = addFreeVars tipe Map.empty
349 let overlap = Map.size (Map.intersection boundVars freeVars)
350 if Map.size boundVars == overlap && Map.size freeVars == overlap
351 then Result.ok (map A.toValue args)
353 let toLoc (arg, region) = A.At region arg in
355 Error.TypeVarsMessedUpInAlias aliasRegion name
357 (map toLoc (Map.toList (Map.difference boundVars freeVars)))
358 (map toLoc (Map.toList (Map.difference freeVars boundVars)))
361addFreeVars :: Src.Type -> Map.Map N.Name R.Region -> Map.Map N.Name R.Region
362addFreeVars (A.At region tipe) freeVars =
364 Src.TLambda arg result ->
365 addFreeVars arg (addFreeVars result freeVars)
368 Map.insert name region freeVars
370 Src.TType _ _ _ args ->
371 foldr addFreeVars freeVars args
373 Src.TRecord fields Nothing ->
374 foldr addFreeVars freeVars (map snd fields)
376 Src.TRecord fields (Just ext) ->
377 foldr addFreeVars (addFreeVars ext freeVars) (map snd fields)
383 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