From 96de730528148cfc6b30fcb93e9236c5f6c648df Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Fri, 10 Apr 2026 18:35:20 +0200 Subject: [PATCH] Fix @adapt_structure for modules that only import the macro. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous fix used `esc(quote ... end)`, which made the generated code resolve `Adapt.adapt_structure` in the caller's module. This broke modules that do `using Adapt: @adapt_structure` (e.g. DataInterpolationsND) because `Adapt` itself is not bound there. Switch to value-interpolating the Adapt module directly via `$Adapt` (and `$$Adapt` to reach into the inner quote that runs at codegen time). The function-argument names `to` and `obj` are escaped explicitly so hygiene does not gensym them — that keeps them matching the literal `:to`/`:obj` symbols inside the inner quote. The resulting IR is unchanged (direct getfield + %new). Co-Authored-By: Claude Opus 4.6 (1M context) --- Project.toml | 2 +- src/macro.jl | 10 +++++----- test/runtests.jl | 11 +++++++++++ 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Project.toml b/Project.toml index bd9aebe..75dae1e 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "Adapt" uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" -version = "4.5.1" +version = "4.5.2" [deps] LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" diff --git a/src/macro.jl b/src/macro.jl index 2bc455b..f8d0eb9 100644 --- a/src/macro.jl +++ b/src/macro.jl @@ -5,10 +5,10 @@ Define a method `adapt_structure(to, obj::T)` which calls `adapt_structure` on e of `obj` and constructs a new instance of `T` using the default constuctor `T(...)`. """ macro adapt_structure(T) - esc(quote - @generated function Adapt.adapt_structure(to, obj::$T) - assignments = Any[:(Adapt.adapt_structure(to, obj.$name)) for name in fieldnames(obj)] - return Expr(:call, $T, assignments...) + quote + @generated function $Adapt.adapt_structure($(esc(:to)), $(esc(:obj))::$(esc(T))) + assignments = Any[:($$Adapt.adapt_structure(to, obj.$name)) for name in fieldnames($(esc(:obj)))] + return Expr(:call, $(esc(T)), assignments...) end - end) + end end diff --git a/test/runtests.jl b/test/runtests.jl index 3e47edd..0e08935 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -221,6 +221,17 @@ end end Adapt.@adapt_structure LocalStruct @test adapt(CustomArray, LocalStruct(1)) === LocalStruct(1) + + # The macro must work in modules that only import @adapt_structure, + # not the Adapt module itself (e.g. `using Adapt: @adapt_structure`). + @eval module ModuleOnlyImportingMacro + using Adapt: @adapt_structure + struct S + x::Int + end + @adapt_structure S + end + @test adapt(CustomArray, ModuleOnlyImportingMacro.S(1)) === ModuleOnlyImportingMacro.S(1) end