@@ -1,7 +1,7 @@
1module Nitpick.PatternMatches (patternMatches) where
1module Nitpick.PatternMatches (patternMatches) where
3import Control.Applicative ((<$>), (<*))
3import Control.Applicative ((<$>), (<*))
4−import Control.Monad.Except (forM, liftM)
4+import Control.Arrow (second)
5import qualified Data.Foldable as F
5import qualified Data.Foldable as F
6import qualified Data.Map as Map
6import qualified Data.Map as Map
7import qualified Data.Maybe as Maybe
7import qualified Data.Maybe as Maybe
@@ -9,79 +9,146 @@ import qualified Data.Set as Set
10import qualified AST.Expression.General as E
10import qualified AST.Expression.General as E
11import qualified AST.Expression.Canonical as Canonical
11import qualified AST.Expression.Canonical as Canonical
12+import qualified AST.Literal as L
12import qualified AST.Module as Module
13import qualified AST.Module as Module
13−import qualified AST.Pattern as Pattern
14+import qualified AST.Pattern as P
14import qualified AST.Variable as Var
15import qualified AST.Variable as Var
15import Elm.Utils ((|>))
16import Elm.Utils ((|>))
16−import qualified Nitpick.Pattern as P
17import qualified Reporting.Annotation as A
17import qualified Reporting.Annotation as A
18−import qualified Reporting.Error.Nitpick as Error
19import qualified Reporting.Region as Region
18import qualified Reporting.Region as Region
20import qualified Reporting.Result as Result
19import qualified Reporting.Result as Result
21−import qualified Reporting.Warning.Nitpick as Warning
20+import qualified Reporting.Warning as Warning
24patternMatches
23patternMatches
25 :: Module.Interfaces
24 :: Module.Interfaces
26− -> Module.CanonicalBody
25+ -> Module.Body Canonical.Expr
27 -> Result.Result Warning.Warning e ()
26 -> Result.Result Warning.Warning e ()
28patternMatches interfaces body =
27patternMatches interfaces body =
29− checkExpression (toAdtDict interfaces) (Module.program body)
28+ checkExpression (toTagDict interfaces) (Module.program body)
32−-- ADT DICT
31+-- PATTERN MATCH DATA STRUCTURE
34−type AdtDict =
33+data Pattern
35− Map.Map Var.Home (Map.Map String (Module.AdtInfo String))
34+ = Data Var.Canonical [Pattern]
36+ | Alias String Pattern
40+ | AnythingBut (Set.Set L.Literal)
44+fromCanonicalPattern :: P.CanonicalPattern -> Pattern
45+fromCanonicalPattern (A.A _ pattern) =
47+ P.Data ctor patterns ->
48+ Data ctor (map fromCanonicalPattern patterns)
53+ P.Alias name pattern ->
54+ Alias name (fromCanonicalPattern pattern)
70+ Map.Map Var.Home (Map.Map Tag [(Tag, Int)])
38−toAdtDict :: Module.Interfaces -> AdtDict
76+toTagDict :: Module.Interfaces -> TagDict
39−toAdtDict =
77+toTagDict interfaces =
41− -- TODO
79+ listTags =
80+ [ ("::", 2), ("[]", 0) ]
42 builtinDict =
82 builtinDict =
43− Map.empty
83+ Map.singleton Var.BuiltIn $
45 interfaceDict =
89 interfaceDict =
46 interfaces
90 interfaces
47− |> Map.map Module.iAdts
91+ |> Map.map (toTagMapping . Module.iAdts)
48 |> Map.mapKeysMonotonic Var.Module
92 |> Map.mapKeysMonotonic Var.Module
50 Map.union builtinDict interfaceDict
94 Map.union builtinDict interfaceDict
53−-- TODO this is wrong
97+toTagMapping :: Module.ADTs -> Map.Map Tag ([(Tag,Int)])
54−lookupOtherCtors
98+toTagMapping adts =
55− :: Var.Canonical
99+ let
56− -> AdtDict
100+ toTagAndArity (_tvars, tagInfoList) =
57− -> [(Var.Canonical, [Type.Canonical])]
101+ let
58−lookupOtherCtors (Var.Canonical home name) adtDict =
102+ info = map (\(tag, args) -> (tag, length args)) tagInfoList
59− case Map.lookup name =<< Map.lookup home adtDict of
103+ in
60− Nothing ->
104+ map (second (const info)) tagInfoList
107+ |> concatMap toTagAndArity
63− Just (_tvars, ctors) ->
110+
64− ctors
111+lookupOtherCtors :: Var.Canonical -> TagDict -> [(Tag, Int)]
112+lookupOtherCtors (Var.Canonical home name) tagDict =
113+ case Map.lookup name =<< Map.lookup home tagDict of
119+ "Since the Nitpick phase happens after canonicalization and type \
120+ \inference, it is impossible that a pattern in a case cannot be \
67-- CHECK EXPRESSIONS
124-- CHECK EXPRESSIONS
69checkExpression
126checkExpression
70− :: AdtDict
127+ :: TagDict
71 -> Canonical.Expr
128 -> Canonical.Expr
72 -> Result.Result Warning.Warning e ()
129 -> Result.Result Warning.Warning e ()
73−checkExpression adtDict (A.A region expression) =
130+checkExpression tagDict (A.A region expression) =
76− checkExpression adtDict
133+ checkExpression tagDict
78 go2 a b =
135 go2 a b =
79 F.traverse_ go [a,b]
136 F.traverse_ go [a,b]
81 goPattern =
138 goPattern =
82− checkPatterns adtDict region
139+ checkPatterns tagDict region
84 case expression of
141 case expression of
85 E.ExplicitList listExprs ->
152 E.ExplicitList listExprs ->
86 F.traverse_ go listExprs
153 F.traverse_ go listExprs
@@ -95,15 +162,16 @@ checkExpression adtDict (A.A region expression) =
95 E.App func arg ->
162 E.App func arg ->
96 go2 func arg
163 go2 func arg
98− E.MultiIf branches ->
165+ E.MultiIf branches finally ->
99 F.traverse_ (uncurry go2) branches
166 F.traverse_ (uncurry go2) branches
101 E.Let defs body ->
169 E.Let defs body ->
103 <* F.traverse_ goDef defs
171 <* F.traverse_ goDef defs
105 goDef (Canonical.Definition pattern expr _) =
173 goDef (Canonical.Definition pattern expr _) =
106− goPattern [p]
174+ goPattern [pattern]
107 <* go expr
175 <* go expr
109 E.Case expr branches ->
177 E.Case expr branches ->
@@ -130,109 +198,130 @@ checkExpression adtDict (A.A region expression) =
130 E.Record fields ->
198 E.Record fields ->
131 F.traverse_ (go . snd) fields
199 F.traverse_ (go . snd) fields
134-- CHECK PATTERNS
219-- CHECK PATTERNS
136checkPatterns
221checkPatterns
137− :: AdtDict
222+ :: TagDict
138 -> Region.Region
223 -> Region.Region
139− -> [Pattern.CanonicalPattern]
224+ -> [P.CanonicalPattern]
140 -> Result.Result Warning.Warning e ()
225 -> Result.Result Warning.Warning e ()
141−checkPatterns adtDict region patterns =
226+checkPatterns tagDict region patterns =
142− checkPatternsHelp [P.Anything] patterns
227+ checkPatternsHelp tagDict region [Anything] patterns
145checkPatternsHelp
230checkPatternsHelp
146− :: AdtDict
231+ :: TagDict
147 -> Region.Region
232 -> Region.Region
148− -> [P.Pattern]
233+ -> [Pattern]
149− -> [Pattern.CanonicalPattern]
234+ -> [P.CanonicalPattern]
150 -> Result.Result Warning.Warning e ()
235 -> Result.Result Warning.Warning e ()
151−checkPatternsHelp adtDict region unhandled patterns =
236+checkPatternsHelp tagDict region unhandled patterns =
152 case (unhandled, patterns) of
237 case (unhandled, patterns) of
153 ([], []) ->
238 ([], []) ->
154 return ()
239 return ()
156 (_:_, []) ->
241 (_:_, []) ->
157− Result.warn region (Inexhaustive unhandled)
242+ Result.warn region Warning.InexhaustivePatternMatch
159− (_, A.A region pattern : remainingPatterns) ->
244+ (_, pattern@(A.A localRegion _) : remainingPatterns) ->
160− do newUnhandled <- filterPatterns adtDict region pattern unhandled
245+ do newUnhandled <- filterPatterns tagDict localRegion pattern unhandled
161− checkPatternsHelp adtDict newUnhandled remainingPatterns
246+ checkPatternsHelp tagDict region newUnhandled remainingPatterns
164filterPatterns
249filterPatterns
165− :: AdtDict
250+ :: TagDict
166 -> Region.Region
251 -> Region.Region
167− -> P.Pattern
252+ -> P.CanonicalPattern
168− -> [P.Pattern]
253+ -> [Pattern]
169− -> Result.Result Warning.Warning e [P.Pattern]
254+ -> Result.Result Warning.Warning e [Pattern]
170−filterPatterns adtDict region pattern unhandled =
255+filterPatterns tagDict region pattern unhandled =
172 nitPattern =
257 nitPattern =
173− P.fromPattern pattern
258+ fromCanonicalPattern pattern
175 noIntersection pat =
260 noIntersection pat =
176 intersection pat nitPattern == Nothing
261 intersection pat nitPattern == Nothing
178− if all noIntersection unhandled
263+ if all noIntersection unhandled then
180− do Result.warn region Redundant
264+ do Result.warn region Warning.RedundantPatternMatch
181− return unhandled
265+ return unhandled
183− do let complementPatterns = complement adtDict nitPattern
267+ do let complementPatterns = complement tagDict nitPattern
184− return $
268+ return $
185− concatMap (\p -> Maybe.mapMaybe (intersection p) complementPatterns) unhandled
270+ (\p -> Maybe.mapMaybe (intersection p) complementPatterns)
188-- PATTERN INTERSECTION
274-- PATTERN INTERSECTION
190−intersection :: P.Pattern -> P.Pattern -> Maybe P.Pattern
276+intersection :: Pattern -> Pattern -> Maybe Pattern
191intersection pattern1 pattern2 =
277intersection pattern1 pattern2 =
192 case (pattern1, pattern2) of
278 case (pattern1, pattern2) of
193− (P.Alias _ pattern1', _) ->
279+ (Alias _ pattern1', _) ->
194 intersection pattern1' pattern2
280 intersection pattern1' pattern2
196− (_, P.Alias _ pattern2') ->
282+ (_, Alias _ pattern2') ->
197 intersection pattern1 pattern2'
283 intersection pattern1 pattern2'
199− (P.Anything, _) ->
285+ (Anything, _) ->
200 Just pattern2
286 Just pattern2
202− (P.Var _, _) ->
288+ (Var _, _) ->
203 Just pattern2
289 Just pattern2
205− (_, P.Anything) ->
291+ (_, Anything) ->
206 Just pattern1
292 Just pattern1
208− (_, P.Var _) ->
294+ (_, Var _) ->
209 Just pattern1
295 Just pattern1
211− (P.Data ctor1 args1, P.Data ctor2 args2) ->
297+ (Data ctor1 args1, Data ctor2 args2) ->
212− if ctor1 /= ctor2
298+ if ctor1 /= ctor2 then
213− then Nothing
299+ Nothing
214− else Data ctor1 <$> sequence (zipWith intersection args1 args2)
301+ Data ctor1 <$> sequence (zipWith intersection args1 args2)
216− -- TODO Assuming the fields are identical.
217− (P.Record _fields, P.Record _) ->
303+ (Record _, Record _) ->
218 Just pattern1
304 Just pattern1
220− (P.Literal lit1, P.Literal lit2) ->
306+ (Literal lit1, Literal lit2) ->
221− if lit1 == lit2
307+ if lit1 == lit2 then
222− then Just pattern1
308+ Just pattern1
223− else Nothing
310+ Nothing
225− (P.AnythingBut literals, P.Literal lit) ->
312+ (AnythingBut literals, Literal lit) ->
226− if Set.member lit literals
313+ if Set.member lit literals then
227− then Nothing
314+ Nothing
228− else Just pattern2
316+ Just pattern2
230− (P.Literal lit, P.AnythingBut literals) ->
318+ (Literal lit, AnythingBut literals) ->
231− if Set.membur lit literals
319+ if Set.member lit literals then
232− then Nothing
320+ Nothing
233− else Just pattern1
322+ Just pattern1
235− (P.AnythingBut literals1, P.AnythingBut literals2) ->
324+ (AnythingBut literals1, AnythingBut literals2) ->
236 Just (AnythingBut (Set.union literals1 literals2))
325 Just (AnythingBut (Set.union literals1 literals2))
@@ -241,64 +330,67 @@ intersection pattern1 pattern2 =
242-- PATTERN COMPLEMENT
331-- PATTERN COMPLEMENT
244−complement :: AdtDict -> P.Pattern -> [P.Pattern]
333+complement :: TagDict -> Pattern -> [Pattern]
245−complement adtDict nitPattern =
334+complement tagDict nitPattern =
246 case nitPattern of
335 case nitPattern of
247− P.Record _fields ->
336+ Record _fields ->
250− P.Alias _name pattern ->
339+ Alias _name pattern ->
251− complement adtDict pattern
340+ complement tagDict pattern
253− P.Var _name ->
342+ Var _name ->
256− P.Anything ->
345+ Anything ->
259− P.Literal lit ->
348+ Literal lit ->
260 [AnythingBut (Set.singleton lit)]
349 [AnythingBut (Set.singleton lit)]
262− P.AnythingBut literals ->
351+ AnythingBut literals ->
263 map Literal (Set.toList literals)
352 map Literal (Set.toList literals)
265− P.Data ctor patterns ->
354+ Data ctor patterns ->
266− complementData adtDict ctor patterns
355+ complementData tagDict ctor patterns
269−complementData :: AdtDict -> Var.Canonical -> [P.Pattern] -> [P.Pattern]
358+complementData :: TagDict -> Var.Canonical -> [Pattern] -> [Pattern]
270−complementData adtDict canonicalTag patterns =
359+complementData tagDict tag patterns =
272− ctors =
361+ otherTags =
273− lookupOtherCtors ctor adtDict
362+ lookupOtherCtors tag tagDict
275− dataComplements =
364+ tagComplements =
276− Maybe.mapMaybe (maybeData canonicalTag) ctors
365+ Maybe.mapMaybe (tagToPattern tag) otherTags
278− numArgs = length patterns
368+ length patterns
280 argComplements =
370 argComplements =
281− concat (zipWith (makeArgComplements adtDict numArgs) [0..] patterns)
371+ concat (zipWith (makeArgComplements tagDict tag arity) [0..] patterns)
283− dataComplements ++ argComplements
373+ tagComplements ++ argComplements
286−maybeData :: Var.Canonical -> (String, Module.AdtInfo) -> Maybe P.Pattern
376+tagToPattern :: Var.Canonical -> (Tag, Int) -> Maybe Pattern
287−maybeData (Var.Canonical home name) (tag, args) =
377+tagToPattern (Var.Canonical home rootTag) (tag, arity) =
289− then
378+ if rootTag == tag then
292− Just (P.Data (Var.Canonical home tag) (replicate (length args) P.Anything))
381+ Just (Data (Var.Canonical home tag) (replicate arity Anything))
295−makeArgComplements :: AdtDict -> Int -> Int -> P.Pattern -> [P.Pattern]
384+makeArgComplements :: TagDict -> Var.Canonical -> Int -> Int -> Pattern -> [Pattern]
296−makeArgComplements adtDict numArgs index argPattern =
385+makeArgComplements tagDict tag arity index argPattern =
298 complementList =
387 complementList =
299− complement adtDict argPattern
388+ complement tagDict argPattern
301− paddedArgs pat =
390+ padArgs pattern =
302− replicate index P.Anything ++ pat : replicate (numArgs - index - 1) P.Anything
391+ replicate index Anything
393+ : replicate (arity - index - 1) Anything
304− map (P.Data ctor . paddedArgs) complementList
395+ map (Data tag . padArgs) complementList