Skip to content

Commit 67aa462

Browse files
committed
add typemap filtering option for Union{}
Based on the new morespecific rule for Union{} and method definitions of the specific form `f(..., Type{Union{}}, Vararg)`. If a method definition exists with that specific form, the intersection visitor will ignore all intersections that have that as their only result, saving significant effort when working with lookups involving `Type{<:T}` (which usually ended up mostly ambiguous anyways). Fixes: #33780 This pattern turns out to have still to been making package loading slow. We could keep adding methods following the ambiguity pattern #46000 for the couple specific functions that need it (constructor, eltype, IteratorEltype, IteratorSize, and maybe a couple others) so the internals can detect those and optimize functions that have that method pair. But it seems somewhat odd, convoluted, and non-obvious behavior there. Instead, this breaks all ambiguities in which Union{} is present explicitly in favor of the method with Union{}. This means that when computing method matches, as soon as we see one method definition with Union{}, we can record that the method is the only possible match for that slot. This, in essence, permits creating a rule for dispatch that a TypeVar lower bound must be strictly a supertype of Union{}, but this creates it at the function level, instead of expecting the user to add it to every TypeVar they use to define methods. This also lets us improve the error message for these cases (generally they should error to avoid polluting the inference result), since we can be assured this method will be called, and not result in an ambiguous MethodError instead! Reverts the functional change of #46000
1 parent 44b3d2c commit 67aa462

29 files changed

+319
-150
lines changed

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: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ See also: [`round`](@ref), [`trunc`](@ref), [`oftype`](@ref), [`reinterpret`](@r
311311
function convert end
312312

313313
# ensure this is never ambiguous, and therefore fast for lookup
314-
convert(T::Type{Union{}}, x) = throw(MethodError(convert, (T, x)))
314+
convert(T::Type{Union{}}, x...) = throw(ArgumentError("cannot convert a value to Union{} for assignment"))
315315

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

537537
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...)
538539
cconvert(::Type{<:Ptr}, x) = x # but defer the conversion to Ptr to unsafe_convert
539540
unsafe_convert(::Type{T}, x::T) where {T} = x # unsafe_convert (like convert) defaults to assuming the convert occurred
540541
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()

base/indices.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ particular, [`eachindex`](@ref) creates an iterator whose type depends
9292
on the setting of this trait.
9393
"""
9494
IndexStyle(A::AbstractArray) = IndexStyle(typeof(A))
95-
IndexStyle(::Type{Union{}}) = IndexLinear()
95+
IndexStyle(::Type{Union{}}, slurp...) = IndexLinear()
9696
IndexStyle(::Type{<:AbstractArray}) = IndexCartesian()
9797
IndexStyle(::Type{<:Array}) = IndexLinear()
9898
IndexStyle(::Type{<:AbstractRange}) = IndexLinear()

0 commit comments

Comments
 (0)