Conversation
3b5d8cd to
cbee3a9
Compare
We query the HasCallStack backtrace from an exception and if it's present, use that to show a location to the user.
94d3fd9 to
6c7581f
Compare
|
Brilliant stuff. The MR looks great. Just a matter of fixing the CI |
|
@alt-romes I introduced a new module into What should I do about these helper functions? |
|
If the code is pertaining to implementing an exception view, I think it is fine to keep it in haskell-debugger-view. If not, then you could either compile it remotely or we could introduce a new module in say extra-source-files which gets unconditionally loaded into the debuggee session and contains new utilities. However, that new module would then need to be checked to contain the functions needed by the specific hdb version at runtime. We already do this for haskell-debugger-view, where we check at runtime that the version we loaded is a version supported by the hdb version running. |
dd1f48c to
e36fb45
Compare
The ExceptionInfo request is used by debuggers in order to display information about the exception we are stopped at.
|
@alt-romes This is ready for review now. |
alt-romes
left a comment
There was a problem hiding this comment.
This looks great.
I commented on some individual commits but I see that in the end some things ended up different, so you can ignore my previous comments in favor of the following two requested changes:
- Move the whole new section
"Exception context helpers"to a new moduleGHC.Debugger.Stopped.Exception - Use MultilineStrings for the long raw expressions (
exceptionInfoExprandexceptionLocationExpr)
Great work!
|
|
||
| -------------------------------------------------------------------------------- | ||
| -- * Exception context helpers | ||
| -------------------------------------------------------------------------------- | ||
|
|
||
| exceptionSourceSpanFromContext :: Debugger (Maybe SourceSpan) | ||
| exceptionSourceSpanFromContext = do | ||
| GHC.getResumeContext >>= \case | ||
| r:_ | resumeHistoryIx r == 0 | ||
| , Nothing <- GHC.resumeBreakpointId r -> do | ||
| let excRef = resumeApStack r | ||
| evalRes <- Remote.eval | ||
| (Remote.raw exceptionLocationExpr `Remote.app` Remote.untypedRef excRef) | ||
| case evalRes of | ||
| Left err -> do | ||
| logSDoc Logger.Debug $ | ||
| Ppr.text "Failed to evaluate exception context:" Ppr.<+> Ppr.text (show err) | ||
| return Nothing | ||
| Right fhv -> do | ||
| parsed <- obtainParsedTerm "Exception context location" 4 True anyTy (castForeignRef fhv) | ||
| (maybeParser exceptionLocationTupleParser) | ||
| case parsed of | ||
| Left errs -> do | ||
| logSDoc Logger.Debug $ | ||
| Ppr.text "Failed to parse exception context location:" | ||
| Ppr.<+> Ppr.vcat (map (Ppr.text . getTermErrorMessage) errs) | ||
| return Nothing | ||
| Right Nothing -> return Nothing | ||
| Right (Just (file, line, col)) -> | ||
| return $ Just SourceSpan | ||
| { file = file | ||
| , startLine = line | ||
| , startCol = col | ||
| , endLine = line | ||
| , endCol = col | ||
| } | ||
| _ -> return Nothing | ||
|
|
||
| exceptionLocationTupleParser :: TermParser (String, Int, Int) | ||
| exceptionLocationTupleParser = | ||
| (,,) <$> subtermWith 0 stringParser | ||
| <*> subtermWith 1 intParser | ||
| <*> subtermWith 2 intParser | ||
|
|
||
| exceptionLocationExpr :: String | ||
| exceptionLocationExpr = unlines | ||
| [ "let" | ||
| , " fromCallStack cs = case GHC.Internal.Data.Maybe.listToMaybe (GHC.Internal.Stack.getCallStack cs) of" | ||
| , " Just (_, loc) -> Just ( GHC.Internal.Stack.Types.srcLocFile loc" | ||
| , " , GHC.Internal.Stack.Types.srcLocStartLine loc" | ||
| , " , GHC.Internal.Stack.Types.srcLocStartCol loc)" | ||
| , " go exc =" | ||
| , " let ctx = GHC.Internal.Exception.Type.someExceptionContext exc" | ||
| , " bts :: [GHC.Internal.Exception.Backtrace.Backtraces]" | ||
| , " bts = Control.Exception.Context.getExceptionAnnotations ctx" | ||
| , " in case bts of" | ||
| , " bt : _ -> case GHC.Internal.Exception.Backtrace.btrHasCallStack bt of" | ||
| , " Just cs -> fromCallStack cs" | ||
| , " Nothing -> Nothing" | ||
| , " [] -> Nothing" | ||
| , " in go" | ||
| ] | ||
|
|
||
| fallbackExceptionSourceSpan :: Maybe SrcSpan -> SourceSpan | ||
| fallbackExceptionSourceSpan mspan = | ||
| let fileLabel = maybe "<exception>" spanLabel mspan | ||
| in SourceSpan | ||
| { file = fileLabel | ||
| , startLine = 0 | ||
| , startCol = 0 | ||
| , endLine = 0 | ||
| , endCol = 0 | ||
| } | ||
| where | ||
| spanLabel (RealSrcSpan rss _) = unpackFS (srcSpanFile rss) | ||
| spanLabel (UnhelpfulSpan reason) = unpackFS (unhelpfulSpanFS reason) |
There was a problem hiding this comment.
Sorry for the busy work, but could you move this to a new module GHC.Debugger.Stopped.Exception
e36fb45 to
160fbf9
Compare
|
I moved the helpers to a new module in a new commit. |
|
For the record, Rodrigo says that the reason there are 5 exceptions thrown in the integration test is that..
|
Note, requires haskell-debugger/dap#26