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
26type Result warning a =
27 Result.Result () warning Error.Error a
30patternMatches :: Module.Interfaces -> Module.Canonical -> Result wrn DT.VariantDict
31patternMatches interfaces (Module.Module name _ info) =
34 toTagDict interfaces name (Module.unions info)
36 const (Map.map (Map.map length) tagDict)
37 <$> checkExpression tagDict (Module.program info)
45 Map.Map Var.Home (Map.Map Tag [TagInfo])
57toTagDict :: Module.Interfaces -> ModuleName.Canonical -> Module.Unions -> TagDict
58toTagDict interfaces localName localUnions =
71 Map.singleton Var.BuiltIn $
81 |> Map.map (toTagMapping . Module.iUnions)
82 |> Map.mapKeysMonotonic Var.Module
83 |> Map.insert (Var.Module localName) (toTagMapping localUnions)
85 Map.union builtinDict interfaceDict
88toTagMapping :: Module.Unions -> Map.Map Tag [TagInfo]
91 toTagAndArity (_tvars, tagInfoList) =
93 info = map (\(tag, args) -> TagInfo tag (length args)) tagInfoList
95 map (second (const info)) tagInfoList
98 |> concatMap toTagAndArity
102lookupOtherTags :: Var.Canonical -> TagDict -> [TagInfo]
103lookupOtherTags (Var.Canonical home name) tagDict =
104 case Map.lookup name =<< Map.lookup home tagDict of
109 if Help.isTuple name then
110 [ TagInfo name (read (drop 6 name)) ]
113 "Since the Nitpick phase happens after canonicalization and type \
114 \inference, it is impossible that a pattern in a case cannot be \
122checkExpression :: TagDict -> Canonical.Expr -> Result wrn ()
123checkExpression tagDict (A.A region expression) =
126 checkExpression tagDict
141 E.ExplicitList listExprs ->
142 F.traverse_ go listExprs
144 E.Binop _ leftExpr rightExpr ->
145 go2 leftExpr rightExpr
147 E.Lambda pattern@(A.A patRegion _) body ->
148 checkPatterns tagDict patRegion Error.Arg [pattern]
154 E.If branches finally ->
155 F.traverse_ (uncurry go2) branches
160 <* F.traverse_ goDef defs
162 goDef (Canonical.Def _ pattern@(A.A patRegion _) expr _) =
163 checkPatterns tagDict patRegion Error.LetBound [pattern]
166 E.Case expr branches ->
168 <* checkPatterns tagDict region Error.Case (map fst branches)
169 <* F.traverse_ (go . snd) branches
171 E.Data _ctor exprs ->
174 E.Access record _field ->
177 E.Update record fields ->
179 <* F.traverse_ (go . snd) fields
182 F.traverse_ (go . snd) fields
197 error "DANGER - Program AST nodes should not be in Nitpick.PatternMatches."
210checkPatterns :: TagDict -> Region.Region -> Error.Origin -> [Pattern.Canonical] -> Result wrn ()
211checkPatterns tagDict region origin patterns =
212 checkPatternsHelp tagDict region origin [Anything] patterns
220 -> [Pattern.Canonical]
222checkPatternsHelp tagDict region origin unhandled patterns =
223 case (unhandled, patterns) of
228 Result.throw region (Error.Incomplete origin unhandled)
230 (_, pattern@(A.A localRegion _) : remainingPatterns) ->
231 do newUnhandled <- filterPatterns tagDict localRegion pattern unhandled
232 checkPatternsHelp tagDict region origin newUnhandled remainingPatterns
240 -> Result wrn [Pattern]
241filterPatterns tagDict region pattern unhandled =
244 fromCanonicalPattern pattern
247 intersection pat nitPattern == Nothing
249 if all noIntersection unhandled then
250 Result.throw region Error.Redundant
253 do let complementPatterns = complement tagDict nitPattern
256 (\p -> Maybe.mapMaybe (intersection p) complementPatterns)
261-- PATTERN INTERSECTION
264intersection :: Pattern -> Pattern -> Maybe Pattern
265intersection pattern1 pattern2 =
266 case (pattern1, pattern2) of
267 (Alias _ pattern1', _) ->
268 intersection pattern1' pattern2
270 (_, Alias _ pattern2') ->
271 intersection pattern1 pattern2'
285 (Data ctor1 args1, Data ctor2 args2) ->
286 if ctor1 /= ctor2 then
289 Data ctor1 <$> sequence (zipWith intersection args1 args2)
291 (Record _, Record _) ->
294 (Literal lit1, Literal lit2) ->
300 (AnythingBut literals, Literal lit) ->
301 if Set.member lit literals then
306 (Literal lit, AnythingBut literals) ->
307 if Set.member lit literals then
312 (AnythingBut literals1, AnythingBut literals2) ->
313 Just (AnythingBut (Set.union literals1 literals2))
323complement :: TagDict -> Pattern -> [Pattern]
324complement tagDict nitPattern =
329 Alias _name pattern ->
330 complement tagDict pattern
339 [AnythingBut (Set.singleton lit)]
341 AnythingBut literals ->
342 map Literal (Set.toList literals)
344 Data ctor patterns ->
345 complementData tagDict ctor patterns
348complementData :: TagDict -> Var.Canonical -> [Pattern] -> [Pattern]
349complementData tagDict tag patterns =
352 lookupOtherTags tag tagDict
355 Maybe.mapMaybe (tagToPattern tag) otherTags
361 concat (zipWith (makeArgComplements tagDict tag arity) [0..] patterns)
363 tagComplements ++ argComplements
366tagToPattern :: Var.Canonical -> TagInfo -> Maybe Pattern
367tagToPattern (Var.Canonical home rootTag) (TagInfo tag arity) =
368 if rootTag == tag then
371 Just (Data (Var.Canonical home tag) (replicate arity Anything))
374makeArgComplements :: TagDict -> Var.Canonical -> Int -> Int -> Pattern -> [Pattern]
375makeArgComplements tagDict tag arity index argPattern =
378 complement tagDict argPattern
381 replicate index Anything
383 : replicate (arity - index - 1) Anything
385 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