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 Optimize.Patterns.DecisionTree as Opt
20import qualified Reporting.Annotation as A
21import qualified Reporting.Error.Pattern as Error
22import qualified Reporting.Region as Region
23import qualified Reporting.Result as Result
28 -> Module.CanonicalModule
29 -> Result.Result w Error.Error Opt.VariantDict
30patternMatches interfaces modul =
32 name = Module.name modul
33 body = Module.body modul
35 toTagDict interfaces name (Module.datatypes body)
37 const (Map.map (Map.map length) tagDict)
38 <$> checkExpression tagDict (Module.program body)
44 Map.Map Var.Home (Map.Map Tag [TagInfo])
56toTagDict :: Module.Interfaces -> ModuleName.Canonical -> Module.ADTs -> TagDict
57toTagDict interfaces localName localAdts =
65 Map.singleton Var.BuiltIn $
73 |> Map.map (toTagMapping . Module.iAdts)
74 |> Map.mapKeysMonotonic Var.Module
75 |> Map.insert (Var.Module localName) (toTagMapping localAdts)
77 Map.union builtinDict interfaceDict
80toTagMapping :: Module.ADTs -> Map.Map Tag [TagInfo]
83 toTagAndArity (_tvars, tagInfoList) =
85 info = map (\(tag, args) -> TagInfo tag (length args)) tagInfoList
87 map (second (const info)) tagInfoList
90 |> concatMap toTagAndArity
94lookupOtherTags :: Var.Canonical -> TagDict -> [TagInfo]
95lookupOtherTags (Var.Canonical home name) tagDict =
96 case Map.lookup name =<< Map.lookup home tagDict of
101 if Help.isTuple name then
102 [ TagInfo name (read (drop 6 name)) ]
105 "Since the Nitpick phase happens after canonicalization and type \
106 \inference, it is impossible that a pattern in a case cannot be \
115 -> Result.Result w Error.Error ()
116checkExpression tagDict (A.A region expression) =
119 checkExpression tagDict
125 checkPatterns tagDict region
137 E.ExplicitList listExprs ->
138 F.traverse_ go listExprs
140 E.Binop _ leftExpr rightExpr ->
141 go2 leftExpr rightExpr
143 E.Lambda pattern body ->
150 E.If branches finally ->
151 F.traverse_ (uncurry go2) branches
156 <* F.traverse_ goDef defs
158 goDef (Canonical.Definition _ pattern expr _) =
162 E.Case expr branches ->
164 <* goPattern (map fst branches)
165 <* F.traverse_ (go . snd) branches
167 E.Data _ctor exprs ->
170 E.Access record _field ->
173 E.Update record fields ->
175 <* F.traverse_ (go . snd) fields
178 F.traverse_ (go . snd) fields
200 -> [Pattern.CanonicalPattern]
201 -> Result.Result w Error.Error ()
202checkPatterns tagDict region patterns =
203 checkPatternsHelp tagDict region [Anything] patterns
210 -> [Pattern.CanonicalPattern]
211 -> Result.Result w Error.Error ()
212checkPatternsHelp tagDict region unhandled patterns =
213 case (unhandled, patterns) of
218 Result.throw region (Error.Incomplete unhandled)
220 (_, pattern@(A.A localRegion _) : remainingPatterns) ->
221 do newUnhandled <- filterPatterns tagDict localRegion pattern unhandled
222 checkPatternsHelp tagDict region newUnhandled remainingPatterns
228 -> Pattern.CanonicalPattern
230 -> Result.Result w Error.Error [Pattern]
231filterPatterns tagDict region pattern unhandled =
234 fromCanonicalPattern pattern
237 intersection pat nitPattern == Nothing
239 if all noIntersection unhandled then
240 Result.throw region Error.Redundant
243 do let complementPatterns = complement tagDict nitPattern
246 (\p -> Maybe.mapMaybe (intersection p) complementPatterns)
250-- PATTERN INTERSECTION
252intersection :: Pattern -> Pattern -> Maybe Pattern
253intersection pattern1 pattern2 =
254 case (pattern1, pattern2) of
255 (Alias _ pattern1', _) ->
256 intersection pattern1' pattern2
258 (_, Alias _ pattern2') ->
259 intersection pattern1 pattern2'
273 (Data ctor1 args1, Data ctor2 args2) ->
274 if ctor1 /= ctor2 then
277 Data ctor1 <$> sequence (zipWith intersection args1 args2)
279 (Record _, Record _) ->
282 (Literal lit1, Literal lit2) ->
288 (AnythingBut literals, Literal lit) ->
289 if Set.member lit literals then
294 (Literal lit, AnythingBut literals) ->
295 if Set.member lit literals then
300 (AnythingBut literals1, AnythingBut literals2) ->
301 Just (AnythingBut (Set.union literals1 literals2))
309complement :: TagDict -> Pattern -> [Pattern]
310complement tagDict nitPattern =
315 Alias _name pattern ->
316 complement tagDict pattern
325 [AnythingBut (Set.singleton lit)]
327 AnythingBut literals ->
328 map Literal (Set.toList literals)
330 Data ctor patterns ->
331 complementData tagDict ctor patterns
334complementData :: TagDict -> Var.Canonical -> [Pattern] -> [Pattern]
335complementData tagDict tag patterns =
338 lookupOtherTags tag tagDict
341 Maybe.mapMaybe (tagToPattern tag) otherTags
347 concat (zipWith (makeArgComplements tagDict tag arity) [0..] patterns)
349 tagComplements ++ argComplements
352tagToPattern :: Var.Canonical -> TagInfo -> Maybe Pattern
353tagToPattern (Var.Canonical home rootTag) (TagInfo tag arity) =
354 if rootTag == tag then
357 Just (Data (Var.Canonical home tag) (replicate arity Anything))
360makeArgComplements :: TagDict -> Var.Canonical -> Int -> Int -> Pattern -> [Pattern]
361makeArgComplements tagDict tag arity index argPattern =
364 complement tagDict argPattern
367 replicate index Anything
369 : replicate (arity - index - 1) Anything
371 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