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.Module.Name as ModuleName
15import qualified AST.Pattern as Pattern
16import qualified AST.Variable as Var
17import Elm.Utils ((|>))
18import Nitpick.Pattern (Pattern(..), fromCanonicalPattern)
19import qualified Reporting.Annotation as A
20import qualified Reporting.Region as Region
21import qualified Reporting.Result as Result
22import qualified Reporting.Warning as Warning
27 -> Module.CanonicalModule
28 -> Result.Result Warning.Warning e ()
29patternMatches interfaces modul =
31 name = Module.name modul
32 body = Module.body modul
35 (toTagDict interfaces name (Module.datatypes body))
42 Map.Map Var.Home (Map.Map Tag [(Tag, Int)])
48toTagDict :: Module.Interfaces -> ModuleName.Canonical -> Module.ADTs -> TagDict
49toTagDict interfaces localName localAdts =
52 [ ("::", 2), ("[]", 0) ]
55 Map.singleton Var.BuiltIn $
63 |> Map.map (toTagMapping . Module.iAdts)
64 |> Map.mapKeysMonotonic Var.Module
65 |> Map.insert (Var.Module localName) (toTagMapping localAdts)
67 Map.union builtinDict interfaceDict
70toTagMapping :: Module.ADTs -> Map.Map Tag ([(Tag,Int)])
73 toTagAndArity (_tvars, tagInfoList) =
75 info = map (\(tag, args) -> (tag, length args)) tagInfoList
77 map (second (const info)) tagInfoList
80 |> concatMap toTagAndArity
84lookupOtherTags :: Var.Canonical -> TagDict -> [(Tag, Int)]
85lookupOtherTags (Var.Canonical home name) tagDict =
86 case Map.lookup name =<< Map.lookup home tagDict of
91 if Help.isTuple name then
92 [(name, read (drop 6 name))]
95 "Since the Nitpick phase happens after canonicalization and type \
96 \inference, it is impossible that a pattern in a case cannot be \
105 -> Result.Result Warning.Warning e ()
106checkExpression tagDict (A.A region expression) =
109 checkExpression tagDict
115 checkPatterns tagDict region
127 E.ExplicitList listExprs ->
128 F.traverse_ go listExprs
130 E.Binop _ leftExpr rightExpr ->
131 go2 leftExpr rightExpr
133 E.Lambda pattern body ->
140 E.If branches finally ->
141 F.traverse_ (uncurry go2) branches
146 <* F.traverse_ goDef defs
148 goDef (Canonical.Definition _ pattern expr _) =
152 E.Case expr branches ->
154 <* goPattern (map fst branches)
155 <* F.traverse_ (go . snd) branches
157 E.Data _ctor exprs ->
160 E.Access record _field ->
163 E.Update record fields ->
165 <* F.traverse_ (go . snd) fields
168 F.traverse_ (go . snd) fields
193 -> [Pattern.CanonicalPattern]
194 -> Result.Result Warning.Warning e ()
195checkPatterns tagDict region patterns =
196 checkPatternsHelp tagDict region [Anything] patterns
203 -> [Pattern.CanonicalPattern]
204 -> Result.Result Warning.Warning e ()
205checkPatternsHelp tagDict region unhandled patterns =
206 case (unhandled, patterns) of
211 Result.warn region (Warning.InexhaustivePatternMatch unhandled)
213 (_, pattern@(A.A localRegion _) : remainingPatterns) ->
214 do newUnhandled <- filterPatterns tagDict localRegion pattern unhandled
215 checkPatternsHelp tagDict region newUnhandled remainingPatterns
221 -> Pattern.CanonicalPattern
223 -> Result.Result Warning.Warning e [Pattern]
224filterPatterns tagDict region pattern unhandled =
227 fromCanonicalPattern pattern
230 intersection pat nitPattern == Nothing
232 if all noIntersection unhandled then
233 do Result.warn region Warning.RedundantPatternMatch
236 do let complementPatterns = complement tagDict nitPattern
239 (\p -> Maybe.mapMaybe (intersection p) complementPatterns)
243-- PATTERN INTERSECTION
245intersection :: Pattern -> Pattern -> Maybe Pattern
246intersection pattern1 pattern2 =
247 case (pattern1, pattern2) of
248 (Alias _ pattern1', _) ->
249 intersection pattern1' pattern2
251 (_, Alias _ pattern2') ->
252 intersection pattern1 pattern2'
266 (Data ctor1 args1, Data ctor2 args2) ->
267 if ctor1 /= ctor2 then
270 Data ctor1 <$> sequence (zipWith intersection args1 args2)
272 (Record _, Record _) ->
275 (Literal lit1, Literal lit2) ->
281 (AnythingBut literals, Literal lit) ->
282 if Set.member lit literals then
287 (Literal lit, AnythingBut literals) ->
288 if Set.member lit literals then
293 (AnythingBut literals1, AnythingBut literals2) ->
294 Just (AnythingBut (Set.union literals1 literals2))
302complement :: TagDict -> Pattern -> [Pattern]
303complement tagDict nitPattern =
308 Alias _name pattern ->
309 complement tagDict pattern
318 [AnythingBut (Set.singleton lit)]
320 AnythingBut literals ->
321 map Literal (Set.toList literals)
323 Data ctor patterns ->
324 complementData tagDict ctor patterns
327complementData :: TagDict -> Var.Canonical -> [Pattern] -> [Pattern]
328complementData tagDict tag patterns =
331 lookupOtherTags tag tagDict
334 Maybe.mapMaybe (tagToPattern tag) otherTags
340 concat (zipWith (makeArgComplements tagDict tag arity) [0..] patterns)
342 tagComplements ++ argComplements
345tagToPattern :: Var.Canonical -> (Tag, Int) -> Maybe Pattern
346tagToPattern (Var.Canonical home rootTag) (tag, arity) =
347 if rootTag == tag then
350 Just (Data (Var.Canonical home tag) (replicate arity Anything))
353makeArgComplements :: TagDict -> Var.Canonical -> Int -> Int -> Pattern -> [Pattern]
354makeArgComplements tagDict tag arity index argPattern =
357 complement tagDict argPattern
360 replicate index Anything
362 : replicate (arity - index - 1) Anything
364 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