@@ -135,13 +135,44 @@ ProjectTo(::Real) = ProjectTo{Real}()
135135ProjectTo (:: Complex ) = ProjectTo {Complex} ()
136136ProjectTo (:: Number ) = ProjectTo {Number} ()
137137for T in (Float16, Float32, Float64, ComplexF16, ComplexF32, ComplexF64)
138- # Preserve low-precision floats as accidental promotion is a common perforance bug
138+ # Preserve low-precision floats as accidental promotion is a common perforance bug
139139 @eval ProjectTo (:: $T ) = ProjectTo {$T} ()
140140end
141141ProjectTo (x:: Integer ) = ProjectTo (float (x))
142142ProjectTo (x:: Complex{<:Integer} ) = ProjectTo (float (x))
143- (:: ProjectTo{T} )(dx:: Number ) where {T<: Number } = convert (T, dx)
144- (:: ProjectTo{T} )(dx:: Number ) where {T<: Real } = convert (T, real (dx))
143+
144+ # Preserve low-precision floats as accidental promotion is a common perforance bug
145+ (:: ProjectTo{T} )(dx:: AbstractFloat ) where T<: AbstractFloat = convert (T, dx)
146+ (:: ProjectTo{T} )(dx:: Integer ) where T<: AbstractFloat = convert (T, dx)
147+
148+
149+ # We asked for a number/real and they gave use one. We did ask for a particular concrete
150+ # type, but that is just for the preserving low precision floats, which is handled above.
151+ # Any Number/Real actually occupies the same subspace, so we can trust them.
152+ # In particular, this makes weirder Real subtypes that are not simply the values like
153+ # ForwardDiff.Dual and Symbolics.Sym work, because we stay out of their way.
154+ (:: ProjectTo{<:Number} )(dx:: Number ) where {T<: Number } = dx
155+ (:: ProjectTo{<:Real} )(dx:: Real ) = dx
156+
157+ (:: ProjectTo{T} )(dx:: Complex ) where T<: Real = ProjectTo (zero (T))(real (dx))
158+
159+ # Complex
160+ function (proj:: ProjectTo{<:Complex{<:AbstractFloat}} )(
161+ dx:: Complex{<:Union{AbstractFloat,Integer}}
162+ )
163+ # in this case we can just convert as we know we are dealing with
164+ # boring floating point types or integers
165+ return convert (project_type (proj), dx)
166+ end
167+ # Pass though non-AbstractFloat to project each component
168+ function (:: ProjectTo{<:Complex{T}} )(dx:: Complex ) where T
169+ project = ProjectTo (zero (T))
170+ return Complex (project (real (dx)), project (imag (dx)))
171+ end
172+ function (:: ProjectTo{<:Complex{T}} )(dx:: Real ) where T
173+ project = ProjectTo (zero (T))
174+ return Complex (project (dx), project (zero (dx)))
175+ end
145176
146177# Arrays
147178# If we don't have a more specialized `ProjectTo` rule, we just assume that there is
0 commit comments