mirror of
https://github.com/JuliaLang/julia.git
synced 2026-05-28 03:10:33 +08:00
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: https://github.com/JuliaLang/julia/issues/33780
This pattern turns out to have still to been making package loading
slow. We could keep adding methods following the ambiguity pattern
https://github.com/JuliaLang/julia/pull/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
65 lines
2.6 KiB
Julia
65 lines
2.6 KiB
Julia
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
|
|
|
## numeric/object traits
|
|
# trait for objects that have an ordering
|
|
abstract type OrderStyle end
|
|
struct Ordered <: OrderStyle end
|
|
struct Unordered <: OrderStyle end
|
|
|
|
OrderStyle(instance) = OrderStyle(typeof(instance))
|
|
OrderStyle(::Type{<:Real}) = Ordered()
|
|
OrderStyle(::Type{<:AbstractString}) = Ordered()
|
|
OrderStyle(::Type{Symbol}) = Ordered()
|
|
OrderStyle(::Type{<:Any}) = Unordered()
|
|
OrderStyle(::Type{Union{}}, slurp...) = Ordered()
|
|
|
|
# trait for objects that support arithmetic
|
|
abstract type ArithmeticStyle end
|
|
struct ArithmeticRounds <: ArithmeticStyle end # least significant bits can be lost
|
|
struct ArithmeticWraps <: ArithmeticStyle end # most significant bits can be lost
|
|
struct ArithmeticUnknown <: ArithmeticStyle end
|
|
|
|
ArithmeticStyle(instance) = ArithmeticStyle(typeof(instance))
|
|
ArithmeticStyle(::Type{<:AbstractFloat}) = ArithmeticRounds()
|
|
ArithmeticStyle(::Type{<:Integer}) = ArithmeticWraps()
|
|
ArithmeticStyle(::Type{<:Any}) = ArithmeticUnknown()
|
|
ArithmeticStyle(::Type{Union{}}, slurp...) = ArithmeticUnknown()
|
|
|
|
# trait for objects that support ranges with regular step
|
|
"""
|
|
RangeStepStyle(instance)
|
|
RangeStepStyle(T::Type)
|
|
|
|
Indicate whether an instance or a type supports constructing a range with
|
|
a perfectly regular step or not. A regular step means that
|
|
[`step`](@ref) will always be exactly equal to the difference between two
|
|
subsequent elements in a range, i.e. for a range `r::AbstractRange{T}`:
|
|
```julia
|
|
all(diff(r) .== step(r))
|
|
```
|
|
|
|
When a type `T` always leads to ranges with regular steps, it should
|
|
define the following method:
|
|
```julia
|
|
Base.RangeStepStyle(::Type{<:AbstractRange{<:T}}) = Base.RangeStepRegular()
|
|
```
|
|
This will allow [`hash`](@ref) to use an O(1) algorithm for `AbstractRange{T}`
|
|
objects instead of the default O(N) algorithm (with N the length of the range).
|
|
|
|
In some cases, whether the step will be regular depends not only on the
|
|
element type `T`, but also on the type of the step `S`. In that case, more
|
|
specific methods should be defined:
|
|
```julia
|
|
Base.RangeStepStyle(::Type{<:OrdinalRange{<:T, <:S}}) = Base.RangeStepRegular()
|
|
```
|
|
|
|
By default, all range types are assumed to be `RangeStepIrregular`, except
|
|
ranges with an element type which is a subtype of `Integer`.
|
|
"""
|
|
abstract type RangeStepStyle end
|
|
struct RangeStepRegular <: RangeStepStyle end # range with regular step
|
|
struct RangeStepIrregular <: RangeStepStyle end # range with rounding error
|
|
RangeStepStyle(::Type{Union{}}, slurp...) = RangeStepIrregular()
|
|
|
|
RangeStepStyle(instance) = RangeStepStyle(typeof(instance))
|