Skip to content

Commit 71b63f3

Browse files
authored
fewer convert methods for Missing and Nothing (#31602)
And use `typesubtract` instead of subtyping to improve usability by handling undef sparams. Co-Authored-By: Jameson Nash <[email protected]>
1 parent 7b4fa51 commit 71b63f3

File tree

5 files changed

+51
-56
lines changed

5 files changed

+51
-56
lines changed

base/essentials.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ true
163163
"""
164164
function convert end
165165

166+
convert(::Type{Union{}}, x) = throw(MethodError(convert, (Union{}, x)))
166167
convert(::Type{Any}, @nospecialize(x)) = x
167168
convert(::Type{T}, x::T) where {T} = x
168169
convert(::Type{Type}, x::Type) = x # the ssair optimizer is strongly dependent on this method existing to avoid over-specialization

base/missing.jl

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -19,35 +19,35 @@ showerror(io::IO, ex::MissingException) =
1919
print(io, "MissingException: ", ex.msg)
2020

2121
nonmissingtype(::Type{T}) where {T} = Core.Compiler.typesubtract(T, Missing)
22+
function nonmissingtype_checked(T::Type)
23+
R = nonmissingtype(T)
24+
R >: T && error("could not compute non-missing type")
25+
return R
26+
end
2227

23-
for U in (:Nothing, :Missing)
24-
@eval begin
25-
promote_rule(::Type{$U}, ::Type{T}) where {T} = Union{T, $U}
26-
promote_rule(::Type{Union{S,$U}}, ::Type{Any}) where {S} = Any
27-
promote_rule(::Type{Union{S,$U}}, ::Type{T}) where {T,S} = Union{promote_type(T, S), $U}
28-
promote_rule(::Type{Any}, ::Type{$U}) = Any
29-
promote_rule(::Type{$U}, ::Type{Any}) = Any
30-
# This definition is never actually used, but disambiguates the above definitions
31-
promote_rule(::Type{$U}, ::Type{$U}) = $U
32-
end
28+
promote_rule(T::Type{Missing}, S::Type) = Union{S, Missing}
29+
promote_rule(T::Type{Union{Nothing, Missing}}, S::Type) = Union{S, Nothing, Missing}
30+
function promote_rule(T::Type{>:Union{Nothing, Missing}}, S::Type)
31+
R = nonnothingtype(T)
32+
R >: T && return Any
33+
T = R
34+
R = nonmissingtype(T)
35+
R >: T && return Any
36+
T = R
37+
R = promote_type(T, S)
38+
return Union{R, Nothing, Missing}
3339
end
34-
promote_rule(::Type{Union{Nothing, Missing}}, ::Type{Any}) = Any
35-
promote_rule(::Type{Union{Nothing, Missing}}, ::Type{T}) where {T} =
36-
Union{Nothing, Missing, T}
37-
promote_rule(::Type{Union{Nothing, Missing, S}}, ::Type{Any}) where {S} = Any
38-
promote_rule(::Type{Union{Nothing, Missing, S}}, ::Type{T}) where {T,S} =
39-
Union{Nothing, Missing, promote_type(T, S)}
40-
41-
convert(::Type{Union{T, Missing}}, x::Union{T, Missing}) where {T} = x
42-
convert(::Type{Union{T, Missing}}, x) where {T} = convert(T, x)
43-
# To fix ambiguities
44-
convert(::Type{Missing}, ::Missing) = missing
45-
convert(::Type{Union{Nothing, Missing}}, x::Union{Nothing, Missing}) = x
46-
convert(::Type{Union{Nothing, Missing, T}}, x::Union{Nothing, Missing, T}) where {T} = x
47-
convert(::Type{Union{Nothing, Missing}}, x) =
48-
throw(MethodError(convert, (Union{Nothing, Missing}, x)))
49-
# To print more appropriate message than "T not defined"
50-
convert(::Type{Missing}, x) = throw(MethodError(convert, (Missing, x)))
40+
function promote_rule(T::Type{>:Missing}, S::Type)
41+
R = nonmissingtype(T)
42+
R >: T && return Any
43+
T = R
44+
R = promote_type(T, S)
45+
return Union{R, Missing}
46+
end
47+
48+
convert(T::Type{>:Union{Missing, Nothing}}, x) = convert(nonmissingtype_checked(nonnothingtype_checked(T)), x)
49+
convert(T::Type{>:Missing}, x) = convert(nonmissingtype_checked(T), x)
50+
5151

5252
# Comparison operators
5353
==(::Missing, ::Missing) = missing
@@ -108,10 +108,10 @@ round(::Missing, ::RoundingMode=RoundNearest; sigdigits::Integer=0, digits::Inte
108108
round(::Type{>:Missing}, ::Missing, ::RoundingMode=RoundNearest) = missing
109109
round(::Type{T}, ::Missing, ::RoundingMode=RoundNearest) where {T} =
110110
throw(MissingException("cannot convert a missing value to type $T: use Union{$T, Missing} instead"))
111-
round(::Type{T}, x::Any, r::RoundingMode=RoundNearest) where {T>:Missing} = round(nonmissingtype(T), x, r)
111+
round(::Type{T}, x::Any, r::RoundingMode=RoundNearest) where {T>:Missing} = round(nonmissingtype_checked(T), x, r)
112112
# to fix ambiguities
113-
round(::Type{T}, x::Rational, r::RoundingMode=RoundNearest) where {T>:Missing} = round(nonmissingtype(T), x, r)
114-
round(::Type{T}, x::Rational{Bool}, r::RoundingMode=RoundNearest) where {T>:Missing} = round(nonmissingtype(T), x, r)
113+
round(::Type{T}, x::Rational, r::RoundingMode=RoundNearest) where {T>:Missing} = round(nonmissingtype_checked(T), x, r)
114+
round(::Type{T}, x::Rational{Bool}, r::RoundingMode=RoundNearest) where {T>:Missing} = round(nonmissingtype_checked(T), x, r)
115115

116116
# Handle ceil, floor, and trunc separately as they have no RoundingMode argument
117117
for f in (:(ceil), :(floor), :(trunc))
@@ -120,9 +120,9 @@ for f in (:(ceil), :(floor), :(trunc))
120120
($f)(::Type{>:Missing}, ::Missing) = missing
121121
($f)(::Type{T}, ::Missing) where {T} =
122122
throw(MissingException("cannot convert a missing value to type $T: use Union{$T, Missing} instead"))
123-
($f)(::Type{T}, x::Any) where {T>:Missing} = $f(nonmissingtype(T), x)
123+
($f)(::Type{T}, x::Any) where {T>:Missing} = $f(nonmissingtype_checked(T), x)
124124
# to fix ambiguities
125-
($f)(::Type{T}, x::Rational) where {T>:Missing} = $f(nonmissingtype(T), x)
125+
($f)(::Type{T}, x::Rational) where {T>:Missing} = $f(nonmissingtype_checked(T), x)
126126
end
127127
end
128128

base/promotion.jl

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -231,10 +231,6 @@ it for new types as appropriate.
231231
function promote_rule end
232232

233233
promote_rule(::Type{<:Any}, ::Type{<:Any}) = Bottom
234-
# To fix ambiguities
235-
promote_rule(::Type{Any}, ::Type{<:Any}) = Any
236-
promote_rule(::Type{<:Any}, ::Type{Any}) = Any
237-
promote_rule(::Type{Any}, ::Type{Any}) = Any
238234

239235
promote_result(::Type{<:Any},::Type{<:Any},::Type{T},::Type{S}) where {T,S} = (@_inline_meta; promote_type(T,S))
240236
# If no promote_rule is defined, both directions give Bottom. In that

base/some.jl

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,26 @@ struct Some{T}
1313
end
1414

1515
promote_rule(::Type{Some{T}}, ::Type{Some{S}}) where {T, S<:T} = Some{T}
16-
promote_rule(::Type{Some{T}}, ::Type{Nothing}) where {T} = Union{Some{T}, Nothing}
1716

18-
convert(::Type{Some{T}}, x::Some) where {T} = Some{T}(convert(T, x.value))
19-
convert(::Type{Some{T}}, x::Some{T}) where {T} = x
20-
convert(::Type{Union{Some{T}, Nothing}}, x::Some) where {T} = convert(Some{T}, x)
17+
nonnothingtype(::Type{T}) where {T} = Core.Compiler.typesubtract(T, Nothing)
18+
promote_rule(T::Type{Nothing}, S::Type) = Union{S, Nothing}
19+
function promote_rule(T::Type{>:Nothing}, S::Type)
20+
R = nonnothingtype(T)
21+
R >: T && return Any
22+
T = R
23+
R = promote_type(T, S)
24+
return Union{R, Nothing}
25+
end
2126

22-
convert(::Type{Union{T, Nothing}}, x::Union{T, Nothing}) where {T} = x
23-
convert(::Type{Union{T, Nothing}}, x::Any) where {T} = convert(T, x)
24-
convert(::Type{Nothing}, x::Nothing) = nothing
25-
convert(::Type{Nothing}, x::Any) = throw(MethodError(convert, (Nothing, x)))
27+
function nonnothingtype_checked(T::Type)
28+
R = nonnothingtype(T)
29+
R >: T && error("could not compute non-nothing type")
30+
return R
31+
end
32+
33+
convert(T::Type{>:Nothing}, x) = convert(nonnothingtype_checked(T), x)
34+
convert(::Type{Some{T}}, x::Some{T}) where {T} = x
35+
convert(::Type{Some{T}}, x::Some) where {T} = Some{T}(convert(T, x.value))
2636

2737
function show(io::IO, x::Some)
2838
if get(io, :typeinfo, Any) == typeof(x)

test/ambiguous.jl

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -283,23 +283,11 @@ end
283283
pop!(need_to_handle_undef_sparam, which(Base.byteenv, (Union{AbstractArray{Pair{T}, 1}, Tuple{Vararg{Pair{T}}}} where T<:AbstractString,)))
284284
pop!(need_to_handle_undef_sparam, which(Base._cat, (Any, SparseArrays._TypedDenseConcatGroup{T} where T)))
285285
pop!(need_to_handle_undef_sparam, which(Base.float, Tuple{AbstractArray{Union{Missing, T},N} where {T, N}}))
286-
pop!(need_to_handle_undef_sparam, which(Base.convert, Tuple{Type{Union{Missing, T}} where T, Any}))
287-
pop!(need_to_handle_undef_sparam, which(Base.promote_rule, Tuple{Type{Union{Nothing, S}} where S, Type{T} where T}))
288-
pop!(need_to_handle_undef_sparam, which(Base.promote_rule, Tuple{Type{Union{Missing, S}} where S, Type{T} where T}))
289-
pop!(need_to_handle_undef_sparam, which(Base.promote_rule, Tuple{Type{Union{Missing, Nothing, S}} where S, Type{T} where T}))
290286
pop!(need_to_handle_undef_sparam, which(Base.zero, Tuple{Type{Union{Missing, T}} where T}))
291287
pop!(need_to_handle_undef_sparam, which(Base.one, Tuple{Type{Union{Missing, T}} where T}))
292288
pop!(need_to_handle_undef_sparam, which(Base.oneunit, Tuple{Type{Union{Missing, T}} where T}))
293-
pop!(need_to_handle_undef_sparam, which(Base.convert, (Type{Union{Some{T}, Nothing}} where T, Some)))
294-
pop!(need_to_handle_undef_sparam, which(Base.convert, (Type{Union{T, Nothing}} where T, Some)))
295289
pop!(need_to_handle_undef_sparam, which(Base.convert, Tuple{Type{Tuple{Vararg{Int}}}, Tuple{}}))
296290
pop!(need_to_handle_undef_sparam, which(Base.convert, Tuple{Type{Tuple{Vararg{Int}}}, Tuple{Int8}}))
297-
pop!(need_to_handle_undef_sparam, which(Base.convert, Tuple{Type{Union{Nothing,T}},Union{Nothing,T}} where T))
298-
pop!(need_to_handle_undef_sparam, which(Base.convert, Tuple{Type{Union{Missing,T}},Union{Missing,T}} where T))
299-
pop!(need_to_handle_undef_sparam, which(Base.convert, Tuple{Type{Union{Missing,Nothing,T}},Union{Missing,Nothing,T}} where T))
300-
pop!(need_to_handle_undef_sparam, which(Base.promote_rule, Tuple{Type{Union{Nothing,T}},Type{Any}} where T))
301-
pop!(need_to_handle_undef_sparam, which(Base.promote_rule, Tuple{Type{Union{Missing,T}},Type{Any}} where T))
302-
pop!(need_to_handle_undef_sparam, which(Base.promote_rule, Tuple{Type{Union{Missing,Nothing,T}},Type{Any}} where T))
303291
@test need_to_handle_undef_sparam == Set()
304292
end
305293
end

0 commit comments

Comments
 (0)