@@ -141,16 +141,42 @@ end
141141# dx::AbstractArray (when both are possible), or the reverse. So for now we just pass them through:
142142(:: ProjectTo{T} )(dx:: Tangent{<:T} ) where {T} = dx
143143
144+ # ####
145+ # #### A related utility which wants to live nearby
146+ # ####
147+
148+ """
149+ is_non_differentiable(x) == is_non_differentiable(typeof(x))
150+
151+ Returns `true` if `x` is known from its type not to have derivatives, else `false`.
152+
153+ Should mostly agree with whether `ProjectTo(x)` maps to `AbstractZero`,
154+ which is what the fallback method checks. The exception is that it will not look
155+ inside abstractly typed containers like `x = Any[true, false]`.
156+ """
157+ is_non_differentiable (x) = is_non_differentiable (typeof (x))
158+
159+ is_non_differentiable (:: Type{<:Number} ) = false
160+ is_non_differentiable (:: Type{<:NTuple{N,T}} ) where {N,T} = is_non_differentiable (T)
161+ is_non_differentiable (:: Type{<:AbstractArray{T}} ) where {T} = is_non_differentiable (T)
162+
163+ function is_non_differentiable (:: Type{T} ) where {T} # fallback
164+ PT = Base. _return_type (ProjectTo, Tuple{T}) # might be Union{} if unstable
165+ return isconcretetype (PT) && PT <: ProjectTo{<:AbstractZero}
166+ end
167+
144168# ####
145169# #### `Base`
146170# ####
147171
148172# Bool
149173ProjectTo (:: Bool ) = ProjectTo {NoTangent} () # same projector as ProjectTo(::AbstractZero) above
174+ is_non_differentiable (:: Type{Bool} ) = true
150175
151176# Other never-differentiable types
152177for T in (:Symbol , :Char , :AbstractString , :RoundingMode , :IndexStyle )
153178 @eval ProjectTo (:: $T ) = ProjectTo {NoTangent} ()
179+ @eval is_non_differentiable (:: Type{<:$T} ) = true
154180end
155181
156182# Numbers
0 commit comments