diff options
author | Péter Diviánszky <divipp@gmail.com> | 2016-05-04 17:11:42 +0200 |
---|---|---|
committer | Péter Diviánszky <divipp@gmail.com> | 2016-05-04 17:11:42 +0200 |
commit | b6133b895cd6d18909184f974b2d2c5157b20839 (patch) | |
tree | e3581ede03f169c38ff5dcdf9ef43fd003e68d34 /src/LambdaCube/Compiler/InferMonad.hs | |
parent | d09859323b7213d6b3c3baf485d8389100faf469 (diff) |
split Infer.hs
Diffstat (limited to 'src/LambdaCube/Compiler/InferMonad.hs')
-rw-r--r-- | src/LambdaCube/Compiler/InferMonad.hs | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/src/LambdaCube/Compiler/InferMonad.hs b/src/LambdaCube/Compiler/InferMonad.hs new file mode 100644 index 00000000..6efaee3a --- /dev/null +++ b/src/LambdaCube/Compiler/InferMonad.hs | |||
@@ -0,0 +1,223 @@ | |||
1 | {-# LANGUAGE OverloadedStrings #-} | ||
2 | {-# LANGUAGE LambdaCase #-} | ||
3 | {-# LANGUAGE ViewPatterns #-} | ||
4 | {-# LANGUAGE PatternSynonyms #-} | ||
5 | {-# LANGUAGE FlexibleContexts #-} | ||
6 | {-# LANGUAGE FlexibleInstances #-} | ||
7 | {-# LANGUAGE NoMonomorphismRestriction #-} | ||
8 | {-# LANGUAGE ScopedTypeVariables #-} | ||
9 | {-# LANGUAGE RecursiveDo #-} | ||
10 | {-# LANGUAGE RankNTypes #-} | ||
11 | {-# LANGUAGE MultiParamTypeClasses #-} | ||
12 | {-# LANGUAGE GeneralizedNewtypeDeriving #-} | ||
13 | {-# LANGUAGE DeriveFunctor #-} | ||
14 | {-# OPTIONS_GHC -fno-warn-unused-binds #-} -- TODO: remove | ||
15 | module LambdaCube.Compiler.InferMonad where | ||
16 | |||
17 | import Data.Monoid | ||
18 | import Data.List | ||
19 | import qualified Data.Set as Set | ||
20 | import qualified Data.Map as Map | ||
21 | |||
22 | import Control.Monad.Except | ||
23 | import Control.Monad.Reader | ||
24 | import Control.Monad.Writer | ||
25 | import Control.Arrow hiding ((<+>)) | ||
26 | import Control.DeepSeq | ||
27 | |||
28 | import LambdaCube.Compiler.DeBruijn | ||
29 | import LambdaCube.Compiler.Pretty hiding (braces, parens) | ||
30 | import LambdaCube.Compiler.DesugaredSource hiding (getList) | ||
31 | import LambdaCube.Compiler.Parser (ParseWarning) -- TODO: remove | ||
32 | import LambdaCube.Compiler.Core | ||
33 | |||
34 | -------------------------------------------------------------------------------- error messages | ||
35 | |||
36 | data ErrorMsg | ||
37 | = ErrorMsg Doc | ||
38 | | ECantFind SName SI | ||
39 | | ETypeError Doc SI | ||
40 | | ERedefined SName SI SI | ||
41 | |||
42 | instance NFData ErrorMsg where rnf = rnf . ppShow | ||
43 | {- | ||
44 | rnf = \case | ||
45 | ErrorMsg m -> rnf m | ||
46 | ECantFind a b -> rnf (a, b) | ||
47 | ETypeError a b -> rnf (a, b) | ||
48 | ERedefined a b c -> rnf (a, b, c) | ||
49 | -} | ||
50 | errorRange_ = \case | ||
51 | ErrorMsg s -> [] | ||
52 | ECantFind s si -> [si] | ||
53 | ETypeError msg si -> [si] | ||
54 | ERedefined s si si' -> [si, si'] | ||
55 | |||
56 | instance PShow ErrorMsg where | ||
57 | pShow = \case | ||
58 | ErrorMsg s -> s | ||
59 | ECantFind s si -> "can't find:" <+> text s <+> "in" <+> pShow si | ||
60 | ETypeError msg si -> "type error:" <+> msg <$$> "in" <+> pShow si | ||
61 | ERedefined s si si' -> "already defined" <+> text s <+> "at" <+> pShow si <$$> "and at" <+> pShow si' | ||
62 | |||
63 | |||
64 | -------------------------------------------------------------------------------- infos | ||
65 | |||
66 | data Info | ||
67 | = Info Range Doc | ||
68 | | IType SIName Exp | ||
69 | | ITrace String String | ||
70 | | IError ErrorMsg | ||
71 | | ParseWarning ParseWarning | ||
72 | |||
73 | instance NFData Info where rnf = rnf . ppShow | ||
74 | {- | ||
75 | where | ||
76 | rnf = \case | ||
77 | Info r s -> rnf (r, s) | ||
78 | IType a b -> rnf (a, b) | ||
79 | ITrace i s -> rnf (i, s) | ||
80 | IError x -> rnf x | ||
81 | ParseWarning w -> rnf w | ||
82 | -} | ||
83 | instance PShow Info where | ||
84 | pShow = \case | ||
85 | Info r s -> nest 4 $ shortForm (pShow r) <$$> s | ||
86 | IType a b -> shAnn (pShow a) (pShow b) | ||
87 | ITrace i s -> text i <> ": " <+> text s | ||
88 | IError e -> "!" <> pShow e | ||
89 | ParseWarning w -> pShow w | ||
90 | |||
91 | errorRange is = [r | IError e <- is, RangeSI r <- errorRange_ e ] | ||
92 | |||
93 | type Infos = [Info] | ||
94 | |||
95 | throwError' e = tell [IError e] >> throwError e | ||
96 | |||
97 | mkInfoItem (RangeSI r) i = [Info r i] | ||
98 | mkInfoItem _ _ = mempty | ||
99 | |||
100 | listAllInfos m = h "trace" (listTraceInfos m) | ||
101 | ++ h "tooltips" [ nest 4 $ shortForm $ pShow r <$$> hsep (intersperse "|" is) | (r, is) <- listTypeInfos m ] | ||
102 | ++ h "warnings" [ pShow w | ParseWarning w <- m ] | ||
103 | where | ||
104 | h x [] = [] | ||
105 | h x xs = ("------------" <+> x) : xs | ||
106 | |||
107 | listTraceInfos m = [DResetFreshNames $ pShow i | i <- m, case i of Info{} -> False; ParseWarning{} -> False; _ -> True] | ||
108 | listTypeInfos m = Map.toList $ Map.unionsWith (<>) [Map.singleton r [DResetFreshNames i] | Info r i <- m] | ||
109 | |||
110 | tellType si t = tell $ mkInfoItem (sourceInfo si) $ DTypeNamespace True $ mkDoc False t | ||
111 | |||
112 | -------------------------------------------------------------------------------- global env | ||
113 | |||
114 | type GlobalEnv = Map.Map SName (Exp, Type, SI) | ||
115 | |||
116 | initEnv :: GlobalEnv | ||
117 | initEnv = Map.fromList | ||
118 | [ (,) "'Type" (TType, TType, debugSI "source-of-Type") | ||
119 | ] | ||
120 | |||
121 | -- inference monad | ||
122 | type IM m = ExceptT ErrorMsg (ReaderT (Extensions, GlobalEnv) (WriterT Infos m)) | ||
123 | |||
124 | expAndType s (e, t, si) = (ET e t) | ||
125 | |||
126 | -- todo: do only if NoTypeNamespace extension is not on | ||
127 | lookupName s@(Ticked s') m = expAndType s <$> (Map.lookup s m `mplus` Map.lookup s' m) | ||
128 | lookupName s m = expAndType s <$> Map.lookup s m | ||
129 | |||
130 | getDef te si s = do | ||
131 | nv <- asks snd | ||
132 | maybe (throwError' $ ECantFind s si) return (lookupName s nv) | ||
133 | |||
134 | addToEnv :: Monad m => SIName -> ExpType -> IM m GlobalEnv | ||
135 | addToEnv sn@(SIName si s) (ET x t) = do | ||
136 | -- maybe (pure ()) throwError_ $ ambiguityCheck s t -- TODO | ||
137 | -- b <- asks $ (TraceTypeCheck `elem`) . fst | ||
138 | tell [IType sn t] | ||
139 | v <- asks $ Map.lookup s . snd | ||
140 | case v of | ||
141 | Nothing -> return $ Map.singleton s (closedExp x, closedExp t, si) | ||
142 | Just (_, _, si') -> throwError' $ ERedefined s si si' | ||
143 | |||
144 | |||
145 | removeHiddenUnit (Pi Hidden (hnf -> Unit) (down 0 -> Just t)) = removeHiddenUnit t | ||
146 | removeHiddenUnit (Pi h a b) = Pi h a $ removeHiddenUnit b | ||
147 | removeHiddenUnit t = t | ||
148 | |||
149 | addParams ps t = foldr (uncurry Pi) t ps | ||
150 | |||
151 | addLams ps t = foldr (const Lam) t ps | ||
152 | |||
153 | lamify t x = addLams (fst $ getParams t) $ x $ downTo 0 $ arity t | ||
154 | |||
155 | arity :: Exp -> Int | ||
156 | arity = length . fst . getParams | ||
157 | |||
158 | downTo n m = map Var [n+m-1, n+m-2..n] | ||
159 | |||
160 | withEnv e = local $ second (<> e) | ||
161 | |||
162 | mkELet n x xt = {-(if null vs then id else trace_ $ "mkELet " ++ show (length vs) ++ " " ++ show n)-} term | ||
163 | where | ||
164 | vs = [Var i | i <- Set.toList $ free x <> free xt] | ||
165 | fn = FunName (mkFName n) (ExpDef x) xt | ||
166 | |||
167 | term = pmLabel fn vs [] $ getFix x 0 | ||
168 | |||
169 | getFix (Lam z) i = Lam $ getFix z (i+1) | ||
170 | getFix (TFun FprimFix _ [t, Lam f]) i = subst 0 (foldl app_ term (downTo 0 i)) f | ||
171 | getFix x _ = x | ||
172 | |||
173 | lamPi h t (ET x y) = ET (Lam x) (Pi h t y) | ||
174 | |||
175 | -- Ambiguous: (Int ~ F a) => Int | ||
176 | -- Not ambiguous: (Show a, a ~ F b) => b | ||
177 | ambiguityCheck :: String -> Exp -> Maybe String | ||
178 | ambiguityCheck s ty = case ambigVars ty of | ||
179 | [] -> Nothing | ||
180 | err -> Just $ s ++ " has ambiguous type:\n" ++ ppShow ty ++ "\nproblematic vars:\n" ++ ppShow err | ||
181 | |||
182 | ambigVars :: Exp -> [(Int, Exp)] | ||
183 | ambigVars ty = [(n, c) | (n, c) <- hid, not $ any (`Set.member` defined) $ Set.insert n $ free c] | ||
184 | where | ||
185 | (defined, hid, _i) = compDefined False ty | ||
186 | |||
187 | floatLetMeta :: Exp -> Bool | ||
188 | floatLetMeta ty = (i-1) `Set.member` defined | ||
189 | where | ||
190 | (defined, hid, i) = compDefined True ty | ||
191 | |||
192 | compDefined b ty = (defined, hid, i) | ||
193 | where | ||
194 | defined = dependentVars hid $ Set.map (if b then (+i) else id) $ free ty | ||
195 | |||
196 | i = length hid_ | ||
197 | hid = zipWith (\k t -> (k, up (k+1) t)) (reverse [0..i-1]) hid_ | ||
198 | (hid_, ty') = hiddenVars ty | ||
199 | |||
200 | hiddenVars (Pi Hidden a b) = first (a:) $ hiddenVars b | ||
201 | hiddenVars t = ([], t) | ||
202 | |||
203 | -- compute dependent type vars in constraints | ||
204 | -- Example: dependentVars [(a, b) ~ F b c, d ~ F e] [c] == [a,b,c] | ||
205 | dependentVars :: [(Int, Exp)] -> Set.Set Int -> Set.Set Int | ||
206 | dependentVars ie = cycle mempty | ||
207 | where | ||
208 | freeVars = free | ||
209 | |||
210 | cycle acc s | ||
211 | | Set.null s = acc | ||
212 | | otherwise = cycle (acc <> s) (grow s Set.\\ acc) | ||
213 | |||
214 | grow = flip foldMap ie $ \case | ||
215 | (n, t) -> (Set.singleton n <-> freeVars t) <> case t of | ||
216 | (hnf -> CW (hnf -> CstrT _{-todo-} ty f)) -> freeVars ty <-> freeVars f | ||
217 | (hnf -> CSplit a b c) -> freeVars a <-> (freeVars b <> freeVars c) | ||
218 | _ -> mempty | ||
219 | where | ||
220 | a --> b = \s -> if Set.null $ a `Set.intersection` s then mempty else b | ||
221 | a <-> b = (a --> b) <> (b --> a) | ||
222 | |||
223 | |||