Fix batch-forward typeassert: Enzyme returns AnonymousStruct, not NTuple#50
Merged
ChrisRackauckas merged 2 commits intoMay 21, 2026
Conversation
The forward rules for batch width > 1 asserted
`shadow_result[1]::NTuple{W, T}` but `Enzyme.autodiff(Forward, …,
BatchDuplicated{T,W}, …)` returns the batch shadow wrapped in
`Enzyme.Compiler.AnonymousStruct` — a
`NamedTuple{(:1, :2, …), NTuple{W, T}}` (see
`Enzyme/src/compiler/utils.jl:480`).
The mismatch tripped the existing `Enzyme batch forward mode (width > 1)`
testset on `main` with:
```
TypeError: in typeassert, expected Tuple{Float64, Float64},
got a value of type @NamedTuple{1::Float64, 2::Float64}
```
Wrap the shadow in `Tuple(...)` before the type-assert so the rule's
return matches the `BatchDuplicated` shadow contract that Enzyme expects
from a forward rule. Applies to both `{false, true, W>1, …}`
(shadow-only) and `{true, true, W>1, …}` (ForwardWithPrimal) rules.
The existing testset (which was failing on `main`) now passes. Full
local test summary on Julia 1.11 + Enzyme v0.13.147:
```
FunctionWrappersWrappers.jl | 48 48
BigFloat support | 5 5
UnionAll return types | 2 2
Enzyme extension | 44 44
Mooncake extension | 13 13
```
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Calls `EnzymeRules.forward` directly so the rule's actual return value
is observable. The pre-existing `Enzyme.autodiff(Forward, …)`-driven
testset doesn't catch a regression on its own because the outer
`Enzyme.autodiff` ALSO wraps in `AnonymousStruct`, and `shadow[1]`
indexing works on both `NamedTuple` and `Tuple`.
The new testset asserts:
- the shadow-only rule (`{false, true, W=2, …}`) returns `NTuple{2, Float64}`,
not `NamedTuple`;
- the ForwardWithPrimal rule (`{true, true, W=2, …}`) puts an
`NTuple{2, Float64}` (not a `NamedTuple`) into `result.dval`;
- the conversion generalises to W = 3.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the long-failing
Enzyme batch forward mode (width > 1)testset onmain. The failure existed before issue #48 and is unrelated to it — surfaced while running the test suite during #48 investigation.The forward rules for batch width > 1 asserted:
But Enzyme's batch shadow comes back wrapped in
Enzyme.Compiler.AnonymousStruct, which is defined (Enzyme/src/compiler/utils.jl:480) as:So the runtime type is
@NamedTuple{1::Float64, 2::Float64}, notTuple{Float64, Float64}— the typeassert fires with:Fix
Wrap with
Tuple(...)before the typeassert in both batch-mode rule branches:Tuple(::NamedTuple)strips the field-name wrapper and yields a plainNTuple{W, T}(the underlying storage), which is what theBatchDuplicatedshadow contract expects.Bisect
Not an Enzyme regression. Tested Enzyme 0.13.100 → 0.13.148 — every version returns the
AnonymousStruct/NamedTuple shape. The FWW rule's assertion was wrong from the moment it was written (introduced in PR #45 / v1.8.0).Smallest reproducer
Tests
The existing
Enzyme batch forward mode (width > 1)testset (test/enzyme_tests.jl:55) — which was the failing one — now passes. Full local suite on Julia 1.11 + Enzyme v0.13.147:Enzyme extensionwas previously 39 pass / 1 error.Relationship to #49
Independent of PR #49 (the issue #48 fix). This PR branches off
main; #49 should rebase cleanly on top of (or under) this one. Could be merged in either order.Test plan
Enzyme batch forward mode (width > 1)testset passes locally🤖 Generated with Claude Code