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