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.Literal as L
14import qualified AST.Module as Module
15import qualified AST.Pattern as P
16import qualified AST.Variable as Var
17import Elm.Utils ((|>))
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))
38-- PATTERN MATCH DATA STRUCTURE
41 = Data Var.Canonical [Pattern]
43 | Alias String Pattern
47 | AnythingBut (Set.Set L.Literal)
51fromCanonicalPattern :: P.CanonicalPattern -> Pattern
52fromCanonicalPattern (A.A _ pattern) =
54 P.Data ctor patterns ->
55 Data ctor (map fromCanonicalPattern patterns)
60 P.Alias name pattern ->
61 Alias name (fromCanonicalPattern pattern)
77 Map.Map Var.Home (Map.Map Tag [(Tag, Int)])
83toTagDict :: Module.Interfaces -> Module.Name -> Module.ADTs -> TagDict
84toTagDict interfaces localName localAdts =
87 [ ("::", 2), ("[]", 0) ]
90 Map.singleton Var.BuiltIn $
98 |> Map.map (toTagMapping . Module.iAdts)
99 |> Map.mapKeysMonotonic Var.Module
100 |> Map.insert (Var.Module localName) (toTagMapping localAdts)
102 Map.union builtinDict interfaceDict
105toTagMapping :: Module.ADTs -> Map.Map Tag ([(Tag,Int)])
108 toTagAndArity (_tvars, tagInfoList) =
110 info = map (\(tag, args) -> (tag, length args)) tagInfoList
112 map (second (const info)) tagInfoList
115 |> concatMap toTagAndArity
119lookupOtherCtors :: Var.Canonical -> TagDict -> [(Tag, Int)]
120lookupOtherCtors (Var.Canonical home name) tagDict =
121 case Map.lookup name =<< Map.lookup home tagDict of
126 if Help.isTuple name then
127 [(name, read (drop 6 name))]
130 "Since the Nitpick phase happens after canonicalization and type \
131 \inference, it is impossible that a pattern in a case cannot be \
140 -> Result.Result Warning.Warning e ()
141checkExpression tagDict (A.A region expression) =
144 checkExpression tagDict
150 checkPatterns tagDict region
163 E.ExplicitList listExprs ->
164 F.traverse_ go listExprs
166 E.Binop _ leftExpr rightExpr ->
167 go2 leftExpr rightExpr
169 E.Lambda pattern body ->
176 E.MultiIf branches finally ->
177 F.traverse_ (uncurry go2) branches
182 <* F.traverse_ goDef defs
184 goDef (Canonical.Definition pattern expr _) =
188 E.Case expr branches ->
190 <* goPattern (map fst branches)
191 <* F.traverse_ (go . snd) branches
193 E.Data _ctor exprs ->
196 E.Access record _field ->
199 E.Remove record _field ->
202 E.Insert record _field value ->
205 E.Modify record fields ->
207 <* F.traverse_ (go . snd) fields
210 F.traverse_ (go . snd) fields
235 -> [P.CanonicalPattern]
236 -> Result.Result Warning.Warning e ()
237checkPatterns tagDict region patterns =
238 checkPatternsHelp tagDict region [Anything] patterns
245 -> [P.CanonicalPattern]
246 -> Result.Result Warning.Warning e ()
247checkPatternsHelp tagDict region unhandled patterns =
248 case (unhandled, patterns) of
253 Result.warn region Warning.InexhaustivePatternMatch
255 (_, pattern@(A.A localRegion _) : remainingPatterns) ->
256 do newUnhandled <- filterPatterns tagDict localRegion pattern unhandled
257 checkPatternsHelp tagDict region newUnhandled remainingPatterns
263 -> P.CanonicalPattern
265 -> Result.Result Warning.Warning e [Pattern]
266filterPatterns tagDict region pattern unhandled =
269 fromCanonicalPattern pattern
272 intersection pat nitPattern == Nothing
274 if all noIntersection unhandled then
275 do Result.warn region Warning.RedundantPatternMatch
278 do let complementPatterns = complement tagDict nitPattern
281 (\p -> Maybe.mapMaybe (intersection p) complementPatterns)
285-- PATTERN INTERSECTION
287intersection :: Pattern -> Pattern -> Maybe Pattern
288intersection pattern1 pattern2 =
289 case (pattern1, pattern2) of
290 (Alias _ pattern1', _) ->
291 intersection pattern1' pattern2
293 (_, Alias _ pattern2') ->
294 intersection pattern1 pattern2'
308 (Data ctor1 args1, Data ctor2 args2) ->
309 if ctor1 /= ctor2 then
312 Data ctor1 <$> sequence (zipWith intersection args1 args2)
314 (Record _, Record _) ->
317 (Literal lit1, Literal lit2) ->
323 (AnythingBut literals, Literal lit) ->
324 if Set.member lit literals then
329 (Literal lit, AnythingBut literals) ->
330 if Set.member lit literals then
335 (AnythingBut literals1, AnythingBut literals2) ->
336 Just (AnythingBut (Set.union literals1 literals2))
344complement :: TagDict -> Pattern -> [Pattern]
345complement tagDict nitPattern =
350 Alias _name pattern ->
351 complement tagDict pattern
360 [AnythingBut (Set.singleton lit)]
362 AnythingBut literals ->
363 map Literal (Set.toList literals)
365 Data ctor patterns ->
366 complementData tagDict ctor patterns
369complementData :: TagDict -> Var.Canonical -> [Pattern] -> [Pattern]
370complementData tagDict tag patterns =
373 lookupOtherCtors tag tagDict
376 Maybe.mapMaybe (tagToPattern tag) otherTags
382 concat (zipWith (makeArgComplements tagDict tag arity) [0..] patterns)
384 tagComplements ++ argComplements
387tagToPattern :: Var.Canonical -> (Tag, Int) -> Maybe Pattern
388tagToPattern (Var.Canonical home rootTag) (tag, arity) =
389 if rootTag == tag then
392 Just (Data (Var.Canonical home tag) (replicate arity Anything))
395makeArgComplements :: TagDict -> Var.Canonical -> Int -> Int -> Pattern -> [Pattern]
396makeArgComplements tagDict tag arity index argPattern =
399 complement tagDict argPattern
402 replicate index Anything
404 : replicate (arity - index - 1) Anything
406 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