Commit 41afbb3f authored by Matthew Pickering's avatar Matthew Pickering Committed by Ben Gamari

Add flag -fno-it

This flag stops ghci creating the special variable `it`
after evaluating an expression. This stops ghci leaking
as much memory when evaluating expressions. See #14336

Reviewers: bgamari

Reviewed By: bgamari

Subscribers: rwbarton, thomie, carter

GHC Trac Issues: #14336

Differential Revision: https://phabricator.haskell.org/D4299
parent 2feed118
...@@ -522,6 +522,7 @@ data GeneralFlag ...@@ -522,6 +522,7 @@ data GeneralFlag
| Opt_GhciSandbox | Opt_GhciSandbox
| Opt_GhciHistory | Opt_GhciHistory
| Opt_LocalGhciHistory | Opt_LocalGhciHistory
| Opt_NoIt
| Opt_HelpfulErrors | Opt_HelpfulErrors
| Opt_DeferTypeErrors | Opt_DeferTypeErrors
| Opt_DeferTypedHoles | Opt_DeferTypedHoles
...@@ -3824,6 +3825,7 @@ fFlagsDeps = [ ...@@ -3824,6 +3825,7 @@ fFlagsDeps = [
flagSpec "gen-manifest" Opt_GenManifest, flagSpec "gen-manifest" Opt_GenManifest,
flagSpec "ghci-history" Opt_GhciHistory, flagSpec "ghci-history" Opt_GhciHistory,
flagGhciSpec "local-ghci-history" Opt_LocalGhciHistory, flagGhciSpec "local-ghci-history" Opt_LocalGhciHistory,
flagGhciSpec "no-it" Opt_NoIt,
flagSpec "ghci-sandbox" Opt_GhciSandbox, flagSpec "ghci-sandbox" Opt_GhciSandbox,
flagSpec "helpful-errors" Opt_HelpfulErrors, flagSpec "helpful-errors" Opt_HelpfulErrors,
flagSpec "hpc" Opt_Hpc, flagSpec "hpc" Opt_Hpc,
......
...@@ -2010,17 +2010,23 @@ tcUserStmt (L loc (BodyStmt expr _ _ _)) ...@@ -2010,17 +2010,23 @@ tcUserStmt (L loc (BodyStmt expr _ _ _))
(mkRnSyntaxExpr thenIOName) (mkRnSyntaxExpr thenIOName)
noSyntaxExpr placeHolderType noSyntaxExpr placeHolderType
-- The plans are: -- NewA
-- A. [it <- e; print it] but not if it::() no_it_a = L loc $ BodyStmt (nlHsApps bindIOName
-- B. [it <- e] [rn_expr , nlHsVar interPrintName])
-- C. [let it = e; print it] (mkRnSyntaxExpr thenIOName)
-- noSyntaxExpr placeHolderType
-- Ensure that type errors don't get deferred when type checking the
-- naked expression. Deferring type errors here is unhelpful because the no_it_b = L loc $ BodyStmt (rn_expr)
-- expression gets evaluated right away anyway. It also would potentially (mkRnSyntaxExpr thenIOName)
-- emit two redundant type-error warnings, one from each plan. noSyntaxExpr placeHolderType
; plan <- unsetGOptM Opt_DeferTypeErrors $
unsetGOptM Opt_DeferTypedHoles $ runPlans [ no_it_c = L loc $ BodyStmt (nlHsApp (nlHsVar interPrintName) rn_expr)
(mkRnSyntaxExpr thenIOName)
noSyntaxExpr placeHolderType
-- See Note [GHCi Plans]
it_plans = [
-- Plan A -- Plan A
do { stuff@([it_id], _) <- tcGhciStmts [bind_stmt, print_it] do { stuff@([it_id], _) <- tcGhciStmts [bind_stmt, print_it]
; it_ty <- zonkTcType (idType it_id) ; it_ty <- zonkTcType (idType it_id)
...@@ -2039,6 +2045,25 @@ tcUserStmt (L loc (BodyStmt expr _ _ _)) ...@@ -2039,6 +2045,25 @@ tcUserStmt (L loc (BodyStmt expr _ _ _))
--- checkNoErrs defeats the error recovery of let-bindings --- checkNoErrs defeats the error recovery of let-bindings
; tcGhciStmts [let_stmt, print_it] } ] ; tcGhciStmts [let_stmt, print_it] } ]
-- Plans where we don't bind "it"
no_it_plans = [
tcGhciStmts [no_it_a] ,
tcGhciStmts [no_it_b] ,
tcGhciStmts [no_it_c] ]
-- Ensure that type errors don't get deferred when type checking the
-- naked expression. Deferring type errors here is unhelpful because the
-- expression gets evaluated right away anyway. It also would potentially
-- emit two redundant type-error warnings, one from each plan.
; generate_it <- goptM Opt_NoIt
; plan <- unsetGOptM Opt_DeferTypeErrors $
unsetGOptM Opt_DeferTypedHoles $
runPlans $ if generate_it
then no_it_plans
else it_plans
; fix_env <- getFixityEnv ; fix_env <- getFixityEnv
; return (plan, fix_env) } ; return (plan, fix_env) }
...@@ -2080,6 +2105,27 @@ tcUserStmt rdr_stmt@(L loc _) ...@@ -2080,6 +2105,27 @@ tcUserStmt rdr_stmt@(L loc _)
(mkRnSyntaxExpr thenIOName) noSyntaxExpr (mkRnSyntaxExpr thenIOName) noSyntaxExpr
placeHolderType placeHolderType
{-
Note [GHCi Plans]
When a user types an expression in the repl we try to print it in three different
ways. Also, depending on whether -fno-it is set, we bind a variable called `it`
which can be used to refer to the result of the expression subsequently in the repl.
The normal plans are :
A. [it <- e; print e] but not if it::()
B. [it <- e]
C. [let it = e; print it]
When -fno-it is set, the plans are:
A. [e >>= print]
B. [e]
C. [let it = e in print it]
The reason for -fno-it is explained in #14336. `it` can lead to the repl
leaking memory as it is repeatedly queried.
-}
-- | Typecheck the statements given and then return the results of the -- | Typecheck the statements given and then return the results of the
-- statement in the form 'IO [()]'. -- statement in the form 'IO [()]'.
tcGhciStmts :: [GhciLStmt GhcRn] -> TcM PlanResult tcGhciStmts :: [GhciLStmt GhcRn] -> TcM PlanResult
......
...@@ -1027,6 +1027,20 @@ The corresponding translation for an IO-typed ``e`` is ...@@ -1027,6 +1027,20 @@ The corresponding translation for an IO-typed ``e`` is
Note that ``it`` is shadowed by the new value each time you evaluate a Note that ``it`` is shadowed by the new value each time you evaluate a
new expression, and the old value of ``it`` is lost. new expression, and the old value of ``it`` is lost.
In order to stop the value ``it`` being bound on each command, the flag
:ghc-flag:`-fno-it` can be set. The ``it`` variable can be the source
of space leaks due to how shadowed declarations are handled by
GHCi (see :ref:`ghci-decls`).
.. ghc-flag:: -fno-it
:shortdesc: No longer set the special variable ``it``.
:type: dynamic
:reverse: -fno-no-it
:category:
When this flag is set, the variable ``it`` will no longer be set
to the result of the previously evaluated expression.
.. _extended-default-rules: .. _extended-default-rules:
Type defaulting in GHCi Type defaulting in GHCi
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment