@@ -1,7 +1,9 @@
11{-# OPTIONS_GHC -Wall #-}
22module Canonicalize.Expression
33 ( canonicalize
4− , removeLocals
4+ , FreeLocals
5+ , Uses(..)
6+ , verifyBindings
57 , gatherTypedArgs
68 )
79 where
@@ -9,7 +11,6 @@ module Canonicalize.Expression
911
1012import qualified Data.Graph as Graph
1113import qualified Data.Map.Strict as Map
12−import qualified Data.Set as Set
1314
1415import qualified AST.Canonical as Can
1516import qualified AST.Source as Src
@@ -19,34 +20,42 @@ import qualified AST.Valid as Valid
1920import qualified Canonicalize.Environment as Env
2021import qualified Canonicalize.Environment.Dups as Dups
2122import qualified Canonicalize.Pattern as Pattern
23+import qualified Canonicalize.Result as Result
2224import qualified Canonicalize.Type as Type
2325import qualified Data.Bag as Bag
2426import qualified Data.Index as Index
27+import qualified Data.OneOrMore as OneOrMore
2528import qualified Elm.Name as N
2629import qualified Reporting.Annotation as A
2730import qualified Reporting.Error.Canonicalize as Error
2831import qualified Reporting.Region as R
29−import qualified Reporting.Result as Result
30−import qualified Reporting.Warning as Warning
32+import qualified Reporting.Warning as W
3133
3234
3335
3436-- RESULTS
3537
3638
37−type Result i a =
38− Result.Result i Warning.Warning Error.Error a
39+type Result i w a =
40+ Result.Result i w Error.Error a
3941
4042
4143type FreeLocals =
42− Set.Set N.Name
44+ Map.Map N.Name Uses
4345
4446
47+data Uses =
48+ Uses
49+ { _direct :: {-# UNPACK #-} !Int
50+ , _delayed :: {-# UNPACK #-} !Int
51+ }
4552
46−-- EXPRESSIONS
4753
4854
49−canonicalize :: Env.Env -> Valid.Expr -> Result FreeLocals Can.Expr
55+-- CANONICALIZE
56+
57+
58+canonicalize :: Env.Env -> Valid.Expr -> Result FreeLocals [W.Warning] Can.Expr
5059canonicalize env (A.At region expression) =
5160 A.At region <$>
5261 case expression of
@@ -63,7 +72,7 @@ canonicalize env (A.At region expression) =
6372 Result.ok (Can.Float float)
6473
6574 Valid.Var maybePrefix name ->
66− Env.findVar region env maybePrefix name
75+ findVar region env maybePrefix name
6776
6877 Valid.List exprs ->
6978 Can.List <$> traverse (canonicalize env) exprs
@@ -79,13 +88,18 @@ canonicalize env (A.At region expression) =
7988 A.drop <$> canonicalizeBinops region env ops final
8089
8190 Valid.Lambda srcArgs body ->
82− addLocals $
83− do (args, destructors) <-
91+ delayedUsage $
92+ do (args, bindings) <-
8493 Pattern.verify Error.DPLambdaArgs $
8594 Index.indexedTraverse (Pattern.canonicalizeArg env) srcArgs
86− newEnv <- Env.addLocals destructors env
87− removeLocals Warning.Pattern destructors $
88− Can.Lambda args destructors <$> canonicalize newEnv body
95+
96+ newEnv <-
97+ Env.addLocals bindings env
98+
99+ (cbody, destructors, freeLocals) <-
100+ verifyBindings W.Pattern bindings (canonicalize newEnv body)
101+
102+ return (Can.Lambda args destructors cbody, freeLocals)
89103
90104 Valid.Call func args ->
91105 Can.Call
@@ -114,13 +128,13 @@ canonicalize env (A.At region expression) =
114128 <*> Result.ok field
115129
116130 Valid.Update (A.At reg name) fields ->
117− do fieldDict <- Result.untracked $ Dups.checkFields fields
118− name_ <- Env.findVar reg env Nothing name
131+ do fieldDict <- Dups.checkFields fields
132+ name_ <- findVar reg env Nothing name
119133 Can.Update (A.At reg name_)
120134 <$> traverse (canonicalize env) fieldDict
121135
122136 Valid.Record fields ->
123− do fieldDict <- Result.untracked $ Dups.checkFields fields
137+ do fieldDict <- Dups.checkFields fields
124138 Can.Record <$> traverse (canonicalize env) fieldDict
125139
126140 Valid.Unit ->
@@ -140,7 +154,7 @@ canonicalize env (A.At region expression) =
140154-- CANONICALIZE TUPLE EXTRAS
141155
142156
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)
144158canonicalizeTupleExtras region env extras =
145159 case extras of
146160 [] ->
@@ -151,14 +165,14 @@ canonicalizeTupleExtras region env extras =
151165
152166 _ : others ->
153167 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))
155169
156170
157171
158172-- CANONICALIZE IF BRANCH
159173
160174
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)
162176canonicalizeIfBranch env (condition, branch) =
163177 (,)
164178 <$> canonicalize env condition
@@ -169,22 +183,25 @@ canonicalizeIfBranch env (condition, branch) =
169183-- CANONICALIZE CASE BRANCH
170184
171185
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
173187canonicalizeCaseBranch env (pattern, expr) =
174− addLocals $
175− do (cpattern, destructors) <-
188+ directUsage $
189+ do (cpattern, bindings) <-
176190 Pattern.verify Error.DPCaseBranch $
177191 Pattern.canonicalize env Index.first pattern
178− newEnv <- Env.addLocals destructors env
179− removeLocals Warning.Pattern destructors $
180− Can.CaseBranch cpattern destructors <$> canonicalize newEnv expr
192+ newEnv <- Env.addLocals bindings env
193+
194+ (cexpr, destructors, freeLocals) <-
195+ verifyBindings W.Pattern bindings (canonicalize newEnv expr)
196+
197+ return (Can.CaseBranch cpattern destructors cexpr, freeLocals)
181198
182199
183200
184201-- CANONICALIZE BINOPS
185202
186203
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
188205canonicalizeBinops overallRegion env ops final =
189206 let
190207 canonicalizeHelp (expr, A.At region op) =
@@ -205,7 +222,7 @@ data Step
205222 | Error Env.Binop Env.Binop
206223
207224
208−runBinopStepper :: R.Region -> Step -> Result FreeLocals Can.Expr
225+runBinopStepper :: R.Region -> Step -> Result FreeLocals w Can.Expr
209226runBinopStepper overallRegion step =
210227 case step of
211228 Done expr ->
@@ -219,7 +236,7 @@ runBinopStepper overallRegion step =
219236 toBinopStep (toBinop op expr) op rest final
220237
221238 Error (Env.Binop op1 _ _ _ _ _) (Env.Binop op2 _ _ _ _ _) ->
222− Result.throw overallRegion (Error.Binop op1 op2)
239+ Result.throw (Error.Binop overallRegion op1 op2)
223240
224241
225242toBinopStep :: (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 =
267284-- CANONICALIZE LET
268285
269286
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
271288canonicalizeLet letRegion env defs body =
272− addLocals $
289+ directUsage $
273290 do let keyedDefs = zip defs [ 0 .. length defs ]
274− let toError name () () = Error.DuplicatePattern Error.DPLetBinding name
275291 let names = foldr addBindings Dups.none keyedDefs
276− boundNames <- Dups.detect toError names
292+ boundNames <- Dups.detect (Error.DuplicatePattern Error.DPLetBinding) names
293+
277294 newEnv <- Env.addLocals boundNames env
278295 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
283296
297+ (nodes, cbody, bindingUses, freeLocals) <-
298+ verifyLetBindings boundNames $
299+ (,)
300+ <$> traverse (defToNode defKeys newEnv) keyedDefs
301+ <*> canonicalize newEnv body
284302
285−addLocals :: Result () (expr, FreeLocals) -> Result FreeLocals expr
286−addLocals (Result.Result () warnings answer) =
287− case answer of
288− Result.Ok (value, freeLocals) ->
289− Result.Result freeLocals warnings (Result.Ok value)
303+ letExpr <-
304+ detectCycles letRegion bindingUses (Graph.stronglyConnComp nodes) cbody
290305
291− Result.Err err ->
292− Result.Result Set.empty warnings (Result.Err err)
306+ return (letExpr, freeLocals)
293307
294308
295−removeLocals :: Warning.Unused -> Map.Map N.Name (A.Located a) -> Result FreeLocals expr -> Result () (expr, FreeLocals)
296−removeLocals unused boundNames (Result.Result freeLocals warnings answer) =
297− case answer of
298− Result.Err err ->
299− Result.Result () warnings (Result.Err err)
300−
301− Result.Ok value ->
302− let
303− newFreeLocals =
304− Set.difference freeLocals (Map.keysSet boundNames)
305−
306− newWarnings =
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
310− warnings
311− else
312− Bag.append warnings $ Bag.fromList (toUnusedWarning unused) $
313− Map.toList (Map.withoutKeys boundNames freeLocals)
314− in
315− Result.Result () newWarnings (Result.Ok (value, newFreeLocals))
316−
317−
318−toUnusedWarning :: Warning.Unused -> (N.Name, A.Located a) -> A.Located Warning.Warning
319−toUnusedWarning unused (name, A.At region _) =
320− A.At region (Warning.UnusedVariable unused name)
309+verifyLetBindings
310+ :: Map.Map N.Name (A.Located Int)
311+ -> Result FreeLocals [W.Warning] ([Node], Can.Expr)
312+ -> Result info [W.Warning] ([Node], Can.Expr, FreeLocals, FreeLocals)
313+verifyLetBindings bindings (Result.Result k) =
314+ Result.Result $ \info warnings bad good ->
315+ k Map.empty warnings
316+ (\_ warnings1 err ->
317+ bad info warnings1 err
318+ )
319+ (\freeLocals warnings1 (nodes, body) ->
320+ let
321+ newFreeLocals = Map.difference freeLocals bindings
322+ bindingUses = Map.intersection freeLocals bindings
323+ in
324+ good info
325+ (addUnusedWarnings W.Def bindings bindingUses warnings1)
326+ (nodes, body, bindingUses, newFreeLocals)
327+ )
321328
322329
323330
@@ -386,71 +393,92 @@ addBindingsHelp key (A.At region pattern) bindings =
386393-- BUILD BINDINGS GRAPH
387394
388395
389−data Node = Node Binding FreeLocals
396+type Node =
397+ (Binding, Int, [Int])
390398
391399
392400data Binding
393401 = 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
395403
396404
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
398406defToNode defKeys env (def, key) =
399407 case def of
400408 Valid.Define region aname@(A.At _ name) srcArgs body Nothing ->
401− do (args, destructors) <-
409+ do (args, argBindings) <-
402410 Pattern.verify (Error.DPFuncArgs name) $
403411 Index.indexedTraverse (Pattern.canonicalizeArg env) srcArgs
404− newEnv <- Env.addLocals destructors env
405− toNode defKeys key destructors $
406− do cbody <- canonicalize newEnv body
407− return $ Define region $
408− Can.Def aname args destructors cbody
412+
413+ newEnv <-
414+ Env.addLocals argBindings env
415+
416+ (cbody, destructors, freeLocals) <-
417+ verifyBindings W.Pattern argBindings (canonicalize newEnv body)
418+
419+ logLetLocals args freeLocals
420+ ( Define region (Can.Def aname args destructors cbody)
421+ , key
422+ , Map.elems (Map.intersection defKeys freeLocals)
423+ )
409424
410425 Valid.Destruct region pattern body ->
411− do (cpattern, destructors) <-
426+ do (cpattern, bindings) <-
412427 Pattern.verify Error.DPDestruct $
413428 Pattern.canonicalize env Index.first pattern
414429
415− toNode defKeys key destructors $
416− Destruct region cpattern destructors <$> canonicalize env body
430+ Result.Result $ \freeLocals warnings bad good ->
431+ case canonicalize env body of
432+ Result.Result k ->
433+ k Map.empty warnings
434+ (\_ ws es -> bad freeLocals ws es)
435+ (\newFreeLocals warnings1 cbody ->
436+ good
437+ (Map.unionWith combineUses freeLocals newFreeLocals)
438+ warnings1
439+ ( Destruct region cpattern bindings cbody
440+ , key
441+ , Map.elems (Map.intersection defKeys freeLocals)
442+ )
443+ )
417444
418445 Valid.Define region aname@(A.At _ name) srcArgs body (Just tipe) ->
419446 do (Can.Forall freeVars ctipe) <- Type.toAnnotation env tipe
420− ((args, resultType), destructors) <-
447+ ((args, resultType), argBindings) <-
421448 Pattern.verify (Error.DPFuncArgs name) $
422449 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
428450
451+ newEnv <-
452+ Env.addLocals argBindings env
429453
430−toNode :: Map.Map N.Name Int -> Int -> Map.Map N.Name a -> Result FreeLocals Binding -> Result () (Node, Int, [Int])
431−toNode defKeys key args (Result.Result freeLocals warnings answer) =
432− Result.Result () warnings $
433− case answer of
434− Result.Err err ->
435− Result.Err err
454+ (cbody, destructors, freeLocals) <-
455+ verifyBindings W.Pattern argBindings (canonicalize newEnv body)
436456
437− Result.Ok binding ->
438− let
439− actuallyFreeLocals = Set.difference freeLocals (Map.keysSet args)
440− locallyDefinedLocals = Map.restrictKeys defKeys freeLocals
441− in
442− Result.Ok
443− ( Node binding actuallyFreeLocals
444− , key
445− , Map.elems locallyDefinedLocals
446− )
457+ logLetLocals args freeLocals
458+ ( Define region (Can.TypedDef aname freeVars args destructors cbody resultType)
459+ , key
460+ , Map.elems (Map.intersection defKeys freeLocals)
461+ )
462+
463+
464+logLetLocals :: [arg] -> FreeLocals -> value -> Result FreeLocals w value
465+logLetLocals args letLocals value =
466+ Result.Result $ \freeLocals warnings _ good ->
467+ good
468+ ( Map.unionWith combineUses freeLocals $
469+ case args of
470+ [] -> letLocals
471+ _ -> Map.map delayUse letLocals
472+ )
473+ warnings
474+ value
447475
448476
449477
450478-- GATHER TYPED ARGS
451479
452480
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)
454482gatherTypedArgs env name srcArgs tipe index revTypedArgs =
455483 case srcArgs of
456484 [] ->
@@ -466,16 +494,16 @@ gatherTypedArgs env name srcArgs tipe index revTypedArgs =
466494
467495 _ ->
468496 let (A.At start _, A.At end _) = (head srcArgs, last srcArgs) in
469− Result.throw (R.merge start end) $
470− Error.AnnotationTooShort name index (length srcArgs)
497+ Result.throw $
498+ Error.AnnotationTooShort (R.merge start end) name index (length srcArgs)
471499
472500
473501
474502-- DETECT CYCLES
475503
476504
477−detectCycles :: R.Region -> [Graph.SCC Node] -> Can.Expr -> Result FreeLocals Can.Expr
478−detectCycles letRegion sccs body =
505+detectCycles :: R.Region -> FreeLocals -> [Graph.SCC Binding] -> Can.Expr -> Result i w Can.Expr
506+detectCycles letRegion bindingUses sccs body =
479507 case sccs of
480508 [] ->
481509 Result.ok body
@@ -483,41 +511,45 @@ detectCycles letRegion sccs body =
483511 scc : subSccs ->
484512 A.At letRegion <$>
485513 case scc of
486− Graph.AcyclicSCC (Node binding freeLocals) ->
514+ Graph.AcyclicSCC binding ->
487515 case binding of
488516 Define _ def ->
489− Result.accumulate freeLocals (Can.Let def)
490− <*> detectCycles letRegion subSccs body
517+ Can.Let def
518+ <$> detectCycles letRegion bindingUses subSccs body
519+
520+ Destruct _ pattern bindings expr ->
521+ let
522+ destructors =
523+ Map.intersectionWith toDestructorInfo bindings bindingUses
524+ in
525+ Can.LetDestruct pattern destructors expr
526+ <$> detectCycles letRegion bindingUses subSccs body
527+
528+ Graph.CyclicSCC bindings ->
529+ case traverse requireFunction bindings of
530+ Just defs ->
531+ Can.LetRec defs
532+ <$> detectCycles letRegion bindingUses subSccs body
491533
492− Destruct _ pattern destructors expr ->
493− Result.accumulate freeLocals (Can.LetDestruct pattern destructors expr)
494− <*> detectCycles letRegion subSccs body
495−
496− Graph.CyclicSCC nodes ->
497− case unzip <$> traverse requireFunction nodes of
498534 Nothing ->
499− Result.throw letRegion (Error.RecursiveLet (map toCycleNodes nodes))
500−
501− Just (defs, freeLocals) ->
502− Result.accumulate (Set.unions freeLocals) (Can.LetRec defs)
503− <*> detectCycles letRegion subSccs body
535+ Result.throw (Error.RecursiveLet letRegion (map toCycleNodes bindings))
504536
505537
506−requireFunction :: Node -> Maybe (Can.Def, FreeLocals)
507−requireFunction (Node binding freeLocals) =
538+requireFunction :: Binding -> Maybe Can.Def
539+requireFunction binding =
508540 case binding of
509541 Define _ def@(Can.Def _ (_:_) _ _) ->
510− Just (def, freeLocals)
542+ Just def
511543
512544 Define _ def@(Can.TypedDef _ _ (_:_) _ _ _) ->
513− Just (def, freeLocals)
545+ Just def
514546
515547 _ ->
516548 Nothing
517549
518550
519−toCycleNodes :: Node -> Error.CycleNode
520−toCycleNodes (Node binding _) =
551+toCycleNodes :: Binding -> Error.CycleNode
552+toCycleNodes binding =
521553 case binding of
522554 Define _ def ->
523555 case def of
@@ -529,3 +561,140 @@ toCycleNodes (Node binding _) =
529561
530562 Destruct _ pattern _ _ ->
531563 Error.CyclePattern pattern
564+
565+
566+
567+-- LOG VARIABLE USES
568+
569+
570+logVar :: N.Name -> a -> Result FreeLocals w a
571+logVar name value =
572+ Result.Result $ \freeLocals warnings _ good ->
573+ good (Map.insertWith combineUses name oneDirectUse freeLocals) warnings value
574+
575+
576+{-# NOINLINE oneDirectUse #-}
577+oneDirectUse :: Uses
578+oneDirectUse =
579+ Uses 1 0
580+
581+
582+combineUses :: Uses -> Uses -> Uses
583+combineUses (Uses a b) (Uses x y) =
584+ Uses (a + x) (b + y)
585+
586+
587+delayUse :: Uses -> Uses
588+delayUse (Uses direct delayed) =
589+ Uses 0 (direct + delayed)
590+
591+
592+
593+-- MANAGING BINDINGS
594+
595+
596+verifyBindings
597+ :: W.Context
598+ -> Pattern.Bindings
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
606+ )
607+ (\freeLocals warnings1 body ->
608+ let
609+ destructors =
610+ Map.intersectionWith toDestructorInfo bindings freeLocals
611+ in
612+ good info
613+ (addUnusedWarnings context bindings destructors warnings1)
614+ (body, destructors, Map.difference freeLocals bindings)
615+ )
616+
617+
618+toDestructorInfo :: A.Located Can.Destructor -> Uses -> Can.DestructorInfo
619+toDestructorInfo (A.At _ destructor) (Uses direct delayed) =
620+ Can.DestructorInfo destructor direct delayed
621+
622+
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
628+ warnings
629+ else
630+ Map.foldlWithKey (addUnusedWarning context) warnings $
631+ Map.difference bindings uses
632+
633+
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
637+
638+
639+directUsage :: Result () w (expr, FreeLocals) -> Result FreeLocals w expr
640+directUsage (Result.Result k) =
641+ Result.Result $ \freeLocals warnings bad good ->
642+ k () warnings
643+ (\() ws es -> bad freeLocals ws es)
644+ (\() ws (value, newFreeLocals) ->
645+ good (Map.unionWith combineUses freeLocals newFreeLocals) ws value
646+ )
647+
648+
649+delayedUsage :: Result () w (expr, FreeLocals) -> Result FreeLocals w expr
650+delayedUsage (Result.Result k) =
651+ Result.Result $ \freeLocals warnings bad good ->
652+ k () warnings
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
657+ )
658+
659+
660+
661+-- FIND VARIABLE
662+
663+
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
667+ Nothing ->
668+ Result.throw (error "TODO no name" region)
669+
670+ Just (Env.VarHomes unqualified qualified) ->
671+ case maybePrefix of
672+ Nothing ->
673+ case unqualified of
674+ Env.Local ->
675+ logVar name (Can.VarLocal name)
676+
677+ Env.TopLevel ->
678+ logVar name (Can.VarTopLevel localHome name)
679+
680+ Env.Foreign bag ->
681+ case bag of
682+ Bag.One (Env.ForeignVarHome home annotation) ->
683+ Result.ok (Can.VarForeign home name annotation)
684+
685+ Bag.Empty ->
686+ Result.throw (error "TODO no unqualified" region)
687+
688+ Bag.Two _ _ ->
689+ Result.throw (error "TODO ambiguous unqualified" region)
690+
691+ Just prefix ->
692+ case Map.lookup prefix qualified of
693+ Nothing ->
694+ Result.throw (error "TODO no qualified" region)
695+
696+ Just (OneOrMore.One (Env.ForeignVarHome home annotation)) ->
697+ Result.ok (Can.VarForeign home name annotation)
698+
699+ Just _ ->
700+ Result.throw (error "TODO ambiguous qualified" region)