-
-
Notifications
You must be signed in to change notification settings - Fork 5.7k
Open
Labels
designDesign of APIs or of the language itselfDesign of APIs or of the language itselfdocsThis change adds or pertains to documentationThis change adds or pertains to documentation
Description
Suppose a type T is defined in a package. Further suppose that S is some type not owned by the same package, and T <: S. Defining either of the following method signatures should be forbidden, because it causes dispatch ambiguity for perfectly valid promote_rule definitions from third-party packages:
Base.promote_rule(::Type{ T}, ::Type{<:S})
Base.promote_rule(::Type{<:T}, ::Type{<:S})
Base.promote_rule(::Type{<:S}, ::Type{ T})
Base.promote_rule(::Type{<:S}, ::Type{<:T})NB: Base doesn't respect this rule, though perhaps this is OK/less bad, given that Base is an implicit dependency of everything anyway. Examples:
promote_rule(::Type{BigInt}, ::Type{<:Integer}) in Base.GMP at gmp.jl:460
promote_rule(::Type{BigFloat}, ::Type{<:Real}) in Base.MPFR at mpfr.jl:366
promote_rule(::Type{Bool}, ::Type{T}) where T<:Number @ Base bool.jl:4
promote_rule(::Type{<:AbstractIrrational}, ::Type{T}) where T<:Real @ Base irrationals.jl:47
promote_rule(::Type{S}, ::Type{T}) where {S<:AbstractIrrational, T<:Number} @ Base irrationals.jl:48
Example code for ambiguity errors:
# package A
struct TA <: Integer end
Base.promote_rule(::Type{TA}, t::Type{<:Real}) = promote_type(Int, t) # offending definition
Base.promote_rule(t::Type{<:Real}, ::Type{TA}) = promote_type(Int, t) # offending definition
# package B
struct TB <: AbstractFloat end
Base.promote_rule(::Type{TB}, t::Type{<:Integer}) = promote_type(Float64, t) # OKjulia> promote_type(TA, TB)
ERROR: MethodError: promote_rule(::Type{TB}, ::Type{TA}) is ambiguous.
Candidates:
promote_rule(::Type{TB}, t::Type{<:Integer})
@ Main REPL[5]:1
promote_rule(t::Type{<:Real}, ::Type{TA})
@ Main REPL[3]:1
Possible fix, define
promote_rule(::Type{TB}, ::Type{TA})
Stacktrace:
[1] promote_type(::Type{TA}, ::Type{TB})
@ Base ./promotion.jl:318
[2] top-level scope
@ REPL[6]:1
julia> using Test
julia> detect_ambiguities(Main, recursive=true)
8-element Vector{Tuple{Method, Method}}:
(promote_rule(t::Type{<:Real}, ::Type{TA}) @ Main REPL[3]:1, promote_rule(::Type{BigInt}, ::Type{<:Integer}) @ Base.GMP gmp.jl:480)
(promote_rule(t::Type{<:Real}, ::Type{TA}) @ Main REPL[3]:1, promote_rule(::Type{Bool}, ::Type{T}) where T<:Number @ Base bool.jl:4)
(promote_rule(t::Type{<:Real}, ::Type{TA}) @ Main REPL[3]:1, promote_rule(::Type{Rational{T}}, ::Type{S}) where {T<:Integer, S<:Integer} @ Base rational.jl:180)
(promote_rule(t::Type{<:Real}, ::Type{TA}) @ Main REPL[3]:1, promote_rule(::Type{TB}, t::Type{<:Integer}) @ Main REPL[5]:1)
(promote_rule(t::Type{<:Real}, ::Type{TA}) @ Main REPL[3]:1, promote_rule(::Type{<:AbstractIrrational}, ::Type{T}) where T<:Real @ Base irrationals.jl:47)
(promote_rule(::Type{TA}, t::Type{<:Real}) @ Main REPL[2]:1, promote_rule(t::Type{<:Real}, ::Type{TA}) @ Main REPL[3]:1)
(promote_rule(t::Type{<:Real}, ::Type{TA}) @ Main REPL[3]:1, promote_rule(::Type{S}, ::Type{T}) where {S<:AbstractIrrational, T<:Number} @ Base irrationals.jl:48)
(promote_rule(t::Type{<:Real}, ::Type{TA}) @ Main REPL[3]:1, promote_rule(::Type{BigFloat}, ::Type{<:Real}) @ Base.MPFR mpfr.jl:478)brainandforce
Metadata
Metadata
Assignees
Labels
designDesign of APIs or of the language itselfDesign of APIs or of the language itselfdocsThis change adds or pertains to documentationThis change adds or pertains to documentation