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
138 E.ExplicitList listExprs ->
139 F.traverse_ go listExprs
141 E.Binop _ leftExpr rightExpr ->
142 go2 leftExpr rightExpr
144 E.Lambda pattern@(A.A patRegion _) body ->
145 checkPatterns tagDict patRegion Error.Arg [pattern]
151 E.If branches finally ->
152 F.traverse_ (uncurry go2) branches
157 <* F.traverse_ goDef defs
159 goDef (Canonical.Def _ pattern@(A.A patRegion _) expr _) =
160 checkPatterns tagDict patRegion Error.LetBound [pattern]
163 E.Case expr branches ->
165 <* checkPatterns tagDict region Error.Case (map fst branches)
166 <* F.traverse_ (go . snd) branches
168 E.Data _ctor exprs ->
171 E.Access record _field ->
174 E.Update record fields ->
176 <* F.traverse_ (go . snd) fields
179 F.traverse_ (go . snd) fields
187 E.OutgoingPort _ _ ->
190 E.IncomingPort _ _ ->
194 error "DANGER - Program AST nodes should not be in Nitpick.PatternMatches."
207checkPatterns :: TagDict -> Region.Region -> Error.Origin -> [Pattern.Canonical] -> Result wrn ()
208checkPatterns tagDict region origin patterns =
209 checkPatternsHelp tagDict region origin [Anything] patterns
217 -> [Pattern.Canonical]
219checkPatternsHelp tagDict region origin unhandled patterns =
220 case (unhandled, patterns) of
225 Result.throw region (Error.Incomplete origin unhandled)
227 (_, pattern@(A.A localRegion _) : remainingPatterns) ->
228 do newUnhandled <- filterPatterns tagDict localRegion pattern unhandled
229 checkPatternsHelp tagDict region origin newUnhandled remainingPatterns
237 -> Result wrn [Pattern]
238filterPatterns tagDict region pattern unhandled =
241 fromCanonicalPattern pattern
244 intersection pat nitPattern == Nothing
246 if all noIntersection unhandled then
247 Result.throw region Error.Redundant
250 do let complementPatterns = complement tagDict nitPattern
253 (\p -> Maybe.mapMaybe (intersection p) complementPatterns)
258-- PATTERN INTERSECTION
261intersection :: Pattern -> Pattern -> Maybe Pattern
262intersection pattern1 pattern2 =
263 case (pattern1, pattern2) of
264 (Alias _ pattern1', _) ->
265 intersection pattern1' pattern2
267 (_, Alias _ pattern2') ->
268 intersection pattern1 pattern2'
282 (Data ctor1 args1, Data ctor2 args2) ->
283 if ctor1 /= ctor2 then
286 Data ctor1 <$> sequence (zipWith intersection args1 args2)
288 (Record _, Record _) ->
291 (Literal lit1, Literal lit2) ->
297 (AnythingBut literals, Literal lit) ->
298 if Set.member lit literals then
303 (Literal lit, AnythingBut literals) ->
304 if Set.member lit literals then
309 (AnythingBut literals1, AnythingBut literals2) ->
310 Just (AnythingBut (Set.union literals1 literals2))
320complement :: TagDict -> Pattern -> [Pattern]
321complement tagDict nitPattern =
326 Alias _name pattern ->
327 complement tagDict pattern
336 [AnythingBut (Set.singleton lit)]
338 AnythingBut literals ->
339 map Literal (Set.toList literals)
341 Data ctor patterns ->
342 complementData tagDict ctor patterns
345complementData :: TagDict -> Var.Canonical -> [Pattern] -> [Pattern]
346complementData tagDict tag patterns =
349 lookupOtherTags tag tagDict
352 Maybe.mapMaybe (tagToPattern tag) otherTags
358 concat (zipWith (makeArgComplements tagDict tag arity) [0..] patterns)
360 tagComplements ++ argComplements
363tagToPattern :: Var.Canonical -> TagInfo -> Maybe Pattern
364tagToPattern (Var.Canonical home rootTag) (TagInfo tag arity) =
365 if rootTag == tag then
368 Just (Data (Var.Canonical home tag) (replicate arity Anything))
371makeArgComplements :: TagDict -> Var.Canonical -> Int -> Int -> Pattern -> [Pattern]
372makeArgComplements tagDict tag arity index argPattern =
375 complement tagDict argPattern
378 replicate index Anything
380 : replicate (arity - index - 1) Anything
382 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