summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornineonine <mail4chemik@gmail.com>2022-01-28 00:29:01 -0800
committerMarge Bot <ben+marge-bot@smart-cactus.org>2022-02-05 19:21:49 -0500
commit299acff08aa1b7b720ad2b69c459c514033bc395 (patch)
tree12cf8090a0b6a405b49a29aeefa47a24f3883452
parent6af8e71ed7e749ba94e7a7eaf8b2229341bf35da (diff)
downloadhaskell-299acff08aa1b7b720ad2b69c459c514033bc395.tar.gz
Exit with failure when -e fails (fixes #18411 #9916 #17560)
-rw-r--r--ghc/GHCi/UI.hs142
-rw-r--r--ghc/GHCi/UI/Monad.hs19
-rw-r--r--testsuite/tests/driver/T16167.stderr1
-rw-r--r--testsuite/tests/ghc-e/should_fail/Makefile66
-rw-r--r--testsuite/tests/ghc-e/should_fail/T18441fail0.stderr3
-rw-r--r--testsuite/tests/ghc-e/should_fail/T18441fail1.stderr3
-rw-r--r--testsuite/tests/ghc-e/should_fail/T18441fail10.stderr2
-rw-r--r--testsuite/tests/ghc-e/should_fail/T18441fail11.stderr2
-rw-r--r--testsuite/tests/ghc-e/should_fail/T18441fail12.stderr5
-rw-r--r--testsuite/tests/ghc-e/should_fail/T18441fail13.stderr3
-rw-r--r--testsuite/tests/ghc-e/should_fail/T18441fail14.stderr2
-rw-r--r--testsuite/tests/ghc-e/should_fail/T18441fail15.stderr2
-rw-r--r--testsuite/tests/ghc-e/should_fail/T18441fail16.stderr4
-rw-r--r--testsuite/tests/ghc-e/should_fail/T18441fail17.stderr3
-rw-r--r--testsuite/tests/ghc-e/should_fail/T18441fail18.stderr5
-rw-r--r--testsuite/tests/ghc-e/should_fail/T18441fail2.stderr2
-rw-r--r--testsuite/tests/ghc-e/should_fail/T18441fail4.stderr3
-rw-r--r--testsuite/tests/ghc-e/should_fail/T18441fail5.stderr3
-rw-r--r--testsuite/tests/ghc-e/should_fail/T18441fail6.stderr2
-rw-r--r--testsuite/tests/ghc-e/should_fail/T18441fail7.stderr2
-rw-r--r--testsuite/tests/ghc-e/should_fail/T18441fail8.stderr2
-rw-r--r--testsuite/tests/ghc-e/should_fail/T18441fail9.stderr3
-rw-r--r--testsuite/tests/ghc-e/should_fail/T7962.stderr1
-rw-r--r--testsuite/tests/ghc-e/should_fail/T9905fail1.stderr1
-rw-r--r--testsuite/tests/ghc-e/should_fail/T9905fail2.stderr1
-rw-r--r--testsuite/tests/ghc-e/should_fail/T9905fail3.stderr1
-rw-r--r--testsuite/tests/ghc-e/should_fail/all.T40
-rw-r--r--testsuite/tests/ghc-e/should_fail/ghc-e-fail1.stderr1
-rw-r--r--testsuite/tests/ghc-e/should_fail/ghc-e-fail2.stderr1
-rw-r--r--testsuite/tests/ghci/scripts/T10508.stderr2
-rw-r--r--testsuite/tests/ghci/scripts/T10508.stdout2
-rw-r--r--testsuite/tests/ghci/scripts/T14676.stderr2
-rw-r--r--testsuite/tests/ghci/scripts/T14676.stdout2
33 files changed, 263 insertions, 70 deletions
diff --git a/ghc/GHCi/UI.hs b/ghc/GHCi/UI.hs
index 9a62d53d17..4043f3e247 100644
--- a/ghc/GHCi/UI.hs
+++ b/ghc/GHCi/UI.hs
@@ -67,6 +67,7 @@ import GHC.Types.TyThing
import GHC.Types.TyThing.Ppr
import GHC.Core.TyCo.Ppr
import GHC.Types.SafeHaskell ( getSafeMode )
+import GHC.Types.SourceError ( SourceError )
import GHC.Types.Name
import GHC.Types.Var ( varType )
import GHC.Iface.Syntax ( showToHeader )
@@ -291,13 +292,13 @@ flagWordBreakChars :: String
flagWordBreakChars = " \t\n"
-keepGoing :: (String -> GHCi ()) -> (String -> InputT GHCi Bool)
+keepGoing :: (String -> GHCi ()) -> (String -> InputT GHCi CmdExecOutcome)
keepGoing a str = keepGoing' (lift . a) str
-keepGoingMulti :: (String -> GHCi ()) -> (String -> InputT GHCi Bool)
+keepGoingMulti :: (String -> GHCi ()) -> (String -> InputT GHCi CmdExecOutcome)
keepGoingMulti a str = keepGoingMulti' (lift . a) str
-keepGoing' :: GhciMonad m => (a -> m ()) -> a -> m Bool
+keepGoing' :: GhciMonad m => (a -> m ()) -> a -> m CmdExecOutcome
keepGoing' a str = do
in_multi <- inMultiMode
if in_multi
@@ -305,19 +306,19 @@ keepGoing' a str = do
liftIO $ hPutStrLn stderr "Command is not supported (yet) in multi-mode"
else
a str
- return False
+ return CmdSuccess
-- For commands which are actually support in multi-mode, initially just :reload
-keepGoingMulti' :: GhciMonad m => (String -> m ()) -> String -> m Bool
-keepGoingMulti' a str = a str >> return False
+keepGoingMulti' :: GhciMonad m => (String -> m ()) -> String -> m CmdExecOutcome
+keepGoingMulti' a str = a str >> return CmdSuccess
inMultiMode :: GhciMonad m => m Bool
inMultiMode = multiMode <$> getGHCiState
-keepGoingPaths :: ([FilePath] -> InputT GHCi ()) -> (String -> InputT GHCi Bool)
+keepGoingPaths :: ([FilePath] -> InputT GHCi ()) -> (String -> InputT GHCi CmdExecOutcome)
keepGoingPaths a str
= do case toArgsNoLoc str of
- Left err -> liftIO $ hPutStrLn stderr err >> return False
+ Left err -> liftIO $ hPutStrLn stderr err >> return CmdSuccess
Right args -> keepGoing' a args
defShortHelpText :: String
@@ -763,7 +764,7 @@ runGHCi paths maybe_exprs = do
$ topHandler e
-- this used to be topHandlerFastExit, see #2228
runInputTWithPrefs defaultPrefs defaultSettings $ do
- -- make `ghc -e` exit nonzero on invalid input, see #7962
+ -- make `ghc -e` exit nonzero on failure, see #7962, #9916, #17560, #18441
_ <- runCommands' hdle
(Just $ hdle (toException $ ExitFailure 1) >> return ())
(return Nothing)
@@ -1029,7 +1030,7 @@ queryQueue = do
return (Just c)
-- Reconfigurable pretty-printing Ticket #5461
-installInteractivePrint :: GHC.GhcMonad m => Maybe String -> Bool -> m ()
+installInteractivePrint :: GhciMonad m => Maybe String -> Bool -> m ()
installInteractivePrint Nothing _ = return ()
installInteractivePrint (Just ipFun) exprmode = do
ok <- trySuccess $ do
@@ -1072,6 +1073,7 @@ runCommands' eh sourceErrorHandler gCmd = mask $ \unmask -> do
-- Otherwise the result is Just b where b is True if the command succeeded;
-- this is relevant only to ghc -e, which will exit with status 1
-- if the command was unsuccessful. GHCi will continue in either case.
+-- TODO: replace Bool with CmdExecOutcome
runOneCommand :: (SomeException -> GHCi Bool) -> InputT GHCi (Maybe String)
-> InputT GHCi (Maybe Bool)
runOneCommand eh gCmd = do
@@ -1123,15 +1125,18 @@ runOneCommand eh gCmd = do
-- SDM (2007-11-07): is userError the one to use here?
collectError = userError "unterminated multiline command :{ .. :}"
+ cmdOutcome :: CmdExecOutcome -> Maybe Bool
+ cmdOutcome CleanExit = Nothing
+ cmdOutcome CmdSuccess = Just True
+ cmdOutcome CmdFailure = Just False
+
-- | Handle a line of input
doCommand :: String -> InputT GHCi CommandResult
-- command
doCommand stmt | stmt'@(':' : cmd) <- removeSpaces stmt = do
(stats, result) <- runWithStats (const Nothing) $ specialCommand cmd
- let processResult True = Nothing
- processResult False = Just True
- return $ CommandComplete stmt' (processResult <$> result) stats
+ return $ CommandComplete stmt' (cmdOutcome <$> result) stats
-- haskell
doCommand stmt = do
@@ -1409,7 +1414,7 @@ printTypeOfName n
data MaybeCommand = GotCommand Command | BadCommand | NoLastCommand
-- | Entry point for execution a ':<command>' input from user
-specialCommand :: String -> InputT GHCi Bool
+specialCommand :: String -> InputT GHCi CmdExecOutcome
specialCommand ('!':str) = lift $ shellEscape (dropWhile isSpace str)
specialCommand str = do
let (cmd,rest) = break isSpace str
@@ -1418,16 +1423,20 @@ specialCommand str = do
case maybe_cmd of
GotCommand cmd -> (cmdAction cmd) (dropWhile isSpace rest)
BadCommand ->
- do liftIO $ hPutStr stdout ("unknown command ':" ++ cmd ++ "'\n"
+ do liftIO $ hPutStr stderr ("unknown command ':" ++ cmd ++ "'\n"
++ htxt)
- return False
+ return CmdFailure
NoLastCommand ->
- do liftIO $ hPutStr stdout ("there is no last command to perform\n"
+ do liftIO $ hPutStr stderr ("there is no last command to perform\n"
++ htxt)
- return False
+ return CmdFailure
-shellEscape :: MonadIO m => String -> m Bool
-shellEscape str = liftIO (system str >> return False)
+shellEscape :: MonadIO m => String -> m CmdExecOutcome
+shellEscape str = liftIO $ do
+ exitCode <- system str
+ case exitCode of
+ ExitSuccess -> return CmdSuccess
+ ExitFailure _ -> return CmdFailure
lookupCommand :: GhciMonad m => String -> m (MaybeCommand)
lookupCommand "" = do
@@ -1662,15 +1671,15 @@ changeDirectory dir = do
liftIO $ evalIO interp fhv
_ -> pure ()
-trySuccess :: GHC.GhcMonad m => m SuccessFlag -> m SuccessFlag
+trySuccess :: GhciMonad m => m SuccessFlag -> m SuccessFlag
trySuccess act =
- handleSourceError (\e -> do GHC.printException e
+ handleSourceError (\e -> do printErrAndMaybeExit e -- immediately exit fith failure if in ghc -e
return Failed) $ do
act
-trySuccessWithRes :: (Monoid a, GHC.GhcMonad m) => m (SuccessFlag, a) -> m (SuccessFlag, a)
+trySuccessWithRes :: (Monoid a, GhciMonad m) => m (SuccessFlag, a) -> m (SuccessFlag, a)
trySuccessWithRes act =
- handleSourceError (\e -> do GHC.printException e
+ handleSourceError (\e -> do printErrAndMaybeExit e -- immediately exit fith failure if in ghc -e
return (Failed, mempty))
act
@@ -1739,10 +1748,12 @@ chooseEditFile =
-- :def
defineMacro :: GhciMonad m => Bool{-overwrite-} -> String -> m ()
-defineMacro _ (':':_) = liftIO $ putStrLn
- "macro name cannot start with a colon"
-defineMacro _ ('!':_) = liftIO $ putStrLn
- "macro name cannot start with an exclamation mark"
+defineMacro _ (':':_) = (liftIO $ hPutStrLn stderr
+ "macro name cannot start with a colon")
+ >> failIfExprEvalMode
+defineMacro _ ('!':_) = (liftIO $ hPutStrLn stderr
+ "macro name cannot start with an exclamation mark")
+ >> failIfExprEvalMode
-- little code duplication allows to grep error msg
defineMacro overwrite s = do
let (macro_name, definition) = break isSpace s
@@ -1765,7 +1776,7 @@ defineMacro overwrite s = do
unless overwrite check_newname
-- compile the expression
- handleSourceError GHC.printException $ do
+ handleSourceError printErrAndMaybeExit $ do
step <- getGhciStepIO
expr <- GHC.parseExpr definition
-- > ghciStepIO . definition :: String -> IO String
@@ -1795,12 +1806,12 @@ runMacro
:: GhciMonad m
=> GHC.ForeignHValue -- String -> IO String
-> String
- -> m Bool
+ -> m CmdExecOutcome
runMacro fun s = do
interp <- hscInterp <$> GHC.getSession
str <- liftIO $ evalStringToIOString interp fun s
enqueueCommands (lines str)
- return False
+ return CmdSuccess
-----------------------------------------------------------------------------
@@ -1824,7 +1835,7 @@ undefineMacro str = mapM_ undef (words str)
-- :cmd
cmdCmd :: GhciMonad m => String -> m ()
-cmdCmd str = handleSourceError GHC.printException $ do
+cmdCmd str = handleSourceError printErrAndMaybeExit $ do
step <- getGhciStepIO
expr <- GHC.parseExpr str
-- > ghciStepIO str :: IO String
@@ -1854,7 +1865,7 @@ getGhciStepIO = do
checkModule :: GhciMonad m => String -> m ()
checkModule m = do
let modl = GHC.mkModuleName m
- ok <- handleSourceError (\e -> GHC.printException e >> return False) $ do
+ ok <- handleSourceError (\e -> printErrAndMaybeExit e >> return False) $ do
r <- GHC.typecheckModule =<< GHC.parseModule =<< GHC.getModSummary modl
dflags <- getDynFlags
liftIO $ putStrLn $ showSDoc dflags $
@@ -2048,11 +2059,11 @@ addModule files = do
_ <- doLoadAndCollectInfo False LoadAllTargets
return ()
where
- checkTarget :: GHC.GhcMonad m => Target -> m Bool
+ checkTarget :: GhciMonad m => Target -> m Bool
checkTarget Target { targetId = TargetModule m } = checkTargetModule m
- checkTarget Target { targetId = TargetFile f _ } = liftIO $ checkTargetFile f
+ checkTarget Target { targetId = TargetFile f _ } = checkTargetFile f
- checkTargetModule :: GHC.GhcMonad m => ModuleName -> m Bool
+ checkTargetModule :: GhciMonad m => ModuleName -> m Bool
checkTargetModule m = do
hsc_env <- GHC.getSession
let home_unit = hsc_home_unit hsc_env
@@ -2060,13 +2071,15 @@ addModule files = do
Finder.findImportedModule hsc_env m (ThisPkg (homeUnitId home_unit))
case result of
Found _ _ -> return True
- _ -> (liftIO $ putStrLn $
- "Module " ++ moduleNameString m ++ " not found") >> return False
+ _ -> do liftIO $ hPutStrLn stderr ("Module " ++ moduleNameString m ++ " not found")
+ failIfExprEvalMode
+ return False
- checkTargetFile :: String -> IO Bool
+ checkTargetFile :: GhciMonad m => String -> m Bool
checkTargetFile f = do
- exists <- (doesFileExist f) :: IO Bool
- unless exists $ putStrLn $ "File " ++ f ++ " not found"
+ exists <- liftIO (doesFileExist f)
+ unless exists $ liftIO $ hPutStrLn stderr $ "File " ++ f ++ " not found"
+ failIfExprEvalMode
return exists
-- | @:unadd@ command
@@ -2083,10 +2096,11 @@ reloadModule :: GhciMonad m => String -> m ()
reloadModule m = do
session <- GHC.getSession
let home_unit = homeUnitId (hsc_home_unit session)
- void $ doLoadAndCollectInfo True (loadTargets home_unit)
+ ok <- doLoadAndCollectInfo True (loadTargets home_unit)
+ when (failed ok) failIfExprEvalMode
where
loadTargets hu | null m = LoadAllTargets
- | otherwise = LoadUpTo (mkModule hu (GHC.mkModuleName m))
+ | otherwise = LoadUpTo (mkModule hu (GHC.mkModuleName m))
reloadModuleDefer :: GhciMonad m => String -> m ()
reloadModuleDefer = wrapDeferTypeErrors . reloadModule
@@ -2268,16 +2282,18 @@ modulesLoadedMsg ok mods = do
-- Fix #9887
-- | Run an 'ExceptT' wrapped 'GhcMonad' while handling source errors
--- and printing 'throwE' strings to 'stderr'
-runExceptGhcMonad :: GHC.GhcMonad m => ExceptT SDoc m () -> m ()
-runExceptGhcMonad act = handleSourceError GHC.printException $
- either handleErr pure =<<
- runExceptT act
+-- and printing 'throwE' strings to 'stderr'. If in expression
+-- evaluation mode - throw GhcException and exit.
+runExceptGhciMonad :: GhciMonad m => ExceptT SDoc m () -> m ()
+runExceptGhciMonad act = handleSourceError GHC.printException $
+ either handleErr pure =<<
+ runExceptT act
where
handleErr sdoc = do
dflags <- getDynFlags
unit_state <- hsc_units <$> GHC.getSession
liftIO . hPutStrLn stderr . showSDocForUser dflags unit_state alwaysQualify $ sdoc
+ failIfExprEvalMode
-- | Inverse of 'runExceptT' for \"pure\" computations
-- (c.f. 'except' for 'Except')
@@ -2287,8 +2303,8 @@ exceptT = ExceptT . pure
-----------------------------------------------------------------------------
-- | @:type@ command. See also Note [TcRnExprMode] in GHC.Tc.Module.
-typeOfExpr :: GHC.GhcMonad m => String -> m ()
-typeOfExpr str = handleSourceError GHC.printException $
+typeOfExpr :: GhciMonad m => String -> m ()
+typeOfExpr str = handleSourceError printErrAndMaybeExit $
case break isSpace str of
("+v", _) -> printForUser (text "`:type +v' has gone; use `:type' instead")
("+d", rest) -> do_it GHC.TM_Default (dropWhile isSpace rest)
@@ -2303,7 +2319,7 @@ typeOfExpr str = handleSourceError GHC.printException $
-- | @:type-at@ command
typeAtCmd :: GhciMonad m => String -> m ()
-typeAtCmd str = runExceptGhcMonad $ do
+typeAtCmd str = runExceptGhciMonad $ do
(span',sample) <- exceptT $ parseSpanArg str
infos <- lift $ mod_infos <$> getGHCiState
(info, ty) <- findType infos span' sample
@@ -2314,7 +2330,7 @@ typeAtCmd str = runExceptGhcMonad $ do
-- | @:uses@ command
usesCmd :: GhciMonad m => String -> m ()
-usesCmd str = runExceptGhcMonad $ do
+usesCmd str = runExceptGhciMonad $ do
(span',sample) <- exceptT $ parseSpanArg str
infos <- lift $ mod_infos <$> getGHCiState
uses <- findNameUses infos span' sample
@@ -2324,7 +2340,7 @@ usesCmd str = runExceptGhcMonad $ do
-- | @:loc-at@ command
locAtCmd :: GhciMonad m => String -> m ()
-locAtCmd str = runExceptGhcMonad $ do
+locAtCmd str = runExceptGhciMonad $ do
(span',sample) <- exceptT $ parseSpanArg str
infos <- lift $ mod_infos <$> getGHCiState
(_,_,sp) <- findLoc infos span' sample
@@ -2334,7 +2350,7 @@ locAtCmd str = runExceptGhcMonad $ do
-- | @:all-types@ command
allTypesCmd :: GhciMonad m => String -> m ()
-allTypesCmd _ = runExceptGhcMonad $ do
+allTypesCmd _ = runExceptGhciMonad $ do
infos <- lift $ mod_infos <$> getGHCiState
forM_ (M.elems infos) $ \mi ->
forM_ (modinfoSpans mi) (lift . printSpan)
@@ -2427,8 +2443,8 @@ showRealSrcSpan spn = concat [ fp, ":(", show sl, ",", show sc
-----------------------------------------------------------------------------
-- | @:kind@ command
-kindOfType :: GHC.GhcMonad m => Bool -> String -> m ()
-kindOfType norm str = handleSourceError GHC.printException $ do
+kindOfType :: GhciMonad m => Bool -> String -> m ()
+kindOfType norm str = handleSourceError printErrAndMaybeExit $ do
(ty, kind) <- GHC.typeKind norm str
printForUser $ vcat [ text str <+> dcolon <+> pprSigmaType kind
, ppWhen norm $ equals <+> pprSigmaType ty ]
@@ -2436,8 +2452,8 @@ kindOfType norm str = handleSourceError GHC.printException $ do
-----------------------------------------------------------------------------
-- :quit
-quit :: Monad m => String -> m Bool
-quit _ = return True
+quit :: Monad m => String -> m CmdExecOutcome
+quit _ = return CleanExit
-----------------------------------------------------------------------------
@@ -4497,6 +4513,16 @@ showException se =
where
putException = hPutStrLn stderr
+failIfExprEvalMode :: GhciMonad m => m ()
+failIfExprEvalMode = do
+ s <- getGHCiState
+ when (ghc_e s) $
+ liftIO (exitWith (ExitFailure 1))
+
+-- | When in expression evaluation mode (ghc -e), we want to exit immediately.
+-- Otherwis, just print out the message.
+printErrAndMaybeExit :: (GhciMonad m, MonadIO m, HasLogger m) => SourceError -> m ()
+printErrAndMaybeExit = (>> failIfExprEvalMode) . GHC.printException
-----------------------------------------------------------------------------
-- recursive exception handlers
diff --git a/ghc/GHCi/UI/Monad.hs b/ghc/GHCi/UI/Monad.hs
index 3aead3e91e..aede0a9dc1 100644
--- a/ghc/GHCi/UI/Monad.hs
+++ b/ghc/GHCi/UI/Monad.hs
@@ -15,6 +15,7 @@ module GHCi.UI.Monad (
GHCiState(..), GhciMonad(..),
GHCiOption(..), isOptionSet, setOption, unsetOption,
Command(..), CommandResult(..), cmdSuccess,
+ CmdExecOutcome(..),
LocalConfigBehaviour(..),
PromptFunction,
BreakLocation(..),
@@ -173,8 +174,8 @@ data Command
= Command
{ cmdName :: String
-- ^ Name of GHCi command (e.g. "exit")
- , cmdAction :: String -> InputT GHCi Bool
- -- ^ The 'Bool' value denotes whether to exit GHCi
+ , cmdAction :: String -> InputT GHCi CmdExecOutcome
+ -- ^ The 'CmdExecOutcome' value denotes whether to exit GHCi cleanly or error out
, cmdHidden :: Bool
-- ^ Commands which are excluded from default completion
-- and @:help@ summary. This is usually set for commands not
@@ -183,6 +184,20 @@ data Command
-- ^ 'CompletionFunc' for arguments
}
+-- | Used to denote GHCi command execution result. Specifically, used to
+-- distinguish between two ghci execution modes - "REPL" and "Expression
+-- evaluation mode (ghc -e)". When in "REPL" mode, we don't want to exit
+-- GHCi session when error occurs, (which is when we use "CmdSuccess").
+-- Otherwise, when in expression evaluation mode, all command failures
+-- should lead to GHCi session termination (with ExitFailure 1) which is
+-- when "CmdFailure" is used(this is useful when executing scripts).
+-- "CleanExit" is used to signal end of GHCi session (for example, when
+-- ":quit" command is called).
+data CmdExecOutcome
+ = CleanExit
+ | CmdSuccess
+ | CmdFailure
+
data CommandResult
= CommandComplete
{ cmdInput :: String
diff --git a/testsuite/tests/driver/T16167.stderr b/testsuite/tests/driver/T16167.stderr
new file mode 100644
index 0000000000..59eac9cfdb
--- /dev/null
+++ b/testsuite/tests/driver/T16167.stderr
@@ -0,0 +1 @@
+*** Exception: ExitFailure 1
diff --git a/testsuite/tests/ghc-e/should_fail/Makefile b/testsuite/tests/ghc-e/should_fail/Makefile
index 827dfc776a..627d85fe43 100644
--- a/testsuite/tests/ghc-e/should_fail/Makefile
+++ b/testsuite/tests/ghc-e/should_fail/Makefile
@@ -3,22 +3,76 @@ include $(TOP)/mk/boilerplate.mk
include $(TOP)/mk/test.mk
T7962:
- -'$(TEST_HC)' $(TEST_HC_OPTS) -ignore-dot-ghci -e "return ("
+ -'$(TEST_HC)' $(TEST_HC_OPTS) -ignore-dot-ghci -e "return (" || echo $$? >&2
T9905fail1:
- -'$(TEST_HC)' $(TEST_HC_OPTS) -ignore-dot-ghci -e "import This.Module.Does.Not.Exist"
+ -'$(TEST_HC)' $(TEST_HC_OPTS) -ignore-dot-ghci -e "import This.Module.Does.Not.Exist" || echo $$? >&2
T9905fail2:
- -'$(TEST_HC)' $(TEST_HC_OPTS) -ignore-dot-ghci -e "import Data.List (bogusIdentifier)"
+ -'$(TEST_HC)' $(TEST_HC_OPTS) -ignore-dot-ghci -e "import Data.List (bogusIdentifier)" || echo $$? >&2
T9905fail3:
- -'$(TEST_HC)' $(TEST_HC_OPTS) -ignore-dot-ghci -e "import Prelude (+)" # syntax error
+ -'$(TEST_HC)' $(TEST_HC_OPTS) -ignore-dot-ghci -e "import Prelude (+)" || echo $$? >&2 # syntax error
ghc-e-fail1:
- -'$(TEST_HC)' $(TEST_HC_OPTS) -ignore-dot-ghci -e "class ["
+ -'$(TEST_HC)' $(TEST_HC_OPTS) -ignore-dot-ghci -e "class [" || echo $$? >&2
ghc-e-fail2:
- -'$(TEST_HC)' $(TEST_HC_OPTS) -ignore-dot-ghci -e "type A = A"
+ -'$(TEST_HC)' $(TEST_HC_OPTS) -ignore-dot-ghci -e "type A = A" || echo $$? >&2
T9930fail:
-'$(TEST_HC)' $(TEST_HC_OPTS) -v0 -x hs T9930
+
+T18441fail0:
+ -'$(TEST_HC)' $(TEST_HC_OPTS) -ignore-dot-ghci -e ":" || echo $$? >&2
+
+T18441fail1:
+ -'$(TEST_HC)' $(TEST_HC_OPTS) -ignore-dot-ghci -e ":abcde" || echo $$? >&2
+
+T18441fail2:
+ -'$(TEST_HC)' $(TEST_HC_OPTS) -ignore-dot-ghci -e ":set -Xabcde" || echo $$? >&2 # unrecognized flag
+
+T18441fail4:
+ -'$(TEST_HC)' $(TEST_HC_OPTS) -ignore-dot-ghci -e ":load Abcde" || echo $$? >&2 # no module
+
+T18441fail5:
+ -'$(TEST_HC)' $(TEST_HC_OPTS) -ignore-dot-ghci -e ":reload Abcde" || echo $$? >&2 # no module
+
+T18441fail6:
+ -'$(TEST_HC)' $(TEST_HC_OPTS) -ignore-dot-ghci -e ":add Abcde" || echo $$? >&2 # no module
+
+T18441fail7:
+ -'$(TEST_HC)' $(TEST_HC_OPTS) -ignore-dot-ghci -e ":script Abcde" || echo $$? >&2 # no script
+
+T18441fail8:
+ -'$(TEST_HC)' $(TEST_HC_OPTS) -ignore-dot-ghci -e ":script Abc def" || echo $$? >&2 # bad script input
+
+T18441fail9:
+ -'$(TEST_HC)' $(TEST_HC_OPTS) -ignore-dot-ghci -e ":def abc" || echo $$? >&2 # macro not an expr
+
+T18441fail10:
+ -'$(TEST_HC)' $(TEST_HC_OPTS) -ignore-dot-ghci -e ":def :abc" || echo $$? >&2 # bad macro
+
+T18441fail11:
+ -'$(TEST_HC)' $(TEST_HC_OPTS) -ignore-dot-ghci -e ":def !abc" || echo $$? >&2 # bad macro
+
+T18441fail12:
+ -'$(TEST_HC)' $(TEST_HC_OPTS) -ignore-dot-ghci -e ":cmd abc" || echo $$? >&2 # cmd compilation failure
+
+T18441fail13:
+ -'$(TEST_HC)' $(TEST_HC_OPTS) -ignore-dot-ghci -e ":t" || echo $$? >&2
+
+T18441fail14:
+ -'$(TEST_HC)' $(TEST_HC_OPTS) -ignore-dot-ghci -e ":type-at H.hs 1 1 1 1 f" || echo $$? >&2
+
+T18441fail15:
+ -'$(TEST_HC)' $(TEST_HC_OPTS) -ignore-dot-ghci -e ":loc-at H.hs 1 1 1 1 f" || echo $$? >&2
+
+T18441fail16:
+ -'$(TEST_HC)' $(TEST_HC_OPTS) -ignore-dot-ghci -e ":k" || echo $$? >&2
+
+T18441fail17:
+ -'$(TEST_HC)' $(TEST_HC_OPTS) -ignore-dot-ghci -e ":run a" || echo $$? >&2
+
+T18441fail18:
+ -'$(TEST_HC)' $(TEST_HC_OPTS) -ignore-dot-ghci -e ":main" || echo $$? >&2
diff --git a/testsuite/tests/ghc-e/should_fail/T18441fail0.stderr b/testsuite/tests/ghc-e/should_fail/T18441fail0.stderr
new file mode 100644
index 0000000000..1918b09df9
--- /dev/null
+++ b/testsuite/tests/ghc-e/should_fail/T18441fail0.stderr
@@ -0,0 +1,3 @@
+there is no last command to perform
+use :? for help.
+1
diff --git a/testsuite/tests/ghc-e/should_fail/T18441fail1.stderr b/testsuite/tests/ghc-e/should_fail/T18441fail1.stderr
new file mode 100644
index 0000000000..10d382d050
--- /dev/null
+++ b/testsuite/tests/ghc-e/should_fail/T18441fail1.stderr
@@ -0,0 +1,3 @@
+unknown command ':abcde'
+use :? for help.
+1
diff --git a/testsuite/tests/ghc-e/should_fail/T18441fail10.stderr b/testsuite/tests/ghc-e/should_fail/T18441fail10.stderr
new file mode 100644
index 0000000000..2e71b287e3
--- /dev/null
+++ b/testsuite/tests/ghc-e/should_fail/T18441fail10.stderr
@@ -0,0 +1,2 @@
+macro name cannot start with a colon
+1
diff --git a/testsuite/tests/ghc-e/should_fail/T18441fail11.stderr b/testsuite/tests/ghc-e/should_fail/T18441fail11.stderr
new file mode 100644
index 0000000000..298e204c62
--- /dev/null
+++ b/testsuite/tests/ghc-e/should_fail/T18441fail11.stderr
@@ -0,0 +1,2 @@
+macro name cannot start with an exclamation mark
+1
diff --git a/testsuite/tests/ghc-e/should_fail/T18441fail12.stderr b/testsuite/tests/ghc-e/should_fail/T18441fail12.stderr
new file mode 100644
index 0000000000..38ea987f38
--- /dev/null
+++ b/testsuite/tests/ghc-e/should_fail/T18441fail12.stderr
@@ -0,0 +1,5 @@
+
+<interactive>:1:1: error:
+ Variable not in scope: abc :: IO String
+ Suggested fix: Perhaps use ‘abs’ (imported from Prelude)
+1
diff --git a/testsuite/tests/ghc-e/should_fail/T18441fail13.stderr b/testsuite/tests/ghc-e/should_fail/T18441fail13.stderr
new file mode 100644
index 0000000000..35f740c0a9
--- /dev/null
+++ b/testsuite/tests/ghc-e/should_fail/T18441fail13.stderr
@@ -0,0 +1,3 @@
+
+<no location info>: error: not an expression: ‘’
+1
diff --git a/testsuite/tests/ghc-e/should_fail/T18441fail14.stderr b/testsuite/tests/ghc-e/should_fail/T18441fail14.stderr
new file mode 100644
index 0000000000..c1515dae77
--- /dev/null
+++ b/testsuite/tests/ghc-e/should_fail/T18441fail14.stderr
@@ -0,0 +1,2 @@
+Couldn't guess that module name. Does it exist?
+1
diff --git a/testsuite/tests/ghc-e/should_fail/T18441fail15.stderr b/testsuite/tests/ghc-e/should_fail/T18441fail15.stderr
new file mode 100644
index 0000000000..c1515dae77
--- /dev/null
+++ b/testsuite/tests/ghc-e/should_fail/T18441fail15.stderr
@@ -0,0 +1,2 @@
+Couldn't guess that module name. Does it exist?
+1
diff --git a/testsuite/tests/ghc-e/should_fail/T18441fail16.stderr b/testsuite/tests/ghc-e/should_fail/T18441fail16.stderr
new file mode 100644
index 0000000000..2194e5f81b
--- /dev/null
+++ b/testsuite/tests/ghc-e/should_fail/T18441fail16.stderr
@@ -0,0 +1,4 @@
+
+<interactive>:1:1: error:
+ parse error (possibly incorrect indentation or mismatched brackets)
+1
diff --git a/testsuite/tests/ghc-e/should_fail/T18441fail17.stderr b/testsuite/tests/ghc-e/should_fail/T18441fail17.stderr
new file mode 100644
index 0000000000..d0749cc833
--- /dev/null
+++ b/testsuite/tests/ghc-e/should_fail/T18441fail17.stderr
@@ -0,0 +1,3 @@
+
+<interactive>:0:33: error: Variable not in scope: a :: IO a
+1
diff --git a/testsuite/tests/ghc-e/should_fail/T18441fail18.stderr b/testsuite/tests/ghc-e/should_fail/T18441fail18.stderr
new file mode 100644
index 0000000000..9981715a36
--- /dev/null
+++ b/testsuite/tests/ghc-e/should_fail/T18441fail18.stderr
@@ -0,0 +1,5 @@
+
+<interactive>:0:53: error:
+ Variable not in scope: main :: IO a0
+ Suggested fix: Perhaps use ‘min’ (imported from Prelude)
+1
diff --git a/testsuite/tests/ghc-e/should_fail/T18441fail2.stderr b/testsuite/tests/ghc-e/should_fail/T18441fail2.stderr
new file mode 100644
index 0000000000..849747f5eb
--- /dev/null
+++ b/testsuite/tests/ghc-e/should_fail/T18441fail2.stderr
@@ -0,0 +1,2 @@
+<interactive>: Some flags have not been recognized: -Xabcde
+1
diff --git a/testsuite/tests/ghc-e/should_fail/T18441fail4.stderr b/testsuite/tests/ghc-e/should_fail/T18441fail4.stderr
new file mode 100644
index 0000000000..91e20fe8f1
--- /dev/null
+++ b/testsuite/tests/ghc-e/should_fail/T18441fail4.stderr
@@ -0,0 +1,3 @@
+
+<no location info>: error: module ‘Abcde’ cannot be found locally
+1
diff --git a/testsuite/tests/ghc-e/should_fail/T18441fail5.stderr b/testsuite/tests/ghc-e/should_fail/T18441fail5.stderr
new file mode 100644
index 0000000000..05578a2262
--- /dev/null
+++ b/testsuite/tests/ghc-e/should_fail/T18441fail5.stderr
@@ -0,0 +1,3 @@
+
+<no location info>: error: no such module: ‘main:Abcde’
+1
diff --git a/testsuite/tests/ghc-e/should_fail/T18441fail6.stderr b/testsuite/tests/ghc-e/should_fail/T18441fail6.stderr
new file mode 100644
index 0000000000..6979f8d919
--- /dev/null
+++ b/testsuite/tests/ghc-e/should_fail/T18441fail6.stderr
@@ -0,0 +1,2 @@
+Module Abcde not found
+1
diff --git a/testsuite/tests/ghc-e/should_fail/T18441fail7.stderr b/testsuite/tests/ghc-e/should_fail/T18441fail7.stderr
new file mode 100644
index 0000000000..aaf284760a
--- /dev/null
+++ b/testsuite/tests/ghc-e/should_fail/T18441fail7.stderr
@@ -0,0 +1,2 @@
+<interactive>: IO error: "Abcde" does not exist
+1
diff --git a/testsuite/tests/ghc-e/should_fail/T18441fail8.stderr b/testsuite/tests/ghc-e/should_fail/T18441fail8.stderr
new file mode 100644
index 0000000000..80b40ae5f5
--- /dev/null
+++ b/testsuite/tests/ghc-e/should_fail/T18441fail8.stderr
@@ -0,0 +1,2 @@
+<interactive>: syntax: :script <filename>
+1
diff --git a/testsuite/tests/ghc-e/should_fail/T18441fail9.stderr b/testsuite/tests/ghc-e/should_fail/T18441fail9.stderr
new file mode 100644
index 0000000000..35f740c0a9
--- /dev/null
+++ b/testsuite/tests/ghc-e/should_fail/T18441fail9.stderr
@@ -0,0 +1,3 @@
+
+<no location info>: error: not an expression: ‘’
+1
diff --git a/testsuite/tests/ghc-e/should_fail/T7962.stderr b/testsuite/tests/ghc-e/should_fail/T7962.stderr
index b58aa89502..cf1fdb92be 100644
--- a/testsuite/tests/ghc-e/should_fail/T7962.stderr
+++ b/testsuite/tests/ghc-e/should_fail/T7962.stderr
@@ -1,3 +1,4 @@
<interactive>:0:9: error:
parse error (possibly incorrect indentation or mismatched brackets)
+1
diff --git a/testsuite/tests/ghc-e/should_fail/T9905fail1.stderr b/testsuite/tests/ghc-e/should_fail/T9905fail1.stderr
index 1f0fb05138..9d0d79c23e 100644
--- a/testsuite/tests/ghc-e/should_fail/T9905fail1.stderr
+++ b/testsuite/tests/ghc-e/should_fail/T9905fail1.stderr
@@ -2,3 +2,4 @@
<no location info>: error:
Could not find module ‘This.Module.Does.Not.Exist’
It is not a module in the current program, or in any known package.
+1
diff --git a/testsuite/tests/ghc-e/should_fail/T9905fail2.stderr b/testsuite/tests/ghc-e/should_fail/T9905fail2.stderr
index 9143eccae4..8be6c2aadb 100644
--- a/testsuite/tests/ghc-e/should_fail/T9905fail2.stderr
+++ b/testsuite/tests/ghc-e/should_fail/T9905fail2.stderr
@@ -1,3 +1,4 @@
<interactive>:0:19: error:
Module ‘Data.List’ does not export ‘bogusIdentifier’
+1
diff --git a/testsuite/tests/ghc-e/should_fail/T9905fail3.stderr b/testsuite/tests/ghc-e/should_fail/T9905fail3.stderr
index 85226ea2b4..de9de0b88f 100644
--- a/testsuite/tests/ghc-e/should_fail/T9905fail3.stderr
+++ b/testsuite/tests/ghc-e/should_fail/T9905fail3.stderr
@@ -1,2 +1,3 @@
<interactive>:0:17: error: parse error on input ‘+’
+1
diff --git a/testsuite/tests/ghc-e/should_fail/all.T b/testsuite/tests/ghc-e/should_fail/all.T
index 76f9afe0a8..7196bbe969 100644
--- a/testsuite/tests/ghc-e/should_fail/all.T
+++ b/testsuite/tests/ghc-e/should_fail/all.T
@@ -14,3 +14,43 @@ test('ghc-e-fail2', req_interp, makefile_test, ['ghc-e-fail2'])
# and no failure is induced.
test('T9930fail', [extra_files(['T9930']), when(opsys('mingw32'), skip)],
makefile_test, ['T9930fail'])
+
+test('T18441fail0', req_interp, makefile_test, ['T18441fail0'])
+
+test('T18441fail1', req_interp, makefile_test, ['T18441fail1'])
+
+test('T18441fail2', req_interp, makefile_test, ['T18441fail2'])
+
+test('T18441fail3', [ignore_stderr, exit_code(1)], run_command, ['{compiler} -e ":! abcde"'])
+
+test('T18441fail4', req_interp, makefile_test, ['T18441fail4'])
+
+test('T18441fail5', req_interp, makefile_test, ['T18441fail5'])
+
+test('T18441fail6', req_interp, makefile_test, ['T18441fail6'])
+
+test('T18441fail7', req_interp, makefile_test, ['T18441fail7'])
+
+test('T18441fail8', req_interp, makefile_test, ['T18441fail8'])
+
+test('T18441fail9', req_interp, makefile_test, ['T18441fail9'])
+
+test('T18441fail10', req_interp, makefile_test, ['T18441fail10'])
+
+test('T18441fail11', req_interp, makefile_test, ['T18441fail11'])
+
+test('T18441fail12', req_interp, makefile_test, ['T18441fail12'])
+
+test('T18441fail13', req_interp, makefile_test, ['T18441fail13'])
+
+test('T18441fail14', req_interp, makefile_test, ['T18441fail14'])
+
+test('T18441fail15', req_interp, makefile_test, ['T18441fail15'])
+
+test('T18441fail16', req_interp, makefile_test, ['T18441fail16'])
+
+test('T18441fail17', req_interp, makefile_test, ['T18441fail17'])
+
+test('T18441fail18', req_interp, makefile_test, ['T18441fail18'])
+
+test('T18441fail19', [ignore_stderr, exit_code(1)], run_command, ['{compiler} -e ":cd abcd"'])
diff --git a/testsuite/tests/ghc-e/should_fail/ghc-e-fail1.stderr b/testsuite/tests/ghc-e/should_fail/ghc-e-fail1.stderr
index cf75b40644..d1f2d18251 100644
--- a/testsuite/tests/ghc-e/should_fail/ghc-e-fail1.stderr
+++ b/testsuite/tests/ghc-e/should_fail/ghc-e-fail1.stderr
@@ -1,3 +1,4 @@
<interactive>:0:8: error:
parse error (possibly incorrect indentation or mismatched brackets)
+1
diff --git a/testsuite/tests/ghc-e/should_fail/ghc-e-fail2.stderr b/testsuite/tests/ghc-e/should_fail/ghc-e-fail2.stderr
index bcd0565d6a..858139c117 100644
--- a/testsuite/tests/ghc-e/should_fail/ghc-e-fail2.stderr
+++ b/testsuite/tests/ghc-e/should_fail/ghc-e-fail2.stderr
@@ -2,3 +2,4 @@
<interactive>:0:1: error:
Cycle in type synonym declarations:
<interactive>:0:1-10: type A = A
+1
diff --git a/testsuite/tests/ghci/scripts/T10508.stderr b/testsuite/tests/ghci/scripts/T10508.stderr
index 8cbcb2936d..89392b3ea8 100644
--- a/testsuite/tests/ghci/scripts/T10508.stderr
+++ b/testsuite/tests/ghci/scripts/T10508.stderr
@@ -8,3 +8,5 @@
In the first argument of ‘return’, namely ‘id’
In the expression: return id
In the second argument of ‘(.)’, namely ‘(\ _ -> return id)’
+unknown command ':macro'
+use :? for help.
diff --git a/testsuite/tests/ghci/scripts/T10508.stdout b/testsuite/tests/ghci/scripts/T10508.stdout
index c6c8d3a447..d2a5eee71e 100644
--- a/testsuite/tests/ghci/scripts/T10508.stdout
+++ b/testsuite/tests/ghci/scripts/T10508.stdout
@@ -2,5 +2,3 @@
1
2
0
-unknown command ':macro'
-use :? for help.
diff --git a/testsuite/tests/ghci/scripts/T14676.stderr b/testsuite/tests/ghci/scripts/T14676.stderr
new file mode 100644
index 0000000000..c99d0900d5
--- /dev/null
+++ b/testsuite/tests/ghci/scripts/T14676.stderr
@@ -0,0 +1,2 @@
+File Notfound.hs not found
+Module NotFound not found
diff --git a/testsuite/tests/ghci/scripts/T14676.stdout b/testsuite/tests/ghci/scripts/T14676.stdout
index c3e9fbd6b4..9c1e707676 100644
--- a/testsuite/tests/ghci/scripts/T14676.stdout
+++ b/testsuite/tests/ghci/scripts/T14676.stdout
@@ -1,3 +1 @@
-File Notfound.hs not found
-Module NotFound not found
prog002/A1.hs