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 qualified AST.Expression.General as General
18import qualified AST.Expression.Canonical as Canonical
19import qualified AST.Module as Module
20import qualified AST.Pattern as Pattern
21import AST.Pattern (CanonicalPattern)
22import qualified Reporting.Annotation as Annotation
23import qualified Reporting.Region as Region
24import qualified AST.Variable as Var
25import qualified Reporting.Error.CheckMatch as Error
26import Reporting.Warning.CheckMatch
28fromPattern :: CanonicalPattern -> CanonicalPat
29fromPattern (Annotation.A _region p) = case p of
30 Pattern.Data ctor ps -> Data ctor (map fromPattern ps)
31 Pattern.Record fs -> Record fs
32 Pattern.Alias s p -> Alias s (fromPattern p)
33 Pattern.Var s -> Var s
34 Pattern.Anything -> Anything
35 Pattern.Literal l -> Literal l
37concatMapM :: Monad m => (a -> m [b]) -> [a] -> m [b]
38concatMapM f = liftM concat . mapM f
40mapMaybeM :: Monad m => (a -> m (Maybe b)) -> [a] -> m [b]
41mapMaybeM f = liftM catMaybes . mapM f
43maybeCons :: Maybe a -> [a] -> [a]
44maybeCons = maybe id (:)
46type M = Either (Annotation.Located Error.Error)
49 -> Module.CanonicalBody
50 -> M [Annotation.Located Warning]
51checkBody interfaces = checkExpr . Module.program where
52 checkExpr :: Canonical.Expr -> M [Annotation.Located Warning]
53 checkExpr (Annotation.A r e) = case e of
54 General.ExplicitList es -> concatMapM checkExpr es
55 General.Binop _ e e' -> (++) <$> checkExpr e <*> checkExpr e'
56 General.Lambda p e -> maybeCons <$> checkMatch r [p] <*> checkExpr e
57 General.App e e' -> (++) <$> checkExpr e <*> checkExpr e'
58 General.MultiIf branches -> concatMapM (\(b,e) -> (++) <$> checkExpr b <*> checkExpr e) branches
60 General.Let defs e -> fmap concat $ sequence [ps, rhssResults, checkExpr e]
62 ps = mapMaybeM (\(Canonical.Definition p _ _) -> checkMatch r [p]) defs
63 rhssResults = concatMapM (\(Canonical.Definition _ e _) -> checkExpr e) defs
65 General.Case e branches -> do
66 eResults <- checkExpr e
67 result <- checkMatch r ps
68 branchResults <- concatMapM (checkExpr . snd) branches
69 return (eResults ++ maybeCons result branchResults)
70 where ps = map fst branches
72 General.Data _ctor es -> concatMapM checkExpr es
73 General.Access e _f -> checkExpr e
74 General.Remove e _f -> checkExpr e
75 General.Insert e _f e' -> (++) <$> checkExpr e <*> checkExpr e'
76 General.Modify e _ -> checkExpr e
77 General.Record fields -> concatMapM (checkExpr . snd) fields
78 General.Port _pi -> return []
81 ctorToAdt :: Var.Canonical -> Maybe (Module.AdtInfo String)
82 ctorToAdt = \(Var.Canonical {Var.home,Var.name}) -> Map.lookup name =<< Map.lookup home m where
83 m :: Map.Map Var.Home (Map.Map String {- ctor name -} (Module.AdtInfo String))
84 m = builtins `Map.union` fromModules where
85 builtins = Map.empty -- TODO
87 fromModules = Map.mapKeysMonotonic Var.Module (Map.map Module.iAdts interfaces)
89 ctorToAdtErr :: Region.Region -> Var.Canonical -> M (Module.AdtInfo String)
90 ctorToAdtErr region c = case ctorToAdt c of
91 Nothing -> throwError (Annotation.A region (Error.ConstructorTypeNotFound c))
92 Just adt -> return adt
94 complement :: Region.Region -> CanonicalPat -> M [CanonicalPat]
95 complement region p = case p of
97 let ctorName = Var.name ctor
98 ctorHome = Var.home ctor
99 (_tyVars, ctors) <- ctorToAdtErr region ctor
100 -- A pattern is in the complement of this one if it uses one of the
101 -- other constructors of this type...
102 let otherCtorPatterns =
103 map (\(ctor',args) ->
104 Data (Var.Canonical {Var.name = ctor', Var.home = ctorHome})
105 (replicate (length args) Anything))
106 $ filter (\(ctor', _) -> ctor' /= ctorName) ctors
107 -- or if it uses this constructor and one of its argument patterns is
108 -- in the complement of an argument pattern here.
110 sandwich pat i = replicate i Anything ++ pat : replicate (numArgs - i - 1) Anything
112 argComplement <- fmap concat . forM (zip [0..] ps) $ \(i, argP) ->
113 map (\argP' -> Data ctor (sandwich argP' i)) <$> (complement region argP)
115 return (otherCtorPatterns ++ argComplement)
117 Record _fs -> return []
118 Alias _s p -> complement region p
120 Anything -> return []
121 Literal l -> return [AnythingBut (Set.singleton l)]
122 AnythingBut ls -> return (map Literal (Set.toList ls))
124 intersection :: CanonicalPat -> CanonicalPat -> Maybe CanonicalPat
125 intersection p1 p2 = case (p1, p2) of
126 (Alias _ p1', _) -> intersection p1' p2
127 (_, Alias _ p2') -> intersection p1 p2'
128 (Anything, _) -> Just p2
129 (Var _, _) -> Just p2
130 (_, Anything) -> Just p1
131 (_, Var _) -> Just p1
133 (Data ctor1 args1, Data ctor2 args2) ->
136 -- TODO: Assumes that args must be the same length. I think that's ok.
137 else fmap (Data ctor1) (sequence (zipWith intersection args1 args2))
139 -- TODO Assuming the fields are identical.
140 (Record _fs, Record _) -> Just p1
141 (Literal l1, Literal l2) -> if l1 == l2 then Just p1 else Nothing
142 (AnythingBut ls, Literal l) -> if l `Set.member` ls then Nothing else Just p2
143 (Literal l, AnythingBut ls) -> if l `Set.member` ls then Nothing else Just p1
144 (AnythingBut ls1, AnythingBut ls2) -> Just (AnythingBut (Set.union ls1 ls2))
147 checkMatch :: Region.Region -> [CanonicalPattern] -> M (Maybe (Annotation.Located Warning))
148 checkMatch region = go [Anything] where
149 go :: [CanonicalPat] -> [CanonicalPattern] -> M (Maybe (Annotation.Located Warning))
150 go [] [] = return Nothing
151 go qs@(_:_) [] = return (Just (Annotation.A region (Inexhaustive qs)))
152 go unhandled (p:ps) =
153 let pp = fromPattern p
154 Annotation.A region _ = p
156 if all (\q -> intersection q pp == Nothing) unhandled
157 then return (Just (Annotation.A region (Redundant p)))
159 pComp <- complement region pp
160 go (concatMap (\q -> mapMaybe (intersection q) pComp) unhandled) ps
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