@@ -18,6 +18,7 @@ import qualified Canonicalize.Environment as Env
18import qualified Canonicalize.Environment.Dups as Dups
18import qualified Canonicalize.Environment.Dups as Dups
19import qualified Canonicalize.Pattern as Pattern
19import qualified Canonicalize.Pattern as Pattern
20import qualified Canonicalize.Type as Type
20import qualified Canonicalize.Type as Type
21+import qualified Data.Bag as Bag
21import qualified Elm.Name as N
22import qualified Elm.Name as N
22import qualified Reporting.Annotation as A
23import qualified Reporting.Annotation as A
23import qualified Reporting.Error.Canonicalize as Error
24import qualified Reporting.Error.Canonicalize as Error
@@ -69,7 +70,7 @@ canonicalize env (A.A region expression) =
69 addLocals $
70 addLocals $
70 do cargs@(Can.Args _ destructors) <- Pattern.canonicalizeArgs env args
71 do cargs@(Can.Args _ destructors) <- Pattern.canonicalizeArgs env args
71 newEnv <- Env.addLocals destructors env
72 newEnv <- Env.addLocals destructors env
72− removeLocals destructors $
73+ removeLocals Warning.Pattern destructors $
73 Can.Lambda cargs <$> canonicalize newEnv body
74 Can.Lambda cargs <$> canonicalize newEnv body
75 Valid.Call func args ->
76 Valid.Call func args ->
@@ -159,7 +160,7 @@ canonicalizeCaseBranch env (pattern, expr) =
159 addLocals $
160 addLocals $
160 do match@(Can.Match _ destructors) <- Pattern.canonicalizeMatch env pattern
161 do match@(Can.Match _ destructors) <- Pattern.canonicalizeMatch env pattern
161 newEnv <- Env.addLocals destructors env
162 newEnv <- Env.addLocals destructors env
162− removeLocals destructors $
163+ removeLocals Warning.Pattern destructors $
163 (,) match <$> canonicalize newEnv expr
164 (,) match <$> canonicalize newEnv expr
@@ -257,7 +258,7 @@ canonicalizeLet region env defs body =
257 newEnv <- Env.addLocals boundNames env
258 newEnv <- Env.addLocals boundNames env
258 let defKeys = Map.map A.drop boundNames
259 let defKeys = Map.map A.drop boundNames
259 nodes <- Result.untracked $ traverse (bindingToNode defKeys newEnv) bindings
260 nodes <- Result.untracked $ traverse (bindingToNode defKeys newEnv) bindings
260− removeLocals defKeys $
261+ removeLocals Warning.Binding boundNames $
261 do cbody <- canonicalize env body
262 do cbody <- canonicalize env body
262 detectCycles region (Graph.stronglyConnComp nodes) cbody
263 detectCycles region (Graph.stronglyConnComp nodes) cbody
@@ -272,18 +273,32 @@ addLocals (Result.Result () warnings answer) =
272 Result.Result Set.empty warnings (Result.Err err)
273 Result.Result Set.empty warnings (Result.Err err)
275−removeLocals :: Map.Map N.Name a -> Result FreeLocals expr -> Result () (expr, FreeLocals)
276+removeLocals :: Warning.Unused -> Map.Map N.Name (A.Located a) -> Result FreeLocals expr -> Result () (expr, FreeLocals)
276−removeLocals boundNames (Result.Result freeLocals warnings answer) =
277+removeLocals unused boundNames (Result.Result freeLocals warnings answer) =
277− Result.Result () warnings $
278− case answer of
278+ case answer of
280+ Result.Result () warnings (Result.Err err)
279− Result.Ok value ->
282+ Result.Ok value ->
281− ( value
284+ newFreeLocals =
282− , Set.difference freeLocals (Map.keysSet boundNames)
285+ Set.difference freeLocals (Map.keysSet boundNames)
285− Result.Err err ->
288+ -- NOTE: check for unused variables without any large allocations.
286− Result.Err err
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
293+ Bag.append warnings $ Bag.fromList (toUnusedWarning unused) $
294+ Map.toList (Map.withoutKeys boundNames freeLocals)
296+ Result.Result () newWarnings (Result.Ok (value, newFreeLocals))
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)