Skip to content

Commit cb1cc27

Browse files
authored
Merge pull request #49470 from JuliaLang/jn/morespecific-bottom
reland: add morespecific rule for Type{Union{}}
2 parents 2180db1 + 7f4e129 commit cb1cc27

File tree

36 files changed

+371
-159
lines changed

36 files changed

+371
-159
lines changed

NEWS.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ Language changes
88
----------------
99

1010
* When a task forks a child, the parent task's task-local RNG (random number generator) is no longer affected. The seeding of child based on the parent task also takes a more disciplined approach to collision resistance, using a design based on the SplitMix and DotMix splittable RNG schemes ([#49110]).
11+
* A new morespecific rule for methods resolves ambiguities containing Union{} in favor of
12+
the method defined explicitly to handle the Union{} argument. This makes it possible to
13+
define methods to explicitly handle Union{} without the ambiguities that commonly would
14+
result previously. This also lets the runtime optimize certain method lookups in a way
15+
that significantly improves load and inference times for heavily overloaded methods that
16+
dispatch on Types (such as traits and constructors).
1117

1218
Compiler/Runtime improvements
1319
-----------------------------

base/abstractarray.jl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,11 +183,13 @@ CartesianIndex{2}
183183
For arrays, this function requires at least Julia 1.2.
184184
"""
185185
keytype(a::AbstractArray) = keytype(typeof(a))
186+
keytype(::Type{Union{}}, slurp...) = eltype(Union{})
186187

187188
keytype(A::Type{<:AbstractArray}) = CartesianIndex{ndims(A)}
188189
keytype(A::Type{<:AbstractVector}) = Int
189190

190191
valtype(a::AbstractArray) = valtype(typeof(a))
192+
valtype(::Type{Union{}}, slurp...) = eltype(Union{})
191193

192194
"""
193195
valtype(T::Type{<:AbstractArray})
@@ -232,7 +234,7 @@ UInt8
232234
```
233235
"""
234236
eltype(::Type) = Any
235-
eltype(::Type{Bottom}) = throw(ArgumentError("Union{} does not have elements"))
237+
eltype(::Type{Bottom}, slurp...) = throw(ArgumentError("Union{} does not have elements"))
236238
eltype(x) = eltype(typeof(x))
237239
eltype(::Type{<:AbstractArray{E}}) where {E} = @isdefined(E) ? E : Any
238240

@@ -268,6 +270,7 @@ julia> ndims(A)
268270
"""
269271
ndims(::AbstractArray{T,N}) where {T,N} = N
270272
ndims(::Type{<:AbstractArray{<:Any,N}}) where {N} = N
273+
ndims(::Type{Union{}}, slurp...) = throw(ArgumentError("Union{} does not have elements"))
271274

272275
"""
273276
length(collection) -> Integer

base/array.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,10 @@ function bitsunionsize(u::Union)
252252
return sz
253253
end
254254

255+
# Deprecate this, as it seems to have no documented meaning and is unused here,
256+
# but is frequently accessed in packages
255257
elsize(@nospecialize _::Type{A}) where {T,A<:Array{T}} = aligned_sizeof(T)
258+
elsize(::Type{Union{}}, slurp...) = 0
256259
sizeof(a::Array) = Core.sizeof(a)
257260

258261
function isassigned(a::Array, i::Int...)

base/arrayshow.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,10 +540,12 @@ end
540540
# returning Any, as this would cause incorrect printing in e.g. `Vector[Any[1]]`,
541541
# because eltype(Vector) == Any so `Any` wouldn't be printed in `Any[1]`)
542542
typeinfo_eltype(typeinfo) = nothing # element type not precisely known
543+
typeinfo_eltype(typeinfo::Type{Union{}}, slurp...) = nothing
543544
typeinfo_eltype(typeinfo::Type{<:AbstractArray{T}}) where {T} = eltype(typeinfo)
544545
typeinfo_eltype(typeinfo::Type{<:AbstractDict{K,V}}) where {K,V} = eltype(typeinfo)
545546
typeinfo_eltype(typeinfo::Type{<:AbstractSet{T}}) where {T} = eltype(typeinfo)
546547

548+
547549
# types that can be parsed back accurately from their un-decorated representations
548550
function typeinfo_implicit(@nospecialize(T))
549551
if T === Float64 || T === Int || T === Char || T === String || T === Symbol ||

base/boot.jl

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -258,9 +258,17 @@ UnionAll(v::TypeVar, @nospecialize(t)) = ccall(:jl_type_unionall, Any, (Any, Any
258258

259259
const Vararg = ccall(:jl_toplevel_eval_in, Any, (Any, Any), Core, _expr(:new, TypeofVararg))
260260

261-
# let the compiler assume that calling Union{} as a constructor does not need
262-
# to be considered ever (which comes up often as Type{<:T})
263-
Union{}(a...) = throw(MethodError(Union{}, a))
261+
# dispatch token indicating a kwarg (keyword sorter) call
262+
function kwcall end
263+
# deprecated internal functions:
264+
kwfunc(@nospecialize(f)) = kwcall
265+
kwftype(@nospecialize(t)) = typeof(kwcall)
266+
267+
# Let the compiler assume that calling Union{} as a constructor does not need
268+
# to be considered ever (which comes up often as Type{<:T} inference, and
269+
# occasionally in user code from eltype).
270+
Union{}(a...) = throw(ArgumentError("cannot construct a value of type Union{} for return result"))
271+
kwcall(kwargs, ::Type{Union{}}, a...) = Union{}(a...)
264272

265273
Expr(@nospecialize args...) = _expr(args...)
266274

@@ -369,12 +377,6 @@ include(m::Module, fname::String) = ccall(:jl_load_, Any, (Any, Any), m, fname)
369377

370378
eval(m::Module, @nospecialize(e)) = ccall(:jl_toplevel_eval_in, Any, (Any, Any), m, e)
371379

372-
# dispatch token indicating a kwarg (keyword sorter) call
373-
function kwcall end
374-
# deprecated internal functions:
375-
kwfunc(@nospecialize(f)) = kwcall
376-
kwftype(@nospecialize(t)) = typeof(kwcall)
377-
378380
mutable struct Box
379381
contents::Any
380382
Box(@nospecialize(x)) = new(x)

base/broadcast.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ that you may be able to leverage; see the
3434
"""
3535
abstract type BroadcastStyle end
3636

37+
struct Unknown <: BroadcastStyle end
38+
BroadcastStyle(::Type{Union{}}, slurp...) = Unknown() # ambiguity resolution
39+
3740
"""
3841
`Broadcast.Style{C}()` defines a [`BroadcastStyle`](@ref) signaling through the type
3942
parameter `C`. You can use this as an alternative to creating custom subtypes of `BroadcastStyle`,
@@ -45,9 +48,6 @@ struct Style{T} <: BroadcastStyle end
4548

4649
BroadcastStyle(::Type{<:Tuple}) = Style{Tuple}()
4750

48-
struct Unknown <: BroadcastStyle end
49-
BroadcastStyle(::Type{Union{}}) = Unknown() # ambiguity resolution
50-
5151
"""
5252
`Broadcast.AbstractArrayStyle{N} <: BroadcastStyle` is the abstract supertype for any style
5353
associated with an `AbstractArray` type.

base/complex.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ Float64
120120
real(T::Type) = typeof(real(zero(T)))
121121
real(::Type{T}) where {T<:Real} = T
122122
real(C::Type{<:Complex}) = fieldtype(C, 1)
123+
real(::Type{Union{}}, slurp...) = Union{}(im)
123124

124125
"""
125126
isreal(x) -> Bool

base/essentials.jl

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -310,13 +310,8 @@ See also: [`round`](@ref), [`trunc`](@ref), [`oftype`](@ref), [`reinterpret`](@r
310310
"""
311311
function convert end
312312

313-
# make convert(::Type{<:Union{}}, x::T) intentionally ambiguous for all T
314-
# so it will never get called or invalidated by loading packages
315-
# with carefully chosen types that won't have any other convert methods defined
316-
convert(T::Type{<:Core.IntrinsicFunction}, x) = throw(MethodError(convert, (T, x)))
317-
convert(T::Type{<:Nothing}, x) = throw(MethodError(convert, (Nothing, x)))
318-
convert(::Type{T}, x::T) where {T<:Core.IntrinsicFunction} = x
319-
convert(::Type{T}, x::T) where {T<:Nothing} = x
313+
# ensure this is never ambiguous, and therefore fast for lookup
314+
convert(T::Type{Union{}}, x...) = throw(ArgumentError("cannot convert a value to Union{} for assignment"))
320315

321316
convert(::Type{Type}, x::Type) = x # the ssair optimizer is strongly dependent on this method existing to avoid over-specialization
322317
# in the absence of inlining-enabled
@@ -540,6 +535,7 @@ Neither `convert` nor `cconvert` should take a Julia object and turn it into a `
540535
function cconvert end
541536

542537
cconvert(T::Type, x) = x isa T ? x : convert(T, x) # do the conversion eagerly in most cases
538+
cconvert(::Type{Union{}}, x...) = convert(Union{}, x...)
543539
cconvert(::Type{<:Ptr}, x) = x # but defer the conversion to Ptr to unsafe_convert
544540
unsafe_convert(::Type{T}, x::T) where {T} = x # unsafe_convert (like convert) defaults to assuming the convert occurred
545541
unsafe_convert(::Type{T}, x::T) where {T<:Ptr} = x # to resolve ambiguity with the next method

base/float.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ Float64
310310
"""
311311
float(::Type{T}) where {T<:Number} = typeof(float(zero(T)))
312312
float(::Type{T}) where {T<:AbstractFloat} = T
313+
float(::Type{Union{}}, slurp...) = Union{}(0.0)
313314

314315
"""
315316
unsafe_trunc(T, x)

base/generator.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,13 @@ Base.HasLength()
9292
"""
9393
IteratorSize(x) = IteratorSize(typeof(x))
9494
IteratorSize(::Type) = HasLength() # HasLength is the default
95+
IteratorSize(::Type{Union{}}, slurp...) = throw(ArgumentError("Union{} does not have elements"))
96+
IteratorSize(::Type{Any}) = SizeUnknown()
9597

9698
IteratorSize(::Type{<:Tuple}) = HasLength()
9799
IteratorSize(::Type{<:AbstractArray{<:Any,N}}) where {N} = HasShape{N}()
98100
IteratorSize(::Type{Generator{I,F}}) where {I,F} = IteratorSize(I)
99101

100-
IteratorSize(::Type{Any}) = SizeUnknown()
101-
102102
haslength(iter) = IteratorSize(iter) isa Union{HasShape, HasLength}
103103

104104
abstract type IteratorEltype end
@@ -126,7 +126,7 @@ Base.HasEltype()
126126
"""
127127
IteratorEltype(x) = IteratorEltype(typeof(x))
128128
IteratorEltype(::Type) = HasEltype() # HasEltype is the default
129+
IteratorEltype(::Type{Union{}}, slurp...) = throw(ArgumentError("Union{} does not have elements"))
130+
IteratorEltype(::Type{Any}) = EltypeUnknown()
129131

130132
IteratorEltype(::Type{Generator{I,T}}) where {I,T} = EltypeUnknown()
131-
132-
IteratorEltype(::Type{Any}) = EltypeUnknown()

0 commit comments

Comments
 (0)