1{-# LANGUAGE NamedFieldPuns, TupleSections #-}
8import Control.Applicative ((<$>), (<*>))
9import Control.Monad.Except (throwError)
10import Control.Monad (liftM)
11import Control.Monad (forM)
13import Data.Maybe (mapMaybe, catMaybes)
14import qualified Data.Set as Set
15import qualified Data.Map as Map
17import Elm.Utils ((|>))
18import qualified AST.Expression.General as General
19import qualified AST.Expression.Canonical as Canonical
20import qualified AST.Module as Module
21import qualified AST.Pattern as Pattern
22import AST.Pattern (CanonicalPattern)
23import qualified Reporting.Annotation as Annotation
24import qualified Reporting.Region as Region
25import qualified AST.Variable as Var
26import qualified Reporting.Error.CheckMatch as Error
27import Reporting.Warning.CheckMatch
29type M = Either (Annotation.Located Error.Error)
32fromPattern :: CanonicalPattern -> CanonicalPat
33fromPattern (Annotation.A _region p) = case p of
34 Pattern.Data ctor ps ->
35 Data ctor (map fromPattern ps)
41 Alias s (fromPattern p)
55 -> Module.CanonicalBody
56 -> M [Annotation.Located Warning]
57checkBody interfaces = checkExpr . Module.program where
58 checkExpr :: Canonical.Expr -> M [Annotation.Located Warning]
59 checkExpr (Annotation.A r e) = case e of
60 General.ExplicitList es ->
61 concatMapM checkExpr es
63 General.Binop _ e e' ->
64 (++) <$> checkExpr e <*> checkExpr e'
67 maybeCons <$> checkMatch r [p] <*> checkExpr e
70 (++) <$> checkExpr e <*> checkExpr e'
72 General.MultiIf branches ->
73 concatMapM (\(b,e) -> (++) <$> checkExpr b <*> checkExpr e) branches
76 concat <$> sequence [ps, rhssResults, checkExpr e]
78 ps = mapMaybeM (\(Canonical.Definition p _ _) -> checkMatch r [p]) defs
79 rhssResults = concatMapM (\(Canonical.Definition _ e _) -> checkExpr e) defs
81 General.Case e branches ->
82 do eResults <- checkExpr e
83 result <- checkMatch r ps
84 branchResults <- concatMapM (checkExpr . snd) branches
85 return (eResults ++ maybeCons result branchResults)
86 where ps = map fst branches
88 General.Data _ctor es ->
89 concatMapM checkExpr es
91 General.Access e _f ->
94 General.Remove e _f ->
97 General.Insert e _f e' ->
98 (++) <$> checkExpr e <*> checkExpr e'
100 General.Modify e _ ->
103 General.Record fields ->
104 concatMapM (checkExpr . snd) fields
110 ctorToAdt :: Var.Canonical -> Maybe (Module.AdtInfo String)
111 ctorToAdt = \(Var.Canonical {Var.home,Var.name}) -> Map.lookup name =<< Map.lookup home m where
112 -- Maps home to ctor name to the adt to which that ctor belongs
113 m :: Map.Map Var.Home (Map.Map String (Module.AdtInfo String))
114 m = builtins `Map.union` fromModules where
118 fromModules = Map.mapKeysMonotonic Var.Module (Map.map Module.iAdts interfaces)
121 ctorToAdtErr :: Region.Region -> Var.Canonical -> M (Module.AdtInfo String)
122 ctorToAdtErr region c = case ctorToAdt c of
124 throwError (Annotation.A region (Error.ConstructorTypeNotFound c))
130 complement :: Region.Region -> CanonicalPat -> M [CanonicalPat]
131 complement region p = case p of
133 do let ctorName = Var.name ctor
134 ctorHome = Var.home ctor
135 (_tyVars, ctors) <- ctorToAdtErr region ctor
136 -- A pattern is in the complement of this one if it uses one of the
137 -- other constructors of this type...
138 let otherCtorPat (ctor', args) =
139 Data (Var.Canonical {Var.name = ctor', Var.home = ctorHome})
140 (replicate (length args) Anything)
143 filter (\(ctor', _) -> ctor' /= ctorName) ctors
146 -- or if it uses this constructor and one of its argument patterns is
147 -- in the complement of an argument pattern here.
149 sandwich pat i = replicate i Anything ++ pat : replicate (numArgs - i - 1) Anything
151 argComplement <- fmap concat . forM (zip [0..] ps) $ \(i, argP) ->
152 map (\argP' -> Data ctor (sandwich argP' i)) <$> (complement region argP)
154 return (otherCtorPatterns ++ argComplement)
156 Record _fs -> return []
157 Alias _s p -> complement region p
159 Anything -> return []
160 Literal l -> return [AnythingBut (Set.singleton l)]
161 AnythingBut ls -> return (map Literal (Set.toList ls))
163 intersection :: CanonicalPat -> CanonicalPat -> Maybe CanonicalPat
184 (Data ctor1 args1, Data ctor2 args2) ->
187 else fmap (Data ctor1) (sequence (zipWith intersection args1 args2))
189 -- TODO Assuming the fields are identical.
190 (Record _fs, Record _) ->
193 (Literal l1, Literal l2) ->
194 if l1 == l2 then Just p1 else Nothing
196 (AnythingBut ls, Literal l) ->
197 if l `Set.member` ls then Nothing else Just p2
199 (Literal l, AnythingBut ls) ->
200 if l `Set.member` ls then Nothing else Just p1
202 (AnythingBut ls1, AnythingBut ls2) ->
203 Just (AnythingBut (Set.union ls1 ls2))
207 checkMatch :: Region.Region -> [CanonicalPattern] -> M (Maybe (Annotation.Located Warning))
208 checkMatch region = go [Anything] where
209 go :: [CanonicalPat] -> [CanonicalPattern] -> M (Maybe (Annotation.Located Warning))
211 case (unhandled, ps) of
216 return (Just (Annotation.A region (Inexhaustive unhandled)))
219 let pp = fromPattern p
220 Annotation.A region _ = p
222 if all (\q -> intersection q pp == Nothing) unhandled
223 then return (Just (Annotation.A region (Redundant p)))
225 do pComp <- complement region pp
226 go (concatMap (\q -> mapMaybe (intersection q) pComp) unhandled) ps'
229concatMapM :: Monad m => (a -> m [b]) -> [a] -> m [b]
230concatMapM f = liftM concat . mapM f
233mapMaybeM :: Monad m => (a -> m (Maybe b)) -> [a] -> m [b]
234mapMaybeM f = liftM catMaybes . mapM f
237maybeCons :: Maybe a -> [a] -> [a]
238maybeCons = maybe id (:)
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