1module Nitpick.PatternMatches (patternMatches) where
3import Control.Arrow (second)
4import qualified Data.Foldable as F
5import qualified Data.Map as Map
6import qualified Data.Maybe as Maybe
7import qualified Data.Set as Set
9import qualified AST.Expression.General as E
10import qualified AST.Expression.Canonical as Canonical
11import qualified AST.Helpers as Help
12import qualified AST.Module as Module
13import qualified AST.Module.Name as ModuleName
14import qualified AST.Pattern as Pattern
15import qualified AST.Variable as Var
16import Elm.Utils ((|>))
17import Nitpick.Pattern (Pattern(..), fromCanonicalPattern)
18import qualified Optimize.DecisionTree as DT
19import qualified Reporting.Annotation as A
20import qualified Reporting.Error.Pattern as Error
21import qualified Reporting.Region as Region
22import qualified Reporting.Result as Result
27 -> Module.CanonicalModule
28 -> Result.Result w Error.Error DT.VariantDict
29patternMatches interfaces modul =
31 name = Module.name modul
32 body = Module.body modul
34 toTagDict interfaces name (Module.datatypes body)
36 const (Map.map (Map.map length) tagDict)
37 <$> checkExpression tagDict (Module.program body)
43 Map.Map Var.Home (Map.Map Tag [TagInfo])
55toTagDict :: Module.Interfaces -> ModuleName.Canonical -> Module.ADTs -> TagDict
56toTagDict interfaces localName localAdts =
69 Map.singleton Var.BuiltIn $
79 |> Map.map (toTagMapping . Module.iAdts)
80 |> Map.mapKeysMonotonic Var.Module
81 |> Map.insert (Var.Module localName) (toTagMapping localAdts)
83 Map.union builtinDict interfaceDict
86toTagMapping :: Module.ADTs -> Map.Map Tag [TagInfo]
89 toTagAndArity (_tvars, tagInfoList) =
91 info = map (\(tag, args) -> TagInfo tag (length args)) tagInfoList
93 map (second (const info)) tagInfoList
96 |> concatMap toTagAndArity
100lookupOtherTags :: Var.Canonical -> TagDict -> [TagInfo]
101lookupOtherTags (Var.Canonical home name) tagDict =
102 case Map.lookup name =<< Map.lookup home tagDict of
107 if Help.isTuple name then
108 [ TagInfo name (read (drop 6 name)) ]
111 "Since the Nitpick phase happens after canonicalization and type \
112 \inference, it is impossible that a pattern in a case cannot be \
121 -> Result.Result w Error.Error ()
122checkExpression tagDict (A.A region expression) =
125 checkExpression tagDict
140 E.ExplicitList listExprs ->
141 F.traverse_ go listExprs
143 E.Binop _ leftExpr rightExpr ->
144 go2 leftExpr rightExpr
146 E.Lambda pattern@(A.A patRegion _) body ->
147 checkPatterns tagDict patRegion Error.Arg [pattern]
153 E.If branches finally ->
154 F.traverse_ (uncurry go2) branches
159 <* F.traverse_ goDef defs
161 goDef (Canonical.Definition _ pattern@(A.A patRegion _) expr _) =
162 checkPatterns tagDict patRegion Error.LetBound [pattern]
165 E.Case expr branches ->
167 <* checkPatterns tagDict region Error.Case (map fst branches)
168 <* F.traverse_ (go . snd) branches
170 E.Data _ctor exprs ->
173 E.Access record _field ->
176 E.Update record fields ->
178 <* F.traverse_ (go . snd) fields
181 F.traverse_ (go . snd) fields
193 -> [Pattern.CanonicalPattern]
194 -> Result.Result w Error.Error ()
195checkPatterns tagDict region origin patterns =
196 checkPatternsHelp tagDict region origin [Anything] patterns
204 -> [Pattern.CanonicalPattern]
205 -> Result.Result w Error.Error ()
206checkPatternsHelp tagDict region origin unhandled patterns =
207 case (unhandled, patterns) of
212 Result.throw region (Error.Incomplete origin unhandled)
214 (_, pattern@(A.A localRegion _) : remainingPatterns) ->
215 do newUnhandled <- filterPatterns tagDict localRegion pattern unhandled
216 checkPatternsHelp tagDict region origin newUnhandled remainingPatterns
222 -> Pattern.CanonicalPattern
224 -> Result.Result w Error.Error [Pattern]
225filterPatterns tagDict region pattern unhandled =
228 fromCanonicalPattern pattern
231 intersection pat nitPattern == Nothing
233 if all noIntersection unhandled then
234 Result.throw region Error.Redundant
237 do let complementPatterns = complement tagDict nitPattern
240 (\p -> Maybe.mapMaybe (intersection p) complementPatterns)
244-- PATTERN INTERSECTION
246intersection :: Pattern -> Pattern -> Maybe Pattern
247intersection pattern1 pattern2 =
248 case (pattern1, pattern2) of
249 (Alias _ pattern1', _) ->
250 intersection pattern1' pattern2
252 (_, Alias _ pattern2') ->
253 intersection pattern1 pattern2'
267 (Data ctor1 args1, Data ctor2 args2) ->
268 if ctor1 /= ctor2 then
271 Data ctor1 <$> sequence (zipWith intersection args1 args2)
273 (Record _, Record _) ->
276 (Literal lit1, Literal lit2) ->
282 (AnythingBut literals, Literal lit) ->
283 if Set.member lit literals then
288 (Literal lit, AnythingBut literals) ->
289 if Set.member lit literals then
294 (AnythingBut literals1, AnythingBut literals2) ->
295 Just (AnythingBut (Set.union literals1 literals2))
303complement :: TagDict -> Pattern -> [Pattern]
304complement tagDict nitPattern =
309 Alias _name pattern ->
310 complement tagDict pattern
319 [AnythingBut (Set.singleton lit)]
321 AnythingBut literals ->
322 map Literal (Set.toList literals)
324 Data ctor patterns ->
325 complementData tagDict ctor patterns
328complementData :: TagDict -> Var.Canonical -> [Pattern] -> [Pattern]
329complementData tagDict tag patterns =
332 lookupOtherTags tag tagDict
335 Maybe.mapMaybe (tagToPattern tag) otherTags
341 concat (zipWith (makeArgComplements tagDict tag arity) [0..] patterns)
343 tagComplements ++ argComplements
346tagToPattern :: Var.Canonical -> TagInfo -> Maybe Pattern
347tagToPattern (Var.Canonical home rootTag) (TagInfo tag arity) =
348 if rootTag == tag then
351 Just (Data (Var.Canonical home tag) (replicate arity Anything))
354makeArgComplements :: TagDict -> Var.Canonical -> Int -> Int -> Pattern -> [Pattern]
355makeArgComplements tagDict tag arity index argPattern =
358 complement tagDict argPattern
361 replicate index Anything
363 : replicate (arity - index - 1) Anything
365 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