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.Patterns.DecisionTree as Opt
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 Opt.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 =
64 Map.singleton Var.BuiltIn $
72 |> Map.map (toTagMapping . Module.iAdts)
73 |> Map.mapKeysMonotonic Var.Module
74 |> Map.insert (Var.Module localName) (toTagMapping localAdts)
76 Map.union builtinDict interfaceDict
79toTagMapping :: Module.ADTs -> Map.Map Tag [TagInfo]
82 toTagAndArity (_tvars, tagInfoList) =
84 info = map (\(tag, args) -> TagInfo tag (length args)) tagInfoList
86 map (second (const info)) tagInfoList
89 |> concatMap toTagAndArity
93lookupOtherTags :: Var.Canonical -> TagDict -> [TagInfo]
94lookupOtherTags (Var.Canonical home name) tagDict =
95 case Map.lookup name =<< Map.lookup home tagDict of
100 if Help.isTuple name then
101 [ TagInfo name (read (drop 6 name)) ]
104 "Since the Nitpick phase happens after canonicalization and type \
105 \inference, it is impossible that a pattern in a case cannot be \
114 -> Result.Result w Error.Error ()
115checkExpression tagDict (A.A region expression) =
118 checkExpression tagDict
133 E.ExplicitList listExprs ->
134 F.traverse_ go listExprs
136 E.Binop _ leftExpr rightExpr ->
137 go2 leftExpr rightExpr
139 E.Lambda pattern@(A.A patRegion _) body ->
140 checkPatterns tagDict patRegion Error.Arg [pattern]
146 E.If branches finally ->
147 F.traverse_ (uncurry go2) branches
152 <* F.traverse_ goDef defs
154 goDef (Canonical.Definition _ pattern@(A.A patRegion _) expr _) =
155 checkPatterns tagDict patRegion Error.LetBound [pattern]
158 E.Case expr branches ->
160 <* checkPatterns tagDict region Error.Case (map fst branches)
161 <* F.traverse_ (go . snd) branches
163 E.Data _ctor exprs ->
166 E.Access record _field ->
169 E.Update record fields ->
171 <* F.traverse_ (go . snd) fields
174 F.traverse_ (go . snd) fields
197 -> [Pattern.CanonicalPattern]
198 -> Result.Result w Error.Error ()
199checkPatterns tagDict region origin patterns =
200 checkPatternsHelp tagDict region origin [Anything] patterns
208 -> [Pattern.CanonicalPattern]
209 -> Result.Result w Error.Error ()
210checkPatternsHelp tagDict region origin unhandled patterns =
211 case (unhandled, patterns) of
216 Result.throw region (Error.Incomplete origin unhandled)
218 (_, pattern@(A.A localRegion _) : remainingPatterns) ->
219 do newUnhandled <- filterPatterns tagDict localRegion pattern unhandled
220 checkPatternsHelp tagDict region origin newUnhandled remainingPatterns
226 -> Pattern.CanonicalPattern
228 -> Result.Result w Error.Error [Pattern]
229filterPatterns tagDict region pattern unhandled =
232 fromCanonicalPattern pattern
235 intersection pat nitPattern == Nothing
237 if all noIntersection unhandled then
238 Result.throw region Error.Redundant
241 do let complementPatterns = complement tagDict nitPattern
244 (\p -> Maybe.mapMaybe (intersection p) complementPatterns)
248-- PATTERN INTERSECTION
250intersection :: Pattern -> Pattern -> Maybe Pattern
251intersection pattern1 pattern2 =
252 case (pattern1, pattern2) of
253 (Alias _ pattern1', _) ->
254 intersection pattern1' pattern2
256 (_, Alias _ pattern2') ->
257 intersection pattern1 pattern2'
271 (Data ctor1 args1, Data ctor2 args2) ->
272 if ctor1 /= ctor2 then
275 Data ctor1 <$> sequence (zipWith intersection args1 args2)
277 (Record _, Record _) ->
280 (Literal lit1, Literal lit2) ->
286 (AnythingBut literals, Literal lit) ->
287 if Set.member lit literals then
292 (Literal lit, AnythingBut literals) ->
293 if Set.member lit literals then
298 (AnythingBut literals1, AnythingBut literals2) ->
299 Just (AnythingBut (Set.union literals1 literals2))
307complement :: TagDict -> Pattern -> [Pattern]
308complement tagDict nitPattern =
313 Alias _name pattern ->
314 complement tagDict pattern
323 [AnythingBut (Set.singleton lit)]
325 AnythingBut literals ->
326 map Literal (Set.toList literals)
328 Data ctor patterns ->
329 complementData tagDict ctor patterns
332complementData :: TagDict -> Var.Canonical -> [Pattern] -> [Pattern]
333complementData tagDict tag patterns =
336 lookupOtherTags tag tagDict
339 Maybe.mapMaybe (tagToPattern tag) otherTags
345 concat (zipWith (makeArgComplements tagDict tag arity) [0..] patterns)
347 tagComplements ++ argComplements
350tagToPattern :: Var.Canonical -> TagInfo -> Maybe Pattern
351tagToPattern (Var.Canonical home rootTag) (TagInfo tag arity) =
352 if rootTag == tag then
355 Just (Data (Var.Canonical home tag) (replicate arity Anything))
358makeArgComplements :: TagDict -> Var.Canonical -> Int -> Int -> Pattern -> [Pattern]
359makeArgComplements tagDict tag arity index argPattern =
362 complement tagDict argPattern
365 replicate index Anything
367 : replicate (arity - index - 1) Anything
369 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