Skip to content
Browse files

Merge branch 'master' of http://darcs.haskell.org/ghc

  • Loading branch information...
2 parents 20705df + 5ac223a commit bcf55e05d6065d4e2c826e27bdd01f221b96dbe4 @igfoo igfoo committed Oct 6, 2011
Showing with 222 additions and 64 deletions.
  1. +74 −16 compiler/coreSyn/CorePrep.lhs
  2. +14 −3 compiler/main/HscMain.lhs
  3. +132 −44 docs/users_guide/ghci.xml
  4. +2 −1 ghc/InteractiveUI.hs
View
90 compiler/coreSyn/CorePrep.lhs
@@ -5,6 +5,7 @@
Core pass to saturate constructors and PrimOps
\begin{code}
+{-# LANGUAGE BangPatterns #-}
module CorePrep (
corePrepPgm, corePrepExpr
) where
@@ -19,7 +20,6 @@ import CoreMonad ( endPass, CoreToDo(..) )
import CoreSyn
import CoreSubst
import MkCore
-import OccurAnal ( occurAnalyseExpr )
import Type
import Literal
import Coercion
@@ -288,23 +288,29 @@ After specialisation and SpecConstr, we would get something like this:
g$Bool_True_Just = ...
g$Unit_Unit_Just = ...
-Note that the g$Bool and g$Unit functions are actually dead code: they are only kept
-alive by the occurrence analyser because they are referred to by the rules of g,
-which is being kept alive by the fact that it is used (unspecialised) in the returned pair.
+Note that the g$Bool and g$Unit functions are actually dead code: they
+are only kept alive by the occurrence analyser because they are
+referred to by the rules of g, which is being kept alive by the fact
+that it is used (unspecialised) in the returned pair.
-However, at the CorePrep stage there is no way that the rules for g will ever fire,
-and it really seems like a shame to produce an output program that goes to the trouble
-of allocating a closure for the unreachable g$Bool and g$Unit functions.
+However, at the CorePrep stage there is no way that the rules for g
+will ever fire, and it really seems like a shame to produce an output
+program that goes to the trouble of allocating a closure for the
+unreachable g$Bool and g$Unit functions.
The way we fix this is to:
* In cloneBndr, drop all unfoldings/rules
- * In deFloatTop, run the occurrence analyser on each top-level RHS to drop
- the dead local bindings
-
-The reason we don't just OccAnal the whole output of CorePrep is that the tidier
-ensures that all top-level binders are GlobalIds, so they don't show up in the free
-variables any longer. So if you run the occurrence analyser on the output of CoreTidy
-(or later) you e.g. turn this program:
+ * In deFloatTop, run a simple dead code analyser on each top-level RHS to drop
+ the dead local bindings. (we used to run the occurrence analyser to do
+ this job, but the occurrence analyser sometimes introduces new let
+ bindings for case binders, which lead to the bug in #5433, hence we
+ now have a special-purpose dead code analyser).
+
+The reason we don't just OccAnal the whole output of CorePrep is that
+the tidier ensures that all top-level binders are GlobalIds, so they
+don't show up in the free variables any longer. So if you run the
+occurrence analyser on the output of CoreTidy (or later) you e.g. turn
+this program:
Rec {
f = ... f ...
@@ -1006,8 +1012,60 @@ deFloatTop (Floats _ floats)
get b _ = pprPanic "corePrepPgm" (ppr b)
-- See Note [Dead code in CorePrep]
- occurAnalyseRHSs (NonRec x e) = NonRec x (occurAnalyseExpr e)
- occurAnalyseRHSs (Rec xes) = Rec [(x, occurAnalyseExpr e) | (x, e) <- xes]
+ occurAnalyseRHSs (NonRec x e) = NonRec x (fst (dropDeadCode e))
+ occurAnalyseRHSs (Rec xes) = Rec [ (x, fst (dropDeadCode e))
+ | (x, e) <- xes]
+
+---------------------------------------------------------------------------
+-- Simple dead-code analyser, see Note [Dead code in CorePrep]
+
+dropDeadCode :: CoreExpr -> (CoreExpr, VarSet)
+dropDeadCode (Var v)
+ = (Var v, if isLocalId v then unitVarSet v else emptyVarSet)
+dropDeadCode (App fun arg)
+ = (App fun' arg', fun_fvs `unionVarSet` arg_fvs)
+ where !(fun', fun_fvs) = dropDeadCode fun
+ !(arg', arg_fvs) = dropDeadCode arg
+dropDeadCode (Lam v e)
+ = (Lam v e', delVarSet fvs v)
+ where !(e', fvs) = dropDeadCode e
+dropDeadCode (Let (NonRec v rhs) body)
+ | v `elemVarSet` body_fvs
+ = (Let (NonRec v rhs') body', rhs_fvs `unionVarSet` (body_fvs `delVarSet` v))
+ | otherwise
+ = (body', body_fvs) -- drop the dead let bind!
+ where !(body', body_fvs) = dropDeadCode body
+ !(rhs', rhs_fvs) = dropDeadCode rhs
+dropDeadCode (Let (Rec prs) body)
+ | any (`elemVarSet` all_fvs) bndrs
+ -- approximation: strictly speaking we should do SCC analysis here,
+ -- but for simplicity we just look to see whether any of the binders
+ -- is used and drop the entire group if all are unused.
+ = (Let (Rec (zip bndrs rhss')) body', all_fvs `delVarSetList` bndrs)
+ | otherwise
+ = (body', body_fvs) -- drop the dead let bind!
+ where !(body', body_fvs) = dropDeadCode body
+ !(bndrs, rhss) = unzip prs
+ !(rhss', rhs_fvss) = unzip (map dropDeadCode rhss)
+ all_fvs = unionVarSets (body_fvs : rhs_fvss)
+
+dropDeadCode (Case scrut bndr t alts)
+ = (Case scrut' bndr t alts', scrut_fvs `unionVarSet` alts_fvs)
+ where !(scrut', scrut_fvs) = dropDeadCode scrut
+ !(alts', alts_fvs) = dropDeadCodeAlts alts
+dropDeadCode (Cast e c)
+ = (Cast e' c, fvs)
+ where !(e', fvs) = dropDeadCode e
+dropDeadCode (Note n e)
+ = (Note n e', fvs)
+ where !(e', fvs) = dropDeadCode e
+dropDeadCode e = (e, emptyVarSet) -- Lit, Type, Coercion
+
+dropDeadCodeAlts :: [CoreAlt] -> ([CoreAlt], VarSet)
+dropDeadCodeAlts alts = (alts', unionVarSets fvss)
+ where !(alts', fvss) = unzip (map do_alt alts)
+ do_alt (c, vs, e) = ((c,vs,e'), fvs `delVarSetList` vs)
+ where !(e', fvs) = dropDeadCode e
-------------------------------------------
canFloatFromNoCaf :: Floats -> CpeRhs -> Maybe (Floats, CpeRhs)
View
17 compiler/main/HscMain.lhs
@@ -83,6 +83,7 @@ import VarSet
import VarEnv ( emptyTidyEnv )
import Panic
import Class
+import Data.List
#endif
import Id
@@ -145,7 +146,7 @@ import Bag
import Exception
import Control.Monad
-import Data.Maybe ( catMaybes )
+import Data.Maybe
import Data.IORef
\end{code}
#include "HsVersions.h"
@@ -1364,16 +1365,26 @@ hscDeclsWithLocation hsc_env str source linenumber = runHsc hsc_env $ do
let
tcs = filter (not . isImplicitTyCon) $ mg_tcs simpl_mg
clss = mg_clss simpl_mg
- tythings = map ATyCon tcs ++ map (ATyCon . classTyCon) clss
- sys_vars = filter (isExternalName . idName) $
+
+ ext_vars = filter (isExternalName . idName) $
bindersOfBinds (cg_binds tidy_cg)
+
+ (sys_vars, user_vars) = partition is_sys_var ext_vars
+ is_sys_var id = isDFunId id
+ || isRecordSelector id
+ || isJust (isClassOpId_maybe id)
-- we only need to keep around the external bindings
-- (as decided by TidyPgm), since those are the only ones
-- that might be referenced elsewhere.
+ tythings = map AnId user_vars
+ ++ map ATyCon tcs
+ ++ map (ATyCon . classTyCon) clss
+
-- pprTrace "new tycons" (ppr tcs) $ return ()
-- pprTrace "new classes" (ppr clss) $ return ()
-- pprTrace "new sys Ids" (ppr sys_vars) $ return ()
+ -- pprTrace "new user Ids" (ppr user_vars) $ return ()
let ictxt1 = extendInteractiveContext icontext tythings
ictxt = ictxt1 {
View
176 docs/users_guide/ghci.xml
@@ -38,12 +38,11 @@ Prelude>
<para>There may be a short pause while GHCi loads the prelude and
standard libraries, after which the prompt is shown. As the banner
- says, you can type <literal>:?</literal> to see the list of commands
- available, and a half line description of each of them.</para>
-
- <para>We'll explain most of these commands as we go along. For
- Hugs users: many things work the same as in Hugs, so you should be
- able to get going straight away.</para>
+ says, you can type <literal>:?</literal> to see the list of
+ commands available, and a half line description of each of them.
+ We'll explain most of these commands as we go along, and there is
+ complete documentation for all the commands in
+ <xref linkend="ghci-commands" />.</para>
<para>Haskell expressions can be typed at the prompt:</para>
<indexterm><primary>prompt</primary><secondary>GHCi</secondary>
@@ -61,49 +60,12 @@ Prelude>
The expression may not span several lines - as soon as you press enter,
GHCi will attempt to evaluate it.</para>
- <para>GHCi also has a multiline mode,
- <indexterm><primary><literal>:set +m</literal></primary></indexterm>,
- which is terminated by an empty line:</para>
-
-<screen>
-Prelude> :set +m
-Prelude> let x = 42 in x / 9
-Prelude|
-4.666666666666667
-Prelude>
-</screen>
-
<para>In Haskell, a <literal>let</literal> expression is followed
by <literal>in</literal>. However, in GHCi, since the expression
can also be interpreted in the <literal>IO</literal> monad,
a <literal>let</literal> binding with no accompanying
<literal>in</literal> statement can be signalled by an empty line,
as in the above example.</para>
-
- <para>Multiline mode is useful when entering monadic
- <literal>do</literal> statements:</para>
-
-<screen>
-Control.Monad.State> flip evalStateT 0 $ do
-Control.Monad.State| i &lt;- get
-Control.Monad.State| lift $ do
-Control.Monad.State| putStrLn "Hello World!"
-Control.Monad.State| print i
-Control.Monad.State|
-"Hello World!"
-0
-Control.Monad.State>
-</screen>
-
- <para>During a multiline interaction, the user can interrupt and
- return to the top-level prompt.</para>
-
-<screen>
-Prelude> do
-Prelude| putStrLn "Hello, World!"
-Prelude| ^C
-Prelude>
-</screen>
</sect1>
<sect1 id="loading-source-files">
@@ -570,6 +532,132 @@ xs :: [Integer]
</sect2>
+ <sect2 id="ghci-multiline">
+ <title>Multiline input</title>
+
+ <para>Apart from the <literal>:{ ... :}</literal> syntax for
+ multi-line input mentioned above, GHCi also has a multiline
+ mode, enabled by <literal>:set +m</literal>,
+ <indexterm><primary><literal>:set +m</literal></primary></indexterm>
+ in which GHCi detects automatically when the current statement
+ is unfinished and allows further lines to be added. A
+ multi-line input is terminated with an empty line. For example:</para>
+
+<screen>
+Prelude> :set +m
+Prelude> let x = 42
+Prelude|
+</screen>
+
+ <para>Further bindings can be added to
+ this <literal>let</literal> statement, so GHCi indicates that
+ the next line continues the previous one by changing the
+ prompt. Note that layout is in effect, so to add more bindings
+ to this <literal>let</literal> we have to line them up:</para>
+
+<screen>
+Prelude> :set +m
+Prelude> let x = 42
+Prelude| y = 3
+Prelude|
+Prelude>
+</screen>
+
+ <para>Explicit braces and semicolons can be used instead of
+ layout, as usual:</para>
+
+<screen>
+Prelude> do {
+Prelude| putStrLn "hello"
+Prelude| ;putStrLn "world"
+Prelude| }
+hello
+world
+Prelude>
+</screen>
+
+ <para>Note that after the closing brace, GHCi knows that the
+ current statement is finished, so no empty line is required.</para>
+
+ <para>Multiline mode is useful when entering monadic
+ <literal>do</literal> statements:</para>
+
+<screen>
+Control.Monad.State> flip evalStateT 0 $ do
+Control.Monad.State| i &lt;- get
+Control.Monad.State| lift $ do
+Control.Monad.State| putStrLn "Hello World!"
+Control.Monad.State| print i
+Control.Monad.State|
+"Hello World!"
+0
+Control.Monad.State>
+</screen>
+
+ <para>During a multiline interaction, the user can interrupt and
+ return to the top-level prompt.</para>
+
+<screen>
+Prelude> do
+Prelude| putStrLn "Hello, World!"
+Prelude| ^C
+Prelude>
+</screen>
+ </sect2>
+
+ <sect2 id="ghci-decls">
+ <title>Type, class and other declarations</title>
+
+ <para>[<emphasis role="bold">New in version 7.4.1</emphasis>] At the GHCi
+ prompt you can also enter any top-level Haskell declaration,
+ including <literal>data</literal>, <literal>type</literal>, <literal>newtype</literal>, <literal>class</literal>, <literal>instance</literal>, <literal>deriving</literal>,
+ and <literal>foreign</literal> declarations. For
+ example:</para>
+
+<screen>
+Prelude> data T = A | B | C deriving (Eq, Ord, Show, Enum)
+Prelude> [A ..]
+[A,B,C]
+Prelude> :i T
+data T = A | B | C -- Defined at &lt;interactive>:2:6
+instance Enum T -- Defined at &lt;interactive>:2:45
+instance Eq T -- Defined at &lt;interactive>:2:30
+instance Ord T -- Defined at &lt;interactive>:2:34
+instance Show T -- Defined at &lt;interactive>:2:39
+</screen>
+
+ <para>As with ordinary variable bindings, later definitions shadow
+ earlier ones, so you can re-enter a declaration to fix a problem
+ with it or extend it. But there's a gotcha: when a new type
+ declaration shadows an older one, there might be other
+ declarations that refer to the old type. The thing to remember is
+ that the old type still exists, and these other declarations still
+ refer to the old type. However, while the old and the new type
+ have the same name, GHCi will treat them as distinct. For
+ example:</para>
+
+<screen>
+Prelude> data T = A | B
+Prelude> let f A = True; f B = False
+Prelude> data T = A | B | C
+Prelude> f A
+
+&lt;interactive>:2:3:
+ Couldn't match expected type `main::Interactive.T'
+ with actual type `T'
+ In the first argument of `f', namely `A'
+ In the expression: f A
+ In an equation for `it': it = f A
+Prelude>
+</screen>
+
+ <para>The old, shadowed, version of <literal>T</literal> is
+ displayed as <literal>main::Interactive.T</literal> by GHCi in
+ an attempt to distinguish it from the new <literal>T</literal>,
+ which is displayed as simply <literal>T</literal>.</para>
+
+ </sect2>
+
<sect2 id="ghci-scope">
<title>What's really in scope at the prompt?</title>
@@ -2768,7 +2856,7 @@ bar
<listitem>
<para>Enable parsing of multiline commands. A multiline command
is prompted for when the current input line contains open layout
- contexts.</para>
+ contexts (see <xref linkend="ghci-multiline" />).</para>
</listitem>
</varlistentry>
View
3 ghc/InteractiveUI.hs
@@ -728,7 +728,8 @@ enqueueCommands cmds = do
-- | If we one of these strings prefixes a command, then we treat it as a decl
-- rather than a stmt.
declPrefixes :: [String]
-declPrefixes = ["class ","data ","newtype ","type ","instance ", "deriving "]
+declPrefixes = ["class ","data ","newtype ","type ","instance ", "deriving ",
+ "foreign "]
runStmt :: String -> SingleStep -> GHCi Bool
runStmt stmt step

0 comments on commit bcf55e0

Please sign in to comment.
Something went wrong with that request. Please try again.