2 % (c) The University of Glasgow 2006
3 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
6 @DsMonad@: monadery used in desugaring
10 DsM, mapM, mapAndUnzipM,
11 initDs, initDsTc, fixDs,
12 foldlM, foldrM, ifOptM, unsetOptM,
13 Applicative(..),(<$>),
16 duplicateLocalDs, newSysLocalDs, newSysLocalsDs, newUniqueId,
17 newFailLocalDs, newPredVarDs,
18 getSrcSpanDs, putSrcSpanDs,
21 UniqSupply, newUniqueSupply,
22 getDOptsDs, getGhcModeDs, doptDs,
23 dsLookupGlobal, dsLookupGlobalId, dsLookupTyCon, dsLookupDataCon,
26 DsMetaEnv, DsMetaVal(..), dsLookupMetaEnv, dsExtendMetaEnv,
31 DsWarning, warnDs, failWithDs,
35 EquationInfo(..), MatchResult(..), DsWrapper, idDsWrapper,
66 %************************************************************************
68 Data types for the desugarer
70 %************************************************************************
74 = DsMatchContext (HsMatchContext Name) SrcSpan
79 = EqnInfo { eqn_pats :: [Pat Id], -- The patterns for an eqn
80 eqn_rhs :: MatchResult } -- What to do after match
82 instance Outputable EquationInfo where
83 ppr (EqnInfo pats _) = ppr pats
85 type DsWrapper = CoreExpr -> CoreExpr
86 idDsWrapper :: DsWrapper
89 -- The semantics of (match vs (EqnInfo wrap pats rhs)) is the MatchResult
90 -- \fail. wrap (case vs of { pats -> rhs fail })
91 -- where vs are not bound by wrap
94 -- A MatchResult is an expression with a hole in it
97 CanItFail -- Tells whether the failure expression is used
98 (CoreExpr -> DsM CoreExpr)
99 -- Takes a expression to plug in at the
100 -- failure point(s). The expression should
103 data CanItFail = CanFail | CantFail
105 orFail :: CanItFail -> CanItFail -> CanItFail
106 orFail CantFail CantFail = CantFail
111 %************************************************************************
115 %************************************************************************
117 Now the mondo monad magic (yes, @DsM@ is a silly name)---carry around
118 a @UniqueSupply@ and some annotations, which
119 presumably include source-file location information:
121 type DsM result = TcRnIf DsGblEnv DsLclEnv result
123 -- Compatibility functions
124 fixDs :: (a -> DsM a) -> DsM a
127 type DsWarning = (SrcSpan, SDoc)
128 -- Not quite the same as a WarnMsg, we have an SDoc here
129 -- and we'll do the print_unqual stuff later on to turn it
132 data DsGblEnv = DsGblEnv {
133 ds_mod :: Module, -- For SCC profiling
134 ds_unqual :: PrintUnqualified,
135 ds_msgs :: IORef Messages, -- Warning messages
136 ds_if_env :: (IfGblEnv, IfLclEnv) -- Used for looking up global,
137 -- possibly-imported things
140 data DsLclEnv = DsLclEnv {
141 ds_meta :: DsMetaEnv, -- Template Haskell bindings
142 ds_loc :: SrcSpan -- to put in pattern-matching error msgs
145 -- Inside [| |] brackets, the desugarer looks
146 -- up variables in the DsMetaEnv
147 type DsMetaEnv = NameEnv DsMetaVal
150 = Bound Id -- Bound by a pattern inside the [| |].
151 -- Will be dynamically alpha renamed.
152 -- The Id has type THSyntax.Var
154 | Splice (HsExpr Id) -- These bindings are introduced by
155 -- the PendingSplices on a HsBracketOut
158 -> Module -> GlobalRdrEnv -> TypeEnv
160 -> IO (Messages, Maybe a)
161 -- Print errors and warnings, if any arise
163 initDs hsc_env mod rdr_env type_env thing_inside
164 = do { msg_var <- newIORef (emptyBag, emptyBag)
165 ; let dflags = hsc_dflags hsc_env
166 ; (ds_gbl_env, ds_lcl_env) <- mkDsEnvs dflags mod rdr_env type_env msg_var
168 ; either_res <- initTcRnIf 'd' hsc_env ds_gbl_env ds_lcl_env $
169 tryM thing_inside -- Catch exceptions (= errors during desugaring)
171 -- Display any errors and warnings
172 -- Note: if -Werror is used, we don't signal an error here.
173 ; msgs <- readIORef msg_var
175 ; let final_res | errorsFound dflags msgs = Nothing
176 | otherwise = case either_res of
177 Right res -> Just res
178 Left exn -> pprPanic "initDs" (text (show exn))
179 -- The (Left exn) case happens when the thing_inside throws
180 -- a UserError exception. Then it should have put an error
181 -- message in msg_var, so we just discard the exception
183 ; return (msgs, final_res) }
185 initDsTc :: DsM a -> TcM a
186 initDsTc thing_inside
187 = do { this_mod <- getModule
188 ; tcg_env <- getGblEnv
189 ; msg_var <- getErrsVar
191 ; let type_env = tcg_type_env tcg_env
192 rdr_env = tcg_rdr_env tcg_env
193 ; ds_envs <- liftIO $ mkDsEnvs dflags this_mod rdr_env type_env msg_var
194 ; setEnvs ds_envs thing_inside }
196 mkDsEnvs :: DynFlags -> Module -> GlobalRdrEnv -> TypeEnv -> IORef Messages -> IO (DsGblEnv, DsLclEnv)
197 mkDsEnvs dflags mod rdr_env type_env msg_var
198 = do -- TODO: unnecessarily monadic
199 let if_genv = IfGblEnv { if_rec_types = Just (mod, return type_env) }
200 if_lenv = mkIfLclEnv mod (ptext (sLit "GHC error in desugarer lookup in") <+> ppr mod)
201 gbl_env = DsGblEnv { ds_mod = mod,
202 ds_if_env = (if_genv, if_lenv),
203 ds_unqual = mkPrintUnqualified dflags rdr_env,
205 lcl_env = DsLclEnv { ds_meta = emptyNameEnv,
208 return (gbl_env, lcl_env)
211 %************************************************************************
213 Operations in the monad
215 %************************************************************************
217 And all this mysterious stuff is so we can occasionally reach out and
218 grab one or more names. @newLocalDs@ isn't exported---exported
219 functions are defined with it. The difference in name-strings makes
220 it easier to read debugging output.
223 -- Make a new Id with the same print name, but different type, and new unique
224 newUniqueId :: Id -> Type -> DsM Id
225 newUniqueId id = mkSysLocalM (occNameFS (nameOccName (idName id)))
227 duplicateLocalDs :: Id -> DsM Id
228 duplicateLocalDs old_local
229 = do { uniq <- newUnique
230 ; return (setIdUnique old_local uniq) }
232 newPredVarDs :: PredType -> DsM Var
235 = do { uniq <- newUnique;
236 ; let name = mkSystemName uniq (mkOccNameFS tcName (fsLit "co_pv"))
238 ; return (mkCoVar name kind) }
240 = newSysLocalDs (mkPredTy pred)
242 newSysLocalDs, newFailLocalDs :: Type -> DsM Id
243 newSysLocalDs = mkSysLocalM (fsLit "ds")
244 newFailLocalDs = mkSysLocalM (fsLit "fail")
246 newSysLocalsDs :: [Type] -> DsM [Id]
247 newSysLocalsDs tys = mapM newSysLocalDs tys
250 We can also reach out and either set/grab location information from
251 the @SrcSpan@ being carried around.
254 getDOptsDs :: DsM DynFlags
255 getDOptsDs = getDOpts
257 doptDs :: DynFlag -> TcRnIf gbl lcl Bool
260 getGhcModeDs :: DsM GhcMode
261 getGhcModeDs = getDOptsDs >>= return . ghcMode
263 getModuleDs :: DsM Module
264 getModuleDs = do { env <- getGblEnv; return (ds_mod env) }
266 getSrcSpanDs :: DsM SrcSpan
267 getSrcSpanDs = do { env <- getLclEnv; return (ds_loc env) }
269 putSrcSpanDs :: SrcSpan -> DsM a -> DsM a
270 putSrcSpanDs new_loc thing_inside = updLclEnv (\ env -> env {ds_loc = new_loc}) thing_inside
272 warnDs :: SDoc -> DsM ()
273 warnDs warn = do { env <- getGblEnv
274 ; loc <- getSrcSpanDs
275 ; let msg = mkWarnMsg loc (ds_unqual env)
276 (ptext (sLit "Warning:") <+> warn)
277 ; updMutVar (ds_msgs env) (\ (w,e) -> (w `snocBag` msg, e)) }
279 failWithDs :: SDoc -> DsM a
281 = do { env <- getGblEnv
282 ; loc <- getSrcSpanDs
283 ; let msg = mkErrMsg loc (ds_unqual env) err
284 ; updMutVar (ds_msgs env) (\ (w,e) -> (w, e `snocBag` msg))
289 instance MonadThings (IOEnv (Env DsGblEnv DsLclEnv)) where
290 lookupThing = dsLookupGlobal
292 dsLookupGlobal :: Name -> DsM TyThing
293 -- Very like TcEnv.tcLookupGlobal
295 = do { env <- getGblEnv
296 ; setEnvs (ds_if_env env)
297 (tcIfaceGlobal name) }
299 dsLookupGlobalId :: Name -> DsM Id
300 dsLookupGlobalId name
301 = tyThingId <$> dsLookupGlobal name
303 dsLookupTyCon :: Name -> DsM TyCon
305 = tyThingTyCon <$> dsLookupGlobal name
307 dsLookupDataCon :: Name -> DsM DataCon
309 = tyThingDataCon <$> dsLookupGlobal name
311 dsLookupClass :: Name -> DsM Class
313 = tyThingClass <$> dsLookupGlobal name
317 dsLookupMetaEnv :: Name -> DsM (Maybe DsMetaVal)
318 dsLookupMetaEnv name = do { env <- getLclEnv; return (lookupNameEnv (ds_meta env) name) }
320 dsExtendMetaEnv :: DsMetaEnv -> DsM a -> DsM a
321 dsExtendMetaEnv menv thing_inside
322 = updLclEnv (\env -> env { ds_meta = ds_meta env `plusNameEnv` menv }) thing_inside
326 dsLoadModule :: SDoc -> Module -> DsM ()
328 = do { env <- getGblEnv
329 ; setEnvs (ds_if_env env)
330 (loadSysInterface doc mod >> return ())