1module Nitpick.PatternMatches (patternMatches) where
3import Control.Applicative ((<$>), (<*))
4import Control.Monad.Except (forM, liftM)
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.Module as Module
13import qualified AST.Pattern as Pattern
14import qualified AST.Variable as Var
15import Elm.Utils ((|>))
16import qualified Nitpick.Pattern as P
17import qualified Reporting.Annotation as A
18import qualified Reporting.Error.Nitpick as Error
19import qualified Reporting.Region as Region
20import qualified Reporting.Result as Result
21import qualified Reporting.Warning.Nitpick as Warning
26 -> Module.CanonicalBody
27 -> Result.Result Warning.Warning e ()
28patternMatches interfaces body =
29 checkExpression (toAdtDict interfaces) (Module.program body)
35 Map.Map Var.Home (Map.Map String (Module.AdtInfo String))
38toAdtDict :: Module.Interfaces -> AdtDict
47 |> Map.map Module.iAdts
48 |> Map.mapKeysMonotonic Var.Module
50 Map.union builtinDict interfaceDict
57 -> [(Var.Canonical, [Type.Canonical])]
58lookupOtherCtors (Var.Canonical home name) adtDict =
59 case Map.lookup name =<< Map.lookup home adtDict of
63 Just (_tvars, ctors) ->
72 -> Result.Result Warning.Warning e ()
73checkExpression adtDict (A.A region expression) =
76 checkExpression adtDict
82 checkPatterns adtDict region
85 E.ExplicitList listExprs ->
86 F.traverse_ go listExprs
88 E.Binop _ leftExpr rightExpr ->
89 go2 leftExpr rightExpr
91 E.Lambda pattern body ->
99 F.traverse_ (uncurry go2) branches
103 <* F.traverse_ goDef defs
105 goDef (Canonical.Definition pattern expr _) =
109 E.Case expr branches ->
111 <* goPattern (map fst branches)
112 <* F.traverse_ (go . snd) branches
114 E.Data _ctor exprs ->
117 E.Access record _field ->
120 E.Remove record _field ->
123 E.Insert record _field value ->
126 E.Modify record fields ->
128 <* F.traverse_ (go . snd) fields
131 F.traverse_ (go . snd) fields
139 -> [Pattern.CanonicalPattern]
140 -> Result.Result Warning.Warning e ()
141checkPatterns adtDict region patterns =
142 checkPatternsHelp [P.Anything] patterns
149 -> [Pattern.CanonicalPattern]
150 -> Result.Result Warning.Warning e ()
151checkPatternsHelp adtDict region unhandled patterns =
152 case (unhandled, patterns) of
157 Result.warn region (Inexhaustive unhandled)
159 (_, A.A region pattern : remainingPatterns) ->
160 do newUnhandled <- filterPatterns adtDict region pattern unhandled
161 checkPatternsHelp adtDict newUnhandled remainingPatterns
169 -> Result.Result Warning.Warning e [P.Pattern]
170filterPatterns adtDict region pattern unhandled =
173 P.fromPattern pattern
176 intersection pat nitPattern == Nothing
178 if all noIntersection unhandled
180 do Result.warn region Redundant
183 do let complementPatterns = complement adtDict nitPattern
185 concatMap (\p -> Maybe.mapMaybe (intersection p) complementPatterns) unhandled
188-- PATTERN INTERSECTION
190intersection :: P.Pattern -> P.Pattern -> Maybe P.Pattern
191intersection pattern1 pattern2 =
192 case (pattern1, pattern2) of
193 (P.Alias _ pattern1', _) ->
194 intersection pattern1' pattern2
196 (_, P.Alias _ pattern2') ->
197 intersection pattern1 pattern2'
211 (P.Data ctor1 args1, P.Data ctor2 args2) ->
214 else Data ctor1 <$> sequence (zipWith intersection args1 args2)
216 -- TODO Assuming the fields are identical.
217 (P.Record _fields, P.Record _) ->
220 (P.Literal lit1, P.Literal lit2) ->
225 (P.AnythingBut literals, P.Literal lit) ->
226 if Set.member lit literals
230 (P.Literal lit, P.AnythingBut literals) ->
231 if Set.membur lit literals
235 (P.AnythingBut literals1, P.AnythingBut literals2) ->
236 Just (AnythingBut (Set.union literals1 literals2))
244complement :: AdtDict -> P.Pattern -> [P.Pattern]
245complement adtDict nitPattern =
250 P.Alias _name pattern ->
251 complement adtDict pattern
260 [AnythingBut (Set.singleton lit)]
262 P.AnythingBut literals ->
263 map Literal (Set.toList literals)
265 P.Data ctor patterns ->
266 complementData adtDict ctor patterns
269complementData :: AdtDict -> Var.Canonical -> [P.Pattern] -> [P.Pattern]
270complementData adtDict canonicalTag patterns =
273 lookupOtherCtors ctor adtDict
276 Maybe.mapMaybe (maybeData canonicalTag) ctors
278 numArgs = length patterns
281 concat (zipWith (makeArgComplements adtDict numArgs) [0..] patterns)
283 dataComplements ++ argComplements
286maybeData :: Var.Canonical -> (String, Module.AdtInfo) -> Maybe P.Pattern
287maybeData (Var.Canonical home name) (tag, args) =
292 Just (P.Data (Var.Canonical home tag) (replicate (length args) P.Anything))
295makeArgComplements :: AdtDict -> Int -> Int -> P.Pattern -> [P.Pattern]
296makeArgComplements adtDict numArgs index argPattern =
299 complement adtDict argPattern
302 replicate index P.Anything ++ pat : replicate (numArgs - index - 1) P.Anything
304 map (P.Data ctor . paddedArgs) 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