Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
-
de44e69e
by sheaf at 2025-09-19T05:16:51-04:00
7 changed files:
- compiler/GHC/HsToCore/Monad.hs
- compiler/GHC/Tc/Module.hs
- compiler/GHC/Tc/Utils/Monad.hs
- + testsuite/tests/tcplugins/T26395.hs
- + testsuite/tests/tcplugins/T26395.stderr
- + testsuite/tests/tcplugins/T26395_Plugin.hs
- testsuite/tests/tcplugins/all.T
Changes:
... | ... | @@ -58,6 +58,7 @@ module GHC.HsToCore.Monad ( |
58 | 58 | import GHC.Prelude
|
59 | 59 | |
60 | 60 | import GHC.Driver.Env
|
61 | +import GHC.Driver.Env.KnotVars
|
|
61 | 62 | import GHC.Driver.DynFlags
|
62 | 63 | import GHC.Driver.Ppr
|
63 | 64 | import GHC.Driver.Config.Diagnostic
|
... | ... | @@ -117,7 +118,7 @@ import GHC.Utils.Panic |
117 | 118 | import qualified GHC.Data.Strict as Strict
|
118 | 119 | |
119 | 120 | import Data.IORef
|
120 | -import GHC.Driver.Env.KnotVars
|
|
121 | + |
|
121 | 122 | import GHC.IO.Unsafe (unsafeInterleaveIO)
|
122 | 123 | |
123 | 124 | {-
|
... | ... | @@ -26,6 +26,7 @@ module GHC.Tc.Module ( |
26 | 26 | runTcInteractive, -- Used by GHC API clients (#8878)
|
27 | 27 | withTcPlugins, -- Used by GHC API clients (#20499)
|
28 | 28 | withHoleFitPlugins, -- Used by GHC API clients (#20499)
|
29 | + withDefaultingPlugins,
|
|
29 | 30 | tcRnLookupName,
|
30 | 31 | tcRnGetInfo,
|
31 | 32 | tcRnModule, tcRnModuleTcRnM,
|
... | ... | @@ -53,7 +54,6 @@ import GHC.Driver.DynFlags |
53 | 54 | import GHC.Driver.Config.Diagnostic
|
54 | 55 | import GHC.IO.Unsafe ( unsafeInterleaveIO )
|
55 | 56 | |
56 | -import GHC.Tc.Errors.Hole.Plugin ( HoleFitPluginR (..) )
|
|
57 | 57 | import GHC.Tc.Errors.Types
|
58 | 58 | import {-# SOURCE #-} GHC.Tc.Gen.Splice ( finishTH, runRemoteModFinalizers )
|
59 | 59 | import GHC.Tc.Gen.HsType
|
... | ... | @@ -141,7 +141,6 @@ import GHC.Types.Id as Id |
141 | 141 | import GHC.Types.Id.Info( IdDetails(..) )
|
142 | 142 | import GHC.Types.Var.Env
|
143 | 143 | import GHC.Types.TypeEnv
|
144 | -import GHC.Types.Unique.FM
|
|
145 | 144 | import GHC.Types.Name
|
146 | 145 | import GHC.Types.Name.Env
|
147 | 146 | import GHC.Types.Name.Set
|
... | ... | @@ -212,10 +211,6 @@ tcRnModule hsc_env mod_sum save_rn_syntax |
212 | 211 | (text "Renamer/typechecker"<+>brackets (ppr this_mod))
|
213 | 212 | (const ()) $
|
214 | 213 | initTc hsc_env hsc_src save_rn_syntax this_mod real_loc $
|
215 | - withTcPlugins hsc_env $
|
|
216 | - withDefaultingPlugins hsc_env $
|
|
217 | - withHoleFitPlugins hsc_env $
|
|
218 | - |
|
219 | 214 | tcRnModuleTcRnM hsc_env mod_sum parsedModule this_mod
|
220 | 215 | |
221 | 216 | | otherwise
|
... | ... | @@ -3182,72 +3177,11 @@ hasTopUserName x |
3182 | 3177 | {-
|
3183 | 3178 | ********************************************************************************
|
3184 | 3179 | |
3185 | -Type Checker Plugins
|
|
3180 | + Running plugins
|
|
3186 | 3181 | |
3187 | 3182 | ********************************************************************************
|
3188 | 3183 | -}
|
3189 | 3184 | |
3190 | -withTcPlugins :: HscEnv -> TcM a -> TcM a
|
|
3191 | -withTcPlugins hsc_env m =
|
|
3192 | - case catMaybes $ mapPlugins (hsc_plugins hsc_env) tcPlugin of
|
|
3193 | - [] -> m -- Common fast case
|
|
3194 | - plugins -> do
|
|
3195 | - (solvers, rewriters, stops) <-
|
|
3196 | - unzip3 `fmap` mapM start_plugin plugins
|
|
3197 | - let
|
|
3198 | - rewritersUniqFM :: UniqFM TyCon [TcPluginRewriter]
|
|
3199 | - !rewritersUniqFM = sequenceUFMList rewriters
|
|
3200 | - -- The following ensures that tcPluginStop is called even if a type
|
|
3201 | - -- error occurs during compilation (Fix of #10078)
|
|
3202 | - eitherRes <- tryM $
|
|
3203 | - updGblEnv (\e -> e { tcg_tc_plugin_solvers = solvers
|
|
3204 | - , tcg_tc_plugin_rewriters = rewritersUniqFM }) m
|
|
3205 | - mapM_ runTcPluginM stops
|
|
3206 | - case eitherRes of
|
|
3207 | - Left _ -> failM
|
|
3208 | - Right res -> return res
|
|
3209 | - where
|
|
3210 | - start_plugin (TcPlugin start solve rewrite stop) =
|
|
3211 | - do s <- runTcPluginM start
|
|
3212 | - return (solve s, rewrite s, stop s)
|
|
3213 | - |
|
3214 | -withDefaultingPlugins :: HscEnv -> TcM a -> TcM a
|
|
3215 | -withDefaultingPlugins hsc_env m =
|
|
3216 | - do case catMaybes $ mapPlugins (hsc_plugins hsc_env) defaultingPlugin of
|
|
3217 | - [] -> m -- Common fast case
|
|
3218 | - plugins -> do (plugins,stops) <- mapAndUnzipM start_plugin plugins
|
|
3219 | - -- This ensures that dePluginStop is called even if a type
|
|
3220 | - -- error occurs during compilation
|
|
3221 | - eitherRes <- tryM $ do
|
|
3222 | - updGblEnv (\e -> e { tcg_defaulting_plugins = plugins }) m
|
|
3223 | - mapM_ runTcPluginM stops
|
|
3224 | - case eitherRes of
|
|
3225 | - Left _ -> failM
|
|
3226 | - Right res -> return res
|
|
3227 | - where
|
|
3228 | - start_plugin (DefaultingPlugin start fill stop) =
|
|
3229 | - do s <- runTcPluginM start
|
|
3230 | - return (fill s, stop s)
|
|
3231 | - |
|
3232 | -withHoleFitPlugins :: HscEnv -> TcM a -> TcM a
|
|
3233 | -withHoleFitPlugins hsc_env m =
|
|
3234 | - case catMaybes $ mapPlugins (hsc_plugins hsc_env) holeFitPlugin of
|
|
3235 | - [] -> m -- Common fast case
|
|
3236 | - plugins -> do (plugins,stops) <- mapAndUnzipM start_plugin plugins
|
|
3237 | - -- This ensures that hfPluginStop is called even if a type
|
|
3238 | - -- error occurs during compilation.
|
|
3239 | - eitherRes <- tryM $
|
|
3240 | - updGblEnv (\e -> e { tcg_hf_plugins = plugins }) m
|
|
3241 | - sequence_ stops
|
|
3242 | - case eitherRes of
|
|
3243 | - Left _ -> failM
|
|
3244 | - Right res -> return res
|
|
3245 | - where
|
|
3246 | - start_plugin (HoleFitPluginR init plugin stop) =
|
|
3247 | - do ref <- init
|
|
3248 | - return (plugin ref, stop ref)
|
|
3249 | - |
|
3250 | - |
|
3251 | 3185 | runRenamerPlugin :: TcGblEnv
|
3252 | 3186 | -> HsGroup GhcRn
|
3253 | 3187 | -> TcM (TcGblEnv, HsGroup GhcRn)
|
... | ... | @@ -31,6 +31,9 @@ module GHC.Tc.Utils.Monad( |
31 | 31 | updateEps, updateEps_,
|
32 | 32 | getHpt, getEpsAndHug,
|
33 | 33 | |
34 | + -- * Initialising TcM plugins
|
|
35 | + withTcPlugins, withDefaultingPlugins, withHoleFitPlugins,
|
|
36 | + |
|
34 | 37 | -- * Arrow scopes
|
35 | 38 | newArrowScope, escapeArrowScope,
|
36 | 39 | |
... | ... | @@ -163,6 +166,7 @@ import GHC.Builtin.Names |
163 | 166 | import GHC.Builtin.Types( zonkAnyTyCon )
|
164 | 167 | |
165 | 168 | import GHC.Tc.Errors.Types
|
169 | +import GHC.Tc.Errors.Hole.Plugin ( HoleFitPluginR (..) )
|
|
166 | 170 | import GHC.Tc.Types -- Re-export all
|
167 | 171 | import GHC.Tc.Types.Constraint
|
168 | 172 | import GHC.Tc.Types.CtLoc
|
... | ... | @@ -183,13 +187,17 @@ import GHC.Unit.Module.Warnings |
183 | 187 | import GHC.Unit.Home.PackageTable
|
184 | 188 | |
185 | 189 | import GHC.Core.UsageEnv
|
190 | + |
|
191 | +import GHC.Core.Coercion ( isReflCo )
|
|
186 | 192 | import GHC.Core.Multiplicity
|
187 | 193 | import GHC.Core.InstEnv
|
188 | 194 | import GHC.Core.FamInstEnv
|
189 | 195 | import GHC.Core.Type( mkNumLitTy )
|
196 | +import GHC.Core.TyCon ( TyCon )
|
|
190 | 197 | |
191 | 198 | import GHC.Driver.Env
|
192 | 199 | import GHC.Driver.Env.KnotVars
|
200 | +import GHC.Driver.Plugins ( Plugin(..), mapPlugins )
|
|
193 | 201 | import GHC.Driver.Session
|
194 | 202 | import GHC.Driver.Config.Diagnostic
|
195 | 203 | |
... | ... | @@ -226,7 +234,7 @@ import GHC.Types.SrcLoc |
226 | 234 | import GHC.Types.Name.Env
|
227 | 235 | import GHC.Types.Name.Set
|
228 | 236 | import GHC.Types.Name.Ppr
|
229 | -import GHC.Types.Unique.FM ( emptyUFM )
|
|
237 | +import GHC.Types.Unique.FM ( UniqFM, emptyUFM, sequenceUFMList )
|
|
230 | 238 | import GHC.Types.Unique.DFM
|
231 | 239 | import GHC.Types.Unique.Supply
|
232 | 240 | import GHC.Types.Annotations
|
... | ... | @@ -240,8 +248,6 @@ import Data.IORef |
240 | 248 | import Control.Monad
|
241 | 249 | |
242 | 250 | import qualified Data.Map as Map
|
243 | -import GHC.Core.Coercion (isReflCo)
|
|
244 | - |
|
245 | 251 | |
246 | 252 | {-
|
247 | 253 | ************************************************************************
|
... | ... | @@ -263,129 +269,139 @@ initTc :: HscEnv |
263 | 269 | -- (error messages should have been printed already)
|
264 | 270 | |
265 | 271 | initTc hsc_env hsc_src keep_rn_syntax mod loc do_this
|
266 | - = do { keep_var <- newIORef emptyNameSet ;
|
|
267 | - used_gre_var <- newIORef [] ;
|
|
268 | - th_var <- newIORef False ;
|
|
269 | - infer_var <- newIORef True ;
|
|
270 | - infer_reasons_var <- newIORef emptyMessages ;
|
|
271 | - dfun_n_var <- newIORef emptyOccSet ;
|
|
272 | - zany_n_var <- newIORef 0 ;
|
|
273 | - let { type_env_var = hsc_type_env_vars hsc_env };
|
|
274 | - |
|
275 | - dependent_files_var <- newIORef [] ;
|
|
276 | - dependent_dirs_var <- newIORef [] ;
|
|
277 | - static_wc_var <- newIORef emptyWC ;
|
|
278 | - cc_st_var <- newIORef newCostCentreState ;
|
|
279 | - th_topdecls_var <- newIORef [] ;
|
|
280 | - th_foreign_files_var <- newIORef [] ;
|
|
281 | - th_topnames_var <- newIORef emptyNameSet ;
|
|
282 | - th_modfinalizers_var <- newIORef [] ;
|
|
283 | - th_coreplugins_var <- newIORef [] ;
|
|
284 | - th_state_var <- newIORef Map.empty ;
|
|
285 | - th_remote_state_var <- newIORef Nothing ;
|
|
286 | - th_docs_var <- newIORef Map.empty ;
|
|
287 | - th_needed_deps_var <- newIORef ([], emptyUDFM) ;
|
|
288 | - next_wrapper_num <- newIORef emptyModuleEnv ;
|
|
289 | - let {
|
|
290 | - -- bangs to avoid leaking the env (#19356)
|
|
291 | - !dflags = hsc_dflags hsc_env ;
|
|
292 | - !mhome_unit = hsc_home_unit_maybe hsc_env;
|
|
293 | - !logger = hsc_logger hsc_env ;
|
|
294 | - |
|
295 | - maybe_rn_syntax :: forall a. a -> Maybe a ;
|
|
296 | - maybe_rn_syntax empty_val
|
|
297 | - | logHasDumpFlag logger Opt_D_dump_rn_ast = Just empty_val
|
|
298 | - |
|
299 | - | gopt Opt_WriteHie dflags = Just empty_val
|
|
300 | - |
|
301 | - -- We want to serialize the documentation in the .hi-files,
|
|
302 | - -- and need to extract it from the renamed syntax first.
|
|
303 | - -- See 'GHC.HsToCore.Docs.extractDocs'.
|
|
304 | - | gopt Opt_Haddock dflags = Just empty_val
|
|
305 | - |
|
306 | - | keep_rn_syntax = Just empty_val
|
|
307 | - | otherwise = Nothing ;
|
|
308 | - |
|
309 | - gbl_env = TcGblEnv {
|
|
310 | - tcg_th_topdecls = th_topdecls_var,
|
|
311 | - tcg_th_foreign_files = th_foreign_files_var,
|
|
312 | - tcg_th_topnames = th_topnames_var,
|
|
313 | - tcg_th_modfinalizers = th_modfinalizers_var,
|
|
314 | - tcg_th_coreplugins = th_coreplugins_var,
|
|
315 | - tcg_th_state = th_state_var,
|
|
316 | - tcg_th_remote_state = th_remote_state_var,
|
|
317 | - tcg_th_docs = th_docs_var,
|
|
318 | - |
|
319 | - tcg_mod = mod,
|
|
320 | - tcg_semantic_mod = homeModuleInstantiation mhome_unit mod,
|
|
321 | - tcg_src = hsc_src,
|
|
322 | - tcg_rdr_env = emptyGlobalRdrEnv,
|
|
323 | - tcg_fix_env = emptyNameEnv,
|
|
324 | - tcg_default = emptyDefaultEnv,
|
|
325 | - tcg_default_exports = emptyDefaultEnv,
|
|
326 | - tcg_type_env = emptyNameEnv,
|
|
327 | - tcg_type_env_var = type_env_var,
|
|
328 | - tcg_inst_env = emptyInstEnv,
|
|
329 | - tcg_fam_inst_env = emptyFamInstEnv,
|
|
330 | - tcg_ann_env = emptyAnnEnv,
|
|
331 | - tcg_complete_match_env = [],
|
|
332 | - tcg_th_used = th_var,
|
|
333 | - tcg_th_needed_deps = th_needed_deps_var,
|
|
334 | - tcg_exports = [],
|
|
335 | - tcg_imports = emptyImportAvails,
|
|
336 | - tcg_import_decls = [],
|
|
337 | - tcg_used_gres = used_gre_var,
|
|
338 | - tcg_dus = emptyDUs,
|
|
339 | - |
|
340 | - tcg_rn_imports = [],
|
|
341 | - tcg_rn_exports =
|
|
342 | - if hsc_src == HsigFile
|
|
343 | - -- Always retain renamed syntax, so that we can give
|
|
344 | - -- better errors. (TODO: how?)
|
|
345 | - then Just []
|
|
346 | - else maybe_rn_syntax [],
|
|
347 | - tcg_rn_decls = maybe_rn_syntax emptyRnGroup,
|
|
348 | - tcg_tr_module = Nothing,
|
|
349 | - tcg_binds = emptyLHsBinds,
|
|
350 | - tcg_imp_specs = [],
|
|
351 | - tcg_sigs = emptyNameSet,
|
|
352 | - tcg_ksigs = emptyNameSet,
|
|
353 | - tcg_ev_binds = emptyBag,
|
|
354 | - tcg_warns = emptyWarn,
|
|
355 | - tcg_anns = [],
|
|
356 | - tcg_tcs = [],
|
|
357 | - tcg_insts = [],
|
|
358 | - tcg_fam_insts = [],
|
|
359 | - tcg_rules = [],
|
|
360 | - tcg_fords = [],
|
|
361 | - tcg_patsyns = [],
|
|
362 | - tcg_merged = [],
|
|
363 | - tcg_dfun_n = dfun_n_var,
|
|
364 | - tcg_zany_n = zany_n_var,
|
|
365 | - tcg_keep = keep_var,
|
|
366 | - tcg_hdr_info = (Nothing,Nothing),
|
|
367 | - tcg_main = Nothing,
|
|
368 | - tcg_self_boot = NoSelfBoot,
|
|
369 | - tcg_safe_infer = infer_var,
|
|
370 | - tcg_safe_infer_reasons = infer_reasons_var,
|
|
371 | - tcg_dependent_files = dependent_files_var,
|
|
372 | - tcg_dependent_dirs = dependent_dirs_var,
|
|
373 | - tcg_tc_plugin_solvers = [],
|
|
374 | - tcg_tc_plugin_rewriters = emptyUFM,
|
|
375 | - tcg_defaulting_plugins = [],
|
|
376 | - tcg_hf_plugins = [],
|
|
377 | - tcg_top_loc = loc,
|
|
378 | - tcg_static_wc = static_wc_var,
|
|
379 | - tcg_complete_matches = [],
|
|
380 | - tcg_cc_st = cc_st_var,
|
|
381 | - tcg_next_wrapper_num = next_wrapper_num
|
|
382 | - } ;
|
|
383 | - } ;
|
|
272 | + = do { gbl_env <- initTcGblEnv hsc_env hsc_src keep_rn_syntax mod loc
|
|
384 | 273 | |
385 | 274 | -- OK, here's the business end!
|
386 | - initTcWithGbl hsc_env gbl_env loc do_this
|
|
275 | + ; initTcWithGbl hsc_env gbl_env loc $
|
|
276 | + |
|
277 | + -- Make sure to initialise all TcM plugins from the ambient HscEnv.
|
|
278 | + --
|
|
279 | + -- This ensures that all callers of 'initTc' enable plugins (#26395).
|
|
280 | + withTcPlugins hsc_env $
|
|
281 | + withDefaultingPlugins hsc_env $
|
|
282 | + withHoleFitPlugins hsc_env $
|
|
283 | + |
|
284 | + do_this
|
|
387 | 285 | }
|
388 | 286 | |
287 | +-- | Create an empty 'TcGblEnv'.
|
|
288 | +initTcGblEnv :: HscEnv -> HscSource -> Bool -> Module -> RealSrcSpan -> IO TcGblEnv
|
|
289 | +initTcGblEnv hsc_env hsc_src keep_rn_syntax mod loc =
|
|
290 | + do { keep_var <- newIORef emptyNameSet
|
|
291 | + ; used_gre_var <- newIORef []
|
|
292 | + ; th_var <- newIORef False
|
|
293 | + ; infer_var <- newIORef True
|
|
294 | + ; infer_reasons_var <- newIORef emptyMessages
|
|
295 | + ; dfun_n_var <- newIORef emptyOccSet
|
|
296 | + ; zany_n_var <- newIORef 0
|
|
297 | + ; dependent_files_var <- newIORef []
|
|
298 | + ; dependent_dirs_var <- newIORef []
|
|
299 | + ; static_wc_var <- newIORef emptyWC
|
|
300 | + ; cc_st_var <- newIORef newCostCentreState
|
|
301 | + ; th_topdecls_var <- newIORef []
|
|
302 | + ; th_foreign_files_var <- newIORef []
|
|
303 | + ; th_topnames_var <- newIORef emptyNameSet
|
|
304 | + ; th_modfinalizers_var <- newIORef []
|
|
305 | + ; th_coreplugins_var <- newIORef []
|
|
306 | + ; th_state_var <- newIORef Map.empty
|
|
307 | + ; th_remote_state_var <- newIORef Nothing
|
|
308 | + ; th_docs_var <- newIORef Map.empty
|
|
309 | + ; th_needed_deps_var <- newIORef ([], emptyUDFM)
|
|
310 | + ; next_wrapper_num <- newIORef emptyModuleEnv
|
|
311 | + ; let
|
|
312 | + -- bangs to avoid leaking the env (#19356)
|
|
313 | + !dflags = hsc_dflags hsc_env
|
|
314 | + !mhome_unit = hsc_home_unit_maybe hsc_env
|
|
315 | + !logger = hsc_logger hsc_env
|
|
316 | + |
|
317 | + maybe_rn_syntax :: forall a. a -> Maybe a ;
|
|
318 | + maybe_rn_syntax empty_val
|
|
319 | + | logHasDumpFlag logger Opt_D_dump_rn_ast = Just empty_val
|
|
320 | + |
|
321 | + | gopt Opt_WriteHie dflags = Just empty_val
|
|
322 | + |
|
323 | + -- We want to serialize the documentation in the .hi-files,
|
|
324 | + -- and need to extract it from the renamed syntax first.
|
|
325 | + -- See 'GHC.HsToCore.Docs.extractDocs'.
|
|
326 | + | gopt Opt_Haddock dflags = Just empty_val
|
|
327 | + |
|
328 | + | keep_rn_syntax = Just empty_val
|
|
329 | + | otherwise = Nothing ;
|
|
330 | + |
|
331 | + ; return $ TcGblEnv
|
|
332 | + { tcg_th_topdecls = th_topdecls_var
|
|
333 | + , tcg_th_foreign_files = th_foreign_files_var
|
|
334 | + , tcg_th_topnames = th_topnames_var
|
|
335 | + , tcg_th_modfinalizers = th_modfinalizers_var
|
|
336 | + , tcg_th_coreplugins = th_coreplugins_var
|
|
337 | + , tcg_th_state = th_state_var
|
|
338 | + , tcg_th_remote_state = th_remote_state_var
|
|
339 | + , tcg_th_docs = th_docs_var
|
|
340 | + |
|
341 | + , tcg_mod = mod
|
|
342 | + , tcg_semantic_mod = homeModuleInstantiation mhome_unit mod
|
|
343 | + , tcg_src = hsc_src
|
|
344 | + , tcg_rdr_env = emptyGlobalRdrEnv
|
|
345 | + , tcg_fix_env = emptyNameEnv
|
|
346 | + , tcg_default = emptyDefaultEnv
|
|
347 | + , tcg_default_exports = emptyDefaultEnv
|
|
348 | + , tcg_type_env = emptyNameEnv
|
|
349 | + , tcg_type_env_var = hsc_type_env_vars hsc_env
|
|
350 | + , tcg_inst_env = emptyInstEnv
|
|
351 | + , tcg_fam_inst_env = emptyFamInstEnv
|
|
352 | + , tcg_ann_env = emptyAnnEnv
|
|
353 | + , tcg_complete_match_env = []
|
|
354 | + , tcg_th_used = th_var
|
|
355 | + , tcg_th_needed_deps = th_needed_deps_var
|
|
356 | + , tcg_exports = []
|
|
357 | + , tcg_imports = emptyImportAvails
|
|
358 | + , tcg_import_decls = []
|
|
359 | + , tcg_used_gres = used_gre_var
|
|
360 | + , tcg_dus = emptyDUs
|
|
361 | + |
|
362 | + , tcg_rn_imports = []
|
|
363 | + , tcg_rn_exports = if hsc_src == HsigFile
|
|
364 | + -- Always retain renamed syntax, so that we can give
|
|
365 | + -- better errors. (TODO: how?)
|
|
366 | + then Just []
|
|
367 | + else maybe_rn_syntax []
|
|
368 | + , tcg_rn_decls = maybe_rn_syntax emptyRnGroup
|
|
369 | + , tcg_tr_module = Nothing
|
|
370 | + , tcg_binds = emptyLHsBinds
|
|
371 | + , tcg_imp_specs = []
|
|
372 | + , tcg_sigs = emptyNameSet
|
|
373 | + , tcg_ksigs = emptyNameSet
|
|
374 | + , tcg_ev_binds = emptyBag
|
|
375 | + , tcg_warns = emptyWarn
|
|
376 | + , tcg_anns = []
|
|
377 | + , tcg_tcs = []
|
|
378 | + , tcg_insts = []
|
|
379 | + , tcg_fam_insts = []
|
|
380 | + , tcg_rules = []
|
|
381 | + , tcg_fords = []
|
|
382 | + , tcg_patsyns = []
|
|
383 | + , tcg_merged = []
|
|
384 | + , tcg_dfun_n = dfun_n_var
|
|
385 | + , tcg_zany_n = zany_n_var
|
|
386 | + , tcg_keep = keep_var
|
|
387 | + , tcg_hdr_info = (Nothing,Nothing)
|
|
388 | + , tcg_main = Nothing
|
|
389 | + , tcg_self_boot = NoSelfBoot
|
|
390 | + , tcg_safe_infer = infer_var
|
|
391 | + , tcg_safe_infer_reasons = infer_reasons_var
|
|
392 | + , tcg_dependent_files = dependent_files_var
|
|
393 | + , tcg_dependent_dirs = dependent_dirs_var
|
|
394 | + , tcg_tc_plugin_solvers = []
|
|
395 | + , tcg_tc_plugin_rewriters = emptyUFM
|
|
396 | + , tcg_defaulting_plugins = []
|
|
397 | + , tcg_hf_plugins = []
|
|
398 | + , tcg_top_loc = loc
|
|
399 | + , tcg_static_wc = static_wc_var
|
|
400 | + , tcg_complete_matches = []
|
|
401 | + , tcg_cc_st = cc_st_var
|
|
402 | + , tcg_next_wrapper_num = next_wrapper_num
|
|
403 | + } }
|
|
404 | + |
|
389 | 405 | -- | Run a 'TcM' action in the context of an existing 'GblEnv'.
|
390 | 406 | initTcWithGbl :: HscEnv
|
391 | 407 | -> TcGblEnv
|
... | ... | @@ -686,6 +702,83 @@ withIfaceErr ctx do_this = do |
686 | 702 | liftIO $ throwGhcExceptionIO (ProgramError (renderWithContext ctx msg))
|
687 | 703 | Succeeded result -> return result
|
688 | 704 | |
705 | +{-
|
|
706 | +************************************************************************
|
|
707 | +* *
|
|
708 | + Initialising plugins for TcM
|
|
709 | +* *
|
|
710 | +************************************************************************
|
|
711 | +-}
|
|
712 | + |
|
713 | +-- | Initialise typechecker plugins, run the inner action, then stop
|
|
714 | +-- the typechecker plugins.
|
|
715 | +withTcPlugins :: HscEnv -> TcM a -> TcM a
|
|
716 | +withTcPlugins hsc_env m =
|
|
717 | + case catMaybes $ mapPlugins (hsc_plugins hsc_env) tcPlugin of
|
|
718 | + [] -> m -- Common fast case
|
|
719 | + plugins -> do
|
|
720 | + (solvers, rewriters, stops) <-
|
|
721 | + unzip3 `fmap` mapM start_plugin plugins
|
|
722 | + let
|
|
723 | + rewritersUniqFM :: UniqFM TyCon [TcPluginRewriter]
|
|
724 | + !rewritersUniqFM = sequenceUFMList rewriters
|
|
725 | + -- The following ensures that tcPluginStop is called even if a type
|
|
726 | + -- error occurs during compilation (Fix of #10078)
|
|
727 | + eitherRes <- tryM $
|
|
728 | + updGblEnv (\e -> e { tcg_tc_plugin_solvers = solvers
|
|
729 | + , tcg_tc_plugin_rewriters = rewritersUniqFM })
|
|
730 | + m
|
|
731 | + mapM_ runTcPluginM stops
|
|
732 | + case eitherRes of
|
|
733 | + Left _ -> failM
|
|
734 | + Right res -> return res
|
|
735 | + where
|
|
736 | + start_plugin (TcPlugin start solve rewrite stop) =
|
|
737 | + do s <- runTcPluginM start
|
|
738 | + return (solve s, rewrite s, stop s)
|
|
739 | + |
|
740 | +-- | Initialise defaulting plugins, run the inner action, then stop
|
|
741 | +-- the defaulting plugins.
|
|
742 | +withDefaultingPlugins :: HscEnv -> TcM a -> TcM a
|
|
743 | +withDefaultingPlugins hsc_env m =
|
|
744 | + do case catMaybes $ mapPlugins (hsc_plugins hsc_env) defaultingPlugin of
|
|
745 | + [] -> m -- Common fast case
|
|
746 | + plugins -> do (plugins,stops) <- mapAndUnzipM start_plugin plugins
|
|
747 | + -- This ensures that dePluginStop is called even if a type
|
|
748 | + -- error occurs during compilation
|
|
749 | + eitherRes <- tryM $ do
|
|
750 | + updGblEnv (\e -> e { tcg_defaulting_plugins = plugins })
|
|
751 | + m
|
|
752 | + mapM_ runTcPluginM stops
|
|
753 | + case eitherRes of
|
|
754 | + Left _ -> failM
|
|
755 | + Right res -> return res
|
|
756 | + where
|
|
757 | + start_plugin (DefaultingPlugin start fill stop) =
|
|
758 | + do s <- runTcPluginM start
|
|
759 | + return (fill s, stop s)
|
|
760 | + |
|
761 | +-- | Initialise hole fit plugins, run the inner action, then stop
|
|
762 | +-- the hole fit plugins.
|
|
763 | +withHoleFitPlugins :: HscEnv -> TcM a -> TcM a
|
|
764 | +withHoleFitPlugins hsc_env m =
|
|
765 | + case catMaybes $ mapPlugins (hsc_plugins hsc_env) holeFitPlugin of
|
|
766 | + [] -> m -- Common fast case
|
|
767 | + plugins -> do (plugins,stops) <- mapAndUnzipM start_plugin plugins
|
|
768 | + -- This ensures that hfPluginStop is called even if a type
|
|
769 | + -- error occurs during compilation.
|
|
770 | + eitherRes <- tryM $
|
|
771 | + updGblEnv (\e -> e { tcg_hf_plugins = plugins })
|
|
772 | + m
|
|
773 | + sequence_ stops
|
|
774 | + case eitherRes of
|
|
775 | + Left _ -> failM
|
|
776 | + Right res -> return res
|
|
777 | + where
|
|
778 | + start_plugin (HoleFitPluginR init plugin stop) =
|
|
779 | + do ref <- init
|
|
780 | + return (plugin ref, stop ref)
|
|
781 | + |
|
689 | 782 | {-
|
690 | 783 | ************************************************************************
|
691 | 784 | * *
|
1 | + |
|
2 | +{-# LANGUAGE DataKinds #-}
|
|
3 | +{-# LANGUAGE GADTs #-}
|
|
4 | +{-# LANGUAGE StandaloneKindSignatures #-}
|
|
5 | +{-# LANGUAGE TypeFamilies #-}
|
|
6 | +{-# LANGUAGE TypeOperators #-}
|
|
7 | +{-# LANGUAGE UnliftedDatatypes #-}
|
|
8 | + |
|
9 | +{-# OPTIONS_GHC -fplugin=T26395_Plugin #-}
|
|
10 | + |
|
11 | +{-# OPTIONS_GHC -Wincomplete-patterns #-}
|
|
12 | +{-# OPTIONS_GHC -Winaccessible-code #-}
|
|
13 | +{-# OPTIONS_GHC -Woverlapping-patterns #-}
|
|
14 | + |
|
15 | +module T26395 where
|
|
16 | + |
|
17 | +import Data.Kind
|
|
18 | +import GHC.TypeNats
|
|
19 | +import GHC.Exts ( UnliftedType )
|
|
20 | + |
|
21 | +-- This test verifies that typechecker plugins are enabled
|
|
22 | +-- when we run the solver for pattern-match checking.
|
|
23 | + |
|
24 | +type Peano :: Nat -> UnliftedType
|
|
25 | +data Peano n where
|
|
26 | + Z :: Peano 0
|
|
27 | + S :: Peano n -> Peano (1 + n)
|
|
28 | + |
|
29 | +test1 :: Peano n -> Peano n -> Int
|
|
30 | +test1 Z Z = 0
|
|
31 | +test1 (S n) (S m) = 1 + test1 n m
|
|
32 | + |
|
33 | +{-
|
|
34 | +The following test doesn't work properly due to #26401:
|
|
35 | +the pattern-match checker reports a missing equation
|
|
36 | + |
|
37 | + Z (S _) _
|
|
38 | + |
|
39 | +but there is no invocation of the solver of the form
|
|
40 | + |
|
41 | + [G] n ~ 0
|
|
42 | + [G] m ~ 1 + m1
|
|
43 | + [G] (n-m) ~ m2
|
|
44 | + |
|
45 | +for which we could report the Givens as contradictory.
|
|
46 | + |
|
47 | +test2 :: Peano n -> Peano m -> Peano (n - m) -> Int
|
|
48 | +test2 Z Z Z = 0
|
|
49 | +test2 (S _) (S _) _ = 1
|
|
50 | +test2 (S _) Z (S _) = 2
|
|
51 | +-} |
1 | +[1 of 2] Compiling T26395_Plugin ( T26395_Plugin.hs, T26395_Plugin.o )
|
|
2 | +[2 of 2] Compiling T26395 ( T26395.hs, T26395.o ) |
1 | +{-# LANGUAGE RecordWildCards #-}
|
|
2 | +{-# LANGUAGE LambdaCase #-}
|
|
3 | +{-# LANGUAGE MultiWayIf #-}
|
|
4 | +{-# LANGUAGE BlockArguments #-}
|
|
5 | +{-# LANGUAGE ViewPatterns #-}
|
|
6 | + |
|
7 | +{-# OPTIONS_GHC -Wall -Wno-orphans #-}
|
|
8 | + |
|
9 | +module T26395_Plugin where
|
|
10 | + |
|
11 | +-- base
|
|
12 | +import Prelude hiding ( (<>) )
|
|
13 | +import qualified Data.Semigroup as S
|
|
14 | +import Data.List ( partition )
|
|
15 | +import Data.Maybe
|
|
16 | +import GHC.TypeNats
|
|
17 | + |
|
18 | +-- ghc
|
|
19 | +import GHC.Builtin.Types.Literals
|
|
20 | +import GHC.Core.Predicate
|
|
21 | +import GHC.Core.TyCo.Rep
|
|
22 | +import GHC.Plugins
|
|
23 | +import GHC.Tc.Plugin
|
|
24 | +import GHC.Tc.Types
|
|
25 | +import GHC.Tc.Types.Constraint
|
|
26 | +import GHC.Tc.Types.Evidence
|
|
27 | +import GHC.Tc.Utils.TcType
|
|
28 | +import GHC.Types.Unique.Map
|
|
29 | + |
|
30 | +--------------------------------------------------------------------------------
|
|
31 | + |
|
32 | +plugin :: Plugin
|
|
33 | +plugin =
|
|
34 | + defaultPlugin
|
|
35 | + { pluginRecompile = purePlugin
|
|
36 | + , tcPlugin = \ _-> Just $
|
|
37 | + TcPlugin
|
|
38 | + { tcPluginInit = pure ()
|
|
39 | + , tcPluginSolve = \ _ -> solve
|
|
40 | + , tcPluginRewrite = \ _ -> emptyUFM
|
|
41 | + , tcPluginStop = \ _ -> pure ()
|
|
42 | + }
|
|
43 | + }
|
|
44 | + |
|
45 | +solve :: EvBindsVar -> [Ct] -> [Ct] -> TcPluginM TcPluginSolveResult
|
|
46 | +solve _ givens wanteds
|
|
47 | + -- This plugin only reports inconsistencies among Given constraints.
|
|
48 | + | not $ null wanteds
|
|
49 | + = pure $ TcPluginOk [] []
|
|
50 | + | otherwise
|
|
51 | + = do { let givenLinearExprs = mapMaybe linearExprCt_maybe givens
|
|
52 | + sols = solutions givenLinearExprs
|
|
53 | + |
|
54 | + ; tcPluginTrace "solveLinearExprs" $
|
|
55 | + vcat [ text "givens:" <+> ppr givens
|
|
56 | + , text "linExprs:" <+> ppr givenLinearExprs
|
|
57 | + , text "sols:" <+> ppr (take 1 sols)
|
|
58 | + ]
|
|
59 | + ; return $
|
|
60 | + if null sols
|
|
61 | + then TcPluginContradiction givens
|
|
62 | + else TcPluginOk [] []
|
|
63 | + }
|
|
64 | + |
|
65 | +data LinearExpr =
|
|
66 | + LinearExpr
|
|
67 | + { constant :: Integer
|
|
68 | + , coeffs :: UniqMap TyVar Integer
|
|
69 | + }
|
|
70 | +instance Semigroup LinearExpr where
|
|
71 | + LinearExpr c xs <> LinearExpr d ys =
|
|
72 | + LinearExpr ( c + d ) ( plusMaybeUniqMap_C comb xs ys )
|
|
73 | + where
|
|
74 | + comb a1 a2 =
|
|
75 | + let a = a1 + a2
|
|
76 | + in if a == 0
|
|
77 | + then Nothing
|
|
78 | + else Just a
|
|
79 | + |
|
80 | +instance Monoid LinearExpr where
|
|
81 | + mempty = LinearExpr 0 emptyUniqMap
|
|
82 | + |
|
83 | +mapLinearExpr :: (Integer -> Integer) -> LinearExpr -> LinearExpr
|
|
84 | +mapLinearExpr f (LinearExpr c xs) = LinearExpr (f c) (mapUniqMap f xs)
|
|
85 | + |
|
86 | +minusLinearExpr :: LinearExpr -> LinearExpr -> LinearExpr
|
|
87 | +minusLinearExpr a b = a S.<> mapLinearExpr negate b
|
|
88 | + |
|
89 | +instance Outputable LinearExpr where
|
|
90 | + ppr ( LinearExpr c xs ) =
|
|
91 | + hcat $ punctuate ( text " + " ) $
|
|
92 | + ( ppr c : map ppr_var ( nonDetUniqMapToList xs ) )
|
|
93 | + where
|
|
94 | + ppr_var ( tv, i )
|
|
95 | + | i == 1
|
|
96 | + = ppr tv
|
|
97 | + | i < 0
|
|
98 | + = parens ( text "-" <> ppr (abs i) ) <> text "*" <> ppr tv
|
|
99 | + | otherwise
|
|
100 | + = ppr i <> text "*" <> ppr tv
|
|
101 | + |
|
102 | +maxCoeff :: LinearExpr -> Double
|
|
103 | +maxCoeff ( LinearExpr c xs ) =
|
|
104 | + maximum ( map fromInteger ( c : nonDetEltsUniqMap xs ) )
|
|
105 | + |
|
106 | + |
|
107 | +linearExprCt_maybe :: Ct -> Maybe LinearExpr
|
|
108 | +linearExprCt_maybe ct =
|
|
109 | + case classifyPredType (ctPred ct) of
|
|
110 | + EqPred NomEq lhs rhs
|
|
111 | + | all isNaturalTy [ typeKind lhs, typeKind rhs ]
|
|
112 | + , Just e1 <- linearExprTy_maybe lhs
|
|
113 | + , Just e2 <- linearExprTy_maybe rhs
|
|
114 | + -> Just $ e1 `minusLinearExpr` e2
|
|
115 | + _ -> Nothing
|
|
116 | + |
|
117 | +isNat :: Type -> Maybe Integer
|
|
118 | +isNat ty
|
|
119 | + | Just (NumTyLit n) <- isLitTy ty
|
|
120 | + = Just n
|
|
121 | + | otherwise
|
|
122 | + = Nothing
|
|
123 | + |
|
124 | +linearExprTy_maybe :: Type -> Maybe LinearExpr
|
|
125 | +linearExprTy_maybe ty
|
|
126 | + | Just n <- isNat ty
|
|
127 | + = Just $ LinearExpr n emptyUniqMap
|
|
128 | + | Just (tc, args) <- splitTyConApp_maybe ty
|
|
129 | + = if | tc == typeNatAddTyCon
|
|
130 | + , [x, y] <- args
|
|
131 | + , Just e1 <- linearExprTy_maybe x
|
|
132 | + , Just e2 <- linearExprTy_maybe y
|
|
133 | + -> Just $ e1 S.<> e2
|
|
134 | + | tc == typeNatSubTyCon
|
|
135 | + , [x,y] <- args
|
|
136 | + , Just e1 <- linearExprTy_maybe x
|
|
137 | + , Just e2 <- linearExprTy_maybe y
|
|
138 | + -> Just $ e1 `minusLinearExpr` e2
|
|
139 | + | tc == typeNatMulTyCon
|
|
140 | + , [x, y] <- args
|
|
141 | + ->
|
|
142 | + if | Just ( LinearExpr n xs ) <- linearExprTy_maybe x
|
|
143 | + , isNullUniqMap xs
|
|
144 | + , Just e <- linearExprTy_maybe y
|
|
145 | + -> Just $
|
|
146 | + if n == 0
|
|
147 | + then mempty
|
|
148 | + else mapLinearExpr (n *) e
|
|
149 | + | Just ( LinearExpr n ys ) <- linearExprTy_maybe y
|
|
150 | + , isNullUniqMap ys
|
|
151 | + , Just e <- linearExprTy_maybe x
|
|
152 | + -> Just $
|
|
153 | + if n == 0
|
|
154 | + then mempty
|
|
155 | + else mapLinearExpr (fromIntegral n *) e
|
|
156 | + | otherwise
|
|
157 | + -> Nothing
|
|
158 | + | otherwise
|
|
159 | + -> Nothing
|
|
160 | + | Just tv <- getTyVar_maybe ty
|
|
161 | + = Just $ LinearExpr 0 ( unitUniqMap tv 1 )
|
|
162 | + | otherwise
|
|
163 | + = Nothing
|
|
164 | + |
|
165 | +-- Brute force algorithm to check whether a system of Diophantine
|
|
166 | +-- linear equations is solvable in natural numbers.
|
|
167 | +solutions :: [ LinearExpr ] -> [ UniqMap TyVar Natural ]
|
|
168 | +solutions eqs =
|
|
169 | + let
|
|
170 | + (constEqs, realEqs) = partition (isNullUniqMap . coeffs) eqs
|
|
171 | + d = length realEqs
|
|
172 | + fvs = nonDetKeysUniqMap $ plusUniqMapList ( map coeffs realEqs )
|
|
173 | + in
|
|
174 | + if | any ( ( /= 0 ) . evalLinearExpr emptyUniqMap ) constEqs
|
|
175 | + -> []
|
|
176 | + | d == 0
|
|
177 | + -> [ emptyUniqMap ]
|
|
178 | + | otherwise
|
|
179 | + ->
|
|
180 | + let
|
|
181 | + m = maximum $ map maxCoeff realEqs
|
|
182 | + hadamardBound = sqrt ( fromIntegral $ d ^ d ) * m ^ d
|
|
183 | + tests = mkAssignments ( floor hadamardBound ) fvs
|
|
184 | + in
|
|
185 | + filter ( \ test -> isSolution test realEqs ) tests
|
|
186 | + |
|
187 | + |
|
188 | +mkAssignments :: Natural -> [ TyVar ] -> [ UniqMap TyVar Natural ]
|
|
189 | +mkAssignments _ [] = [ emptyUniqMap ]
|
|
190 | +mkAssignments b (v : vs) =
|
|
191 | + [ addToUniqMap rest v n
|
|
192 | + | n <- [ 0 .. b ]
|
|
193 | + , rest <- mkAssignments b vs
|
|
194 | + ]
|
|
195 | + |
|
196 | +isSolution :: UniqMap TyVar Natural -> [ LinearExpr ] -> Bool
|
|
197 | +isSolution assig =
|
|
198 | + all ( \ expr -> evalLinearExpr assig expr == 0 )
|
|
199 | + |
|
200 | +evalLinearExpr :: UniqMap TyVar Natural -> LinearExpr -> Integer
|
|
201 | +evalLinearExpr vals ( LinearExpr c xs ) = nonDetFoldUniqMap aux c xs
|
|
202 | + where
|
|
203 | + aux ( tv, coeff ) !acc = acc + coeff * val
|
|
204 | + where
|
|
205 | + val :: Integer
|
|
206 | + val = case lookupUniqMap vals tv of
|
|
207 | + Nothing -> pprPanic "evalLinearExpr: missing tv" (ppr tv)
|
|
208 | + Just v -> fromIntegral v |
... | ... | @@ -110,6 +110,19 @@ test('TcPlugin_CtId' |
110 | 110 | , '-dynamic -package ghc' if have_dynamic() else '-package ghc' ]
|
111 | 111 | )
|
112 | 112 | |
113 | +# Checks that we run type-checker plugins for pattern-match warnings.
|
|
114 | +test('T26395'
|
|
115 | + , [ extra_files(
|
|
116 | + [ 'T26395_Plugin.hs'
|
|
117 | + , 'T26395.hs'
|
|
118 | + ])
|
|
119 | + , req_th
|
|
120 | + ]
|
|
121 | + , multimod_compile
|
|
122 | + , [ 'T26395.hs'
|
|
123 | + , '-dynamic -package ghc' if have_dynamic() else '-package ghc' ]
|
|
124 | + )
|
|
125 | + |
|
113 | 126 | test('T11462', [js_broken(22261), req_th, req_plugins], multi_compile,
|
114 | 127 | [None, [('T11462_Plugin.hs', '-package ghc'), ('T11462.hs', '')],
|
115 | 128 | '-dynamic' if have_dynamic() else ''])
|