@@ -1,7 +1,9 @@
1{-# OPTIONS_GHC -Wall #-}
1{-# OPTIONS_GHC -Wall #-}
2module Canonicalize.Expression
2module Canonicalize.Expression
3 ( canonicalize
3 ( canonicalize
4− , removeLocals
4+ , FreeLocals
5 , gatherTypedArgs
7 , gatherTypedArgs
@@ -9,7 +11,6 @@ module Canonicalize.Expression
10import qualified Data.Graph as Graph
12import qualified Data.Graph as Graph
11import qualified Data.Map.Strict as Map
13import qualified Data.Map.Strict as Map
12−import qualified Data.Set as Set
14import qualified AST.Canonical as Can
15import qualified AST.Canonical as Can
15import qualified AST.Source as Src
16import qualified AST.Source as Src
@@ -19,34 +20,42 @@ import qualified AST.Valid as Valid
19import qualified Canonicalize.Environment as Env
20import qualified Canonicalize.Environment as Env
20import qualified Canonicalize.Environment.Dups as Dups
21import qualified Canonicalize.Environment.Dups as Dups
21import qualified Canonicalize.Pattern as Pattern
22import qualified Canonicalize.Pattern as Pattern
23+import qualified Canonicalize.Result as Result
22import qualified Canonicalize.Type as Type
24import qualified Canonicalize.Type as Type
23import qualified Data.Bag as Bag
25import qualified Data.Bag as Bag
24import qualified Data.Index as Index
26import qualified Data.Index as Index
27+import qualified Data.OneOrMore as OneOrMore
25import qualified Elm.Name as N
28import qualified Elm.Name as N
26import qualified Reporting.Annotation as A
29import qualified Reporting.Annotation as A
27import qualified Reporting.Error.Canonicalize as Error
30import qualified Reporting.Error.Canonicalize as Error
28import qualified Reporting.Region as R
31import qualified Reporting.Region as R
29−import qualified Reporting.Result as Result
32+import qualified Reporting.Warning as W
30−import qualified Reporting.Warning as Warning
37−type Result i a =
39+type Result i w a =
38− Result.Result i Warning.Warning Error.Error a
40+ Result.Result i w Error.Error a
41type FreeLocals =
43type FreeLocals =
42− Set.Set N.Name
44+ Map.Map N.Name Uses
49+ { _direct :: {-# UNPACK #-} !Int
50+ , _delayed :: {-# UNPACK #-} !Int
49−canonicalize :: Env.Env -> Valid.Expr -> Result FreeLocals Can.Expr
58+canonicalize :: Env.Env -> Valid.Expr -> Result FreeLocals [W.Warning] Can.Expr
50canonicalize env (A.At region expression) =
59canonicalize env (A.At region expression) =
51 A.At region <$>
60 A.At region <$>
52 case expression of
61 case expression of
@@ -63,7 +72,7 @@ canonicalize env (A.At region expression) =
63 Result.ok (Can.Float float)
72 Result.ok (Can.Float float)
65 Valid.Var maybePrefix name ->
74 Valid.Var maybePrefix name ->
66− Env.findVar region env maybePrefix name
75+ findVar region env maybePrefix name
68 Valid.List exprs ->
77 Valid.List exprs ->
69 Can.List <$> traverse (canonicalize env) exprs
78 Can.List <$> traverse (canonicalize env) exprs
@@ -79,13 +88,18 @@ canonicalize env (A.At region expression) =
79 A.drop <$> canonicalizeBinops region env ops final
88 A.drop <$> canonicalizeBinops region env ops final
81 Valid.Lambda srcArgs body ->
90 Valid.Lambda srcArgs body ->
82− addLocals $
91+ delayedUsage $
83− do (args, destructors) <-
92+ do (args, bindings) <-
84 Pattern.verify Error.DPLambdaArgs $
93 Pattern.verify Error.DPLambdaArgs $
85 Index.indexedTraverse (Pattern.canonicalizeArg env) srcArgs
94 Index.indexedTraverse (Pattern.canonicalizeArg env) srcArgs
86− newEnv <- Env.addLocals destructors env
97+ Env.addLocals bindings env
87− removeLocals Warning.Pattern destructors $
98+
99+ (cbody, destructors, freeLocals) <-
100+ verifyBindings W.Pattern bindings (canonicalize newEnv body)
88− Can.Lambda args destructors <$> canonicalize newEnv body
102+ return (Can.Lambda args destructors cbody, freeLocals)
90 Valid.Call func args ->
104 Valid.Call func args ->
@@ -114,13 +128,13 @@ canonicalize env (A.At region expression) =
114 <*> Result.ok field
128 <*> Result.ok field
116 Valid.Update (A.At reg name) fields ->
130 Valid.Update (A.At reg name) fields ->
117− do fieldDict <- Result.untracked $ Dups.checkFields fields
131+ do fieldDict <- Dups.checkFields fields
118− name_ <- Env.findVar reg env Nothing name
132+ name_ <- findVar reg env Nothing name
119 Can.Update (A.At reg name_)
133 Can.Update (A.At reg name_)
120 <$> traverse (canonicalize env) fieldDict
134 <$> traverse (canonicalize env) fieldDict
122 Valid.Record fields ->
136 Valid.Record fields ->
123− do fieldDict <- Result.untracked $ Dups.checkFields fields
137+ do fieldDict <- Dups.checkFields fields
124 Can.Record <$> traverse (canonicalize env) fieldDict
138 Can.Record <$> traverse (canonicalize env) fieldDict
126 Valid.Unit ->
140 Valid.Unit ->
@@ -140,7 +154,7 @@ canonicalize env (A.At region expression) =
140-- CANONICALIZE TUPLE EXTRAS
154-- CANONICALIZE TUPLE EXTRAS
143−canonicalizeTupleExtras :: R.Region -> Env.Env -> [Valid.Expr] -> Result FreeLocals (Maybe Can.Expr)
157+canonicalizeTupleExtras :: R.Region -> Env.Env -> [Valid.Expr] -> Result FreeLocals [W.Warning] (Maybe Can.Expr)
144canonicalizeTupleExtras region env extras =
158canonicalizeTupleExtras region env extras =
145 case extras of
159 case extras of
@@ -151,14 +165,14 @@ canonicalizeTupleExtras region env extras =
152 _ : others ->
166 _ : others ->
153 let (A.At r1 _, A.At r2 _) = (head others, last others) in
167 let (A.At r1 _, A.At r2 _) = (head others, last others) in
154− Result.throw region (Error.TupleLargerThanThree (R.merge r1 r2))
168+ Result.throw (Error.TupleLargerThanThree region (R.merge r1 r2))
158-- CANONICALIZE IF BRANCH
172-- CANONICALIZE IF BRANCH
161−canonicalizeIfBranch :: Env.Env -> (Valid.Expr, Valid.Expr) -> Result FreeLocals (Can.Expr, Can.Expr)
175+canonicalizeIfBranch :: Env.Env -> (Valid.Expr, Valid.Expr) -> Result FreeLocals [W.Warning] (Can.Expr, Can.Expr)
162canonicalizeIfBranch env (condition, branch) =
176canonicalizeIfBranch env (condition, branch) =
164 <$> canonicalize env condition
178 <$> canonicalize env condition
@@ -169,22 +183,25 @@ canonicalizeIfBranch env (condition, branch) =
169-- CANONICALIZE CASE BRANCH
183-- CANONICALIZE CASE BRANCH
172−canonicalizeCaseBranch :: Env.Env -> (Src.Pattern, Valid.Expr) -> Result FreeLocals Can.CaseBranch
186+canonicalizeCaseBranch :: Env.Env -> (Src.Pattern, Valid.Expr) -> Result FreeLocals [W.Warning] Can.CaseBranch
173canonicalizeCaseBranch env (pattern, expr) =
187canonicalizeCaseBranch env (pattern, expr) =
174− addLocals $
188+ directUsage $
175− do (cpattern, destructors) <-
189+ do (cpattern, bindings) <-
176 Pattern.verify Error.DPCaseBranch $
190 Pattern.verify Error.DPCaseBranch $
177 Pattern.canonicalize env Index.first pattern
191 Pattern.canonicalize env Index.first pattern
178− newEnv <- Env.addLocals destructors env
192+ newEnv <- Env.addLocals bindings env
179− removeLocals Warning.Pattern destructors $
193+
194+ (cexpr, destructors, freeLocals) <-
195+ verifyBindings W.Pattern bindings (canonicalize newEnv expr)
180− Can.CaseBranch cpattern destructors <$> canonicalize newEnv expr
197+ return (Can.CaseBranch cpattern destructors cexpr, freeLocals)
184-- CANONICALIZE BINOPS
201-- CANONICALIZE BINOPS
187−canonicalizeBinops :: R.Region -> Env.Env -> [(Valid.Expr, A.Located N.Name)] -> Valid.Expr -> Result FreeLocals Can.Expr
204+canonicalizeBinops :: R.Region -> Env.Env -> [(Valid.Expr, A.Located N.Name)] -> Valid.Expr -> Result FreeLocals [W.Warning] Can.Expr
188canonicalizeBinops overallRegion env ops final =
205canonicalizeBinops overallRegion env ops final =
190 canonicalizeHelp (expr, A.At region op) =
207 canonicalizeHelp (expr, A.At region op) =
@@ -205,7 +222,7 @@ data Step
205 | Error Env.Binop Env.Binop
222 | Error Env.Binop Env.Binop
208−runBinopStepper :: R.Region -> Step -> Result FreeLocals Can.Expr
225+runBinopStepper :: R.Region -> Step -> Result FreeLocals w Can.Expr
209runBinopStepper overallRegion step =
226runBinopStepper overallRegion step =
210 case step of
227 case step of
211 Done expr ->
228 Done expr ->
@@ -219,7 +236,7 @@ runBinopStepper overallRegion step =
219 toBinopStep (toBinop op expr) op rest final
236 toBinopStep (toBinop op expr) op rest final
221 Error (Env.Binop op1 _ _ _ _ _) (Env.Binop op2 _ _ _ _ _) ->
238 Error (Env.Binop op1 _ _ _ _ _) (Env.Binop op2 _ _ _ _ _) ->
222− Result.throw overallRegion (Error.Binop op1 op2)
239+ Result.throw (Error.Binop overallRegion op1 op2)
225toBinopStep :: (Can.Expr -> Can.Expr) -> Env.Binop -> [(Can.Expr, Env.Binop)] -> Can.Expr -> Step
242toBinopStep :: (Can.Expr -> Can.Expr) -> Env.Binop -> [(Can.Expr, Env.Binop)] -> Can.Expr -> Step
@@ -267,57 +284,47 @@ toBinop (Env.Binop op home name annotation _ _) left right =
267-- CANONICALIZE LET
284-- CANONICALIZE LET
270−canonicalizeLet :: R.Region -> Env.Env -> [Valid.Def] -> Valid.Expr -> Result FreeLocals Can.Expr
287+canonicalizeLet :: R.Region -> Env.Env -> [Valid.Def] -> Valid.Expr -> Result FreeLocals [W.Warning] Can.Expr
271canonicalizeLet letRegion env defs body =
288canonicalizeLet letRegion env defs body =
272− addLocals $
289+ directUsage $
273 do let keyedDefs = zip defs [ 0 .. length defs ]
290 do let keyedDefs = zip defs [ 0 .. length defs ]
274− let toError name () () = Error.DuplicatePattern Error.DPLetBinding name
275 let names = foldr addBindings Dups.none keyedDefs
291 let names = foldr addBindings Dups.none keyedDefs
276− boundNames <- Dups.detect toError names
292+ boundNames <- Dups.detect (Error.DuplicatePattern Error.DPLetBinding) names
277 newEnv <- Env.addLocals boundNames env
294 newEnv <- Env.addLocals boundNames env
278 let defKeys = Map.map A.drop boundNames
295 let defKeys = Map.map A.drop boundNames
279− nodes <- traverse (defToNode defKeys newEnv) keyedDefs
280− removeLocals Warning.Binding boundNames $
281− do cbody <- canonicalize env body
282− detectCycles letRegion (Graph.stronglyConnComp nodes) cbody
297+ (nodes, cbody, bindingUses, freeLocals) <-
298+ verifyLetBindings boundNames $
300+ <$> traverse (defToNode defKeys newEnv) keyedDefs
301+ <*> canonicalize newEnv body
285−addLocals :: Result () (expr, FreeLocals) -> Result FreeLocals expr
303+ letExpr <-
286−addLocals (Result.Result () warnings answer) =
304+ detectCycles letRegion bindingUses (Graph.stronglyConnComp nodes) cbody
288− Result.Ok (value, freeLocals) ->
289− Result.Result freeLocals warnings (Result.Ok value)
291− Result.Err err ->
306+ return (letExpr, freeLocals)
292− Result.Result Set.empty warnings (Result.Err err)
295−removeLocals :: Warning.Unused -> Map.Map N.Name (A.Located a) -> Result FreeLocals expr -> Result () (expr, FreeLocals)
309+verifyLetBindings
296−removeLocals unused boundNames (Result.Result freeLocals warnings answer) =
310+ :: Map.Map N.Name (A.Located Int)
297− case answer of
311+ -> Result FreeLocals [W.Warning] ([Node], Can.Expr)
298− Result.Err err ->
312+ -> Result info [W.Warning] ([Node], Can.Expr, FreeLocals, FreeLocals)
299− Result.Result () warnings (Result.Err err)
313+verifyLetBindings bindings (Result.Result k) =
300−
314+ Result.Result $ \info warnings bad good ->
301− Result.Ok value ->
315+ k Map.empty warnings
316+ (\_ warnings1 err ->
317+ bad info warnings1 err
319+ (\freeLocals warnings1 (nodes, body) ->
303− newFreeLocals =
321+ newFreeLocals = Map.difference freeLocals bindings
304− Set.difference freeLocals (Map.keysSet boundNames)
322+ bindingUses = Map.intersection freeLocals bindings
307− -- NOTE: check for unused variables without any large allocations.
308− -- This relies on the fact that Map.size and Set.size are O(1)
309− if Set.size freeLocals - Map.size boundNames == Set.size newFreeLocals then
312− Bag.append warnings $ Bag.fromList (toUnusedWarning unused) $
313− Map.toList (Map.withoutKeys boundNames freeLocals)
315− Result.Result () newWarnings (Result.Ok (value, newFreeLocals))
324+ good info
316−
325+ (addUnusedWarnings W.Def bindings bindingUses warnings1)
317−
326+ (nodes, body, bindingUses, newFreeLocals)
318−toUnusedWarning :: Warning.Unused -> (N.Name, A.Located a) -> A.Located Warning.Warning
327+ )
319−toUnusedWarning unused (name, A.At region _) =
320− A.At region (Warning.UnusedVariable unused name)
@@ -386,71 +393,92 @@ addBindingsHelp key (A.At region pattern) bindings =
386-- BUILD BINDINGS GRAPH
393-- BUILD BINDINGS GRAPH
389−data Node = Node Binding FreeLocals
396+type Node =
397+ (Binding, Int, [Int])
392data Binding
400data Binding
393 = Define R.Region Can.Def
401 = Define R.Region Can.Def
394− | Destruct R.Region Can.Pattern Can.Destructors Can.Expr
402+ | Destruct R.Region Can.Pattern Pattern.Bindings Can.Expr
397−defToNode :: Map.Map N.Name Int -> Env.Env -> (Valid.Def, Int) -> Result () (Node, Int, [Int])
405+defToNode :: Map.Map N.Name Int -> Env.Env -> (Valid.Def, Int) -> Result FreeLocals [W.Warning] Node
398defToNode defKeys env (def, key) =
406defToNode defKeys env (def, key) =
399 case def of
407 case def of
400 Valid.Define region aname@(A.At _ name) srcArgs body Nothing ->
408 Valid.Define region aname@(A.At _ name) srcArgs body Nothing ->
401− do (args, destructors) <-
409+ do (args, argBindings) <-
402 Pattern.verify (Error.DPFuncArgs name) $
410 Pattern.verify (Error.DPFuncArgs name) $
403 Index.indexedTraverse (Pattern.canonicalizeArg env) srcArgs
411 Index.indexedTraverse (Pattern.canonicalizeArg env) srcArgs
404− newEnv <- Env.addLocals destructors env
414+ Env.addLocals argBindings env
405− toNode defKeys key destructors $
415+
416+ (cbody, destructors, freeLocals) <-
406− do cbody <- canonicalize newEnv body
417+ verifyBindings W.Pattern argBindings (canonicalize newEnv body)
407− return $ Define region $
418+
419+ logLetLocals args freeLocals
408− Can.Def aname args destructors cbody
420+ ( Define region (Can.Def aname args destructors cbody)
422+ , Map.elems (Map.intersection defKeys freeLocals)
410 Valid.Destruct region pattern body ->
425 Valid.Destruct region pattern body ->
411− do (cpattern, destructors) <-
426+ do (cpattern, bindings) <-
412 Pattern.verify Error.DPDestruct $
427 Pattern.verify Error.DPDestruct $
413 Pattern.canonicalize env Index.first pattern
428 Pattern.canonicalize env Index.first pattern
415− toNode defKeys key destructors $
430+ Result.Result $ \freeLocals warnings bad good ->
416− Destruct region cpattern destructors <$> canonicalize env body
431+ case canonicalize env body of
433+ k Map.empty warnings
434+ (\_ ws es -> bad freeLocals ws es)
435+ (\newFreeLocals warnings1 cbody ->
437+ (Map.unionWith combineUses freeLocals newFreeLocals)
439+ ( Destruct region cpattern bindings cbody
441+ , Map.elems (Map.intersection defKeys freeLocals)
418 Valid.Define region aname@(A.At _ name) srcArgs body (Just tipe) ->
445 Valid.Define region aname@(A.At _ name) srcArgs body (Just tipe) ->
419 do (Can.Forall freeVars ctipe) <- Type.toAnnotation env tipe
446 do (Can.Forall freeVars ctipe) <- Type.toAnnotation env tipe
420− ((args, resultType), destructors) <-
447+ ((args, resultType), argBindings) <-
421 Pattern.verify (Error.DPFuncArgs name) $
448 Pattern.verify (Error.DPFuncArgs name) $
422 gatherTypedArgs env name srcArgs ctipe Index.first []
449 gatherTypedArgs env name srcArgs ctipe Index.first []
423− newEnv <- Env.addLocals destructors env
424− toNode defKeys key destructors $
425− do cbody <- canonicalize newEnv body
426− return $ Define region $
427− Can.TypedDef aname freeVars args destructors cbody resultType
452+ Env.addLocals argBindings env
430−toNode :: Map.Map N.Name Int -> Int -> Map.Map N.Name a -> Result FreeLocals Binding -> Result () (Node, Int, [Int])
454+ (cbody, destructors, freeLocals) <-
431−toNode defKeys key args (Result.Result freeLocals warnings answer) =
455+ verifyBindings W.Pattern argBindings (canonicalize newEnv body)
432− Result.Result () warnings $
437− Result.Ok binding ->
457+ logLetLocals args freeLocals
438− let
458+ ( Define region (Can.TypedDef aname freeVars args destructors cbody resultType)
439− actuallyFreeLocals = Set.difference freeLocals (Map.keysSet args)
440− locallyDefinedLocals = Map.restrictKeys defKeys freeLocals
443− ( Node binding actuallyFreeLocals
445− , Map.elems locallyDefinedLocals
460+ , Map.elems (Map.intersection defKeys freeLocals)
464+logLetLocals :: [arg] -> FreeLocals -> value -> Result FreeLocals w value
465+logLetLocals args letLocals value =
466+ Result.Result $ \freeLocals warnings _ good ->
468+ ( Map.unionWith combineUses freeLocals $
471+ _ -> Map.map delayUse letLocals
450-- GATHER TYPED ARGS
478-- GATHER TYPED ARGS
453−gatherTypedArgs :: Env.Env -> N.Name -> [Src.Pattern] -> Can.Type -> Index.ZeroBased -> [Can.TypedArg] -> Result Pattern.Bindings ([Can.TypedArg], Can.Type)
481+gatherTypedArgs :: Env.Env -> N.Name -> [Src.Pattern] -> Can.Type -> Index.ZeroBased -> [Can.TypedArg] -> Result Pattern.DupsDict w ([Can.TypedArg], Can.Type)
454gatherTypedArgs env name srcArgs tipe index revTypedArgs =
482gatherTypedArgs env name srcArgs tipe index revTypedArgs =
455 case srcArgs of
483 case srcArgs of
@@ -466,16 +494,16 @@ gatherTypedArgs env name srcArgs tipe index revTypedArgs =
468 let (A.At start _, A.At end _) = (head srcArgs, last srcArgs) in
496 let (A.At start _, A.At end _) = (head srcArgs, last srcArgs) in
469− Result.throw (R.merge start end) $
497+ Result.throw $
470− Error.AnnotationTooShort name index (length srcArgs)
498+ Error.AnnotationTooShort (R.merge start end) name index (length srcArgs)
474-- DETECT CYCLES
502-- DETECT CYCLES
477−detectCycles :: R.Region -> [Graph.SCC Node] -> Can.Expr -> Result FreeLocals Can.Expr
505+detectCycles :: R.Region -> FreeLocals -> [Graph.SCC Binding] -> Can.Expr -> Result i w Can.Expr
478−detectCycles letRegion sccs body =
506+detectCycles letRegion bindingUses sccs body =
479 case sccs of
507 case sccs of
481 Result.ok body
509 Result.ok body
@@ -483,41 +511,45 @@ detectCycles letRegion sccs body =
483 scc : subSccs ->
511 scc : subSccs ->
484 A.At letRegion <$>
512 A.At letRegion <$>
485 case scc of
513 case scc of
486− Graph.AcyclicSCC (Node binding freeLocals) ->
514+ Graph.AcyclicSCC binding ->
487 case binding of
515 case binding of
488 Define _ def ->
516 Define _ def ->
489− Result.accumulate freeLocals (Can.Let def)
517+ Can.Let def
490− <*> detectCycles letRegion subSccs body
518+ <$> detectCycles letRegion bindingUses subSccs body
520+ Destruct _ pattern bindings expr ->
523+ Map.intersectionWith toDestructorInfo bindings bindingUses
525+ Can.LetDestruct pattern destructors expr
526+ <$> detectCycles letRegion bindingUses subSccs body
528+ Graph.CyclicSCC bindings ->
529+ case traverse requireFunction bindings of
532+ <$> detectCycles letRegion bindingUses subSccs body
492− Destruct _ pattern destructors expr ->
493− Result.accumulate freeLocals (Can.LetDestruct pattern destructors expr)
494− <*> detectCycles letRegion subSccs body
496− Graph.CyclicSCC nodes ->
497− case unzip <$> traverse requireFunction nodes of
498 Nothing ->
534 Nothing ->
499− Result.throw letRegion (Error.RecursiveLet (map toCycleNodes nodes))
535+ Result.throw (Error.RecursiveLet letRegion (map toCycleNodes bindings))
501− Just (defs, freeLocals) ->
502− Result.accumulate (Set.unions freeLocals) (Can.LetRec defs)
503− <*> detectCycles letRegion subSccs body
506−requireFunction :: Node -> Maybe (Can.Def, FreeLocals)
538+requireFunction :: Binding -> Maybe Can.Def
507−requireFunction (Node binding freeLocals) =
539+requireFunction binding =
508 case binding of
540 case binding of
509 Define _ def@(Can.Def _ (_:_) _ _) ->
541 Define _ def@(Can.Def _ (_:_) _ _) ->
510− Just (def, freeLocals)
542+ Just def
512 Define _ def@(Can.TypedDef _ _ (_:_) _ _ _) ->
544 Define _ def@(Can.TypedDef _ _ (_:_) _ _ _) ->
513− Just (def, freeLocals)
545+ Just def
519−toCycleNodes :: Node -> Error.CycleNode
551+toCycleNodes :: Binding -> Error.CycleNode
520−toCycleNodes (Node binding _) =
552+toCycleNodes binding =
521 case binding of
553 case binding of
522 Define _ def ->
554 Define _ def ->
523 case def of
555 case def of
@@ -529,3 +561,140 @@ toCycleNodes (Node binding _) =
530 Destruct _ pattern _ _ ->
562 Destruct _ pattern _ _ ->
531 Error.CyclePattern pattern
563 Error.CyclePattern pattern
570+logVar :: N.Name -> a -> Result FreeLocals w a
572+ Result.Result $ \freeLocals warnings _ good ->
573+ good (Map.insertWith combineUses name oneDirectUse freeLocals) warnings value
576+{-# NOINLINE oneDirectUse #-}
582+combineUses :: Uses -> Uses -> Uses
583+combineUses (Uses a b) (Uses x y) =
584+ Uses (a + x) (b + y)
587+delayUse :: Uses -> Uses
588+delayUse (Uses direct delayed) =
589+ Uses 0 (direct + delayed)
599+ -> Result FreeLocals [W.Warning] Can.Expr
600+ -> Result info [W.Warning] (Can.Expr, Can.Destructors, FreeLocals)
601+verifyBindings context bindings (Result.Result k) =
602+ Result.Result $ \info warnings bad good ->
603+ k Map.empty warnings
604+ (\_ warnings1 err ->
605+ bad info warnings1 err
607+ (\freeLocals warnings1 body ->
610+ Map.intersectionWith toDestructorInfo bindings freeLocals
613+ (addUnusedWarnings context bindings destructors warnings1)
614+ (body, destructors, Map.difference freeLocals bindings)
618+toDestructorInfo :: A.Located Can.Destructor -> Uses -> Can.DestructorInfo
619+toDestructorInfo (A.At _ destructor) (Uses direct delayed) =
620+ Can.DestructorInfo destructor direct delayed
623+-- NOTE: Uses Map.size for O(1) lookup. This means there is
624+-- no dictionary allocation unless a problem is detected.
625+addUnusedWarnings :: W.Context -> Map.Map N.Name (A.Located a) -> Map.Map N.Name b -> [W.Warning] -> [W.Warning]
626+addUnusedWarnings context bindings uses warnings =
627+ if Map.size bindings == Map.size uses then
630+ Map.foldlWithKey (addUnusedWarning context) warnings $
631+ Map.difference bindings uses
634+addUnusedWarning :: W.Context -> [W.Warning] -> N.Name -> A.Located a -> [W.Warning]
635+addUnusedWarning context warnings name (A.At region _) =
636+ W.UnusedVariable region context name : warnings
639+directUsage :: Result () w (expr, FreeLocals) -> Result FreeLocals w expr
640+directUsage (Result.Result k) =
641+ Result.Result $ \freeLocals warnings bad good ->
643+ (\() ws es -> bad freeLocals ws es)
644+ (\() ws (value, newFreeLocals) ->
645+ good (Map.unionWith combineUses freeLocals newFreeLocals) ws value
649+delayedUsage :: Result () w (expr, FreeLocals) -> Result FreeLocals w expr
650+delayedUsage (Result.Result k) =
651+ Result.Result $ \freeLocals warnings bad good ->
653+ (\() ws es -> bad freeLocals ws es)
654+ (\() ws (value, newFreeLocals) ->
655+ let delayedLocals = Map.map delayUse newFreeLocals in
656+ good (Map.unionWith combineUses freeLocals delayedLocals) ws value
664+findVar :: R.Region -> Env.Env -> Maybe N.Name -> N.Name -> Result FreeLocals w Can.Expr_
665+findVar region (Env.Env localHome vars _ _ _) maybePrefix name =
666+ case Map.lookup name vars of
668+ Result.throw (error "TODO no name" region)
670+ Just (Env.VarHomes unqualified qualified) ->
675+ logVar name (Can.VarLocal name)
678+ logVar name (Can.VarTopLevel localHome name)
682+ Bag.One (Env.ForeignVarHome home annotation) ->
683+ Result.ok (Can.VarForeign home name annotation)
686+ Result.throw (error "TODO no unqualified" region)
689+ Result.throw (error "TODO ambiguous unqualified" region)
692+ case Map.lookup prefix qualified of
694+ Result.throw (error "TODO no qualified" region)
696+ Just (OneOrMore.One (Env.ForeignVarHome home annotation)) ->
697+ Result.ok (Can.VarForeign home name annotation)
700+ Result.throw (error "TODO ambiguous qualified" region)