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
190 -> [Pattern.CanonicalPattern]
191 -> Result.Result Warning.Warning e ()
192checkPatterns tagDict region patterns =
193 checkPatternsHelp tagDict region [Anything] patterns
200 -> [Pattern.CanonicalPattern]
201 -> Result.Result Warning.Warning e ()
202checkPatternsHelp tagDict region unhandled patterns =
203 case (unhandled, patterns) of
208 Result.warn region (Warning.InexhaustivePatternMatch unhandled)
210 (_, pattern@(A.A localRegion _) : remainingPatterns) ->
211 do newUnhandled <- filterPatterns tagDict localRegion pattern unhandled
212 checkPatternsHelp tagDict region newUnhandled remainingPatterns
218 -> Pattern.CanonicalPattern
220 -> Result.Result Warning.Warning e [Pattern]
221filterPatterns tagDict region pattern unhandled =
224 fromCanonicalPattern pattern
227 intersection pat nitPattern == Nothing
229 if all noIntersection unhandled then
230 do Result.warn region Warning.RedundantPatternMatch
233 do let complementPatterns = complement tagDict nitPattern
236 (\p -> Maybe.mapMaybe (intersection p) complementPatterns)
240-- PATTERN INTERSECTION
242intersection :: Pattern -> Pattern -> Maybe Pattern
243intersection pattern1 pattern2 =
244 case (pattern1, pattern2) of
245 (Alias _ pattern1', _) ->
246 intersection pattern1' pattern2
248 (_, Alias _ pattern2') ->
249 intersection pattern1 pattern2'
263 (Data ctor1 args1, Data ctor2 args2) ->
264 if ctor1 /= ctor2 then
267 Data ctor1 <$> sequence (zipWith intersection args1 args2)
269 (Record _, Record _) ->
272 (Literal lit1, Literal lit2) ->
278 (AnythingBut literals, Literal lit) ->
279 if Set.member lit literals then
284 (Literal lit, AnythingBut literals) ->
285 if Set.member lit literals then
290 (AnythingBut literals1, AnythingBut literals2) ->
291 Just (AnythingBut (Set.union literals1 literals2))
299complement :: TagDict -> Pattern -> [Pattern]
300complement tagDict nitPattern =
305 Alias _name pattern ->
306 complement tagDict pattern
315 [AnythingBut (Set.singleton lit)]
317 AnythingBut literals ->
318 map Literal (Set.toList literals)
320 Data ctor patterns ->
321 complementData tagDict ctor patterns
324complementData :: TagDict -> Var.Canonical -> [Pattern] -> [Pattern]
325complementData tagDict tag patterns =
328 lookupOtherTags tag tagDict
331 Maybe.mapMaybe (tagToPattern tag) otherTags
337 concat (zipWith (makeArgComplements tagDict tag arity) [0..] patterns)
339 tagComplements ++ argComplements
342tagToPattern :: Var.Canonical -> (Tag, Int) -> Maybe Pattern
343tagToPattern (Var.Canonical home rootTag) (tag, arity) =
344 if rootTag == tag then
347 Just (Data (Var.Canonical home tag) (replicate arity Anything))
350makeArgComplements :: TagDict -> Var.Canonical -> Int -> Int -> Pattern -> [Pattern]
351makeArgComplements tagDict tag arity index argPattern =
354 complement tagDict argPattern
357 replicate index Anything
359 : replicate (arity - index - 1) Anything
361 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