1{-# LANGUAGE NamedFieldPuns, TupleSections #-}
2module Nitpick.PatternMatches
8import Control.Applicative ((<$>), (<*>))
9import Control.Monad.Except (forM, liftM, throwError)
10import Data.Maybe (mapMaybe, catMaybes)
11import qualified Data.Set as Set
12import qualified Data.Map as Map
14import qualified AST.Expression.General as General
15import qualified AST.Expression.Canonical as Canonical
16import qualified AST.Module as Module
17import qualified AST.Pattern as Pattern
18import qualified AST.Variable as Var
19import Elm.Utils ((|>))
20import qualified Reporting.Annotation as Annotation
21import qualified Reporting.Error.Nitpick as Error
22import qualified Reporting.Region as Region
23import qualified Reporting.Warning.Nitpick as Warning
27 Either (Annotation.Located Error.Error)
30fromPattern :: CanonicalPattern -> CanonicalPat
31fromPattern (Annotation.A _region p) =
33 Pattern.Data ctor ps ->
34 Data ctor (map fromPattern ps)
40 Alias s (fromPattern p)
54 -> Module.CanonicalBody
55 -> M [Annotation.Located Warning]
57 checkExpr . Module.program
59 checkExpr :: Canonical.Expr -> M [Annotation.Located Warning]
60 checkExpr (Annotation.A r e) =
62 General.ExplicitList es ->
63 concatMapM checkExpr es
65 General.Binop _ e e' ->
66 (++) <$> checkExpr e <*> checkExpr e'
69 maybeCons <$> checkMatch r [p] <*> checkExpr e
72 (++) <$> checkExpr e <*> checkExpr e'
74 General.MultiIf branches ->
75 concatMapM (\(b,e) -> (++) <$> checkExpr b <*> checkExpr e) branches
78 concat <$> sequence [ps, rhssResults, checkExpr e]
80 ps = filterMapM (\(Canonical.Definition p _ _) -> checkMatch r [p]) defs
82 rhssResults = concatMapM (\(Canonical.Definition _ e _) -> checkExpr e) defs
84 General.Case e branches ->
85 do eResults <- checkExpr e
86 result <- checkMatch r ps
87 branchResults <- concatMapM (checkExpr . snd) branches
88 return (eResults ++ maybeCons result branchResults)
89 where ps = map fst branches
91 General.Data _ctor es ->
92 concatMapM checkExpr es
94 General.Access e _f ->
97 General.Remove e _f ->
100 General.Insert e _f e' ->
101 (++) <$> checkExpr e <*> checkExpr e'
103 General.Modify e _ ->
106 General.Record fields ->
107 concatMapM (checkExpr . snd) fields
113 ctorToAdt :: Var.Canonical -> Maybe (Module.AdtInfo String)
115 \(Var.Canonical {Var.home,Var.name}) -> Map.lookup name =<< Map.lookup home m
117 -- Maps home to ctor name to the adt to which that ctor belongs
118 m :: Map.Map Var.Home (Map.Map String (Module.AdtInfo String))
120 builtins `Map.union` fromModules
125 fromModules = Map.mapKeysMonotonic Var.Module (Map.map Module.iAdts interfaces)
128 ctorToAdtErr :: Region.Region -> Var.Canonical -> M (Module.AdtInfo String)
129 ctorToAdtErr region c =
132 throwError (Annotation.A region (Error.ConstructorTypeNotFound c))
138 complement :: Region.Region -> CanonicalPat -> M [CanonicalPat]
139 complement region p =
142 do let ctorName = Var.name ctor
143 ctorHome = Var.home ctor
144 (_tyVars, ctors) <- ctorToAdtErr region ctor
145 -- A pattern is in the complement of this one if it uses one of the
146 -- other constructors of this type...
147 let otherCtorPat (ctor', args) =
148 Data (Var.Canonical {Var.name = ctor', Var.home = ctorHome})
149 (replicate (length args) Anything)
152 filter (\(ctor', _) -> ctor' /= ctorName) ctors
155 -- or if it uses this constructor and one of its argument patterns is
156 -- in the complement of an argument pattern here.
158 sandwich pat i = replicate i Anything ++ pat : replicate (numArgs - i - 1) Anything
160 argComplement <- fmap concat . forM (zip [0..] ps) $ \(i, argP) ->
161 map (\argP' -> Data ctor (sandwich argP' i)) <$> (complement region argP)
163 return (otherCtorPatterns ++ argComplement)
178 return [AnythingBut (Set.singleton l)]
181 return (map Literal (Set.toList ls))
183 intersection :: CanonicalPat -> CanonicalPat -> Maybe CanonicalPat
204 (Data ctor1 args1, Data ctor2 args2) ->
207 else fmap (Data ctor1) (sequence (zipWith intersection args1 args2))
209 -- TODO Assuming the fields are identical.
210 (Record _fs, Record _) ->
213 (Literal l1, Literal l2) ->
214 if l1 == l2 then Just p1 else Nothing
216 (AnythingBut ls, Literal l) ->
217 if l `Set.member` ls then Nothing else Just p2
219 (Literal l, AnythingBut ls) ->
220 if l `Set.member` ls then Nothing else Just p1
222 (AnythingBut ls1, AnythingBut ls2) ->
223 Just (AnythingBut (Set.union ls1 ls2))
227 checkMatch :: Region.Region -> [CanonicalPattern] -> M (Maybe (Annotation.Located Warning))
231 go :: [CanonicalPat] -> [CanonicalPattern] -> M (Maybe (Annotation.Located Warning))
233 case (unhandled, ps) of
238 return (Just (Annotation.A region (Inexhaustive unhandled)))
241 let pp = fromPattern p
242 Annotation.A region _ = p
244 if all (\q -> intersection q pp == Nothing) unhandled
245 then return (Just (Annotation.A region (Redundant p)))
247 do pComp <- complement region pp
248 go (concatMap (\q -> mapMaybe (intersection q) pComp) unhandled) ps'
253concatMapM :: Monad m => (a -> m [b]) -> [a] -> m [b]
255 liftM concat (mapM f list)
258filterMapM :: Monad m => (a -> m (Maybe b)) -> [a] -> m [b]
260 liftM catMaybes (mapM f list)
263maybeCons :: Maybe a -> [a] -> [a]
264maybeCons maybe list =
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