Commit 79d6745f authored by Simon Marlow's avatar Simon Marlow

Clean up the handling of the import and :module commands in GHCi

Previously we remembered the whole history of commands and replayed
them on every :load/:reload, which lead to some non-linear performance
characteristics (#5317).  The handling of the implicit Prelude import
and the implicit imports of recently loaded modules was also
complicated and wrong in various obscure ways.

The Prelude import works just like the implicit Prelude import in a
Haskell module: it can be overriden with an explicit Prelude
import.

I have added a new ":show imports" command to show which imports are
currently in force.

Prelude> :show imports
import Prelude -- implicit
Prelude> import Prelude ()
Prelude> :show imports
import Prelude ()
Prelude> map

<interactive>:0:1: Not in scope: `map'
Prelude>

Full documentation in the User's Guide.

There are various other little tweaks and improvements, such as when a
module is imported with 'as', we now show the 'as' name in the prompt
rather than the original name.
parent 3b8d1287
...@@ -111,7 +111,7 @@ data IE name ...@@ -111,7 +111,7 @@ data IE name
| IEGroup Int HsDocString -- ^ Doc section heading | IEGroup Int HsDocString -- ^ Doc section heading
| IEDoc HsDocString -- ^ Some documentation | IEDoc HsDocString -- ^ Some documentation
| IEDocNamed String -- ^ Reference to named doc | IEDocNamed String -- ^ Reference to named doc
deriving (Data, Typeable) deriving (Eq, Data, Typeable)
\end{code} \end{code}
\begin{code} \begin{code}
......
...@@ -582,8 +582,12 @@ xs :: [Integer] ...@@ -582,8 +582,12 @@ xs :: [Integer]
<screen>Prelude></screen> <screen>Prelude></screen>
<para>Which indicates that everything from the module <para>Which indicates that everything from the module
<literal>Prelude</literal> is currently in scope. If we now <literal>Prelude</literal> is currently in scope; the visible
load a file into GHCi, the prompt will change:</para> identifiers are exactly those that would be visible in a Haskell
source file with no <literal>import</literal>
declarations.</para>
<para>If we now load a file into GHCi, the prompt will change:</para>
<screen> <screen>
Prelude> :load Main.hs Prelude> :load Main.hs
...@@ -620,26 +624,59 @@ Compiling Main ( Main.hs, interpreted ) ...@@ -620,26 +624,59 @@ Compiling Main ( Main.hs, interpreted )
interpreted version of a module, add the <literal>*</literal> interpreted version of a module, add the <literal>*</literal>
when loading the module, e.g. <literal>:load *M</literal>.</para> when loading the module, e.g. <literal>:load *M</literal>.</para>
<para>The scope is manipulated using the <para>To add modules to the scope, use ordinary Haskell
<literal>:module</literal> command. For example, if the current <literal>import</literal> syntax:</para>
scope is <literal>Prelude</literal>, then we can bring into
scope the exports from the module <literal>IO</literal> like
so:</para>
<screen> <screen>
Prelude> :module +IO Prelude> import System.IO
Prelude IO> hPutStrLn stdout "hello\n" Prelude System.IO> hPutStrLn stdout "hello\n"
hello hello
Prelude IO> Prelude System.IO>
</screen> </screen>
<para>(Note: you can use conventional <para>The full Haskell import syntax is supported, including
haskell <literal>import</literal> syntax as <literal>hiding</literal> and <literal>as</literal> clauses.
well, but this does not support The prompt shows the modules that are currently imported, but it
<literal>*</literal> forms). omits details about <literal>hiding</literal>,
<literal>:module</literal> can also be shortened to <literal>as</literal>, and so on. To see the full story, use
<literal>:m</literal>. The full syntax of the <literal>:show imports</literal>:</para>
<literal>:module</literal> command is:</para>
<screen>
Prelude> import System.IO
Prelude System.IO> import Data.Map as Map
Prelude System.IO Map> :show imports
import Prelude -- implicit
import System.IO
import Data.Map as Map
Prelude System.IO Map>
</screen>
<para>Note that the <literal>Prelude</literal> import is marked
as implicit. It can be overriden with an explicit
<literal>Prelude</literal> import, just like in a Haskell
module.</para>
<para>Another way to manipulate the scope is to use the
<literal>:module</literal> command, which provides a way to do
two things that cannot be done with ordinary
<literal>import</literal> declarations:
<itemizedlist>
<listitem>
<para><literal>:module</literal> supports the
<literal>*</literal> modifier on modules, which opens the
full top-level scope of a module, rather than just its
exports.</para>
</listitem>
<listitem>
<para>Imports can be <emphasis>removed</emphasis> from the
context, using the syntax <literal>:module -M</literal>.
The <literal>import</literal> syntax is cumulative (as in a
Haskell module), so this is the only way to subtract from
the scope.</para>
</listitem>
</itemizedlist>
The full syntax of the <literal>:module</literal> command
is:</para>
<screen> <screen>
:module <optional>+|-</optional> <optional>*</optional><replaceable>mod<subscript>1</subscript></replaceable> ... <optional>*</optional><replaceable>mod<subscript>n</subscript></replaceable> :module <optional>+|-</optional> <optional>*</optional><replaceable>mod<subscript>1</subscript></replaceable> ... <optional>*</optional><replaceable>mod<subscript>n</subscript></replaceable>
...@@ -650,14 +687,12 @@ Prelude IO> ...@@ -650,14 +687,12 @@ Prelude IO>
scope, and <literal>-</literal> removes them. Without either scope, and <literal>-</literal> removes them. Without either
<literal>+</literal> or <literal>-</literal>, the current scope <literal>+</literal> or <literal>-</literal>, the current scope
is replaced by the set of modules specified. Note that if you is replaced by the set of modules specified. Note that if you
use this form and leave out <literal>Prelude</literal>, GHCi use this form and leave out <literal>Prelude</literal>, an
will assume that you really wanted the implicit <literal>Prelude</literal> import will be added
<literal>Prelude</literal> and add it in for you (if you don't automatically.</para>
want the <literal>Prelude</literal>, then ask to remove it with
<literal>:m -Prelude</literal>).</para> <para>After a <literal>:load</literal> command, an automatic
import is added to the scope for the most recently loaded
<para>The scope is automatically set after a
<literal>:load</literal> command, to the most recently loaded
"target" module, in a <literal>*</literal>-form if possible. "target" module, in a <literal>*</literal>-form if possible.
For example, if you say <literal>:load foo.hs bar.hs</literal> For example, if you say <literal>:load foo.hs bar.hs</literal>
and <filename>bar.hs</filename> contains module and <filename>bar.hs</filename> contains module
...@@ -666,7 +701,23 @@ Prelude IO> ...@@ -666,7 +701,23 @@ Prelude IO>
interpreted, or if <literal>Bar</literal> is compiled it will be interpreted, or if <literal>Bar</literal> is compiled it will be
set to <literal>Prelude Bar</literal> (GHCi automatically adds set to <literal>Prelude Bar</literal> (GHCi automatically adds
<literal>Prelude</literal> if it isn't present and there aren't <literal>Prelude</literal> if it isn't present and there aren't
any <literal>*</literal>-form modules).</para> any <literal>*</literal>-form modules). These
automatically-added imports can be seen with
<literal>:show imports</literal>:
<screen>
Prelude> :load hello.hs
[1 of 1] Compiling Main ( hello.hs, interpreted )
Ok, modules loaded: Main.
*Main> :show imports
:module +*Main -- added automatically
*Main>
</screen>
and the automatically-added import is replaced the next time you
use <literal>:load</literal>, <literal>:add</literal>, or
<literal>:reload</literal>. It can also be removed by
<literal>:module</literal> as with normal imports.</para>
<para>With multiple modules in scope, especially multiple <para>With multiple modules in scope, especially multiple
<literal>*</literal>-form modules, it is likely that name <literal>*</literal>-form modules, it is likely that name
...@@ -692,20 +743,20 @@ Prelude IO> ...@@ -692,20 +743,20 @@ Prelude IO>
<itemizedlist> <itemizedlist>
<listitem> <listitem>
<para>The set of modules that are <para>The set of modules that are currently
currently <emphasis>loaded</emphasis>. This set is <emphasis>loaded</emphasis>. This set is modified by
modified <literal>:load</literal>, <literal>:add</literal> and
by <literal>:load</literal>, <literal>:add</literal> <literal>:reload</literal>, and can be shown with
and <literal>:reload</literal>. <literal>:show modules</literal>.
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
<para>The set of modules that are currently <emphasis>in <para>The set of modules that are currently <emphasis>in
scope</emphasis> at the prompt. This set is modified scope</emphasis> at the prompt. This set is modified by
by <literal>:module</literal>, and it is also set <literal>import</literal>, <literal>:module</literal>, and
automatically it is also modified automatically after
after <literal>:load</literal>, <literal>:add</literal>, <literal>:load</literal>, <literal>:add</literal>, and
and <literal>:reload</literal>.</para> <literal>:reload</literal>, as described above.</para>
</listitem> </listitem>
</itemizedlist> </itemizedlist>
...@@ -2534,6 +2585,18 @@ bar ...@@ -2534,6 +2585,18 @@ bar
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term>
<literal>:show imports</literal>
<indexterm><primary><literal>:show imports</literal></primary></indexterm>
</term>
<listitem>
<para>Show the imports that are currently in force, as
created by <literal>import</literal> and
<literal>:module</literal> commands.</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term> <term>
<literal>:show modules</literal> <literal>:show modules</literal>
......
...@@ -56,7 +56,6 @@ data GHCiState = GHCiState ...@@ -56,7 +56,6 @@ data GHCiState = GHCiState
editor :: String, editor :: String,
stop :: String, stop :: String,
options :: [GHCiOption], options :: [GHCiOption],
prelude :: GHC.ModuleName,
line_number :: !Int, -- input line line_number :: !Int, -- input line
break_ctr :: !Int, break_ctr :: !Int,
breaks :: ![(Int, BreakLocation)], breaks :: ![(Int, BreakLocation)],
...@@ -68,23 +67,27 @@ data GHCiState = GHCiState ...@@ -68,23 +67,27 @@ data GHCiState = GHCiState
-- remember is here: -- remember is here:
last_command :: Maybe Command, last_command :: Maybe Command,
cmdqueue :: [String], cmdqueue :: [String],
remembered_ctx :: [CtxtCmd],
-- we remember the :module commands between :loads, so that remembered_ctx :: [InteractiveImport],
-- on a :reload we can replay them. See bugs #2049, -- the imports that the user has asked for, via import
-- \#1873, #1360. Previously we tried to remember modules that -- declarations and :module commands. This list is
-- were supposed to be in the context but currently had errors, -- persistent over :reloads (but any imports for modules
-- but this was complicated. Just replaying the :module commands -- that are not loaded are temporarily ignored). After a
-- seems to be the right thing. -- :load, all the home-package imports are stripped from
-- this list.
-- See bugs #2049, #1873, #1360
transient_ctx :: [InteractiveImport],
-- An import added automatically after a :load, usually of
-- the most recently compiled module. May be empty if
-- there are no modules loaded. This list is replaced by
-- :load, :reload, and :add. In between it may be modified
-- by :module.
ghc_e :: Bool -- True if this is 'ghc -e' (or runghc) ghc_e :: Bool -- True if this is 'ghc -e' (or runghc)
} }
data CtxtCmd -- In each case, the first [String] are the starred modules
-- and the second are the unstarred ones
= SetContext [String] [String]
| AddModules [String] [String]
| RemModules [String] [String]
| Import String
type TickArray = Array Int [(BreakIndex,SrcSpan)] type TickArray = Array Int [(BreakIndex,SrcSpan)]
data GHCiOption data GHCiOption
...@@ -161,6 +164,8 @@ getGHCiState :: GHCi GHCiState ...@@ -161,6 +164,8 @@ getGHCiState :: GHCi GHCiState
getGHCiState = GHCi $ \r -> liftIO $ readIORef r getGHCiState = GHCi $ \r -> liftIO $ readIORef r
setGHCiState :: GHCiState -> GHCi () setGHCiState :: GHCiState -> GHCi ()
setGHCiState s = GHCi $ \r -> liftIO $ writeIORef r s setGHCiState s = GHCi $ \r -> liftIO $ writeIORef r s
modifyGHCiState :: (GHCiState -> GHCiState) -> GHCi ()
modifyGHCiState f = GHCi $ \r -> liftIO $ readIORef r >>= writeIORef r . f
liftGhc :: Ghc a -> GHCi a liftGhc :: Ghc a -> GHCi a
liftGhc m = GHCi $ \_ -> m liftGhc m = GHCi $ \_ -> m
...@@ -209,10 +214,6 @@ instance ExceptionMonad (InputT GHCi) where ...@@ -209,10 +214,6 @@ instance ExceptionMonad (InputT GHCi) where
gblock = Haskeline.block gblock = Haskeline.block
gunblock = Haskeline.unblock gunblock = Haskeline.unblock
-- for convenience...
getPrelude :: GHCi ModuleName
getPrelude = getGHCiState >>= return . prelude
getDynFlags :: GhcMonad m => m DynFlags getDynFlags :: GhcMonad m => m DynFlags
getDynFlags = do getDynFlags = do
GHC.getSessionDynFlags GHC.getSessionDynFlags
......
This diff is collapsed.
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