Files
julia/base/traits.jl
Jameson Nash 67aa46273a 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: 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
2023-04-23 20:42:39 -04:00

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))