@@ -1,331 +1,205 @@
1{-# OPTIONS_GHC -Wall #-}
1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Canonicalize.Environment.Local
3module Canonicalize.Environment.Local
4− ( addVarsAndTypes
4+ ( add
10−import Control.Applicative (liftA2)
11import Control.Monad (foldM)
9import Control.Monad (foldM)
12import qualified Data.Graph as Graph
10import qualified Data.Graph as Graph
11+import qualified Data.List as List
13import qualified Data.Map.Strict as Map
12import qualified Data.Map.Strict as Map
14−import qualified Data.Map.Merge.Strict as Map
16import qualified AST.Canonical as Can
14import qualified AST.Canonical as Can
17import qualified AST.Source as Src
15import qualified AST.Source as Src
18import qualified AST.Valid as Valid
16import qualified AST.Valid as Valid
17+import qualified AST.Module.Name as ModuleName
19import qualified Canonicalize.Environment as Env
18import qualified Canonicalize.Environment as Env
20import qualified Canonicalize.Environment.Dups as Dups
19import qualified Canonicalize.Environment.Dups as Dups
21import qualified Canonicalize.Type as Type
20import qualified Canonicalize.Type as Type
22−import qualified Data.Bag as Bag
23import qualified Data.Index as Index
21import qualified Data.Index as Index
22+import qualified Data.OneOrMore as OneOrMore
24import qualified Elm.Name as N
23import qualified Elm.Name as N
25import qualified Reporting.Annotation as A
24import qualified Reporting.Annotation as A
26import qualified Reporting.Error.Canonicalize as Error
25import qualified Reporting.Error.Canonicalize as Error
27import qualified Reporting.Region as R
26import qualified Reporting.Region as R
28import qualified Reporting.Result as Result
27import qualified Reporting.Result as Result
29−import qualified Reporting.Warning as Warning
36−type Result i a =
34+type Result i w a =
37− Result.Result i [Warning.Warning] Error.Error a
35+ Result.Result i w Error.Error a
38+type Unions = Map.Map N.Name Can.Union
39+type Aliases = Map.Map N.Name Can.Alias
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.
50−addVarsAndTypes :: Valid.Module -> Env.Env -> Result i Env.Env
42+add :: Valid.Module -> Env.Env -> Result i w (Env.Env, Unions, Aliases)
51−addVarsAndTypes module_ env =
43+add module_ env =
52− addVars module_ =<< addTypes module_ env
44+ addCtors module_ =<< 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
61−merge 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.
83−addPatterns :: Map.Map N.Name Can.Union -> Env.Env -> Env.Env
84−addPatterns 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
109-- ADD VARS
48-- ADD VARS
112−addVars :: Valid.Module -> Env.Env -> Result i Env.Env
51+addVars :: Valid.Module -> Env.Env -> Result i w Env.Env
113−addVars module_ (Env.Env home vars types patterns binops) =
52+addVars module_ (Env.Env home vs ts cs bs qvs qts qcs) =
114− do upperDict <- collectUpperVars module_
53+ do topLevelVars <- collectVars module_
115− lowerDict <- collectLowerVars module_
54+ let vs2 = Map.union topLevelVars vs
116− let varDict = Map.union upperDict lowerDict
55+ -- Use union to overwrite foreign stuff.
117− let newVars = addVarsHelp varDict vars
56+ Result.ok $ Env.Env home vs2 ts cs bs qvs qts qcs
118− return $ Env.Env home newVars types patterns binops
121−addVarsHelp :: Map.Map N.Name R.Region -> Map.Map N.Name Env.VarHomes -> Map.Map N.Name Env.VarHomes
59+collectVars :: Valid.Module -> Result i w (Map.Map N.Name Env.Var)
122−addVarsHelp localVars vars =
60+collectVars (Valid.Module _ _ _ _ _ decls _ _ _ effects) =
124− addLeft _ region =
62+ addDecl dict (A.At _ (Valid.Decl (A.At region name) _ _ _)) =
125− Env.VarHomes (Env.TopLevel region) Map.empty
127− addBoth _ region (Env.VarHomes _ qualified) =
128− Env.VarHomes (Env.TopLevel region) qualified
63+ Dups.insert name region (Env.TopLevel region) dict
130− merge addLeft addBoth localVars vars
65+ Dups.detect Error.DuplicateDecl $
131−
66+ List.foldl' addDecl (toEffectDups effects) decls
133−collectLowerVars :: Valid.Module -> Result i (Map.Map N.Name R.Region)
134−collectLowerVars (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
142− effectDict =
69+toEffectDups :: Valid.Effects -> Dups.Dict Env.Var
70+toEffectDups effects =
143− case effects of
71+ case effects of
144− Valid.NoEffects ->
72+ Valid.NoEffects ->
145− Dups.none
73+ Dups.none
147− Valid.Ports ports ->
75+ Valid.Ports ports ->
77+ addPort dict (Valid.Port (A.At region name) _) =
78+ Dups.insert name region (Env.TopLevel region) dict
148− foldr addPort Dups.none ports
80+ List.foldl' addPort Dups.none ports
150− Valid.Manager _ manager ->
82+ Valid.Manager _ manager ->
151− case manager of
83+ case manager of
152− Valid.Cmd (A.At region _) ->
84+ Valid.Cmd (A.At region _) ->
153− Dups.one "command" region region
85+ Dups.one "command" region (Env.TopLevel region)
155− Valid.Sub (A.At region _) ->
87+ Valid.Sub (A.At region _) ->
156− Dups.one "subscription" region region
88+ Dups.one "subscription" region (Env.TopLevel region)
158− Valid.Fx (A.At regionCmd _) (A.At regionSub _) ->
90+ Valid.Fx (A.At regionCmd _) (A.At regionSub _) ->
159− Dups.union
91+ Dups.union
160− (Dups.one "command" regionCmd regionCmd)
92+ (Dups.one "command" regionCmd (Env.TopLevel regionCmd))
161− (Dups.one "subscription" regionSub regionSub)
93+ (Dups.one "subscription" regionSub (Env.TopLevel regionSub))
163− Dups.detect Error.DuplicateDecl $ foldr addDecl effectDict decls
166−collectUpperVars :: Valid.Module -> Result i (Map.Map N.Name R.Region)
167−collectUpperVars (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
188-- ADD TYPES
97-- ADD TYPES
191−addTypes :: Valid.Module -> Env.Env -> Result i Env.Env
100+addTypes :: Valid.Module -> Env.Env -> Result i w Env.Env
192−addTypes (Valid.Module _ _ _ _ _ _ unions aliases _ _) env =
101+addTypes (Valid.Module _ _ _ _ _ _ unions aliases _ _) (Env.Env home vs ts cs bs qvs qts qcs) =
194− aliasToDict alias@(Valid.Alias (A.At region name) _ tipe) =
103+ addAliasDups dups (Valid.Alias (A.At region name) _ _) = Dups.insert name region () dups
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) _ _) =
104+ addUnionDups dups (Valid.Union (A.At region name) _ _) = Dups.insert name region () dups
199− do arity <- checkUnionFreeVars union
105+ typeNameDups =
200− return $ Dups.one name region (Right arity)
106+ List.foldl' addUnionDups (List.foldl' addAliasDups Dups.none aliases) unions
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
108+ do _ <- Dups.detect Error.DuplicateType typeNameDups
210− let (aliasDict, unionDict) = Map.mapEither id types
109+ ts1 <- foldM (addUnion home) ts unions
211− addTypeAliases aliasDict (addUnionTypes unionDict env)
110+ addAliases aliases (Env.Env home vs ts1 cs bs qvs qts qcs)
214−addUnionTypes :: Map.Map N.Name Int -> Env.Env -> Env.Env
215−addUnionTypes 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) =
113+addUnion :: ModuleName.Canonical -> Env.Exposed Env.Type -> Valid.Union -> Result i w (Env.Exposed Env.Type)
221− Env.Homes (Bag.one (Env.Union arity home)) qualified
114+addUnion home types union@(Valid.Union (A.At _ name) _ _) =
222−
115+ do arity <- checkUnionFreeVars union
223− newTypes =
116+ let one = OneOrMore.one (Env.Union arity home)
224− merge addLeft addBoth unions types
117+ Result.ok $ Map.insertWith OneOrMore.more name one types
226− Env.Env home vars newTypes patterns binops
230-- ADD TYPE ALIASES
121-- ADD TYPE ALIASES
235− { _region :: R.Region
242−addTypeAliases :: Map.Map N.Name Alias -> Env.Env -> Result i Env.Env
124+addAliases :: [Valid.Alias] -> Env.Env -> Result i w Env.Env
243−addTypeAliases aliases env =
125+addAliases aliases env =
244− do let nodes = map toNode (Map.elems aliases)
127+ nodes = map toNode aliases
245− let sccs = Graph.stronglyConnComp nodes
128+ sccs = Graph.stronglyConnComp nodes
246− foldM addTypeAlias env sccs
130+ foldM addAlias env sccs
249−addTypeAlias :: Env.Env -> Graph.SCC Alias -> Result i Env.Env
133+addAlias :: Env.Env -> Graph.SCC Valid.Alias -> Result i w Env.Env
250−addTypeAlias env@(Env.Env home vars types patterns binops) scc =
134+addAlias env@(Env.Env home vs ts cs bs qvs qts qcs) scc =
251 case scc of
135 case scc of
252− Graph.AcyclicSCC (Alias _ name args tipe) ->
136+ Graph.AcyclicSCC alias@(Valid.Alias (A.At _ name) _ tipe) ->
137+ do args <- checkAliasFreeVars alias
253− do ctype <- Type.canonicalize env tipe
138+ ctype <- Type.canonicalize env tipe
254− let info = Env.Alias (length args) home args ctype
139+ let one = OneOrMore.one (Env.Alias (length args) home args ctype)
255− let newTypes = Map.alter (addAliasInfo info) name types
140+ let ts1 = Map.insertWith OneOrMore.more name one ts
256− return $ Env.Env home vars newTypes patterns binops
141+ Result.ok $ Env.Env home vs ts1 cs bs qvs qts qcs
258 Graph.CyclicSCC [] ->
143 Graph.CyclicSCC [] ->
259 Result.ok env
144 Result.ok env
261− Graph.CyclicSCC (Alias region name1 args tipe : others) ->
146+ Graph.CyclicSCC (alias@(Valid.Alias (A.At region name1) _ tipe) : others) ->
147+ do args <- checkAliasFreeVars alias
262− let toName (Alias _ name _ _) = name in
148+ let toName (Valid.Alias (A.At _ name) _ _) = name
263− Result.throw (Error.RecursiveAlias region name1 args tipe (map toName others))
149+ Result.throw (Error.RecursiveAlias region name1 args tipe (map toName others))
266−addAliasInfo :: a -> Maybe (Env.Homes a) -> Maybe (Env.Homes a)
267−addAliasInfo 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
153-- DETECT TYPE ALIAS CYCLES
281−toNode :: Alias -> ( Alias, N.Name, [N.Name] )
156+toNode :: Valid.Alias -> (Valid.Alias, N.Name, [N.Name])
282−toNode alias@(Alias _ name _ tipe) =
157+toNode alias@(Valid.Alias (A.At _ name) _ tipe) =
283− ( alias, name, Bag.toList (getEdges tipe) )
158+ ( alias, name, getEdges [] tipe )
286−getEdges :: Src.Type -> Bag.Bag N.Name
161+getEdges :: [N.Name] -> Src.Type -> [N.Name]
287−getEdges (A.At _ tipe) =
162+getEdges edges (A.At _ tipe) =
288 case tipe of
163 case tipe of
289 Src.TLambda arg result ->
164 Src.TLambda arg result ->
290− Bag.append (getEdges arg) (getEdges result)
165+ getEdges (getEdges edges arg) result
292 Src.TVar _ ->
167 Src.TVar _ ->
170+ Src.TType _ name args ->
171+ List.foldl' getEdges (name:edges) args
295− Src.TType _ Nothing name args ->
173+ Src.TTypeQual _ _ _ args ->
296− foldr Bag.append (Bag.one name) (map getEdges args)
174+ List.foldl' getEdges edges args
298− Src.TType _ (Just _) _ args ->
176+ Src.TRecord fields Nothing ->
299− foldr Bag.append Bag.empty (map getEdges args)
177+ List.foldl' (\es (_,t) -> getEdges es t) edges fields
301− Src.TRecord fields ext ->
179+ Src.TRecord fields (Just ext) ->
303− (maybe Bag.empty getEdges ext)
304− (map (getEdges . snd) fields)
180+ List.foldl' (\es (_,t) -> getEdges es t) (getEdges edges ext) fields
306 Src.TUnit ->
182 Src.TUnit ->
309 Src.TTuple a b cs ->
185 Src.TTuple a b cs ->
310− foldr Bag.append
186+ List.foldl' getEdges (getEdges (getEdges edges a) b) cs
312− (getEdges b : map getEdges cs)
316-- CHECK FREE VARIABLES
190-- CHECK FREE VARIABLES
319−checkUnionFreeVars :: Valid.Union -> Result i Int
193+checkUnionFreeVars :: Valid.Union -> Result i w Int
320checkUnionFreeVars (Valid.Union (A.At unionRegion name) args ctors) =
194checkUnionFreeVars (Valid.Union (A.At unionRegion name) args ctors) =
322− addUnion (A.At region arg) dict =
196+ addArg (A.At region arg) dict =
323 Dups.insert arg region region dict
197 Dups.insert arg region region dict
325 addCtorFreeVars (_, tipes) freeVars =
199 addCtorFreeVars (_, tipes) freeVars =
326− foldr addFreeVars freeVars tipes
200+ List.foldl' addFreeVars freeVars tipes
328− do boundVars <- Dups.detect (Error.DuplicateUnionArg name) (foldr addUnion Dups.none args)
202+ do boundVars <- Dups.detect (Error.DuplicateUnionArg name) (foldr addArg Dups.none args)
329 let freeVars = foldr addCtorFreeVars Map.empty ctors
203 let freeVars = foldr addCtorFreeVars Map.empty ctors
330 case Map.toList (Map.difference freeVars boundVars) of
204 case Map.toList (Map.difference freeVars boundVars) of
@@ -337,15 +211,14 @@ checkUnionFreeVars (Valid.Union (A.At unionRegion name) args ctors) =
337 Error.TypeVarsUnboundInUnion unionRegion name (map A.toValue args) (map toLoc unbound)
211 Error.TypeVarsUnboundInUnion unionRegion name (map A.toValue args) (map toLoc unbound)
341−checkAliasFreeVars :: Valid.Alias -> Result i [N.Name]
214+checkAliasFreeVars :: Valid.Alias -> Result i w [N.Name]
342checkAliasFreeVars (Valid.Alias (A.At aliasRegion name) args tipe) =
215checkAliasFreeVars (Valid.Alias (A.At aliasRegion name) args tipe) =
344− addAlias (A.At region arg) dict =
217+ addArg (A.At region arg) dict =
345 Dups.insert arg region region dict
218 Dups.insert arg region region dict
347− do boundVars <- Dups.detect (Error.DuplicateAliasArg name) (foldr addAlias Dups.none args)
220+ do boundVars <- Dups.detect (Error.DuplicateAliasArg name) (foldr addArg Dups.none args)
348− let freeVars = addFreeVars tipe Map.empty
221+ let freeVars = addFreeVars Map.empty tipe
349 let overlap = Map.size (Map.intersection boundVars freeVars)
222 let overlap = Map.size (Map.intersection boundVars freeVars)
350 if Map.size boundVars == overlap && Map.size freeVars == overlap
223 if Map.size boundVars == overlap && Map.size freeVars == overlap
351 then Result.ok (map A.toValue args)
224 then Result.ok (map A.toValue args)
@@ -358,26 +231,125 @@ checkAliasFreeVars (Valid.Alias (A.At aliasRegion name) args tipe) =
358 (map toLoc (Map.toList (Map.difference freeVars boundVars)))
231 (map toLoc (Map.toList (Map.difference freeVars boundVars)))
361−addFreeVars :: Src.Type -> Map.Map N.Name R.Region -> Map.Map N.Name R.Region
234+addFreeVars :: Map.Map N.Name R.Region -> Src.Type -> Map.Map N.Name R.Region
362−addFreeVars (A.At region tipe) freeVars =
235+addFreeVars freeVars (A.At region tipe) =
363 case tipe of
236 case tipe of
364 Src.TLambda arg result ->
237 Src.TLambda arg result ->
365− addFreeVars arg (addFreeVars result freeVars)
238+ addFreeVars (addFreeVars freeVars arg) result
367 Src.TVar name ->
240 Src.TVar name ->
368 Map.insert name region freeVars
241 Map.insert name region freeVars
370− Src.TType _ _ _ args ->
243+ Src.TType _ _ args ->
244+ List.foldl' addFreeVars freeVars args
246+ Src.TTypeQual _ _ _ args ->
371− foldr addFreeVars freeVars args
247+ List.foldl' addFreeVars freeVars args
373 Src.TRecord fields Nothing ->
249 Src.TRecord fields Nothing ->
374− foldr addFreeVars freeVars (map snd fields)
250+ List.foldl' (\fvs (_,t) -> addFreeVars fvs t) freeVars fields
376 Src.TRecord fields (Just ext) ->
252 Src.TRecord fields (Just ext) ->
377− foldr addFreeVars (addFreeVars ext freeVars) (map snd fields)
253+ List.foldl' (\fvs (_,t) -> addFreeVars fvs t) (addFreeVars freeVars ext) fields
379 Src.TUnit ->
255 Src.TUnit ->
382 Src.TTuple a b cs ->
258 Src.TTuple a b cs ->
383− foldr addFreeVars freeVars (a:b:cs)
259+ List.foldl' addFreeVars (addFreeVars (addFreeVars freeVars a) b) cs
266+addCtors :: Valid.Module -> Env.Env -> Result i w (Env.Env, Unions, Aliases)
267+addCtors (Valid.Module _ _ _ _ _ _ unions aliases _ _) env@(Env.Env home vs ts cs bs qvs qts qcs) =
268+ do unionInfo <- traverse (canonicalizeUnion env) unions
269+ aliasInfo <- traverse (canonicalizeAlias env) aliases
272+ Dups.detect Error.DuplicateCtor $
274+ (Dups.unions (map snd unionInfo))
275+ (Dups.unions (map snd aliasInfo))
277+ let cs2 = Map.unionWith OneOrMore.more cs ctors
280+ ( Env.Env home vs ts cs2 bs qvs qts qcs
281+ , Map.fromList (map fst unionInfo)
282+ , Map.fromList (map fst aliasInfo)
286+type CtorDups = Dups.Dict (OneOrMore.OneOrMore Env.Ctor)
290+-- CANONICALIZE ALIAS
293+canonicalizeAlias :: Env.Env -> Valid.Alias -> Result i w ( (N.Name, Can.Alias), CtorDups )
294+canonicalizeAlias env@(Env.Env home _ _ _ _ _ _ _) (Valid.Alias (A.At region name) args tipe) =
296+ A.At _ (Src.TRecord fields Nothing) ->
297+ do cfields <- traverse (traverse (Type.canonicalize env)) fields
298+ fieldDict <- Dups.checkFields cfields
300+ let recordType = Can.TRecord fieldDict Nothing
301+ let ctorType = foldr (Can.TLambda . snd) recordType cfields
302+ let vars = map A.toValue args
303+ let alias = Can.Alias vars recordType (Just (map (A.toValue . fst) fields))
304+ let ctor = Env.RecordCtor home vars ctorType
308+ , Dups.one name region (OneOrMore.one ctor)
312+ do ctipe <- Type.canonicalize env tipe
314+ ( (name, Can.Alias (map A.toValue args) ctipe Nothing)
320+-- CANONICALIZE UNION
323+canonicalizeUnion :: Env.Env -> Valid.Union -> Result i w ( (N.Name, Can.Union), CtorDups )
324+canonicalizeUnion env@(Env.Env home _ _ _ _ _ _ _) (Valid.Union (A.At _ name) avars ctors) =
325+ do cctors <- Index.indexedTraverse (canonicalizeCtor env) ctors
326+ let vars = map A.toValue avars
327+ let alts = map A.toValue cctors
328+ let union = Can.Union vars alts (length alts) (toOpts ctors)
331+ , Dups.unions $ map (toCtor home name union) cctors
335+canonicalizeCtor :: Env.Env -> Index.ZeroBased -> (A.Located N.Name, [Src.Type]) -> Result i w (A.Located Can.Ctor)
336+canonicalizeCtor env index (A.At region ctor, tipes) =
337+ do ctipes <- traverse (Type.canonicalize env) tipes
338+ Result.ok $ A.At region $
339+ Can.Ctor ctor index (length ctipes) ctipes
342+toOpts :: [(A.Located N.Name, [Src.Type])] -> Can.CtorOpts
349+ if all (null . snd) ctors then Can.Enum else Can.Normal
352+toCtor :: ModuleName.Canonical -> N.Name -> Can.Union -> A.Located Can.Ctor -> CtorDups
353+toCtor home typeName union (A.At region (Can.Ctor name index _ args)) =
354+ Dups.one name region $ OneOrMore.one $
355+ Env.Ctor home typeName union index args