Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
-
341223c0
by Rodrigo Mesquita at 2026-10-31T09:24:33-04:00
12 changed files:
- + changelog.d/ghc-api-interactive-ids
- compiler/GHC/Runtime/Context.hs
- compiler/GHC/Runtime/Debugger.hs
- compiler/GHC/Runtime/Eval.hs
- compiler/GHC/Runtime/Eval/Types.hs
- compiler/GHC/Runtime/Heap/Inspect.hs
- ghc/GHCi/UI.hs
- ghc/GHCi/UI/Monad.hs
- + testsuite/tests/ghci.debugger/scripts/RttiSharedTyVar.hs
- + testsuite/tests/ghci.debugger/scripts/RttiSharedTyVar.script
- + testsuite/tests/ghci.debugger/scripts/RttiSharedTyVar.stdout
- testsuite/tests/ghci.debugger/scripts/all.T
Changes:
| 1 | +section: ghc-lib
|
|
| 2 | +synopsis: The GHCi evaluation API now returns ``Id``\s and ``TyThing``\s rather than ``Name``\s
|
|
| 3 | +issues: #28052
|
|
| 4 | +mrs: !16883
|
|
| 5 | + |
|
| 6 | +description: {
|
|
| 7 | +The results of interactive evaluation are now returned directly, rather than as
|
|
| 8 | +``Name``\s that had to be looked up again in the interactive context:
|
|
| 9 | + |
|
| 10 | +- ``ExecComplete``'s ``execResult`` and ``ExecBreak``'s ``breakNames`` now hold ``[Id]``.
|
|
| 11 | +- ``runDecls``, ``runDeclsWithLocation`` and ``runParsedDecls`` now return ``[TyThing]`` rather than ``[Name]``.
|
|
| 12 | +- ``rttiEnvironment`` now returns a Subst with the inferred types.
|
|
| 13 | + |
|
| 14 | +The returned ``Id``\s carry the types refined by runtime type inference.
|
|
| 15 | +} |
| ... | ... | @@ -6,6 +6,8 @@ module GHC.Runtime.Context |
| 6 | 6 | , extendInteractiveContextWithIds
|
| 7 | 7 | , setInteractivePrintName
|
| 8 | 8 | , substInteractiveContext
|
| 9 | + , substInteractiveTyThing
|
|
| 10 | + , substInteractiveId
|
|
| 9 | 11 | , replaceImportEnv
|
| 10 | 12 | , icReaderEnv
|
| 11 | 13 | , icExtendGblRdrEnv
|
| ... | ... | @@ -496,15 +498,18 @@ icExtendGblRdrEnv drop_only_qualified env tythings |
| 496 | 498 | substInteractiveContext :: InteractiveContext -> Subst -> InteractiveContext
|
| 497 | 499 | substInteractiveContext ictxt@InteractiveContext{ ic_tythings = tts } subst
|
| 498 | 500 | | isEmptyTCvSubst subst = ictxt
|
| 499 | - | otherwise = ictxt { ic_tythings = map subst_ty tts }
|
|
| 500 | - where
|
|
| 501 | - subst_ty (AnId id)
|
|
| 502 | - = AnId $ updateIdTypeAndMult (substTyAddInScope subst) id
|
|
| 503 | - -- Variables in the interactive context *can* mention free type variables
|
|
| 504 | - -- because of the runtime debugger. Otherwise you'd expect all
|
|
| 505 | - -- variables bound in the interactive context to be closed.
|
|
| 506 | - subst_ty tt
|
|
| 507 | - = tt
|
|
| 501 | + | otherwise = ictxt { ic_tythings = map (substInteractiveTyThing subst) tts }
|
|
| 502 | + |
|
| 503 | +substInteractiveTyThing :: Subst -> TyThing -> TyThing
|
|
| 504 | +substInteractiveTyThing subst (AnId id) = AnId $ substInteractiveId subst id
|
|
| 505 | +substInteractiveTyThing _ tt = tt
|
|
| 506 | + |
|
| 507 | +substInteractiveId :: Subst -> Id -> Id
|
|
| 508 | +substInteractiveId subst id =
|
|
| 509 | + -- Variables in the interactive context *can* mention free type variables
|
|
| 510 | + -- because of the runtime debugger. Otherwise you'd expect all
|
|
| 511 | + -- variables bound in the interactive context to be closed.
|
|
| 512 | + updateIdTypeAndMult (substTyAddInScope subst) id
|
|
| 508 | 513 | |
| 509 | 514 | instance Outputable InteractiveImport where
|
| 510 | 515 | ppr (IIModule m) = char '*' <> ppr m
|
| ... | ... | @@ -121,8 +121,7 @@ pprintClosureCommand bindThings force str = do |
| 121 | 121 | -- Then, we extract a substitution,
|
| 122 | 122 | -- mapping the old tyvars to the reconstructed types.
|
| 123 | 123 | let reconstructed_type = termType term
|
| 124 | - hsc_env <- getSession
|
|
| 125 | - case (improveRTTIType hsc_env id_ty' reconstructed_type) of
|
|
| 124 | + case improveRTTIType id_ty' reconstructed_type of
|
|
| 126 | 125 | Nothing -> return (subst, term')
|
| 127 | 126 | Just subst' -> do { logger <- getLogger
|
| 128 | 127 | ; liftIO $
|
| ... | ... | @@ -131,7 +131,7 @@ import GHC.ByteCode.Breakpoints |
| 131 | 131 | import Control.Monad
|
| 132 | 132 | import Data.Dynamic
|
| 133 | 133 | import Data.IntMap (IntMap)
|
| 134 | -import Data.List (find,intercalate)
|
|
| 134 | +import Data.List (intercalate)
|
|
| 135 | 135 | import Data.List.NonEmpty (NonEmpty)
|
| 136 | 136 | import Unsafe.Coerce ( unsafeCoerce )
|
| 137 | 137 | import qualified GHC.Unit.Home.Graph as HUG
|
| ... | ... | @@ -241,12 +241,12 @@ execStmt' stmt stmt_text ExecOptions{..} = do |
| 241 | 241 | handleRunStatus execSingleStep stmt_text bindings ids
|
| 242 | 242 | status (emptyHistory size)
|
| 243 | 243 | |
| 244 | -runDecls :: GhcMonad m => String -> m [Name]
|
|
| 244 | +runDecls :: GhcMonad m => String -> m [TyThing]
|
|
| 245 | 245 | runDecls = runDeclsWithLocation "<interactive>" 1
|
| 246 | 246 | |
| 247 | 247 | -- | Run some declarations and return any user-visible names that were brought
|
| 248 | 248 | -- into scope.
|
| 249 | -runDeclsWithLocation :: GhcMonad m => String -> Int -> String -> m [Name]
|
|
| 249 | +runDeclsWithLocation :: GhcMonad m => String -> Int -> String -> m [TyThing]
|
|
| 250 | 250 | runDeclsWithLocation source line_num input = do
|
| 251 | 251 | hsc_env <- getSession
|
| 252 | 252 | decls <- liftIO (hscParseDeclsWithLocation hsc_env source line_num input)
|
| ... | ... | @@ -255,18 +255,18 @@ runDeclsWithLocation source line_num input = do |
| 255 | 255 | -- | Like `runDeclsWithLocation`, but takes parsed declarations as argument.
|
| 256 | 256 | -- Useful when doing preprocessing on the AST before execution, e.g. in GHCi
|
| 257 | 257 | -- (see GHCi.UI.runStmt).
|
| 258 | -runParsedDecls :: GhcMonad m => [LHsDecl GhcPs] -> m [Name]
|
|
| 258 | +runParsedDecls :: GhcMonad m => [LHsDecl GhcPs] -> m [TyThing]
|
|
| 259 | 259 | runParsedDecls decls = do
|
| 260 | - hsc_env <- getSession
|
|
| 261 | - (tyThings, ic) <- liftIO (hscParsedDecls hsc_env decls)
|
|
| 262 | - |
|
| 260 | + hsc_env <- getSession
|
|
| 261 | + (tyThings, ic) <- liftIO $ hscParsedDecls hsc_env decls
|
|
| 263 | 262 | setSession $ hsc_env { hsc_IC = ic }
|
| 264 | 263 | hsc_env <- getSession
|
| 265 | - hsc_env' <- liftIO $ rttiEnvironment hsc_env
|
|
| 264 | + (hsc_env', subst) <- liftIO $ rttiEnvironment hsc_env
|
|
| 266 | 265 | setSession hsc_env'
|
| 267 | - return $ filter (not . isDerivedOccName . nameOccName)
|
|
| 266 | + return $ map (substInteractiveTyThing subst)
|
|
| 267 | + $ filter (not . isDerivedOccName . nameOccName . getName)
|
|
| 268 | 268 | -- For this filter, see Note [What to show to users]
|
| 269 | - $ map getName tyThings
|
|
| 269 | + $ tyThings
|
|
| 270 | 270 | |
| 271 | 271 | {- Note [What to show to users]
|
| 272 | 272 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ... | ... | @@ -310,9 +310,10 @@ handleRunStatus step expr bindings final_ids status history0 = do |
| 310 | 310 | final_ic = extendInteractiveContextWithIds (hsc_IC hsc_env) final_ids
|
| 311 | 311 | final_names = map getName final_ids
|
| 312 | 312 | liftIO $ Loader.extendLoadedEnv interp modifyHomePackageBytecodeState (zip final_names hvals)
|
| 313 | - hsc_env' <- liftIO $ rttiEnvironment hsc_env{hsc_IC=final_ic}
|
|
| 313 | + (hsc_env', subst) <- liftIO $ rttiEnvironment hsc_env{hsc_IC=final_ic}
|
|
| 314 | + let improved_final_ids = map (substInteractiveId subst) final_ids
|
|
| 314 | 315 | setSession hsc_env'
|
| 315 | - return (ExecComplete (Right final_names) allocs)
|
|
| 316 | + return (ExecComplete (Right improved_final_ids) allocs)
|
|
| 316 | 317 | |
| 317 | 318 | -- Completed with an exception
|
| 318 | 319 | EvalComplete alloc (EvalException e) ->
|
| ... | ... | @@ -323,7 +324,7 @@ handleRunStatus step expr bindings final_ids status history0 = do |
| 323 | 324 | resume_ctxt_fhv <- liftIO $ mkFinalizedHValue interp resume_ctxt
|
| 324 | 325 | apStack_fhv <- liftIO $ mkFinalizedHValue interp apStack_ref
|
| 325 | 326 | let span = mkGeneralSrcSpan (fsLit "<unknown>")
|
| 326 | - (hsc_env1, names) <- liftIO $
|
|
| 327 | + (hsc_env1, break_ids) <- liftIO $
|
|
| 327 | 328 | bindLocalsAtBreakpoint hsc_env apStack_fhv span Nothing
|
| 328 | 329 | let
|
| 329 | 330 | resume = Resume
|
| ... | ... | @@ -342,7 +343,7 @@ handleRunStatus step expr bindings final_ids status history0 = do |
| 342 | 343 | hsc_env2 = pushResume hsc_env1 resume
|
| 343 | 344 | |
| 344 | 345 | setSession hsc_env2
|
| 345 | - return (ExecBreak names Nothing)
|
|
| 346 | + return (ExecBreak break_ids Nothing)
|
|
| 346 | 347 | |
| 347 | 348 | -- EvalBreak (Just ...) case: the interpreter stopped at a breakpoint
|
| 348 | 349 | --
|
| ... | ... | @@ -370,7 +371,7 @@ handleRunStatus step expr bindings final_ids status history0 = do |
| 370 | 371 | -- This function only returns control to ghci with 'ExecBreak' when it is really meant to break.
|
| 371 | 372 | -- Specifically, for :steplocal or :stepmodule, don't return control
|
| 372 | 373 | -- and simply resume execution from here until we hit a breakpoint we do want to stop at.
|
| 373 | - (hsc_env1, names) <- liftIO $
|
|
| 374 | + (hsc_env1, break_ids) <- liftIO $
|
|
| 374 | 375 | bindLocalsAtBreakpoint hsc_env apStack_fhv span (Just ibi)
|
| 375 | 376 | let
|
| 376 | 377 | resume = Resume
|
| ... | ... | @@ -388,7 +389,7 @@ handleRunStatus step expr bindings final_ids status history0 = do |
| 388 | 389 | }
|
| 389 | 390 | hsc_env2 = pushResume hsc_env1 resume
|
| 390 | 391 | setSession hsc_env2
|
| 391 | - return (ExecBreak names (Just ibi))
|
|
| 392 | + return (ExecBreak break_ids (Just ibi))
|
|
| 392 | 393 | else do
|
| 393 | 394 | -- resume with the same step type
|
| 394 | 395 | let eval_opts = initEvalOpts dflags (enableGhcStepMode step)
|
| ... | ... | @@ -491,13 +492,13 @@ getBreakArray interp InternalBreakpointId{ibi_info_mod} imbs = do |
| 491 | 492 | ( ld_st'
|
| 492 | 493 | , ba
|
| 493 | 494 | )
|
| 494 | -back :: GhcMonad m => Int -> m ([Name], Int, SrcSpan)
|
|
| 495 | +back :: GhcMonad m => Int -> m ([Id], Int, SrcSpan)
|
|
| 495 | 496 | back n = moveHist (+n)
|
| 496 | 497 | |
| 497 | -forward :: GhcMonad m => Int -> m ([Name], Int, SrcSpan)
|
|
| 498 | +forward :: GhcMonad m => Int -> m ([Id], Int, SrcSpan)
|
|
| 498 | 499 | forward n = moveHist (subtract n)
|
| 499 | 500 | |
| 500 | -moveHist :: GhcMonad m => (Int -> Int) -> m ([Name], Int, SrcSpan)
|
|
| 501 | +moveHist :: GhcMonad m => (Int -> Int) -> m ([Id], Int, SrcSpan)
|
|
| 501 | 502 | moveHist fn = do
|
| 502 | 503 | hsc_env <- getSession
|
| 503 | 504 | case ic_resume (hsc_IC hsc_env) of
|
| ... | ... | @@ -521,7 +522,7 @@ moveHist fn = do |
| 521 | 522 | let hug = hsc_HUG hsc_env
|
| 522 | 523 | brks <- readIModBreaks hug ibi
|
| 523 | 524 | getBreakLoc (readIModModBreaks hug) ibi brks
|
| 524 | - (hsc_env1, names) <-
|
|
| 525 | + (hsc_env1, final_ids) <-
|
|
| 525 | 526 | liftIO $ bindLocalsAtBreakpoint hsc_env apStack span mb_info
|
| 526 | 527 | let ic = hsc_IC hsc_env1
|
| 527 | 528 | r' = r { resumeHistoryIx = new_ix }
|
| ... | ... | @@ -529,7 +530,7 @@ moveHist fn = do |
| 529 | 530 | |
| 530 | 531 | setSession hsc_env1{ hsc_IC = ic' }
|
| 531 | 532 | |
| 532 | - return (names, new_ix, span)
|
|
| 533 | + return (final_ids, new_ix, span)
|
|
| 533 | 534 | |
| 534 | 535 | -- careful: we want apStack to be the AP_STACK itself, not a thunk
|
| 535 | 536 | -- around it, hence the cases are carefully constructed below to
|
| ... | ... | @@ -555,7 +556,7 @@ bindLocalsAtBreakpoint |
| 555 | 556 | -> ForeignHValue
|
| 556 | 557 | -> SrcSpan
|
| 557 | 558 | -> Maybe InternalBreakpointId
|
| 558 | - -> IO (HscEnv, [Name])
|
|
| 559 | + -> IO (HscEnv, [Id])
|
|
| 559 | 560 | |
| 560 | 561 | -- Nothing case: we stopped when an exception was raised, not at a
|
| 561 | 562 | -- breakpoint. We have no location information or local variables to
|
| ... | ... | @@ -575,7 +576,7 @@ bindLocalsAtBreakpoint hsc_env apStack span Nothing = do |
| 575 | 576 | interp = hscInterp hsc_env
|
| 576 | 577 | --
|
| 577 | 578 | Loader.extendLoadedEnv interp modifyHomePackageBytecodeState [(exn_name, apStack)]
|
| 578 | - return (hsc_env{ hsc_IC = ictxt1 }, [exn_name])
|
|
| 579 | + return (hsc_env{ hsc_IC = ictxt1 }, [exn_id])
|
|
| 579 | 580 | |
| 580 | 581 | -- Just case: we stopped at a breakpoint, we have information about the location
|
| 581 | 582 | -- of the breakpoint and the free variables of the expression.
|
| ... | ... | @@ -635,8 +636,9 @@ bindLocalsAtBreakpoint hsc_env apStack_fhv span (Just ibi) = do |
| 635 | 636 | let fhvs = catMaybes mb_hValues
|
| 636 | 637 | Loader.extendLoadedEnv interp modifyHomePackageBytecodeState (zip names fhvs)
|
| 637 | 638 | when result_ok $ Loader.extendLoadedEnv interp modifyHomePackageBytecodeState [(result_name, apStack_fhv)]
|
| 638 | - hsc_env1 <- rttiEnvironment hsc_env{ hsc_IC = ictxt1 }
|
|
| 639 | - return (hsc_env1, if result_ok then result_name:names else names)
|
|
| 639 | + (hsc_env1, subst) <- rttiEnvironment hsc_env{ hsc_IC = ictxt1 }
|
|
| 640 | + let improved_final_ids = map (substInteractiveId subst) final_ids
|
|
| 641 | + return (hsc_env1, improved_final_ids)
|
|
| 640 | 642 | where
|
| 641 | 643 | -- We need a fresh Unique for each Id we bind, because the linker
|
| 642 | 644 | -- state is single-threaded and otherwise we'd spam old bindings
|
| ... | ... | @@ -676,34 +678,33 @@ bindLocalsAtBreakpoint hsc_env apStack_fhv span (Just ibi) = do |
| 676 | 678 | joinOccs = zipWithEqual joinOcc
|
| 677 | 679 | joinOcc mbV oc = (\(a,b) c -> (a,b,c)) <$> mbV <*> pure oc
|
| 678 | 680 | |
| 679 | -rttiEnvironment :: HscEnv -> IO HscEnv
|
|
| 681 | +rttiEnvironment :: HscEnv -> IO (HscEnv, Subst)
|
|
| 680 | 682 | rttiEnvironment hsc_env@HscEnv{hsc_IC=ic} = do
|
| 681 | 683 | let tmp_ids = [id | AnId id <- ic_tythings ic]
|
| 682 | 684 | incompletelyTypedIds =
|
| 683 | 685 | [id | id <- tmp_ids
|
| 684 | 686 | , not $ noSkolems id
|
| 685 | 687 | , (occNameFS.nameOccName.idName) id /= result_fs]
|
| 686 | - foldM improveTypes hsc_env (map idName incompletelyTypedIds)
|
|
| 688 | + foldM improveTypes (hsc_env, emptySubst) incompletelyTypedIds
|
|
| 687 | 689 | where
|
| 688 | 690 | noSkolems = noFreeVarsOfType . idType
|
| 689 | - improveTypes hsc_env@HscEnv{hsc_IC=ic} name = do
|
|
| 690 | - let tmp_ids = [id | AnId id <- ic_tythings ic]
|
|
| 691 | - id = expectJust $ find (\i -> idName i == name) tmp_ids
|
|
| 691 | + improveTypes (hsc_env@HscEnv{hsc_IC=ic}, last_subst) id0 = do
|
|
| 692 | + let id = substInteractiveId last_subst id0
|
|
| 692 | 693 | if noSkolems id
|
| 693 | - then return hsc_env
|
|
| 694 | + then return (hsc_env, last_subst)
|
|
| 694 | 695 | else do
|
| 695 | 696 | mb_new_ty <- reconstructType hsc_env 10 id
|
| 696 | 697 | let old_ty = idType id
|
| 697 | 698 | case mb_new_ty of
|
| 698 | - Nothing -> return hsc_env
|
|
| 699 | + Nothing -> return (hsc_env, last_subst)
|
|
| 699 | 700 | Just new_ty -> do
|
| 700 | - case improveRTTIType hsc_env old_ty new_ty of
|
|
| 701 | + case improveRTTIType old_ty new_ty of
|
|
| 701 | 702 | Nothing -> warnPprTrace True (":print failed to calculate the "
|
| 702 | 703 | ++ "improvement for a type")
|
| 703 | 704 | (vcat [ text "id" <+> ppr id
|
| 704 | 705 | , text "old_ty" <+> debugPprType old_ty
|
| 705 | 706 | , text "new_ty" <+> debugPprType new_ty ]) $
|
| 706 | - return hsc_env
|
|
| 707 | + return (hsc_env, last_subst)
|
|
| 707 | 708 | Just subst -> do
|
| 708 | 709 | let logger = hsc_logger hsc_env
|
| 709 | 710 | putDumpFileMaybe logger Opt_D_dump_rtti "RTTI"
|
| ... | ... | @@ -712,7 +713,7 @@ rttiEnvironment hsc_env@HscEnv{hsc_IC=ic} = do |
| 712 | 713 | ppr subst])
|
| 713 | 714 | |
| 714 | 715 | let ic' = substInteractiveContext ic subst
|
| 715 | - return hsc_env{hsc_IC=ic'}
|
|
| 716 | + return (hsc_env{hsc_IC=ic'}, subst `composeTCvSubst` last_subst)
|
|
| 716 | 717 | |
| 717 | 718 | pushResume :: HscEnv -> Resume -> HscEnv
|
| 718 | 719 | pushResume hsc_env resume = hsc_env { hsc_IC = ictxt1 }
|
| ... | ... | @@ -19,7 +19,6 @@ import GHCi.RemoteTypes |
| 19 | 19 | import GHCi.Message (EvalExpr, ResumeContext)
|
| 20 | 20 | import GHC.ByteCode.Types (InternalBreakpointId(..))
|
| 21 | 21 | import GHC.Types.Id
|
| 22 | -import GHC.Types.Name
|
|
| 23 | 22 | import GHC.Types.TyThing
|
| 24 | 23 | import GHC.Types.Name.Reader
|
| 25 | 24 | import GHC.Types.SrcLoc
|
| ... | ... | @@ -150,7 +149,7 @@ data ExecResult |
| 150 | 149 | -- | Execution is complete with either an exception or the list of
|
| 151 | 150 | -- user-visible names that were brought into scope.
|
| 152 | 151 | = ExecComplete
|
| 153 | - { execResult :: Either SomeException [Name]
|
|
| 152 | + { execResult :: Either SomeException [Id]
|
|
| 154 | 153 | , execAllocation :: Word64
|
| 155 | 154 | }
|
| 156 | 155 | |
| ... | ... | @@ -161,7 +160,7 @@ data ExecResult |
| 161 | 160 | -- subsequently deciding whether to really stop here.
|
| 162 | 161 | -- `ExecBreak` always means GHCi breaks.
|
| 163 | 162 | | ExecBreak
|
| 164 | - { breakNames :: [Name]
|
|
| 163 | + { breakNames :: [Id]
|
|
| 165 | 164 | , breakPointId :: Maybe InternalBreakpointId
|
| 166 | 165 | }
|
| 167 | 166 |
| ... | ... | @@ -1163,8 +1163,8 @@ findPtrTyss i tys = foldM step (i, []) tys |
| 1163 | 1163 | -- improveType <base_type> <rtti_type>
|
| 1164 | 1164 | -- The types can contain skolem type variables, which need to be treated as normal vars.
|
| 1165 | 1165 | -- In particular, we want them to unify with things.
|
| 1166 | -improveRTTIType :: HscEnv -> RttiType -> RttiType -> Maybe Subst
|
|
| 1167 | -improveRTTIType _ base_ty new_ty = U.tcUnifyDebugger base_ty new_ty
|
|
| 1166 | +improveRTTIType :: RttiType -> RttiType -> Maybe Subst
|
|
| 1167 | +improveRTTIType base_ty new_ty = U.tcUnifyDebugger base_ty new_ty
|
|
| 1168 | 1168 | |
| 1169 | 1169 | getDataConArgTys :: DataCon -> Type -> TR [Type]
|
| 1170 | 1170 | -- Given the result type ty of a constructor application (D a b c :: ty)
|
| ... | ... | @@ -1495,7 +1495,7 @@ runOneCommand eh gCmd = do |
| 1495 | 1495 | |
| 1496 | 1496 | -- runStmt wrapper for temporarily overridden line-number
|
| 1497 | 1497 | runStmtWithLineNum :: Int -> String -> SingleStep
|
| 1498 | - -> GHCi (Maybe GHC.ExecResult)
|
|
| 1498 | + -> GHCi (Maybe RunResult)
|
|
| 1499 | 1499 | runStmtWithLineNum lnum stmt step = do
|
| 1500 | 1500 | st0 <- getGHCiState
|
| 1501 | 1501 | setGHCiState st0 { line_number = lnum }
|
| ... | ... | @@ -1560,7 +1560,7 @@ enqueueCommands cmds = do |
| 1560 | 1560 | |
| 1561 | 1561 | -- | Entry point to execute some haskell code from user.
|
| 1562 | 1562 | -- The return value True indicates success, as in `runOneCommand`.
|
| 1563 | -runStmt :: GhciMonad m => String -> SingleStep -> m (Maybe GHC.ExecResult)
|
|
| 1563 | +runStmt :: GhciMonad m => String -> SingleStep -> m (Maybe RunResult)
|
|
| 1564 | 1564 | runStmt input step = do
|
| 1565 | 1565 | dflags <- GHC.getInteractiveDynFlags
|
| 1566 | 1566 | let pflags = initParserOpts dflags
|
| ... | ... | @@ -1582,7 +1582,7 @@ runStmt input step = do |
| 1582 | 1582 | case mb_stmt of
|
| 1583 | 1583 | Nothing ->
|
| 1584 | 1584 | -- empty statement / comment
|
| 1585 | - return (Just exec_complete)
|
|
| 1585 | + return (Just (RunDeclsResult []))
|
|
| 1586 | 1586 | Just stmt ->
|
| 1587 | 1587 | run_stmt stmt
|
| 1588 | 1588 | |
| ... | ... | @@ -1605,8 +1605,6 @@ runStmt input step = do |
| 1605 | 1605 | run_imports imports
|
| 1606 | 1606 | run_decls decls
|
| 1607 | 1607 | where
|
| 1608 | - exec_complete = GHC.ExecComplete (Right []) 0
|
|
| 1609 | - |
|
| 1610 | 1608 | run_imports imports = mapM_ (addImportToContext . unLoc) imports
|
| 1611 | 1609 | |
| 1612 | 1610 | set_pragmas pflags sec supported =
|
| ... | ... | @@ -1615,12 +1613,12 @@ runStmt input step = do |
| 1615 | 1613 | opts = unLoc <$> loc_opts
|
| 1616 | 1614 | in setOptions opts
|
| 1617 | 1615 | |
| 1618 | - run_stmt :: GhciMonad m => GhciLStmt GhcPs -> m (Maybe GHC.ExecResult)
|
|
| 1616 | + run_stmt :: GhciMonad m => GhciLStmt GhcPs -> m (Maybe RunResult)
|
|
| 1619 | 1617 | run_stmt stmt = do
|
| 1620 | 1618 | m_result <- GhciMonad.runStmt stmt input step
|
| 1621 | 1619 | case m_result of
|
| 1622 | 1620 | Nothing -> return Nothing
|
| 1623 | - Just result -> Just <$> afterRunStmt step result
|
|
| 1621 | + Just result -> Just <$> afterRunStmt step (RunStmtResult result)
|
|
| 1624 | 1622 | |
| 1625 | 1623 | -- `x = y` (a declaration) should be treated as `let x = y` (a statement).
|
| 1626 | 1624 | -- The reason is because GHCi wasn't designed to support `x = y`, but then
|
| ... | ... | @@ -1636,7 +1634,7 @@ runStmt input step = do |
| 1636 | 1634 | --
|
| 1637 | 1635 | -- Instead of dealing with all these problems individually here we fix this
|
| 1638 | 1636 | -- mess by just treating `x = y` as `let x = y`.
|
| 1639 | - run_decls :: GhciMonad m => [LHsDecl GhcPs] -> m (Maybe GHC.ExecResult)
|
|
| 1637 | + run_decls :: GhciMonad m => [LHsDecl GhcPs] -> m (Maybe RunResult)
|
|
| 1640 | 1638 | -- Only turn `FunBind` and `VarBind` into statements, other bindings
|
| 1641 | 1639 | -- (e.g. `PatBind`) need to stay as decls.
|
| 1642 | 1640 | run_decls [L l (ValD _ bind@FunBind{})] = run_stmt (mk_stmt (locA l) bind)
|
| ... | ... | @@ -1651,8 +1649,8 @@ runStmt input step = do |
| 1651 | 1649 | -- a file, otherwise the read buffer can't be flushed).
|
| 1652 | 1650 | _ <- liftIO $ tryIO $ hFlushAll stdin
|
| 1653 | 1651 | m_result <- GhciMonad.runDecls' decls
|
| 1654 | - forM m_result $ \result ->
|
|
| 1655 | - afterRunStmt step (GHC.ExecComplete (Right result) 0)
|
|
| 1652 | + forM m_result $ \result -> do
|
|
| 1653 | + afterRunStmt step (RunDeclsResult result)
|
|
| 1656 | 1654 | |
| 1657 | 1655 | mk_stmt :: SrcSpan -> HsBind GhcPs -> GhciLStmt GhcPs
|
| 1658 | 1656 | mk_stmt loc bind =
|
| ... | ... | @@ -1668,32 +1666,39 @@ runStmt input step = do |
| 1668 | 1666 | where
|
| 1669 | 1667 | modStr = moduleNameString $ moduleName $ icInteractiveModule $ ic
|
| 1670 | 1668 | |
| 1669 | +data RunResult
|
|
| 1670 | + = RunStmtResult GHC.ExecResult
|
|
| 1671 | + | RunDeclsResult [TyThing]
|
|
| 1672 | + |
|
| 1671 | 1673 | -- | Clean up the GHCi environment after a statement has run
|
| 1672 | 1674 | afterRunStmt :: GhciMonad m => SingleStep {-^ Type of step we took just before -}
|
| 1673 | - -> GHC.ExecResult -> m GHC.ExecResult
|
|
| 1675 | + -> RunResult -> m RunResult
|
|
| 1674 | 1676 | afterRunStmt step run_result = do
|
| 1675 | 1677 | resumes <- GHC.getResumeContext
|
| 1676 | 1678 | case run_result of
|
| 1677 | - GHC.ExecComplete{..} ->
|
|
| 1678 | - case execResult of
|
|
| 1679 | - Left ex -> liftIO $ Exception.throwIO ex
|
|
| 1680 | - Right names -> do
|
|
| 1681 | - show_types <- isOptionSet ShowType
|
|
| 1682 | - when show_types $ printTypeOfNames names
|
|
| 1683 | - GHC.ExecBreak names mb_info
|
|
| 1684 | - | first_resume : _ <- resumes
|
|
| 1685 | - -> do mb_id_loc <- toBreakIdAndLocation mb_info
|
|
| 1686 | - let bCmd = maybe "" ( \(_,l) -> onBreakCmd l ) mb_id_loc
|
|
| 1687 | - if (null bCmd)
|
|
| 1688 | - then printStoppedAtBreakInfo first_resume names
|
|
| 1689 | - else enqueueCommands [bCmd]
|
|
| 1690 | - -- run the command set with ":set stop <cmd>"
|
|
| 1691 | - st <- getGHCiState
|
|
| 1692 | - enqueueCommands [stop st]
|
|
| 1693 | - return ()
|
|
| 1694 | - |
|
| 1695 | - | otherwise -> resume step Nothing >>=
|
|
| 1696 | - afterRunStmt step >> return ()
|
|
| 1679 | + RunDeclsResult things -> do
|
|
| 1680 | + show_types <- isOptionSet ShowType
|
|
| 1681 | + when show_types $ printTypeOfThings things
|
|
| 1682 | + RunStmtResult GHC.ExecComplete{..} ->
|
|
| 1683 | + case execResult of
|
|
| 1684 | + Left ex -> liftIO $ Exception.throwIO ex
|
|
| 1685 | + Right ids -> do
|
|
| 1686 | + show_types <- isOptionSet ShowType
|
|
| 1687 | + when show_types $ printTypeOfIds ids
|
|
| 1688 | + RunStmtResult (GHC.ExecBreak ids mb_info)
|
|
| 1689 | + | first_resume : _ <- resumes
|
|
| 1690 | + -> do mb_id_loc <- toBreakIdAndLocation mb_info
|
|
| 1691 | + let bCmd = maybe "" ( \(_,l) -> onBreakCmd l ) mb_id_loc
|
|
| 1692 | + if (null bCmd)
|
|
| 1693 | + then printStoppedAtBreakInfo first_resume ids
|
|
| 1694 | + else enqueueCommands [bCmd]
|
|
| 1695 | + -- run the command set with ":set stop <cmd>"
|
|
| 1696 | + st <- getGHCiState
|
|
| 1697 | + enqueueCommands [stop st]
|
|
| 1698 | + return ()
|
|
| 1699 | + |
|
| 1700 | + | otherwise -> resume step Nothing >>=
|
|
| 1701 | + afterRunStmt step . RunStmtResult >> return ()
|
|
| 1697 | 1702 | |
| 1698 | 1703 | flushInterpBuffers
|
| 1699 | 1704 | withSignalHandlers $ do
|
| ... | ... | @@ -1702,16 +1707,19 @@ afterRunStmt step run_result = do |
| 1702 | 1707 | |
| 1703 | 1708 | return run_result
|
| 1704 | 1709 | |
| 1705 | -runSuccess :: Maybe GHC.ExecResult -> Bool
|
|
| 1710 | +runSuccess :: Maybe RunResult -> Bool
|
|
| 1706 | 1711 | runSuccess run_result
|
| 1707 | - | Just (GHC.ExecComplete { execResult = Right _ }) <- run_result = True
|
|
| 1712 | + | Just (RunDeclsResult _) <- run_result = True
|
|
| 1713 | + | Just (RunStmtResult GHC.ExecComplete { execResult = Right _ })
|
|
| 1714 | + <- run_result = True
|
|
| 1708 | 1715 | | otherwise = False
|
| 1709 | 1716 | |
| 1710 | -runAllocs :: Maybe GHC.ExecResult -> Maybe Integer
|
|
| 1717 | +runAllocs :: Maybe RunResult -> Maybe Integer
|
|
| 1711 | 1718 | runAllocs m = do
|
| 1712 | 1719 | res <- m
|
| 1713 | 1720 | case res of
|
| 1714 | - GHC.ExecComplete{..} -> Just (fromIntegral execAllocation)
|
|
| 1721 | + RunDeclsResult _ -> Just 0
|
|
| 1722 | + RunStmtResult GHC.ExecComplete{..} -> Just (fromIntegral execAllocation)
|
|
| 1715 | 1723 | _ -> Nothing
|
| 1716 | 1724 | |
| 1717 | 1725 | toBreakIdAndLocation :: GhciMonad m
|
| ... | ... | @@ -1725,30 +1733,23 @@ toBreakIdAndLocation (Just inf) = do |
| 1725 | 1733 | return $ listToMaybe [ id_loc | id_loc@(_,loc) <- IntMap.assocs (breaks st),
|
| 1726 | 1734 | breakId loc == bi ]
|
| 1727 | 1735 | |
| 1728 | -printStoppedAtBreakInfo :: GHC.GhcMonad m => Resume -> [Name] -> m ()
|
|
| 1729 | -printStoppedAtBreakInfo res names = do
|
|
| 1736 | +printStoppedAtBreakInfo :: GHC.GhcMonad m => Resume -> [GHC.Id] -> m ()
|
|
| 1737 | +printStoppedAtBreakInfo res ids = do
|
|
| 1730 | 1738 | printForUser =<< pprStopped res
|
| 1731 | - -- printTypeOfNames session names
|
|
| 1732 | - let namesSorted = sortBy compareNames names
|
|
| 1733 | - tythings <- catMaybes `liftM` mapM GHC.lookupName namesSorted
|
|
| 1734 | - docs <- mapM pprTypeAndContents [i | AnId i <- tythings]
|
|
| 1739 | + let idsSorted = sortBy (compareNames `on` getName) ids
|
|
| 1740 | + docs <- mapM pprTypeAndContents idsSorted
|
|
| 1735 | 1741 | printForUserPartWay $ vcat docs
|
| 1736 | 1742 | |
| 1737 | -printTypeOfNames :: GHC.GhcMonad m => [Name] -> m ()
|
|
| 1738 | -printTypeOfNames names
|
|
| 1739 | - = mapM_ (printTypeOfName ) $ sortBy compareNames names
|
|
| 1743 | +printTypeOfIds :: GHC.GhcMonad m => [GHC.Id] -> m ()
|
|
| 1744 | +printTypeOfIds = printTypeOfThings . map AnId
|
|
| 1745 | + |
|
| 1746 | +printTypeOfThings :: GHC.GhcMonad m => [GHC.TyThing] -> m ()
|
|
| 1747 | +printTypeOfThings things
|
|
| 1748 | + = mapM_ printTyThing $ sortBy (compareNames `on` getName) things
|
|
| 1740 | 1749 | |
| 1741 | 1750 | compareNames :: Name -> Name -> Ordering
|
| 1742 | 1751 | compareNames = on compare getOccString S.<> on SrcLoc.leftmost_smallest getSrcSpan
|
| 1743 | 1752 | |
| 1744 | -printTypeOfName :: GHC.GhcMonad m => Name -> m ()
|
|
| 1745 | -printTypeOfName n
|
|
| 1746 | - = do maybe_tything <- GHC.lookupName n
|
|
| 1747 | - case maybe_tything of
|
|
| 1748 | - Nothing -> return ()
|
|
| 1749 | - Just thing -> printTyThing thing
|
|
| 1750 | - |
|
| 1751 | - |
|
| 1752 | 1753 | data MaybeCommand = GotCommand Command | BadCommand | NoLastCommand
|
| 1753 | 1754 | |
| 1754 | 1755 | -- | Entry point for execution a ':<command>' input from user
|
| ... | ... | @@ -4400,7 +4401,7 @@ doContinue step = doContinue' step Nothing |
| 4400 | 4401 | doContinue' :: GhciMonad m => SingleStep -> Maybe Int -> m ()
|
| 4401 | 4402 | doContinue' step mbCnt= do
|
| 4402 | 4403 | runResult <- resume step mbCnt
|
| 4403 | - _ <- afterRunStmt step runResult
|
|
| 4404 | + _ <- afterRunStmt step (RunStmtResult runResult)
|
|
| 4404 | 4405 | return ()
|
| 4405 | 4406 | |
| 4406 | 4407 | abandonCmd :: GhciMonad m => String -> m ()
|
| ... | ... | @@ -4551,9 +4552,9 @@ backCmd arg |
| 4551 | 4552 | | otherwise = liftIO $ putStrLn "Syntax: :back [num]"
|
| 4552 | 4553 | where
|
| 4553 | 4554 | back num = withSandboxOnly ":back" $ do
|
| 4554 | - (names, _, pan) <- GHC.back num
|
|
| 4555 | + (ids, _, pan) <- GHC.back num
|
|
| 4555 | 4556 | printForUser $ text "Logged breakpoint at" <+> ppr pan
|
| 4556 | - printTypeOfNames names
|
|
| 4557 | + printTypeOfIds ids
|
|
| 4557 | 4558 | -- run the command set with ":set stop <cmd>"
|
| 4558 | 4559 | st <- getGHCiState
|
| 4559 | 4560 | enqueueCommands [stop st]
|
| ... | ... | @@ -4565,11 +4566,11 @@ forwardCmd arg |
| 4565 | 4566 | | otherwise = liftIO $ putStrLn "Syntax: :forward [num]"
|
| 4566 | 4567 | where
|
| 4567 | 4568 | forward num = withSandboxOnly ":forward" $ do
|
| 4568 | - (names, ix, pan) <- GHC.forward num
|
|
| 4569 | + (ids, ix, pan) <- GHC.forward num
|
|
| 4569 | 4570 | printForUser $ (if (ix == 0)
|
| 4570 | 4571 | then text "Stopped at"
|
| 4571 | 4572 | else text "Logged breakpoint at") <+> ppr pan
|
| 4572 | - printTypeOfNames names
|
|
| 4573 | + printTypeOfIds ids
|
|
| 4573 | 4574 | -- run the command set with ":set stop <cmd>"
|
| 4574 | 4575 | st <- getGHCiState
|
| 4575 | 4576 | enqueueCommands [stop st]
|
| ... | ... | @@ -381,7 +381,7 @@ runStmt stmt stmt_text step = do |
| 381 | 381 | (EvalThis fhv) }
|
| 382 | 382 | Just <$> GHC.execStmt' stmt stmt_text opts
|
| 383 | 383 | |
| 384 | -runDecls :: GhciMonad m => String -> m (Maybe [GHC.Name])
|
|
| 384 | +runDecls :: GhciMonad m => String -> m (Maybe [GHC.TyThing])
|
|
| 385 | 385 | runDecls decls = do
|
| 386 | 386 | st <- getGHCiState
|
| 387 | 387 | reifyGHCi $ \x ->
|
| ... | ... | @@ -393,7 +393,7 @@ runDecls decls = do |
| 393 | 393 | r <- GHC.runDeclsWithLocation (progname st) (line_number st) decls
|
| 394 | 394 | return (Just r)
|
| 395 | 395 | |
| 396 | -runDecls' :: GhciMonad m => [LHsDecl GhcPs] -> m (Maybe [GHC.Name])
|
|
| 396 | +runDecls' :: GhciMonad m => [LHsDecl GhcPs] -> m (Maybe [GHC.TyThing])
|
|
| 397 | 397 | runDecls' decls = do
|
| 398 | 398 | st <- getGHCiState
|
| 399 | 399 | reifyGHCi $ \x ->
|
| 1 | +module RttiSharedTyVar where
|
|
| 2 | + |
|
| 3 | +f :: a -> a -> ()
|
|
| 4 | +f x y = x `seq` y `seq` () |
| 1 | +:l RttiSharedTyVar
|
|
| 2 | +let a = Just undefined :: Maybe Int
|
|
| 3 | +let b = Just 5 :: Maybe Int
|
|
| 4 | +a `seq` b `seq` ()
|
|
| 5 | +:break f
|
|
| 6 | +-- should say x y have type Maybe Int, not Maybe a
|
|
| 7 | +f a b
|
|
| 8 | +:t x
|
|
| 9 | +:t y |
| 1 | +()
|
|
| 2 | +Breakpoint 0 activated at RttiSharedTyVar.hs:4:9-26
|
|
| 3 | +Stopped in RttiSharedTyVar.f, RttiSharedTyVar.hs:4:9-26
|
|
| 4 | +_result :: () = _
|
|
| 5 | +x :: Maybe Int = Just _
|
|
| 6 | +y :: Maybe Int = Just 5
|
|
| 7 | +x :: Maybe Int
|
|
| 8 | +y :: Maybe Int |
| ... | ... | @@ -155,3 +155,5 @@ test('T26042f2', [extra_hc_opts('-O -fno-unoptimized-core-for-interpreter'), ext |
| 155 | 155 | test('T26042g', extra_files(['T26042g.hs']), ghci_script, ['T26042g.script'])
|
| 156 | 156 | |
| 157 | 157 | test('T27633c', extra_files(['T27633c_obj.hs']), ghci_script, ['T27633c.script'])
|
| 158 | + |
|
| 159 | +test('RttiSharedTyVar', extra_files(['RttiSharedTyVar.hs']), ghci_script, ['RttiSharedTyVar.script']) |