Skip to content

feat(hardhat-slang): slang stack traces via debugSymbols, solidityVersion in settings - #8691

Merged
nebasuke merged 8 commits into
mainfrom
bas/hardhat-slang-debug-symbols
Oct 20, 2026
Merged

nebasuke merged 8 commits into
mainfrom
bas/hardhat-slang-debug-symbols

Conversation

@nebasuke

@nebasuke nebasuke commented Oct 9, 2026 •

Copy link
Copy Markdown
Member

Claude summary

Slang stack traces end to end, and the Solidity version passed the way slang now expects it. EDR builds slang stack traces from two compiler outputs, the DWARF debugInfo the plugin already requests and the per-source debugSymbols table (NomicFoundation/solx#786), which stands in for the solc AST. This adds the second one, and pins the first slang prerelease that emits everything EDR reads.

Commits

  1. feat: augmentIfSlang adds debugSymbols to the file-level ["*"][""] selectors, next to ast, so it reaches the solcInput and the build-id hash like the other defaults. addSlangDebugInfoSelectors becomes addSlangStackTraceSelectors, since it now covers both outputs.
  2. test: builds the with-debug-info fixture with the slang profile, reverts in Counter._checkPositive over a network connection, and checks the error stack names the Solidity frames. It needs a release that emits debugSymbols and an EDR that reads them, so it is gated on HARDHAT_SLANG_EXPECT_STACK_TRACES, like the debugInfo test.
  3. feat: augmentIfSlang sets settings.solidityVersion to the entry's version. slang reads the version from standard JSON since feat(slang): add a Solidity version setting solx#787 and rejects --solidity-version next to --standard-json ("Solidity version must be passed via standard JSON input."). In the solcInput, a build info reproduces its compile on its own and the build id tells two versions apart. targetVersionFlag on the release row and targetSolidityVersion on SlangCompiler go, with their three tests. The prerelease pinned at this point ignores the key; commit 4 pins one that reads it.
  4. feat: pins 0.1.0-pre.2026-10-14, solx prerelease 5e6ec5e1 (slang v0.2.0, Solidity 0.8.0 to 0.8.37), which carries Use custom error for http provider errors #767, Update Buidler EVM to support solc >= 0.6.9 #702, add buidler-log-remover to plugin list #786 and Improvements of multi-solc implementation #787. Its binaries are published as slang-*, so the platform asset prefix follows. The debugInfo test loses its opt-in now that the pin emits it, and runs like hardhat-slang-solx's real-binary test. A new test compiles Counter.sol through the plugin at its entry's version, then reruns the same input at 0.8.20, which slang must refuse for ^0.8.34.
  5. test: an override entry gets the solidityVersion of its own version, not the profile's.
  6. feat: a user settings.solidityVersion that differs from the entry's version is a config error at that setting's path. Hardhat picks the entry by matching pragmas against version, so a different value would compile a language version Hardhat didn't choose; until now the plugin overwrote it silently. An equal value is accepted. Entries with their own binary (path) are checked too.
  7. perf: SlangCompiler.compile leaves ast out of the selection it hands the binary. Hardhat requests it from every compiler, but slang's AST isn't the solc AST any consumer reads (EDR uses debugSymbols; the EIP-712 collector skips non-solc ASTs). On OpenZeppelin it is 60 of the 77 MB slang returns, and dropping it takes a local cold compile from 18.0 s to 14.3 s. It is dropped at compile time because Hardhat appends its default selection when building the job's input and the hook that could change that is deprecated, so the build info's input still lists ast while its output has none.
  8. docs: the README no longer tells users to leave settings.solidityVersion unset; commit 6's validation error says so where it matters.

What it takes to turn on

Piece Where Status
debugSymbols output NomicFoundation/solx#786 merged
slang release with #767 (DWARF), #702 (ABI), #786 and #787 solx prerelease 5e6ec5e1 pinned by commit 4
EDR reading compilerType: "slang" build infos NomicFoundation/edr#1811 merged, not yet released (latest EDR is 0.23.0)
Hardhat's @nomicfoundation/edr bump packages/hardhat after the EDR release
hardhat-slang's peerDependencies.hardhat floor, ^3.15.0 today packages/hardhat-slang raise to the first Hardhat release with that bump

Until the EDR bump, a slang build info breaks every network connection, not just stack traces: EDR 0.23.0 does not know "slang" and falls back to the solc path. This is already the case on main (network.connect() throws Failed to parse build info: missing field 'abi'); with this PR the error names ast instead, so merging it ahead of the bump changes no working setup. On EDR 0.22.0, Solidity tests still ran and printed the error as a stack-trace warning.

Verification

Local run with the pinned release downloaded by the plugin, and EDR#1811 at 0438a27dc (napi build linked into packages/hardhat):

Setup hardhat test solidity network revert
EDR 0.22.0 Stack Trace Warning: Failed to process AST network.connect() throws Failed to process AST
EDR#1811 Counter._checkPositive (contracts/Counter.sol:13) ← Counter.set (contracts/Counter.sol:8) ← CounterTest.testSetZeroReverts (contracts/Counter.t.sol:9) SolidityError with the same two Counter frames

The Solidity-test row used a throwaway Counter.t.sol in the with-debug-info fixture.

  • pnpm test in packages/hardhat-slang: 121 pass. Each new test was seen failing first:
    • the selector tests (5) fail without commit 1's change, and the multi-version config test without commit 3's;
    • commit 4's compile test fails on the previous pin, where every slang compile has failed since commit 1 (unknown variant debugSymbols). Run directly, that binary compiles ^0.8.34 at 0.8.20, which is what the test's last assertion rules out;
    • commit 5's test fails without the solidityVersion line in augmentIfSlang, and commit 6's two rejection tests without its check;
    • commit 7's test fails on the previous compile, which forwarded the input unchanged.
  • The gated stack-trace test passes with HARDHAT_SLANG_EXPECT_STACK_TRACES=true against EDR#1811, and fails on EDR 0.22.0.
  • HARDHAT_RUN_MIRROR_TESTS=true: every asset and checksum of the new pin is served.
  • The gated stack-trace test still passes against EDR#1811 after commit 7, with no AST in the build info.
  • After EDR#1811 merged: on this branch merged with main (a90e19617), the gated stack-trace test passes with an napi build of EDR main 1da28b28a and fails on Hardhat's EDR 0.23.0. With the pinned release, every source gets a debugSymbols table, including pragma-only, free-function-only and interface-only files, so EDR's new error for a source without one does not fire on plugin output.
  • pnpm lint and pnpm build clean.

Notes for review

  • 5e6ec5e1's release name ends in debug-fast; the plugin only uses it as the asset suffix.
  • The real-binary tests download the ~100 MB release unless HARDHAT_DISABLE_SLOW_TESTS is set.

The slang compiler emits no solc AST, so EDR builds slang stack traces
from the per-source debugSymbols table next to the DWARF debugInfo.
Without it EDR loads the build info but every frame is an unrecognized
contract. It is a file-level output, so it goes under `["*"][""]`, and,
like debugInfo, into the resolved config so the build-id hash covers
it.
Builds the with-debug-info fixture with the slang profile, reverts in
Counter._checkPositive over a network connection, and checks the error
stack names the Solidity frames. It needs a pinned release that emits
debugSymbols (solx #786) and an EDR that reads them (EDR #1811), so it
is gated on HARDHAT_SLANG_EXPECT_STACK_TRACES like the debugInfo test.
With EDR 0.22.0, network.connect() fails with "Failed to process AST";
with EDR #1811 and solx #786 at 1cc6ed70 via `path`, it passes.
slang takes the Solidity version to compile as from
`settings.solidityVersion` in standard JSON (solx #787) and rejects
`--solidity-version` next to `--standard-json`. Setting it in the
resolved config puts it in the solcInput, so a build info reproduces
its compile on its own and the build id tells two versions apart. The
release row's `targetVersionFlag` and the compiler's
`targetSolidityVersion` have no remaining use. A binary without #787,
like the pinned prerelease, ignores the key.
@changeset-bot

changeset-bot Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: fbe2ee3

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

The 2026-10-01 prerelease predates debugSymbols, so with the stack-trace
selectors every slang compile failed on "unknown variant debugSymbols",
and it ignored settings.solidityVersion. 5e6ec5e1 carries DWARF, the ABI,
debugSymbols and solidityVersion, and publishes its binaries as slang-*,
so the asset prefix follows.

The debugInfo test no longer needs its opt-in since the pin emits it. A
new test compiles through the plugin and then reruns the job's input at
0.8.20: slang refuses the ^0.8.34 pragma there, which the old binary,
reading no solidityVersion, compiled.
The settings.solidityVersion default also runs on override entries, whose version can differ from the profile's compilers; only the compilers had a test.
Hardhat picks a compiler entry by matching pragmas against its version,
and the plugin passes that version to slang as settings.solidityVersion.
A user value that differs would make slang compile a language version
Hardhat didn't choose, and the plugin overwrote it silently. It is now a
config error at the setting's path; an equal value is harmless and
accepted. Entries with their own binary are checked too, since the
setting reaches whatever binary compiles them.
Hardhat requests `ast` from every compiler, but slang's AST is not the
solc AST its consumers read: EDR builds slang stack traces from
debugSymbols, and the EIP-712 collector skips anything that isn't a solc
SourceUnit. On OpenZeppelin it is 60 of the 77 MB slang returns, and
leaving it out saves ~2.4 s of Hardhat parsing and writing the output
(18.0 s -> 14.3 s cold, local).

compile() drops it from the input it hands the binary rather than from
the job's input: Hardhat appends its default selection when it builds
that input, and the hook that could change it is deprecated. The build
info's input therefore still lists `ast`; its output has none.
@kanej
kanej requested a review from marianfe October 14, 2026 15:46
Base automatically changed from feat/hardhat-slang to main October 15, 2026 10:18
Comment thread packages/hardhat-slang/README.md Outdated

@marianfe marianfe left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm with one minor comment , thanks!

@nebasuke nebasuke added no changeset needed This PR doesn't require a changeset no docs needed This PR doesn't require links to documentation no peer bump needed labels Oct 19, 2026
The validation error already explains a mismatched solidityVersion; the README sentence confused more than it helped (review on #8691).
@nebasuke
nebasuke marked this pull request as ready for review October 20, 2026 08:42
@nebasuke
nebasuke added this pull request to the merge queue Oct 20, 2026
Merged via the queue into main with commit db473f4 Oct 20, 2026
27 checks passed
@nebasuke
nebasuke deleted the bas/hardhat-slang-debug-symbols branch October 20, 2026 08:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no changeset needed This PR doesn't require a changeset no docs needed This PR doesn't require links to documentation no peer bump needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants