Skip to content
Closed
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
17 changes: 10 additions & 7 deletions src/macros.jl
Original file line number Diff line number Diff line change
Expand Up @@ -362,20 +362,23 @@ macro grad_from_chainrules(fcall)
# `track` and the exec methods only see positional types
track_whereparams = map(esc, positional_whereparams(d[:whereparams], d[:args]))

# argument names are escaped and may shadow `$f` in the bodies, so bind the function via its type
# argument names are escaped and may shadow `$f` in the bodies, so bind the function via its type,
# under a generated name: the self-argument of a callable-object method is not renamed by macro
# hygiene, so a fixed name would clash with an argument of the same name (#334)
self = gensym(:func)
return quote
(func::$ReverseDiff._selftype($f))($(sig_args...); $(sig_kwargs...)) where {$(whereparams...)} =
$ReverseDiff.track(func, $(call_args...); $(call_kwargs...))
function $ReverseDiff.track(func::$ReverseDiff._selftype($f), $(track_args...); kwargs...) where {$(track_whereparams...)}
($self::$ReverseDiff._selftype($f))($(sig_args...); $(sig_kwargs...)) where {$(whereparams...)} =
$ReverseDiff.track($self, $(call_args...); $(call_kwargs...))
function $ReverseDiff.track($self::$ReverseDiff._selftype($f), $(track_args...); kwargs...) where {$(track_whereparams...)}
args = ($(call_args...),)
tp = $ReverseDiff.tape(args...)
output_value, back = $ChainRulesCore.rrule(func, map($ReverseDiff.value, args)...; kwargs...)
output_value, back = $ChainRulesCore.rrule($self, map($ReverseDiff.value, args)...; kwargs...)
output = $ReverseDiff.track(output_value, tp)
closure(cls_args...; cls_kwargs...) = $ChainRulesCore.rrule(func, map($ReverseDiff.value, cls_args)...; cls_kwargs...)
closure(cls_args...; cls_kwargs...) = $ChainRulesCore.rrule($self, map($ReverseDiff.value, cls_args)...; cls_kwargs...)
$ReverseDiff.record!(
tp,
$ReverseDiff.SpecialInstruction,
func,
$self,
args,
output,
(back, closure, kwargs),
Expand Down
15 changes: 15 additions & 0 deletions test/ChainRulesTests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,21 @@ ReverseDiff.@grad_from_chainrules f_names(
@test results[2] == fill(5, size(y))
end

# an argument named `func`, the name of the generated self-argument in 1.18.8 (#334)
f_func(func, x) = func(sum(4x))

function ChainRulesCore.rrule(::typeof(f_func), func, x)
pb_f_func(Δ) = (NoTangent(), NoTangent(), fill(3 * Δ, size(x)))
return f_func(func, x), pb_f_func
end

ReverseDiff.@grad_from_chainrules f_func(func, x::ReverseDiff.TrackedArray)

@testset "argument named func" begin
x = rand(3, 3)
@test ReverseDiff.gradient(x -> f_func(identity, x), x) == fill(3, size(x))
end

@testset "invalid signatures" begin
@test_throws "has to be applied to a function signature" @eval ReverseDiff.@grad_from_chainrules f_where
@test_throws "at least one positional argument" @eval ReverseDiff.@grad_from_chainrules f_where()
Expand Down
Loading