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.If 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.Update record fields ->
164 <* F.traverse_ (go . snd) fields
167 F.traverse_ (go . snd) fields
192 -> [Pattern.CanonicalPattern]
193 -> Result.Result Warning.Warning e ()
194checkPatterns tagDict region patterns =
195 checkPatternsHelp tagDict region [Anything] patterns
202 -> [Pattern.CanonicalPattern]
203 -> Result.Result Warning.Warning e ()
204checkPatternsHelp tagDict region unhandled patterns =
205 case (unhandled, patterns) of
210 Result.warn region (Warning.InexhaustivePatternMatch unhandled)
212 (_, pattern@(A.A localRegion _) : remainingPatterns) ->
213 do newUnhandled <- filterPatterns tagDict localRegion pattern unhandled
214 checkPatternsHelp tagDict region newUnhandled remainingPatterns
220 -> Pattern.CanonicalPattern
222 -> Result.Result Warning.Warning e [Pattern]
223filterPatterns tagDict region pattern unhandled =
226 fromCanonicalPattern pattern
229 intersection pat nitPattern == Nothing
231 if all noIntersection unhandled then
232 do Result.warn region Warning.RedundantPatternMatch
235 do let complementPatterns = complement tagDict nitPattern
238 (\p -> Maybe.mapMaybe (intersection p) complementPatterns)
242-- PATTERN INTERSECTION
244intersection :: Pattern -> Pattern -> Maybe Pattern
245intersection pattern1 pattern2 =
246 case (pattern1, pattern2) of
247 (Alias _ pattern1', _) ->
248 intersection pattern1' pattern2
250 (_, Alias _ pattern2') ->
251 intersection pattern1 pattern2'
265 (Data ctor1 args1, Data ctor2 args2) ->
266 if ctor1 /= ctor2 then
269 Data ctor1 <$> sequence (zipWith intersection args1 args2)
271 (Record _, Record _) ->
274 (Literal lit1, Literal lit2) ->
280 (AnythingBut literals, Literal lit) ->
281 if Set.member lit literals then
286 (Literal lit, AnythingBut literals) ->
287 if Set.member lit literals then
292 (AnythingBut literals1, AnythingBut literals2) ->
293 Just (AnythingBut (Set.union literals1 literals2))
301complement :: TagDict -> Pattern -> [Pattern]
302complement tagDict nitPattern =
307 Alias _name pattern ->
308 complement tagDict pattern
317 [AnythingBut (Set.singleton lit)]
319 AnythingBut literals ->
320 map Literal (Set.toList literals)
322 Data ctor patterns ->
323 complementData tagDict ctor patterns
326complementData :: TagDict -> Var.Canonical -> [Pattern] -> [Pattern]
327complementData tagDict tag patterns =
330 lookupOtherTags tag tagDict
333 Maybe.mapMaybe (tagToPattern tag) otherTags
339 concat (zipWith (makeArgComplements tagDict tag arity) [0..] patterns)
341 tagComplements ++ argComplements
344tagToPattern :: Var.Canonical -> (Tag, Int) -> Maybe Pattern
345tagToPattern (Var.Canonical home rootTag) (tag, arity) =
346 if rootTag == tag then
349 Just (Data (Var.Canonical home tag) (replicate arity Anything))
352makeArgComplements :: TagDict -> Var.Canonical -> Int -> Int -> Pattern -> [Pattern]
353makeArgComplements tagDict tag arity index argPattern =
356 complement tagDict argPattern
359 replicate index Anything
361 : replicate (arity - index - 1) Anything
363 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