diff --git a/base/missing.jl b/base/missing.jl index 744f2e5f149b08..a5c62819b5b004 100644 --- a/base/missing.jl +++ b/base/missing.jl @@ -48,7 +48,7 @@ isless(::Missing, ::Any) = false isless(::Any, ::Missing) = true # Unary operators/functions -for f in (:(!), :(+), :(-), :(identity), :(zero), +for f in (:(!), :(+), :(-), :(identity), :(zero), :(one), :(oneunit), :(abs), :(abs2), :(sign), :(acos), :(acosh), :(asin), :(asinh), :(atan), :(atanh), :(sin), :(sinh), :(cos), :(cosh), :(tan), :(tanh), @@ -60,9 +60,12 @@ for f in (:(!), :(+), :(-), :(identity), :(zero), @eval Math.$(f)(::Missing) = missing end -zero(::Type{Union{T, Missing}}) where {T} = zero(T) -# To prevent StackOverflowError -zero(::Type{Any}) = throw(MethodError(zero, (Any,))) +for f in (:(Base.zero), :(Base.one), :(Base.oneunit)) + @eval function $(f)(::Type{Union{T, Missing}}) where T + T === Any && throw(MethodError($f, (Any,))) # To prevent StackOverflowError + $f(T) + end +end # Binary operators/functions for f in (:(+), :(-), :(*), :(/), :(^), @@ -112,4 +115,4 @@ function float(A::AbstractArray{Union{T, Missing}}) where {T} U = typeof(float(zero(T))) convert(AbstractArray{Union{U, Missing}}, A) end -float(A::AbstractArray{Missing}) = A \ No newline at end of file +float(A::AbstractArray{Missing}) = A diff --git a/test/missing.jl b/test/missing.jl index 6910b1dbcdf86d..54d8e1de9d2552 100644 --- a/test/missing.jl +++ b/test/missing.jl @@ -105,13 +105,20 @@ end @test ismissing(missing * "a") end +# Emulate a unitful type such as Dates.Minute +struct Unit + value::Int +end +Base.zero(::Type{Unit}) = Unit(0) +Base.one(::Type{Unit}) = 1 + @testset "elementary functions" begin elementary_functions = [abs, abs2, sign, acos, acosh, asin, asinh, atan, atanh, sin, sinh, conj, cos, cosh, tan, tanh, exp, exp2, expm1, log, log10, log1p, log2, exponent, sqrt, gamma, lgamma, - identity, zero, + identity, zero, one, oneunit, iseven, isodd, ispow2, isfinite, isinf, isnan, iszero, isinteger, isreal, isempty, transpose, float] @@ -121,11 +128,21 @@ end @test ismissing(f(missing)) end - @test zero(Union{Int, Missing}) === 0 - @test zero(Union{Float64, Missing}) === 0.0 + for T in (Int, Float64) + @test zero(Union{T, Missing}) === T(0) + @test one(Union{T, Missing}) === T(1) + @test oneunit(Union{T, Missing}) === T(1) + end + + for T in (Unit,) + @test zero(Union{T, Missing}) === T(0) + @test one(Union{T, Missing}) === 1 + @test oneunit(Union{T, Missing}) === T(1) + end + @test_throws MethodError zero(Any) - @test_throws MethodError zero(String) - @test_throws MethodError zero(Union{String, Missing}) + @test_throws MethodError one(Any) + @test_throws MethodError oneunit(Any) end @testset "rounding functions" begin