1module Nitpick.PatternMatches (patternMatches) where
3import Control.Applicative ((<$>), (<*))
4import Control.Arrow (second)
5import qualified Data.Foldable as F
6import qualified Data.Map as Map
7import qualified Data.Maybe as Maybe
8import qualified Data.Set as Set
10import qualified AST.Expression.General as E
11import qualified AST.Expression.Canonical as Canonical
12import qualified AST.Helpers as Help
13import qualified AST.Module as Module
14import qualified AST.Pattern as Pattern
15import qualified AST.Variable as Var
16import Elm.Utils ((|>))
17import Nitpick.Pattern (Pattern(..), fromCanonicalPattern)
18import qualified Reporting.Annotation as A
19import qualified Reporting.Region as Region
20import qualified Reporting.Result as Result
21import qualified Reporting.Warning as Warning
26 -> Module.CanonicalModule
27 -> Result.Result Warning.Warning e ()
28patternMatches interfaces modul =
30 name = Module.names modul
31 body = Module.body modul
34 (toTagDict interfaces name (Module.datatypes body))
41 Map.Map Var.Home (Map.Map Tag [(Tag, Int)])
47toTagDict :: Module.Interfaces -> Module.Name -> Module.ADTs -> TagDict
48toTagDict interfaces localName localAdts =
51 [ ("::", 2), ("[]", 0) ]
54 Map.singleton Var.BuiltIn $
62 |> Map.map (toTagMapping . Module.iAdts)
63 |> Map.mapKeysMonotonic Var.Module
64 |> Map.insert (Var.Module localName) (toTagMapping localAdts)
66 Map.union builtinDict interfaceDict
69toTagMapping :: Module.ADTs -> Map.Map Tag ([(Tag,Int)])
72 toTagAndArity (_tvars, tagInfoList) =
74 info = map (\(tag, args) -> (tag, length args)) tagInfoList
76 map (second (const info)) tagInfoList
79 |> concatMap toTagAndArity
83lookupOtherTags :: Var.Canonical -> TagDict -> [(Tag, Int)]
84lookupOtherTags (Var.Canonical home name) tagDict =
85 case Map.lookup name =<< Map.lookup home tagDict of
90 if Help.isTuple name then
91 [(name, read (drop 6 name))]
94 "Since the Nitpick phase happens after canonicalization and type \
95 \inference, it is impossible that a pattern in a case cannot be \
104 -> Result.Result Warning.Warning e ()
105checkExpression tagDict (A.A region expression) =
108 checkExpression tagDict
114 checkPatterns tagDict region
126 E.ExplicitList listExprs ->
127 F.traverse_ go listExprs
129 E.Binop _ leftExpr rightExpr ->
130 go2 leftExpr rightExpr
132 E.Lambda pattern body ->
139 E.MultiIf branches finally ->
140 F.traverse_ (uncurry go2) branches
145 <* F.traverse_ goDef defs
147 goDef (Canonical.Definition pattern expr _) =
151 E.Case expr branches ->
153 <* goPattern (map fst branches)
154 <* F.traverse_ (go . snd) branches
156 E.Data _ctor exprs ->
159 E.Access record _field ->
162 E.Remove record _field ->
165 E.Insert record _field value ->
168 E.Modify record fields ->
170 <* F.traverse_ (go . snd) fields
173 F.traverse_ (go . snd) fields
198 -> [Pattern.CanonicalPattern]
199 -> Result.Result Warning.Warning e ()
200checkPatterns tagDict region patterns =
201 checkPatternsHelp tagDict region [Anything] patterns
208 -> [Pattern.CanonicalPattern]
209 -> Result.Result Warning.Warning e ()
210checkPatternsHelp tagDict region unhandled patterns =
211 case (unhandled, patterns) of
216 Result.warn region (Warning.InexhaustivePatternMatch unhandled)
218 (_, pattern@(A.A localRegion _) : remainingPatterns) ->
219 do newUnhandled <- filterPatterns tagDict localRegion pattern unhandled
220 checkPatternsHelp tagDict region newUnhandled remainingPatterns
226 -> Pattern.CanonicalPattern
228 -> Result.Result Warning.Warning e [Pattern]
229filterPatterns tagDict region pattern unhandled =
232 fromCanonicalPattern pattern
235 intersection pat nitPattern == Nothing
237 if all noIntersection unhandled then
238 do Result.warn region Warning.RedundantPatternMatch
241 do let complementPatterns = complement tagDict nitPattern
244 (\p -> Maybe.mapMaybe (intersection p) complementPatterns)
248-- PATTERN INTERSECTION
250intersection :: Pattern -> Pattern -> Maybe Pattern
251intersection pattern1 pattern2 =
252 case (pattern1, pattern2) of
253 (Alias _ pattern1', _) ->
254 intersection pattern1' pattern2
256 (_, Alias _ pattern2') ->
257 intersection pattern1 pattern2'
271 (Data ctor1 args1, Data ctor2 args2) ->
272 if ctor1 /= ctor2 then
275 Data ctor1 <$> sequence (zipWith intersection args1 args2)
277 (Record _, Record _) ->
280 (Literal lit1, Literal lit2) ->
286 (AnythingBut literals, Literal lit) ->
287 if Set.member lit literals then
292 (Literal lit, AnythingBut literals) ->
293 if Set.member lit literals then
298 (AnythingBut literals1, AnythingBut literals2) ->
299 Just (AnythingBut (Set.union literals1 literals2))
307complement :: TagDict -> Pattern -> [Pattern]
308complement tagDict nitPattern =
313 Alias _name pattern ->
314 complement tagDict pattern
323 [AnythingBut (Set.singleton lit)]
325 AnythingBut literals ->
326 map Literal (Set.toList literals)
328 Data ctor patterns ->
329 complementData tagDict ctor patterns
332complementData :: TagDict -> Var.Canonical -> [Pattern] -> [Pattern]
333complementData tagDict tag patterns =
336 lookupOtherTags tag tagDict
339 Maybe.mapMaybe (tagToPattern tag) otherTags
345 concat (zipWith (makeArgComplements tagDict tag arity) [0..] patterns)
347 tagComplements ++ argComplements
350tagToPattern :: Var.Canonical -> (Tag, Int) -> Maybe Pattern
351tagToPattern (Var.Canonical home rootTag) (tag, arity) =
352 if rootTag == tag then
355 Just (Data (Var.Canonical home tag) (replicate arity Anything))
358makeArgComplements :: TagDict -> Var.Canonical -> Int -> Int -> Pattern -> [Pattern]
359makeArgComplements tagDict tag arity index argPattern =
362 complement tagDict argPattern
365 replicate index Anything
367 : replicate (arity - index - 1) Anything
369 map (Data tag . padArgs) complementList
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list