summaryrefslogtreecommitdiff
path: root/compiler/simplCore/CoreMonad.lhs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/simplCore/CoreMonad.lhs')
-rw-r--r--compiler/simplCore/CoreMonad.lhs84
1 files changed, 69 insertions, 15 deletions
diff --git a/compiler/simplCore/CoreMonad.lhs b/compiler/simplCore/CoreMonad.lhs
index 31547e14a2..0af8201170 100644
--- a/compiler/simplCore/CoreMonad.lhs
+++ b/compiler/simplCore/CoreMonad.lhs
@@ -50,7 +50,8 @@ module CoreMonad (
getAnnotations, getFirstAnnotations,
-- ** Debug output
- showPass, endPass, dumpPassResult, lintPassResult, dumpIfSet,
+ showPass, endPass, dumpPassResult, lintPassResult,
+ lintInteractiveExpr, dumpIfSet,
-- ** Screen output
putMsg, putMsgS, errorMsg, errorMsgS,
@@ -70,7 +71,7 @@ import Name( Name )
import CoreSyn
import PprCore
import CoreUtils
-import CoreLint ( lintCoreBindings )
+import CoreLint ( lintCoreBindings, lintExpr )
import HscTypes
import Module
import DynFlags
@@ -78,12 +79,13 @@ import StaticFlags
import Rules ( RuleBase )
import BasicTypes ( CompilerPhase(..) )
import Annotations
-import Id ( Id )
import IOEnv hiding ( liftIO, failM, failWithM )
import qualified IOEnv ( liftIO )
import TcEnv ( tcLookupGlobal )
import TcRnMonad ( initTcForLookup )
+import Var
+import VarSet
import Outputable
import FastString
@@ -136,11 +138,12 @@ stuff before and after core passes, and do Core Lint when necessary.
showPass :: DynFlags -> CoreToDo -> IO ()
showPass dflags pass = Err.showPass dflags (showPpr dflags pass)
-endPass :: DynFlags -> CoreToDo -> CoreProgram -> [CoreRule] -> IO ()
-endPass dflags pass binds rules
+endPass :: HscEnv -> CoreToDo -> CoreProgram -> [CoreRule] -> IO ()
+endPass hsc_env pass binds rules
= do { dumpPassResult dflags mb_flag (ppr pass) (pprPassDetails pass) binds rules
- ; lintPassResult dflags pass binds }
+ ; lintPassResult hsc_env pass binds }
where
+ dflags = hsc_dflags hsc_env
mb_flag = case coreDumpFlag pass of
Just flag | dopt flag dflags -> Just flag
| dopt Opt_D_verbose_core2core dflags -> Just flag
@@ -178,12 +181,16 @@ dumpPassResult dflags mb_flag hdr extra_info binds rules
, ptext (sLit "------ Local rules for imported ids --------")
, pprRules rules ]
-lintPassResult :: DynFlags -> CoreToDo -> CoreProgram -> IO ()
-lintPassResult dflags pass binds
- = when (gopt Opt_DoCoreLinting dflags) $
- do { let (warns, errs) = lintCoreBindings binds
+lintPassResult :: HscEnv -> CoreToDo -> CoreProgram -> IO ()
+lintPassResult hsc_env pass binds
+ | not (gopt Opt_DoCoreLinting dflags)
+ = return ()
+ | otherwise
+ = do { let (warns, errs) = lintCoreBindings (interactiveInScope hsc_env) binds
; Err.showPass dflags ("Core Linted result of " ++ showPpr dflags pass)
; displayLintResults dflags pass warns errs binds }
+ where
+ dflags = hsc_dflags hsc_env
displayLintResults :: DynFlags -> CoreToDo
-> Bag Err.MsgDoc -> Bag Err.MsgDoc -> CoreProgram
@@ -191,7 +198,7 @@ displayLintResults :: DynFlags -> CoreToDo
displayLintResults dflags pass warns errs binds
| not (isEmptyBag errs)
= do { log_action dflags dflags Err.SevDump noSrcSpan defaultDumpStyle
- (vcat [ banner "errors", Err.pprMessageBag errs
+ (vcat [ lint_banner "errors" (ppr pass), Err.pprMessageBag errs
, ptext (sLit "*** Offending Program ***")
, pprCoreBindings binds
, ptext (sLit "*** End of Offense ***") ])
@@ -206,19 +213,66 @@ displayLintResults dflags pass warns errs binds
, not opt_NoDebugOutput
, showLintWarnings pass
= log_action dflags dflags Err.SevDump noSrcSpan defaultDumpStyle
- (banner "warnings" $$ Err.pprMessageBag warns)
+ (lint_banner "warnings" (ppr pass) $$ Err.pprMessageBag warns)
| otherwise = return ()
where
- banner string = ptext (sLit "*** Core Lint") <+> text string
- <+> ptext (sLit ": in result of") <+> ppr pass
- <+> ptext (sLit "***")
+
+lint_banner :: String -> SDoc -> SDoc
+lint_banner string pass = ptext (sLit "*** Core Lint") <+> text string
+ <+> ptext (sLit ": in result of") <+> pass
+ <+> ptext (sLit "***")
showLintWarnings :: CoreToDo -> Bool
-- Disable Lint warnings on the first simplifier pass, because
-- there may be some INLINE knots still tied, which is tiresomely noisy
showLintWarnings (CoreDoSimplify _ (SimplMode { sm_phase = InitialPhase })) = False
showLintWarnings _ = True
+
+lintInteractiveExpr :: String -> HscEnv -> CoreExpr -> IO ()
+lintInteractiveExpr what hsc_env expr
+ | not (gopt Opt_DoCoreLinting dflags)
+ = return ()
+ | Just err <- lintExpr (interactiveInScope hsc_env) expr
+ = do { display_lint_err err
+ ; Err.ghcExit dflags 1 }
+ | otherwise
+ = return ()
+ where
+ dflags = hsc_dflags hsc_env
+
+ display_lint_err err
+ = do { log_action dflags dflags Err.SevDump noSrcSpan defaultDumpStyle
+ (vcat [ lint_banner "errors" (text what)
+ , err
+ , ptext (sLit "*** Offending Program ***")
+ , pprCoreExpr expr
+ , ptext (sLit "*** End of Offense ***") ])
+ ; Err.ghcExit dflags 1 }
+
+interactiveInScope :: HscEnv -> [Var]
+-- In GHCi we may lint expressions, or bindings arising from 'deriving'
+-- clauses, that mention variables bound in the interactive context.
+-- These are Local things (see Note [Interactively-bound Ids in GHCi] in TcRnDriver).
+-- So we have to tell Lint about them, lest it reports them as out of scope.
+--
+-- We do this by find local-named things that may appear free in interactive
+-- context. This function is pretty revolting and quite possibly not quite right.
+-- When we are not in GHCi, the interactive context (hsc_IC hsc_env) is empty
+-- so this is a (cheap) no-op.
+--
+-- See Trac #8215 for an example
+interactiveInScope hsc_env
+ = tyvars ++ vars
+ where
+ ictxt = hsc_IC hsc_env
+ te = mkTypeEnvWithImplicits (ic_tythings ictxt ++ map AnId (ic_sys_vars ictxt))
+ vars = typeEnvIds te
+ tyvars = varSetElems $ tyThingsTyVars $ typeEnvElts $ te
+ -- Why the type variables? How can the top level envt have free tyvars?
+ -- I think it's becuase of the GHCi debugger, which can bind variables
+ -- f :: [t] -> [t]
+ -- where t is a RuntimeUnk (see TcType)
\end{code}