Forwarddiff through setindex

I’m having trouble differentiating through the setindex!() of a custom type.

Here’s a minimum example using the ArrayAndChar type from the Julia docs to replicate the issue.

using ForwardDiff

struct ArrayAndChar{T,N} <: AbstractArray{T,N}
    data::Array{T,N}
    char::Char
end
Base.size(A::ArrayAndChar) = size(A.data)
Base.getindex(A::ArrayAndChar{T,N}, inds::Vararg{Int,N}) where {T,N} = A.data[inds...]
Base.setindex!(A::ArrayAndChar{T,N}, val, inds::Vararg{Int,N}) where {T,N} = A.data[inds...] = val
Base.showarg(io::IO, A::ArrayAndChar, toplevel) = print(io, typeof(A), " with char '", A.char, "'")

function f(x) 
    a = ArrayAndChar(ones(5),'a')
    b = ArrayAndChar(zeros(5),'b')
    for i in eachindex(a,b)
        j = oneunit(i)
        b[i] = x*a[max(j,i-j)]
    end
    b
end
f(2)

5-element ArrayAndChar{Float64, 1} with char ‘b’:
2.0
2.0
4.0
6.0
8.0

g(x) = ForwardDiff.derivative(f,x)
g(2)

ERROR: LoadError: MethodError: no method matching Float64(::ForwardDiff.Dual{ForwardDiff.Tag{typeof(f), Int64}, Float64, 1})
Closest candidates are:
(::Type{T})(::Real, ::RoundingMode) where T<:AbstractFloat at rounding.jl:200
(::Type{T})(::T) where T<:Number at boot.jl:760
(::Type{T})(::AbstractChar) where T<:Union{AbstractChar, Number} at char.jl:50

Stacktrace

[1] convert(#unused#::Type{Float64}, x::ForwardDiff.Dual{ForwardDiff.Tag{typeof(f), Int64}, Float64, 1})
@ Base ./number.jl:7
[2] setindex!(A::Vector{Float64}, x::ForwardDiff.Dual{ForwardDiff.Tag{typeof(f), Int64}, Float64, 1}, i1::Int64)
@ Base ./array.jl:839
[3] setindex!(A::ArrayAndChar{Float64, 1}, val::ForwardDiff.Dual{ForwardDiff.Tag{typeof(f), Int64}, Float64, 1}, inds::Int64)
@ Main ~/Workspace/GeometricMultigrid.jl/MWE.jl:9
[4] _setindex!
@ ./abstractarray.jl:1297 [inlined]
[5] setindex!
@ ./abstractarray.jl:1267 [inlined]
[6] f(x::ForwardDiff.Dual{ForwardDiff.Tag{typeof(f), Int64}, Int64, 1})
@ Main ~/Workspace/GeometricMultigrid.jl/MWE.jl:16
[7] derivative
@ ~/.julia/packages/ForwardDiff/5gUap/src/derivative.jl:14 [inlined]
[8] g(x::Int64)
@ Main ~/Workspace/GeometricMultigrid.jl/MWE.jl:21
[9] top-level scope

This example works if I replace the loop with something simple like b=x*a, but this loop with an index shift is more like what I need.

How can I change setindex!() to allow ForwardDiff to change the type to a Dual in this example?

Oh, this works!

function f(x::T) where T
    a = ArrayAndChar([1.,2.,3.,4.,5.],'a')
    b = ArrayAndChar(zeros(T,5),'b')
    for i in eachindex(a,b)
        j = oneunit(i)
        b[i] = x*a[max(j,i-j)]
    end
    b
end

So I just needed to initialize the struct properly.