Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/debugger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@ jobs:
continue-on-error: true # Run all jobs in the matrix to the end
strategy:
matrix:
version: [9.14.0.20250908] #, latest-nightly] disable nightly while its broken
version: [9.14.0.20251007] #, latest-nightly] disable nightly while its broken
include:
# - channel: https://ghc.gitlab.haskell.org/ghcup-metadata/ghcup-nightlies-0.0.7.yaml
# version: latest-nightly
- channel: https://raw.githubusercontent.com/haskell/ghcup-metadata/refs/heads/develop/ghcup-prereleases-0.0.9.yaml
version: 9.14.0.20250908
version: 9.14.0.20251007
steps:
- uses: actions/checkout@v4
with:
Expand Down Expand Up @@ -110,12 +110,12 @@ jobs:
continue-on-error: true # Run all jobs in the matrix to the end
strategy:
matrix:
version: [9.14.0.20250908] #, latest-nightly] disable nightly while its broken
version: [9.14.0.20251007] #, latest-nightly] disable nightly while its broken
include:
# - channel: https://ghc.gitlab.haskell.org/ghcup-metadata/ghcup-nightlies-0.0.7.yaml
# version: latest-nightly
- channel: https://raw.githubusercontent.com/haskell/ghcup-metadata/refs/heads/develop/ghcup-prereleases-0.0.9.yaml
version: 9.14.0.20250908
version: 9.14.0.20251007
steps:
- uses: actions/checkout@v4
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:

- uses: haskell-actions/setup@v2
with:
ghc-version: 9.14.0.20250908
ghc-version: 9.14.0.20251007
cabal-version: 3.14
ghcup-release-channel: https://raw.githubusercontent.com/haskell/ghcup-metadata/refs/heads/develop/ghcup-prereleases-0.0.9.yaml

Expand Down
2 changes: 1 addition & 1 deletion haskell-debugger.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ cabal-version: 3.12
name: haskell-debugger
version: 0.9.0.0
synopsis:
A step-through machine-interface debugger for GHC Haskell
A step-through debugger for GHC Haskell

description: This package provides a standalone executable
called @hdb@ which can be used to step-through Haskell
Expand Down
2 changes: 2 additions & 0 deletions haskell-debugger/GHC/Debugger/Runtime.hs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ obtainTerm key = do
Nothing -> error "Couldn't find labeled field in dataConFieldLabels"
NewtypeWrap{wrapped_term} ->
wrapped_term -- regardless of PathFragment
RefWrap{wrapped_term} ->
wrapped_term -- regardless of PathFragment
_ -> error "Unexpected term for the given TermKey"
in do
term <- getTerm key
Expand Down
4 changes: 4 additions & 0 deletions haskell-debugger/GHC/Debugger/Stopped/Variables.hs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ termVarFields top_key top_term =
wvi <- obtainTerm key >>= termToVarInfo key
return (LabeledFields [wvi])
_ -> error "unexpected number of Newtype fields: larger than 1"
RefWrap{wrapped_term=_{- don't use directly! go through @obtainTerm@ -}} -> do
let key = FromPath top_key (PositionalIndex 1)
wvi <- obtainTerm key >>= termToVarInfo key
return (IndexedFields [wvi])
_ -> return NoFields


Expand Down
10 changes: 10 additions & 0 deletions test/integration-tests/data/T92/T92.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module Main where

import Data.IORef

main = do
r <- newIORef False
putStrLn (const "hi" r) -- make r free in this line
writeIORef r True
putStrLn (const "bye" r) -- what does r look like now?

48 changes: 45 additions & 3 deletions test/integration-tests/test/adapter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -565,11 +565,53 @@ describe("Debug Adapter Tests", function () {
const _1_1_1_1_1_1Var = await _1_1_1_1_1Child.get('_1');
assertIsString(_1_1_1_1_1_1Var, '"hello"');
})

it('inspect mutable variables (#92)', async () => {
let config = mkConfig({
projectRoot: "/data/T92",
entryFile: "T92.hs",
entryPoint: "main",
entryArgs: [],
extraGhcArgs: []
})

const expected = { path: config.projectRoot + "/" + config.entryFile, line: 7 }
await dc.hitBreakpoint(config, { path: config.entryFile, line: 7 }, expected, expected);

async function getMutVarValue() {
let locals = await fetchLocalVars();
const rVar = await locals.get('r');
assert.strictEqual(rVar.value, "IORef (STRef (GHC.Prim.MutVar# _))")
const rChild = await expandVar(rVar);
const r_1_Var = await rChild.get('_1'); // No force
assert.strictEqual(r_1_Var.value, 'STRef');
const r_1_Child = await expandVar(r_1_Var);
const r_1_1_Var = await r_1_Child.get("_1"); // No force
assert.strictEqual(r_1_1_Var.value, 'GHC.Prim.MutVar# _');
const r_1_1_Child = await expandVar(r_1_1_Var);
const r_1_1_1_Var = await forceLazy(r_1_1_Child.get("_1")); // FORCE REFERENCE!
return r_1_1_1_Var
}

const m1 = await getMutVarValue()
assert.strictEqual(m1.value, "False")
await dc.nextRequest({ threadId: 0 });
await dc.nextRequest({ threadId: 0 });
await dc.nextRequest({ threadId: 0 });
// Now we're at the start of the last line, where the ref should be True
// Note how we get it from scratch, the content of the ref must be
// forced again (the forceLazy call in getMutVarValue)
const m2 = await getMutVarValue()
assert.strictEqual(m2.value, "True")
})
})
describe("Stepping out (step-out)", function () {

let step_out_broken = ghc_version < "9.15.20250731" // hasn't been merged yet, but let's use this bound; will probably only be in GHC 9.14.2
let need_opt = step_out_broken
// TODO: Add simpler tests which don't rely on optimisations at all.
// E.g. just simply stepping out to a case expression

let step_out_broken = ghc_version < "9.14.0.20251007" // hasn't been merged yet, but let's use this bound; will probably only be in GHC 9.14.2
let need_opt = true // Currently we depend on this to work around the fact that >>= is in library code because base is not being interpreted

// Mimics GHC's T26042b
it('without tail calls', async () => {
Expand All @@ -596,7 +638,7 @@ describe("Debug Adapter Tests", function () {

// back to main
await dc.stepOutRequest({threadId: 0});
await dc.assertStoppedLocation('step', expected(step_out_broken ? 6 : 6));
await dc.assertStoppedLocation('step', expected(step_out_broken ? 6 : 5));

// exit
await dc.stepOutRequest({threadId: 0});
Expand Down
Loading