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.Canonical as C
10import qualified AST.Helpers as Help
11import qualified AST.Module as Module
12import qualified AST.Module.Name as ModuleName
13import qualified AST.Pattern as Pattern
14import qualified AST.Variable as Var
15import Elm.Utils ((|>))
16import Nitpick.Pattern (Pattern(..), fromCanonicalPattern)
17import qualified Optimize.DecisionTree as DT
18import qualified Reporting.Annotation as A
19import qualified Reporting.Error.Pattern as Error
20import qualified Reporting.Region as Region
21import qualified Reporting.Result as Result
25type Result warning a =
26 Result.Result () warning Error.Error a
29patternMatches :: Module.Interfaces -> Module.Canonical -> Result wrn DT.VariantDict
30patternMatches interfaces (Module.Module name _ info) =
33 toTagDict interfaces name (Module.unions info)
35 const (Map.map (Map.map length) tagDict)
36 <$> checkExpression tagDict (Module.program info)
44 Map.Map Var.Home (Map.Map Tag [TagInfo])
56toTagDict :: Module.Interfaces -> ModuleName.Canonical -> Module.Unions -> TagDict
57toTagDict interfaces localName localUnions =
70 Map.singleton Var.BuiltIn $
80 |> Map.map (toTagMapping . Module.iUnions)
81 |> Map.mapKeysMonotonic Var.Module
82 |> Map.insert (Var.Module localName) (toTagMapping localUnions)
84 Map.union builtinDict interfaceDict
87toTagMapping :: Module.Unions -> Map.Map Tag [TagInfo]
90 toTagAndArity (_tvars, tagInfoList) =
92 info = map (\(tag, args) -> TagInfo tag (length args)) tagInfoList
94 map (second (const info)) tagInfoList
97 |> concatMap toTagAndArity
101lookupOtherTags :: Var.Canonical -> TagDict -> [TagInfo]
102lookupOtherTags (Var.Canonical home name) tagDict =
103 case Map.lookup name =<< Map.lookup home tagDict of
108 if Help.isTuple name then
109 [ TagInfo name (read (drop 6 name)) ]
112 "Since the Nitpick phase happens after canonicalization and type \
113 \inference, it is impossible that a pattern in a case cannot be \
121checkExpression :: TagDict -> C.Expr -> Result wrn ()
122checkExpression tagDict (A.A region expression) =
125 checkExpression tagDict
138 F.traverse_ go listExprs
140 C.Binop _ leftExpr rightExpr ->
141 go2 leftExpr rightExpr
143 C.Lambda pattern@(A.A patRegion _) body ->
144 checkPatterns tagDict patRegion Error.Arg [pattern]
150 C.If branches finally ->
151 F.traverse_ (uncurry go2) branches
156 <* F.traverse_ goDef defs
158 goDef (C.Def _ pattern@(A.A patRegion _) expr _) =
159 checkPatterns tagDict patRegion Error.LetBound [pattern]
162 C.Case expr branches ->
164 <* checkPatterns tagDict region Error.Case (map fst branches)
165 <* F.traverse_ (go . snd) branches
167 C.Ctor _ctor exprs ->
170 C.Access record _field ->
173 C.Update record fields ->
175 <* F.traverse_ (go . snd) fields
178 F.traverse_ (go . snd) fields
186 C.OutgoingPort _ _ ->
189 C.IncomingPort _ _ ->
193 error "DANGER - Program AST nodes should not be in Nitpick.PatternMatches."
206checkPatterns :: TagDict -> Region.Region -> Error.Origin -> [Pattern.Canonical] -> Result wrn ()
207checkPatterns tagDict region origin patterns =
208 checkPatternsHelp tagDict region origin [Anything] patterns
216 -> [Pattern.Canonical]
218checkPatternsHelp tagDict region origin unhandled patterns =
219 case (unhandled, patterns) of
224 Result.throw region (Error.Incomplete origin unhandled)
226 (_, pattern@(A.A localRegion _) : remainingPatterns) ->
227 do newUnhandled <- filterPatterns tagDict localRegion pattern unhandled
228 checkPatternsHelp tagDict region origin newUnhandled remainingPatterns
236 -> Result wrn [Pattern]
237filterPatterns tagDict region pattern unhandled =
240 fromCanonicalPattern pattern
243 intersection pat nitPattern == Nothing
245 if all noIntersection unhandled then
246 Result.throw region Error.Redundant
249 do let complementPatterns = complement tagDict nitPattern
252 (\p -> Maybe.mapMaybe (intersection p) complementPatterns)
257-- PATTERN INTERSECTION
260intersection :: Pattern -> Pattern -> Maybe Pattern
261intersection pattern1 pattern2 =
262 case (pattern1, pattern2) of
263 (Alias _ pattern1', _) ->
264 intersection pattern1' pattern2
266 (_, Alias _ pattern2') ->
267 intersection pattern1 pattern2'
281 (Data ctor1 args1, Data ctor2 args2) ->
282 if ctor1 /= ctor2 then
285 Data ctor1 <$> sequence (zipWith intersection args1 args2)
287 (Record _, Record _) ->
290 (Literal lit1, Literal lit2) ->
296 (AnythingBut literals, Literal lit) ->
297 if Set.member lit literals then
302 (Literal lit, AnythingBut literals) ->
303 if Set.member lit literals then
308 (AnythingBut literals1, AnythingBut literals2) ->
309 Just (AnythingBut (Set.union literals1 literals2))
319complement :: TagDict -> Pattern -> [Pattern]
320complement tagDict nitPattern =
325 Alias _name pattern ->
326 complement tagDict pattern
335 [AnythingBut (Set.singleton lit)]
337 AnythingBut literals ->
338 map Literal (Set.toList literals)
340 Data ctor patterns ->
341 complementData tagDict ctor patterns
344complementData :: TagDict -> Var.Canonical -> [Pattern] -> [Pattern]
345complementData tagDict tag patterns =
348 lookupOtherTags tag tagDict
351 Maybe.mapMaybe (tagToPattern tag) otherTags
357 concat (zipWith (makeArgComplements tagDict tag arity) [0..] patterns)
359 tagComplements ++ argComplements
362tagToPattern :: Var.Canonical -> TagInfo -> Maybe Pattern
363tagToPattern (Var.Canonical home rootTag) (TagInfo tag arity) =
364 if rootTag == tag then
367 Just (Data (Var.Canonical home tag) (replicate arity Anything))
370makeArgComplements :: TagDict -> Var.Canonical -> Int -> Int -> Pattern -> [Pattern]
371makeArgComplements tagDict tag arity index argPattern =
374 complement tagDict argPattern
377 replicate index Anything
379 : replicate (arity - index - 1) Anything
381 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