@@ -23,20 +23,27 @@ using OptimizationBase.FastClosures
2323@inline _prep_valid (:: Type{T} , v) where {T} = typeof (v) === T
2424
2525# Output-buffer eltype for the `p`-accepting constraint wrapper: the type `f.cons` produces,
26- # including the * nested* dual when both `x` (DI's seeds) and `p` (the sensitivity layer) carry
27- # duals with different tags (`promote_op(+, …)` nests them) . Deliberately uses plain `eltype(p)`
26+ # including nested duals when both `x` (DI's seeds) and `p` (the sensitivity layer) carry
27+ # duals. Deliberately uses plain `eltype(p)`
2828# rather than `SciMLBase.anyeltypedual`: this runs *inside* the DI-differentiated wrapper, and
2929# Enzyme's forward mode corrupts the derivative shadow (DataType-valued entries) when the
3030# allocation type flows through `anyeltypedual` — in either its value or its type-level form,
3131# and even with an `EnzymeRules.inactive` mark on this helper. A structured `p` (non-`Number`
3232# eltype) therefore falls back to `eltype(x)`; duals nested inside such a `p` are the one
3333# unsupported case. (`_prep_valid` above runs in the outer closure, outside anything a backend
3434# differentiates, so its type comparison is safe there.)
35+ @inline function _add_output_eltype (:: Type{Tu} , :: Type{Tp} ) where {Tu, Tp}
36+ return try
37+ typeof (zero (Tu) + zero (Tp))
38+ catch
39+ Any
40+ end
41+ end
3542@inline function _cons_out_eltype (x, p)
3643 Tu = eltype (x)
3744 p isa Union{SciMLBase. NullParameters, Nothing} && return Tu
3845 Tp = eltype (p)
39- return Tp <: Number ? Base . promote_op ( + , Tu, Tp) : Tu
46+ return Tp <: Number ? _add_output_eltype ( Tu, Tp) : Tu
4047end
4148
4249function instantiate_function (
0 commit comments