diff --git a/src/tangent_types/abstract_zero.jl b/src/tangent_types/abstract_zero.jl index f921db29d..b3b72d313 100644 --- a/src/tangent_types/abstract_zero.jl +++ b/src/tangent_types/abstract_zero.jl @@ -112,8 +112,6 @@ function zero_tangent end zero_tangent(x::Number) = zero(x) -zero_tangent(::Type) = NoTangent() - function zero_tangent(x::MutableTangent{P}) where {P} zb = backing(zero_tangent(backing(x))) return MutableTangent{P}(zb) @@ -171,10 +169,25 @@ function zero_tangent(x::Array{P,N}) where {P,N} return y end +function zero_tangent(::T) where {K,V,T<:AbstractDict{K,V}} + return Tangent{T}(Dict{K,guess_zero_tangent_type(V)}()) +end + # Sad heauristic methods we need because of unassigned values guess_zero_tangent_type(::Type{T}) where {T<:Number} = T guess_zero_tangent_type(::Type{T}) where {T<:Integer} = typeof(float(zero(T))) function guess_zero_tangent_type(::Type{<:Array{T,N}}) where {T,N} return Array{guess_zero_tangent_type(T),N} end -guess_zero_tangent_type(T::Type) = Any \ No newline at end of file +guess_zero_tangent_type(T::Type) = Any + +# Stuff that conceptually has its own identity regardless of structual implementation and doesn't have a tangent +zero_tangent(::Base.AbstractLogger) = NoTangent() + +# Prevent zero_tangent going wild on the internals +zero_tangent(::Type) = NoTangent() +zero_tangent(::Expr) = NoTangent() +zero_tangent(::Core.Compiler.AbstractInterpreter) = NoTangent() +zero_tangent(::Core.Compiler.InstructionStream) = NoTangent() +zero_tangent(::Core.CodeInfo) = NoTangent() +zero_tangent(::Core.MethodInstance) = NoTangent() \ No newline at end of file diff --git a/src/tangent_types/structural_tangent.jl b/src/tangent_types/structural_tangent.jl index 832d32a22..07a824a69 100644 --- a/src/tangent_types/structural_tangent.jl +++ b/src/tangent_types/structural_tangent.jl @@ -340,7 +340,7 @@ function Tangent{P}() where {P<:Tuple} return Tangent{P,typeof(backing)}(backing) end -function Tangent{P}(d::Dict) where {P<:Dict} +function Tangent{P}(d::Dict) where {P<:AbstractDict} return Tangent{P,typeof(d)}(d) end diff --git a/test/tangent_types/abstract_zero.jl b/test/tangent_types/abstract_zero.jl index 245d9a29d..b7d2eba5c 100644 --- a/test/tangent_types/abstract_zero.jl +++ b/test/tangent_types/abstract_zero.jl @@ -183,6 +183,18 @@ end @test zero_tangent((1.0, 2.0)) == Tangent{Tuple{Float64,Float64}}(0.0, 0.0) + @test ==( + zero_tangent(Dict{Int, Float64}(1 => 2.4)), + Tangent{Dict{Int,Float64}}(Dict{Int, Float64}()) + ) + if isdefined(Base, :PersistentDict) + @test ==( + zero_tangent(Base.PersistentDict(1 => 2.4)), + Tangent{Base.PersistentDict{Int,Float64}}(Dict{Int, Float64}()) + ) + end + + # Higher order # StructuralTangents are valid tangents for themselves (just like Numbers) # and indeed we prefer that, otherwise higher order structural tangents are kinda @@ -200,6 +212,8 @@ end @test iszero(zero_tangent(:abc)) @test iszero(zero_tangent("abc")) @test iszero(zero_tangent(sin)) + + @test iszero(zero_tangent(:(1 + 1))) end @testset "undef elements Vector" begin