@@ -18,6 +18,7 @@ import qualified Canonicalize.Environment as Env
1818import qualified Canonicalize.Environment.Dups as Dups
1919import qualified Canonicalize.Pattern as Pattern
2020import qualified Canonicalize.Type as Type
21+import qualified Data.Bag as Bag
2122import qualified Elm.Name as N
2223import qualified Reporting.Annotation as A
2324import qualified Reporting.Error.Canonicalize as Error
@@ -69,7 +70,7 @@ canonicalize env (A.A region expression) =
6970 addLocals $
7071 do cargs@(Can.Args _ destructors) <- Pattern.canonicalizeArgs env args
7172 newEnv <- Env.addLocals destructors env
72− removeLocals destructors $
73+ removeLocals Warning.Pattern destructors $
7374 Can.Lambda cargs <$> canonicalize newEnv body
7475
7576 Valid.Call func args ->
@@ -159,7 +160,7 @@ canonicalizeCaseBranch env (pattern, expr) =
159160 addLocals $
160161 do match@(Can.Match _ destructors) <- Pattern.canonicalizeMatch env pattern
161162 newEnv <- Env.addLocals destructors env
162− removeLocals destructors $
163+ removeLocals Warning.Pattern destructors $
163164 (,) match <$> canonicalize newEnv expr
164165
165166
@@ -257,7 +258,7 @@ canonicalizeLet region env defs body =
257258 newEnv <- Env.addLocals boundNames env
258259 let defKeys = Map.map A.drop boundNames
259260 nodes <- Result.untracked $ traverse (bindingToNode defKeys newEnv) bindings
260− removeLocals defKeys $
261+ removeLocals Warning.Binding boundNames $
261262 do cbody <- canonicalize env body
262263 detectCycles region (Graph.stronglyConnComp nodes) cbody
263264
@@ -272,18 +273,32 @@ addLocals (Result.Result () warnings answer) =
272273 Result.Result Set.empty warnings (Result.Err err)
273274
274275
275−removeLocals :: Map.Map N.Name a -> Result FreeLocals expr -> Result () (expr, FreeLocals)
276−removeLocals boundNames (Result.Result freeLocals warnings answer) =
277− Result.Result () warnings $
278− case answer of
279− Result.Ok value ->
280− Result.Ok
281− ( value
282− , Set.difference freeLocals (Map.keysSet boundNames)
283− )
284−
285− Result.Err err ->
286− Result.Err err
276+removeLocals :: Warning.Unused -> Map.Map N.Name (A.Located a) -> Result FreeLocals expr -> Result () (expr, FreeLocals)
277+removeLocals unused boundNames (Result.Result freeLocals warnings answer) =
278+ case answer of
279+ Result.Err err ->
280+ Result.Result () warnings (Result.Err err)
281+
282+ Result.Ok value ->
283+ let
284+ newFreeLocals =
285+ Set.difference freeLocals (Map.keysSet boundNames)
286+
287+ newWarnings =
288+ -- NOTE: check for unused variables without any large allocations.
289+ -- This relies on the fact that Map.size and Set.size are O(1)
290+ if Set.size freeLocals - Map.size boundNames == Set.size newFreeLocals then
291+ warnings
292+ else
293+ Bag.append warnings $ Bag.fromList (toUnusedWarning unused) $
294+ Map.toList (Map.withoutKeys boundNames freeLocals)
295+ in
296+ Result.Result () newWarnings (Result.Ok (value, newFreeLocals))
297+
298+
299+toUnusedWarning :: Warning.Unused -> (N.Name, A.Located a) -> A.Located Warning.Warning
300+toUnusedWarning unused (name, A.A region _) =
301+ A.A region (Warning.UnusedVariable unused name)
287302
288303
289304