From daed82028978f0ac96dac9688471352214f71d18 Mon Sep 17 00:00:00 2001 From: Chris Rackauckas Date: Mon, 28 Feb 2022 19:37:56 -0500 Subject: [PATCH 01/11] Revert missing to nothings https://github.com/JuliaArrays/ArrayInterface.jl/pull/232 was found to be a huge mistake. For interface checks, you want `nothing` instead of `missing` because you want to handle the cases. The issue with `missing` is that it propagates, `missing + 1 == missing`. We don't want that here, we want clear and precise error messages at the spot where the `nothing` is found if it's not supposed to be there and it's supposed to be handled. That is antithetical to most of its usage here. So this is a strong revert with a breaking update, which should fix downstream libraries (LoopVectorization, OrdinaryDiffEq, etc.) which were never received the proper downstream PRs from the original change anyways. --- Project.toml | 2 +- docs/src/index.md | 14 +++--- src/ArrayInterface.jl | 14 +++--- src/axes.jl | 18 ++++---- src/dimensions.jl | 6 +-- src/indexing.jl | 2 +- src/ranges.jl | 40 ++++++++--------- src/size.jl | 10 ++--- src/stridelayout.jl | 102 +++++++++++++++++++++--------------------- test/array_index.jl | 2 +- test/dimensions.jl | 2 +- test/ranges.jl | 12 ++--- test/runtests.jl | 72 ++++++++++++++--------------- 13 files changed, 148 insertions(+), 148 deletions(-) diff --git a/Project.toml b/Project.toml index 64dd29bbc..0cd9808fe 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "ArrayInterface" uuid = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9" -version = "4.0.4" +version = "5.0.0" [deps] Compat = "34da2185-b29b-5c13-b0c7-acf172513d20" diff --git a/docs/src/index.md b/docs/src/index.md index 94c8f7e90..ea0f196e1 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -44,7 +44,7 @@ julia> ArrayInterface.size(a) (static(1), 3) julia> ArrayInterface.known_size(typeof(a)) -(1, missing) +(1, nothing) ``` @@ -62,8 +62,8 @@ Methods should avoid forcing conversion to static sizes when dynamic sizes could Fore example, `fxn(x) = _fxn(Static.static(ArrayInterface.size(x)), x)` would result in dynamic dispatch if `x` is an instance of `Matrix`. Additionally, `ArrayInterface.size` should only be used outside of generated functions to avoid possible world age issues. -Generally, `ArrayInterface.size` uses the return of `known_size` to form a static value for those dimensions with known length and only queries dimensions corresponding to `missing`. -For example, the previous example had a known size of `(1, missing)`. +Generally, `ArrayInterface.size` uses the return of `known_size` to form a static value for those dimensions with known length and only queries dimensions corresponding to `nothing`. +For example, the previous example had a known size of `(1, nothing)`. Therefore, `ArrayInterface.size` would have compile time information about the first dimension returned as `static(1)` and would only look up the size of the second dimension at run time. This means the above example `ArrayInterface.size(a)` would lower to code similar to this at compile time: `Static.StaticInt(1), Base.arraysize(x, 1)`. Generic support for `ArrayInterface.known_size` relies on calling `known_length` for each type returned from `axes_types`. @@ -108,13 +108,13 @@ ArrayInterface.dimnames(::StaticDimnames{dnames}) where {dnames} = static(dnames struct DynamicDimnames{N} dimnames::NTuple{N,Symbol} end -ArrayInterface.known_dimnames(::Type{DynamicDimnames{N}}) where {N} = ntuple(_-> missing, Val(N)) +ArrayInterface.known_dimnames(::Type{DynamicDimnames{N}}) where {N} = ntuple(_-> nothing, Val(N)) ArrayInterface.dimnames(x::DynamicDimnames) = getfield(x, :dimnames) ``` -Notice that `DynamicDimnames` returns `missing` instead of a symbol for each dimension. -This indicates dimension names are present for `DynamicDimnames` but that information is missing at compile time. +Notice that `DynamicDimnames` returns `nothing` instead of a symbol for each dimension. +This indicates dimension names are present for `DynamicDimnames` but that information is nothing at compile time. Dimension names should be appropriately propagated between nested arrays using `ArrayInterface.to_parent_dims`. This allows types such as `SubArray` and `PermutedDimsArray` to work with named dimensions. @@ -166,7 +166,7 @@ using ArrayInterface: axes_types, parent_type, to_dims for dim in 1:ndims(A) # offset relative to parent array O = relative_known_offsets(A, dim) - if O === missing # offset is not known at compile time and is an `Int` + if O === nothing # offset is not known at compile time and is an `Int` push!(out.args, :(IdOffsetRange{Int, axes_types($P, $(static(dim)))})) else # offset is known, therefore it is a `StaticInt` push!(out.args, :(IdOffsetRange{StaticInt{$O}, axes_types($P, $(static(dim))})) diff --git a/src/ArrayInterface.jl b/src/ArrayInterface.jl index 6f8c5918c..8c4e122b8 100644 --- a/src/ArrayInterface.jl +++ b/src/ArrayInterface.jl @@ -81,10 +81,10 @@ buffer(x::SparseMatrixCSC) = getfield(x, :nzval) buffer(x::SparseVector) = getfield(x, :nzval) """ - known_length(::Type{T}) -> Union{Int,Missing} + known_length(::Type{T}) -> Union{Int,Nothing} If `length` of an instance of type `T` is known at compile time, return it. -Otherwise, return `missing`. +Otherwise, return `nothing`. """ known_length(x) = known_length(typeof(x)) known_length(::Type{<:NamedTuple{L}}) where {L} = length(L) @@ -94,7 +94,7 @@ known_length(::Type{<:Number}) = 1 known_length(::Type{<:AbstractCartesianIndex{N}}) where {N} = N known_length(::Type{T}) where {T} = _maybe_known_length(Base.IteratorSize(T), T) _maybe_known_length(::Base.HasShape, ::Type{T}) where {T} = prod(known_size(T)) -_maybe_known_length(::Base.IteratorSize, ::Type) = missing +_maybe_known_length(::Base.IteratorSize, ::Type) = nothing function known_length(::Type{<:Iterators.Flatten{I}}) where {I} known_length(I) * known_length(eltype(I)) end @@ -415,10 +415,10 @@ Indicates the most efficient way to access elements from the collection in low-l For `GPUArrays`, will return `ArrayInterface.GPU()`. For `AbstractArray` supporting a `pointer` method, returns `ArrayInterface.CPUPointer()`. For other `AbstractArray`s and `Tuple`s, returns `ArrayInterface.CPUIndex()`. -Otherwise, returns `missing`. +Otherwise, returns `nothing`. """ device(A) = device(typeof(A)) -device(::Type) = missing +device(::Type) = nothing device(::Type{<:Tuple}) = CPUTuple() device(::Type{T}) where {T<:Array} = CPUPointer() device(::Type{T}) where {T<:AbstractArray} = _device(has_parent(T), T) @@ -597,7 +597,7 @@ end function Base.length(A::AbstractArray2) len = known_length(A) - if len === missing + if len === nothing return Int(prod(size(A))) else return Int(len) @@ -1136,7 +1136,7 @@ function __init__() Static.eachop_tuple(_offset_axis_type, Static.nstatic(Val(ndims(T))), ArrayInterface.parent_type(T)) end function ArrayInterface.known_offsets(::Type{A}) where {A<:OffsetArrays.OffsetArray} - ntuple(identity -> missing, Val(ndims(A))) + ntuple(identity -> nothing, Val(ndims(A))) end function ArrayInterface.offsets(A::OffsetArrays.OffsetArray) map(+, ArrayInterface.offsets(parent(A)), relative_offsets(A)) diff --git a/src/axes.jl b/src/axes.jl index 012e085be..8c49780ac 100644 --- a/src/axes.jl +++ b/src/axes.jl @@ -41,7 +41,7 @@ function axes_types(::Type{T}) where {T<:PermutedDimsArray} eachop_tuple(field_type, to_parent_dims(T), axes_types(parent_type(T))) end function axes_types(::Type{T}) where {T<:AbstractRange} - if known_length(T) === missing + if known_length(T) === nothing return Tuple{OneTo{Int}} else return Tuple{SOneTo{known_length(T)}} @@ -62,7 +62,7 @@ end function _non_reshaped_axis_type(::Type{A}, d::StaticInt{D}) where {A,D} paxis = axes_types(parent_type(A), d) if D === 1 - if known_length(paxis) === missing + if known_length(paxis) === nothing return paxis else return SOneTo{div(known_length(paxis) * sizeof(eltype(parent_type(A))), sizeof(eltype(A)))} @@ -191,7 +191,7 @@ end # For now we just make sure the linear elements are accurate. parent_type(::Type{LazyAxis{:,P}}) where {P<:Array} = OneTo{Int} @inline function parent_type(::Type{LazyAxis{:,P}}) where {P} - if known_length(P) === missing + if known_length(P) === nothing return OptionallyStaticUnitRange{StaticInt{1},Int} else return SOneTo{known_length(P)} @@ -208,14 +208,14 @@ known_first(::Type{LazyAxis{N,P}}) where {N,P} = known_offsets(P, static(N)) known_first(::Type{LazyAxis{:,P}}) where {P} = 1 Base.firstindex(x::LazyAxis) = first(x) @inline function Base.first(x::LazyAxis{N})::Int where {N} - if known_first(x) === missing + if known_first(x) === nothing return Int(offsets(parent(x), static(N))) else return Int(known_first(x)) end end @inline function Base.first(x::LazyAxis{:})::Int - if known_first(x) === missing + if known_first(x) === nothing return first(parent(x)) else return known_first(x) @@ -225,20 +225,20 @@ known_last(::Type{LazyAxis{N,P}}) where {N,P} = known_last(axes_types(P, static( known_last(::Type{LazyAxis{:,P}}) where {P} = known_length(P) Base.lastindex(x::LazyAxis) = last(x) Base.last(x::LazyAxis) = _last(known_last(x), x) -_last(::Missing, x) = last(parent(x)) +_last(::Nothing, x) = last(parent(x)) _last(N::Int, x) = N known_length(::Type{LazyAxis{N,P}}) where {N,P} = known_size(P, static(N)) known_length(::Type{LazyAxis{:,P}}) where {P} = known_length(P) @inline function Base.length(x::LazyAxis{N})::Int where {N} - if known_length(x) === missing + if known_length(x) === nothing return size(getfield(x, :parent), static(N)) else return known_length(x) end end @inline function Base.length(x::LazyAxis{:})::Int - if known_length(x) === missing + if known_length(x) === nothing return length(parent(x)) else return known_length(x) @@ -254,7 +254,7 @@ Base.axes1(x::Slice{<:LazyAxis}) = indices(parent(x.indices)) Base.to_shape(x::LazyAxis) = length(x) @inline function Base.checkindex(::Type{Bool}, x::LazyAxis, i::Integer) - if known_first(x) === missing || known_last(x) === missing + if known_first(x) === nothing || known_last(x) === nothing return checkindex(Bool, parent(x), i) else # everything is static so we don't have to retrieve the axis return (!(known_first(x) > i) || !(known_last(x) < i)) diff --git a/src/dimensions.jl b/src/dimensions.jl index 41e6d403e..105ef5fe2 100644 --- a/src/dimensions.jl +++ b/src/dimensions.jl @@ -160,8 +160,8 @@ _is_named(x::NTuple{N,Symbol}) where {N} = x !== _nunderscore(Val(N)) _is_named(::Any) = true """ - known_dimnames(::Type{T}) -> Tuple{Vararg{Union{Symbol,Missing}}} - known_dimnames(::Type{T}, dim::Union{Int,StaticInt}) -> Union{Symbol,Missing} + known_dimnames(::Type{T}) -> Tuple{Vararg{Union{Symbol,Nothing}}} + known_dimnames(::Type{T}, dim::Union{Int,StaticInt}) -> Union{Symbol,Nothing} Return the names of the dimensions for `x`. `:_` is used to indicate a dimension does not have a name. @@ -229,7 +229,7 @@ An error is thrown if any keywords are used which do not occur in `nda`'s names. 1. parse into static dimnension names and key words. 2. find each dimnames in key words -3. if missing is found use Colon() +3. if nothing is found use Colon() 4. if (ndims - ncolon) === nkwargs then all were found, else error =# @generated function find_all_dimnames(x::Tuple{Vararg{Any,ND}}, nd::Tuple{Vararg{Any,NI}}, inds::Tuple, default) where {ND,NI} diff --git a/src/indexing.jl b/src/indexing.jl index 434c44755..794c64749 100644 --- a/src/indexing.jl +++ b/src/indexing.jl @@ -277,7 +277,7 @@ previously executed `to_index(old_axis, arg) -> index`. `to_axis` assumes that """ @inline function to_axis(axis, inds) if !can_change_size(axis) && - (known_length(inds) !== missing && known_length(axis) === known_length(inds)) + (known_length(inds) !== nothing && known_length(axis) === known_length(inds)) return axis else return to_axis(IndexStyle(axis), axis, inds) diff --git a/src/ranges.jl b/src/ranges.jl index 3bf119956..0ec0988be 100644 --- a/src/ranges.jl +++ b/src/ranges.jl @@ -1,16 +1,16 @@ _cartesian_index(i::Tuple{Vararg{Int}}) = CartesianIndex(i) -_cartesian_index(::Any) = missing +_cartesian_index(::Any) = nothing """ - known_first(::Type{T}) -> Union{Int,Missing} + known_first(::Type{T}) -> Union{Int,Nothing} If `first` of an instance of type `T` is known at compile time, return it. -Otherwise, return `missing`. +Otherwise, return `nothing`. ```julia julia> ArrayInterface.known_first(typeof(1:4)) -missing +nothing julia> ArrayInterface.known_first(typeof(Base.OneTo(4))) 1 @@ -19,7 +19,7 @@ julia> ArrayInterface.known_first(typeof(Base.OneTo(4))) known_first(x) = known_first(typeof(x)) function known_first(::Type{T}) where {T} if parent_type(T) <: T - return missing + return nothing else return known_first(parent_type(T)) end @@ -30,14 +30,14 @@ function known_first(::Type{T}) where {N,R,T<:CartesianIndices{N,R}} end """ - known_last(::Type{T}) -> Union{Int,Missing} + known_last(::Type{T}) -> Union{Int,Nothing} If `last` of an instance of type `T` is known at compile time, return it. -Otherwise, return `missing`. +Otherwise, return `nothing`. ```julia julia> ArrayInterface.known_last(typeof(1:4)) -missing +nothing julia> ArrayInterface.known_first(typeof(static(1):static(4))) 4 @@ -47,7 +47,7 @@ julia> ArrayInterface.known_first(typeof(static(1):static(4))) known_last(x) = known_last(typeof(x)) function known_last(::Type{T}) where {T} if parent_type(T) <: T - return missing + return nothing else return known_last(parent_type(T)) end @@ -57,14 +57,14 @@ function known_last(::Type{T}) where {N,R,T<:CartesianIndices{N,R}} end """ - known_step(::Type{T}) -> Union{Int,Missing} + known_step(::Type{T}) -> Union{Int,Nothing} If `step` of an instance of type `T` is known at compile time, return it. -Otherwise, return `missing`. +Otherwise, return `nothing`. ```julia julia> ArrayInterface.known_step(typeof(1:2:8)) -missing +nothing julia> ArrayInterface.known_step(typeof(1:4)) 1 @@ -74,7 +74,7 @@ julia> ArrayInterface.known_step(typeof(1:4)) known_step(x) = known_step(typeof(x)) function known_step(::Type{T}) where {T} if parent_type(T) <: T - return missing + return nothing else return known_step(parent_type(T)) end @@ -215,21 +215,21 @@ known_last(::Type{<:OptionallyStaticUnitRange{<:Any,StaticInt{L}}}) where {L} = known_last(::Type{<:OptionallyStaticStepRange{<:Any,<:Any,StaticInt{L}}}) where {L} = L::Int @inline function Base.first(r::OptionallyStaticRange)::Int - if known_first(r) === missing + if known_first(r) === nothing return getfield(r, :start) else return known_first(r) end end function Base.step(r::OptionallyStaticStepRange)::Int - if known_step(r) === missing + if known_step(r) === nothing return getfield(r, :step) else return known_step(r) end end @inline function Base.last(r::OptionallyStaticRange)::Int - if known_last(r) === missing + if known_last(r) === nothing return getfield(r, :stop) else return known_last(r) @@ -306,9 +306,9 @@ end @noinline unequal_error(x,y) = @assert false "Unequal Indices: x == $x != $y == y" @inline check_equal(x, y) = x == y || unequal_error(x,y) -_try_static(::Missing, ::Missing) = missing -_try_static(x::Int, ::Missing) = x -_try_static(::Missing, y::Int) = y +_try_static(::Nothing, ::Nothing) = nothing +_try_static(x::Int, ::Nothing) = x +_try_static(::Nothing, y::Int) = y @inline _try_static(::StaticInt{N}, ::StaticInt{N}) where {N} = StaticInt{N}() @inline function _try_static(::StaticInt{M}, ::StaticInt{N}) where {M,N} @assert false "Unequal Indices: StaticInt{$M}() != StaticInt{$N}()" @@ -330,7 +330,7 @@ Base.lastindex(x::OptionallyStaticRange) = length(x) end end Base.length(r::OptionallyStaticStepRange) = _range_length(first(r), step(r), last(r)) -_range_length(start, s, stop) = missing +_range_length(start, s, stop) = nothing @inline function _range_length(start::Int, s::Int, stop::Int) if s > 0 if stop < start # isempty diff --git a/src/size.jl b/src/size.jl index 1761b8d09..1d3da2d0a 100644 --- a/src/size.jl +++ b/src/size.jl @@ -56,7 +56,7 @@ size(a::Array, dim::Integer) = Base.arraysize(a, convert(Int, dim)) function size(a::A, dim::Integer) where {A} if parent_type(A) <: A len = known_size(A, dim) - if len === missing + if len === nothing return Int(length(axes(a, dim))) else return StaticInt(len) @@ -77,10 +77,10 @@ size(x::Iterators.Zip) = Static.reduce_tup(promote_shape, map(size, getfield(x, """ known_size(::Type{T}) -> Tuple - known_size(::Type{T}, dim) -> Union{Int,Missing} + known_size(::Type{T}, dim) -> Union{Int,Nothing} Returns the size of each dimension of `A` or along dimension `dim` of `A` that is known at -compile time. If a dimension does not have a known size along a dimension then `missing` is +compile time. If a dimension does not have a known size along a dimension then `nothing` is returned in its position. """ known_size(x) = known_size(typeof(x)) @@ -98,10 +98,10 @@ end # 1. `Zip` doesn't check that its collections are compatible (same size) at construction, # but we assume as much b/c otherwise it will error while iterating. So we promote to the -# known size if matching a `Missing` and `Int` size. +# known size if matching a `Nothing` and `Int` size. # 2. `promote_shape(::Tuple{Vararg{CanonicalInt}}, ::Tuple{Vararg{CanonicalInt}})` promotes # trailing dimensions (which must be of size 1), to `static(1)`. We want to stick to -# `Missing` and `Int` types, so we do one last pass to ensure everything is dynamic +# `Nothing` and `Int` types, so we do one last pass to ensure everything is dynamic @inline function known_size(::Type{<:Iterators.Zip{T}}) where {T} dynamic(reduce_tup(_promote_shape, eachop(_unzip_size, nstatic(Val(known_length(T))), T))) end diff --git a/src/stridelayout.jl b/src/stridelayout.jl index c54cd027b..f765b6c3f 100644 --- a/src/stridelayout.jl +++ b/src/stridelayout.jl @@ -21,10 +21,10 @@ end """ known_offsets(::Type{T}) -> Tuple - known_offsets(::Type{T}, dim) -> Union{Int,Missing} + known_offsets(::Type{T}, dim) -> Union{Int,Nothing} Returns a tuple of offset values known at compile time. If the offset of a given axis is -not known at compile time `missing` is returned its position. +not known at compile time `nothing` is returned its position. """ known_offsets(x, dim) = known_offsets(typeof(x), dim) known_offsets(::Type{T}, dim) where {T} = known_offsets(T, to_dims(T, dim)) @@ -58,7 +58,7 @@ offsets(x::StrideIndex) = getfield(x, :offsets) offsets(x) = eachop(_offsets, nstatic(Val(ndims(x))), x) function _offsets(x::X, dim::StaticInt{D}) where {X,D} start = known_first(axes_types(X, dim)) - if start === missing + if start === nothing return first(axes(x, dim)) else return static(start) @@ -69,7 +69,7 @@ end @inline offsets(x::StrideIndex, ::StaticInt{dim}) where {dim} = getfield(offsets(x), dim) """ - known_offset1(::Type{T}) -> Union{Int,Missing} + known_offset1(::Type{T}) -> Union{Int,Nothing} Returns the linear offset of array `x` if known at compile time. """ @@ -89,7 +89,7 @@ Returns the offset of the linear indices for `x`. """ @inline function offset1(x::X) where {X} o1 = known_offset1(X) - if o1 === missing + if o1 === nothing if ndims(X) === 0 return 1 else @@ -105,14 +105,14 @@ end Returns the axis of an array of type `T` containing contiguous data. If no axis is contiguous, it returns a `StaticInt{-1}`. -If unknown, it returns `missing`. +If unknown, it returns `nothing`. """ contiguous_axis(x) = contiguous_axis(typeof(x)) contiguous_axis(::Type{<:StrideIndex{N,R,C}}) where {N,R,C} = static(C) -contiguous_axis(::Type{<:StrideIndex{N,R,missing}}) where {N,R} = missing +contiguous_axis(::Type{<:StrideIndex{N,R,nothing}}) where {N,R} = nothing function contiguous_axis(::Type{T}) where {T} if parent_type(T) <: T - return missing + return nothing else return contiguous_axis(parent_type(T)) end @@ -123,8 +123,8 @@ contiguous_axis(::Type{<:AbstractRange}) = One() contiguous_axis(::Type{<:Tuple}) = One() function contiguous_axis(::Type{T}) where {T<:VecAdjTrans} c = contiguous_axis(parent_type(T)) - if c === missing - return missing + if c === nothing + return nothing elseif c === One() return StaticInt{2}() else @@ -133,8 +133,8 @@ function contiguous_axis(::Type{T}) where {T<:VecAdjTrans} end function contiguous_axis(::Type{T}) where {T<:MatAdjTrans} c = contiguous_axis(parent_type(T)) - if c === missing - return missing + if c === nothing + return nothing elseif isone(-c) return c else @@ -143,8 +143,8 @@ function contiguous_axis(::Type{T}) where {T<:MatAdjTrans} end function contiguous_axis(::Type{T}) where {T<:PermutedDimsArray} c = contiguous_axis(parent_type(T)) - if c === missing - return missing + if c === nothing + return nothing elseif isone(-c) return c else @@ -152,19 +152,19 @@ function contiguous_axis(::Type{T}) where {T<:PermutedDimsArray} end end function contiguous_axis(::Type{Base.ReshapedArray{T, 1, A, Tuple{}}}) where {T, A} - IfElse.ifelse(is_column_major(A) & is_dense(A), static(1), missing) + IfElse.ifelse(is_column_major(A) & is_dense(A), static(1), nothing) end function contiguous_axis(::Type{Base.ReshapedArray{T, 1, LinearAlgebra.Adjoint{T, A}, Tuple{}}}) where {T, A <: AbstractVector{T}} - IfElse.ifelse(is_column_major(A) & is_dense(A), static(1), missing) + IfElse.ifelse(is_column_major(A) & is_dense(A), static(1), nothing) end function contiguous_axis(::Type{Base.ReshapedArray{T, 1, LinearAlgebra.Transpose{T, A}, Tuple{}}}) where {T, A <: AbstractVector{T}} - IfElse.ifelse(is_column_major(A) & is_dense(A), static(1), missing) + IfElse.ifelse(is_column_major(A) & is_dense(A), static(1), nothing) end function contiguous_axis(::Type{T}) where {T<:SubArray} return _contiguous_axis(T, contiguous_axis(parent_type(T))) end -_contiguous_axis(::Type{A}, ::Missing) where {T,N,P,I,A<:SubArray{T,N,P,I}} = missing +_contiguous_axis(::Type{A}, ::Nothing) where {T,N,P,I,A<:SubArray{T,N,P,I}} = nothing _contiguous_axis(::Type{A}, c::StaticInt{-1}) where {T,N,P,I,A<:SubArray{T,N,P,I}} = c function _contiguous_axis(::Type{A}, c::StaticInt{C}) where {T,N,P,I,A<:SubArray{T,N,P,I},C} if field_type(I, c) <: AbstractUnitRange @@ -174,7 +174,7 @@ function _contiguous_axis(::Type{A}, c::StaticInt{C}) where {T,N,P,I,A<:SubArray elseif field_type(I, c) <: Integer return -One() else - return missing + return nothing end end @@ -184,7 +184,7 @@ function contiguous_axis(::Type{R}) where {T,N,S,A<:Array{S},R<:ReinterpretArray if isbitstype(S) return One() else - return missing + return nothing end end @@ -197,7 +197,7 @@ function contiguous_axis_indicator(::Type{A}) where {D,A<:AbstractArray{<:Any,D} return contiguous_axis_indicator(contiguous_axis(A), Val(D)) end contiguous_axis_indicator(::A) where {A<:AbstractArray} = contiguous_axis_indicator(A) -contiguous_axis_indicator(::Missing, ::Val) = missing +contiguous_axis_indicator(::Nothing, ::Val) = nothing function contiguous_axis_indicator(c::StaticInt{N}, dim::Val{D}) where {N,D} return map(i -> eq(c, i), nstatic(dim)) end @@ -215,7 +215,7 @@ stride_rank(::Type{<:StrideIndex{N,R}}) where {N,R} = static(R) stride_rank(x) = stride_rank(typeof(x)) function stride_rank(::Type{T}) where {T} if parent_type(T) <: T - return missing + return nothing else return stride_rank(parent_type(T)) end @@ -227,7 +227,7 @@ stride_rank(::Type{<:Tuple}) = (One(),) stride_rank(::Type{T}) where {T<:VecAdjTrans} = (StaticInt(2), StaticInt(1)) stride_rank(::Type{T}) where {T<:MatAdjTrans} = _stride_rank(T, stride_rank(parent_type(T))) -_stride_rank(::Type{T}, ::Missing) where {T<:MatAdjTrans} = missing +_stride_rank(::Type{T}, ::Nothing) where {T<:MatAdjTrans} = nothing function _stride_rank(::Type{T}, rank) where {T<:MatAdjTrans} return (getfield(rank, 2), getfield(rank, 1)) end @@ -235,11 +235,11 @@ end function stride_rank(::Type{T},) where {T<:PermutedDimsArray} return _stride_rank(T, stride_rank(parent_type(T))) end -_stride_rank(::Type{T}, ::Missing) where {T<:PermutedDimsArray} = missing +_stride_rank(::Type{T}, ::Nothing) where {T<:PermutedDimsArray} = nothing _stride_rank(::Type{T}, r) where {T<:PermutedDimsArray} = permute(r, to_parent_dims(T)) stride_rank(::Type{T}) where {T<:SubArray} = _stride_rank(T, stride_rank(parent_type(T))) -_stride_rank(::Any, ::Any) = missing +_stride_rank(::Any, ::Any) = nothing _stride_rank(::Type{T}, r::Tuple) where {T<:SubArray} = permute(r, to_parent_dims(T)) stride_rank(x, i) = stride_rank(x)[i] @@ -277,17 +277,17 @@ function stride_rank(::Type{Base.ReshapedArray{T, N, P, Tuple{Vararg{Base.Signed _reshaped_striderank(is_column_major(P), Val{N}(), Val{M}()) end function stride_rank(::Type{Base.ReshapedArray{T, 1, A, Tuple{}}}) where {T, A} - IfElse.ifelse(is_column_major(A) & is_dense(A), (static(1),), missing) + IfElse.ifelse(is_column_major(A) & is_dense(A), (static(1),), nothing) end function stride_rank(::Type{Base.ReshapedArray{T, 1, LinearAlgebra.Adjoint{T, A}, Tuple{}}}) where {T, A <: AbstractVector{T}} - IfElse.ifelse(is_dense(A), (static(1),), missing) + IfElse.ifelse(is_dense(A), (static(1),), nothing) end function stride_rank(::Type{Base.ReshapedArray{T, 1, LinearAlgebra.Transpose{T, A}, Tuple{}}}) where {T, A <: AbstractVector{T}} - IfElse.ifelse(is_dense(A), (static(1),), missing) + IfElse.ifelse(is_dense(A), (static(1),), nothing) end _reshaped_striderank(::True, ::Val{N}, ::Val{0}) where {N} = nstatic(Val(N)) -_reshaped_striderank(_, __, ___) = missing +_reshaped_striderank(_, __, ___) = nothing """ contiguous_batch_size(::Type{T}) -> StaticInt{N} @@ -295,16 +295,16 @@ _reshaped_striderank(_, __, ___) = missing Returns the Base.size of contiguous batches if `!isone(stride_rank(T, contiguous_axis(T)))`. If `isone(stride_rank(T, contiguous_axis(T)))`, then it will return `StaticInt{0}()`. If `contiguous_axis(T) == -1`, it will return `StaticInt{-1}()`. -If unknown, it will return `missing`. +If unknown, it will return `nothing`. """ contiguous_batch_size(x) = contiguous_batch_size(typeof(x)) contiguous_batch_size(::Type{T}) where {T} = _contiguous_batch_size(contiguous_axis(T), stride_rank(T)) -_contiguous_batch_size(_, __) = missing +_contiguous_batch_size(_, __) = nothing function _contiguous_batch_size(::StaticInt{D}, ::R) where {D,R<:Tuple} if R.parameters[D].parameters[1] === 1 return Zero() else - return missing + return nothing end end _contiguous_batch_size(::StaticInt{-1}, ::R) where {R<:Tuple} = -One() @@ -322,7 +322,7 @@ end function contiguous_batch_size(::Type{S}) where {N,NP,T,A<:AbstractArray{T,NP},I,S<:SubArray{T,N,A,I}} return _contiguous_batch_size(S, contiguous_batch_size(A), contiguous_axis(A)) end -_contiguous_batch_size(::Any, ::Any, ::Any) = missing +_contiguous_batch_size(::Any, ::Any, ::Any) = nothing function _contiguous_batch_size(::Type{<:SubArray{T,N,A,I}}, b::StaticInt{B}, c::StaticInt{C}) where {T,N,A,I,B,C} if I.parameters[C] <: AbstractUnitRange return b @@ -338,7 +338,7 @@ contiguous_batch_size(::Type{<:Base.ReinterpretArray{T,N,S,A}}) where {T,N,S,A} Returns `True()` if elements of `A` are stored in column major order. Otherwise returns `False()`. """ is_column_major(A) = is_column_major(stride_rank(A), contiguous_batch_size(A)) -is_column_major(sr::Missing, cbs) = False() +is_column_major(sr::Nothing, cbs) = False() is_column_major(sr::R, cbs) where {R} = _is_column_major(sr, cbs) is_column_major(::AbstractRange) = False() @@ -357,7 +357,7 @@ where `stride_rank(A)[i] + 1 == stride_rank(A)[j]`. dense_dims(x) = dense_dims(typeof(x)) function dense_dims(::Type{T}) where {T} if parent_type(T) <: T - return missing + return nothing else return dense_dims(parent_type(T)) end @@ -370,24 +370,24 @@ dense_dims(::Type{<:AbstractRange}) = (True(),) dense_dims(::Type{<:Tuple}) = (True(),) function dense_dims(::Type{T}) where {T<:VecAdjTrans} dense = dense_dims(parent_type(T)) - if dense === missing - return missing + if dense === nothing + return nothing else return (True(), first(dense)) end end function dense_dims(::Type{T}) where {T<:MatAdjTrans} dense = dense_dims(parent_type(T)) - if dense === missing - return missing + if dense === nothing + return nothing else return (last(dense), first(dense)) end end function dense_dims(::Type{T}) where {T<:PermutedDimsArray} dense = dense_dims(parent_type(T)) - if dense === missing - return missing + if dense === nothing + return nothing else return permute(dense, to_parent_dims(T)) end @@ -402,7 +402,7 @@ if VERSION ≥ v"1.6.0-DEV.1581" end end -_dense_dims(::Type{S}, ::Missing, ::Val{R}) where {R,N,NP,T,A<:AbstractArray{T,NP},I,S<:SubArray{T,N,A,I}} = missing +_dense_dims(::Type{S}, ::Nothing, ::Val{R}) where {R,N,NP,T,A<:AbstractArray{T,NP},I,S<:SubArray{T,N,A,I}} = nothing @generated function _dense_dims( ::Type{S}, ::D, @@ -433,11 +433,11 @@ _dense_dims(::Type{S}, ::Missing, ::Val{R}) where {R,N,NP,T,A<:AbstractArray{T,N push!(dense_tup.args, :(False())) end end - # If n != N, then an axis was indexed by something other than an integer or `AbstractUnitRange`, so we return `missing`. + # If n != N, then an axis was indexed by something other than an integer or `AbstractUnitRange`, so we return `nothing`. if length(dense_tup.args) === N return dense_tup else - return missing + return nothing end end @@ -452,12 +452,12 @@ _is_dense(t::Tuple{True}) = True() _is_dense(t::Tuple{}) = True() -_reshaped_dense_dims(_, __, ___, ____) = missing +_reshaped_dense_dims(_, __, ___, ____) = nothing function _reshaped_dense_dims(dense::D, ::True, ::Val{N}, ::Val{0}) where {D,N} if all(dense) return _all_dense(Val{N}()) else - return missing + return nothing end end function _reshaped_dense_dims(dense::Tuple{Static.False}, ::True, ::Val{N}, ::Val{0}) where {N} @@ -466,10 +466,10 @@ end """ known_strides(::Type{T}) -> Tuple - known_strides(::Type{T}, dim) -> Union{Int,Missing} + known_strides(::Type{T}, dim) -> Union{Int,Nothing} Returns the strides of array `A` known at compile time. Any strides that are not known at -compile time are represented by `missing`. +compile time are represented by `nothing`. """ known_strides(x, dim) = known_strides(typeof(x), dim) known_strides(::Type{T}, dim) where {T} = known_strides(T, to_dims(T, dim)) @@ -624,7 +624,7 @@ function strides(A::SubArray) end maybe_static_step(x::AbstractRange) = static_step(x) -maybe_static_step(_) = missing +maybe_static_step(_) = nothing @generated function size_to_strides(sz::S, init) where {N,S<:Tuple{Vararg{Any,N}}} out = Expr(:block, Expr(:meta, :inline)) @@ -632,8 +632,8 @@ maybe_static_step(_) = missing prev = :init i = 1 while i <= (N - 1) - if S.parameters[i] <: Missing || (i > 1 && t.args[i - 1] === :missing) - push!(t.args, :missing) + if S.parameters[i] <: Nothing || (i > 1 && t.args[i - 1] === :nothing) + push!(t.args, :nothing) else next = Symbol(:val_, i) push!(out.args, :($next = $prev * getfield(sz, $i))) diff --git a/test/array_index.jl b/test/array_index.jl index 1912016b2..b31390e7e 100644 --- a/test/array_index.jl +++ b/test/array_index.jl @@ -15,7 +15,7 @@ end @test @inferred(ArrayInterface.offsets(ap_index, static(1))) === ArrayInterface.offset1(Ap) @test @inferred(ArrayInterface.known_strides(ap_index)) === ArrayInterface.known_strides(Ap) @test @inferred(ArrayInterface.contiguous_axis(ap_index)) == 1 -@test @inferred(ArrayInterface.contiguous_axis(ArrayInterface.StrideIndex{2,(1,2),missing,NTuple{2,Int},NTuple{2,Int}})) === missing +@test @inferred(ArrayInterface.contiguous_axis(ArrayInterface.StrideIndex{2,(1,2),nothing,NTuple{2,Int},NTuple{2,Int}})) === nothing @test @inferred(ArrayInterface.stride_rank(ap_index)) == (1, 3) let v = Float64.(1:10)', v2 = transpose(parent(v)) diff --git a/test/dimensions.jl b/test/dimensions.jl index 215a376ef..86cd6bb0e 100644 --- a/test/dimensions.jl +++ b/test/dimensions.jl @@ -113,7 +113,7 @@ end @test @inferred(dimnames(parent(x), ArrayInterface.One())) === static(:_) @test @inferred(ArrayInterface.known_dimnames(Iterators.flatten(1:10))) === (:_,) @test @inferred(ArrayInterface.known_dimnames(Iterators.flatten(1:10), static(1))) === :_ - @test @inferred(ArrayInterface.known_dimnames(z)) === (missing, :y) + @test @inferred(ArrayInterface.known_dimnames(z)) === (nothing, :y) end @testset "to_dims" begin diff --git a/test/ranges.jl b/test/ranges.jl index 2374dd15e..92fd18f36 100644 --- a/test/ranges.jl +++ b/test/ranges.jl @@ -55,25 +55,25 @@ @test iterate(static(1):static(5), 5) === nothing @test iterate(static(2):static(5), 5) === nothing - @test ismissing(@inferred(ArrayInterface.known_first(typeof(1:4)))) + @test isnothing(@inferred(ArrayInterface.known_first(typeof(1:4)))) @test isone(@inferred(ArrayInterface.known_first(Base.OneTo(4)))) @test isone(@inferred(ArrayInterface.known_first(typeof(Base.OneTo(4))))) @test isone(@inferred(ArrayInterface.known_first(typeof(static(1):2:10)))) - @test ismissing(@inferred(ArrayInterface.known_last(1:4))) - @test ismissing(@inferred(ArrayInterface.known_last(typeof(1:4)))) + @test isnothing(@inferred(ArrayInterface.known_last(1:4))) + @test isnothing(@inferred(ArrayInterface.known_last(typeof(1:4)))) @test isone(@inferred(ArrayInterface.known_last(typeof(static(-1):static(2):static(1))))) # CartesianIndices CI = CartesianIndices((2, 2)) @test @inferred(ArrayInterface.known_first(typeof(CI))) == CartesianIndex(1, 1) - @test @inferred(ArrayInterface.known_last(typeof(CI))) === missing + @test @inferred(ArrayInterface.known_last(typeof(CI))) === nothing CI = CartesianIndices((static(1):static(2), static(1):static(2))) @test @inferred(ArrayInterface.known_first(typeof(CI))) == CartesianIndex(1, 1) @test @inferred(ArrayInterface.known_last(typeof(CI))) == CartesianIndex(2, 2) - @test ismissing(@inferred(ArrayInterface.known_step(typeof(1:0.2:4)))) + @test isnothing(@inferred(ArrayInterface.known_step(typeof(1:0.2:4)))) @test isone(@inferred(ArrayInterface.known_step(1:4))) @test isone(@inferred(ArrayInterface.known_step(typeof(1:4)))) @test isone(@inferred(ArrayInterface.known_step(typeof(Base.Slice(1:4))))) @@ -90,7 +90,7 @@ @test @inferred(length(static(1):static(2):static(0))) == 0 @test @inferred(length(static(0):static(-2):static(1))) == 0 - @test @inferred(ArrayInterface.known_length(typeof(ArrayInterface.OptionallyStaticStepRange(static(1), 2, 10)))) === missing + @test @inferred(ArrayInterface.known_length(typeof(ArrayInterface.OptionallyStaticStepRange(static(1), 2, 10)))) === nothing @test @inferred(ArrayInterface.known_length(typeof(ArrayInterface.SOneTo{-10}()))) === 0 @test @inferred(ArrayInterface.known_length(typeof(ArrayInterface.OptionallyStaticStepRange(static(1), static(1), static(10))))) === 10 @test @inferred(ArrayInterface.known_length(typeof(ArrayInterface.OptionallyStaticStepRange(static(2), static(1), static(10))))) === 9 diff --git a/test/runtests.jl b/test/runtests.jl index 02c82723a..7f8edd79b 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -66,7 +66,7 @@ else @test !fast_scalar_indexing(qr(rand(10, 10), Val(true)).Q) end @test !fast_scalar_indexing(lq(rand(10, 10)).Q) -@test fast_scalar_indexing(Missing) # test default +@test fast_scalar_indexing(Nothing) # test default @testset "can_setindex" begin @test !@inferred(ArrayInterface.can_setindex(1:2)) @@ -286,7 +286,7 @@ ArrayInterface.parent_type(::Type{DenseWrapper{T,N,P}}) where {T,N,P} = P @test @inferred(device(OffsetArray(@SArray(zeros(2,2,2)),-123,29,3231))) === ArrayInterface.CPUTuple() @test @inferred(device(OffsetArray(@view(@SArray(zeros(2,2,2))[1,1:2,:]),-3,4))) === ArrayInterface.CPUTuple() @test @inferred(device(OffsetArray(@MArray(zeros(2,2,2)),8,-2,-5))) === ArrayInterface.CPUPointer() - @test ismissing(device("Hello, world!")) + @test isnothing(device("Hello, world!")) @test @inferred(device(DenseWrapper{Int,2,Matrix{Int}})) === ArrayInterface.CPUPointer() #= @btime ArrayInterface.contiguous_axis($(reshape(view(zeros(100), 1:60), (3,4,5)))) @@ -309,10 +309,10 @@ ArrayInterface.parent_type(::Type{DenseWrapper{T,N,P}}) where {T,N,P} = P @test @inferred(contiguous_axis((3,4))) === StaticInt(1) @test @inferred(contiguous_axis(rand(4)')) === StaticInt(2) @test @inferred(contiguous_axis(view(@view(PermutedDimsArray(A,(3,1,2))[2:3,2,:])', :, 1)')) === StaticInt(-1) - @test @inferred(contiguous_axis(DummyZeros(3,4))) === missing - @test @inferred(contiguous_axis(PermutedDimsArray(DummyZeros(3,4), (2, 1)))) === missing - @test @inferred(contiguous_axis(view(DummyZeros(3,4), 1, :))) === missing - @test @inferred(contiguous_axis(view(DummyZeros(3,4), 1, :)')) === missing + @test @inferred(contiguous_axis(DummyZeros(3,4))) === nothing + @test @inferred(contiguous_axis(PermutedDimsArray(DummyZeros(3,4), (2, 1)))) === nothing + @test @inferred(contiguous_axis(view(DummyZeros(3,4), 1, :))) === nothing + @test @inferred(contiguous_axis(view(DummyZeros(3,4), 1, :)')) === nothing @test @inferred(ArrayInterface.contiguous_axis_indicator(@SArray(zeros(2,2,2)))) == (true,false,false) @test @inferred(ArrayInterface.contiguous_axis_indicator(A)) == (true,false,false) @@ -326,7 +326,7 @@ ArrayInterface.parent_type(::Type{DenseWrapper{T,N,P}}) where {T,N,P} = P @test @inferred(ArrayInterface.contiguous_axis_indicator(@view(PermutedDimsArray(A,(3,1,2))[2:3,2,:])')) == (false,false) @test @inferred(ArrayInterface.contiguous_axis_indicator(@view(PermutedDimsArray(A,(3,1,2))[:,1:2,1])')) == (true,false) @test @inferred(ArrayInterface.contiguous_axis_indicator(@view(PermutedDimsArray(A,(3,1,2))[:,1:2,[1,3,4]]))) == (false,true,false) - @test @inferred(ArrayInterface.contiguous_axis_indicator(DummyZeros(3,4))) === missing + @test @inferred(ArrayInterface.contiguous_axis_indicator(DummyZeros(3,4))) === nothing @test @inferred(contiguous_batch_size(@SArray(zeros(2,2,2)))) === ArrayInterface.StaticInt(0) @test @inferred(contiguous_batch_size(A)) === ArrayInterface.StaticInt(0) @@ -361,9 +361,9 @@ ArrayInterface.parent_type(::Type{DenseWrapper{T,N,P}}) where {T,N,P} = P @test @inferred(stride_rank(@view(PermutedDimsArray(A,(3,1,2))[:,1:2,1])')) == (1, 3) @test @inferred(stride_rank(@view(PermutedDimsArray(A,(3,1,2))[:,2,1])')) == (2, 1) @test @inferred(stride_rank(@view(PermutedDimsArray(A,(3,1,2))[:,1:2,[1,3,4]]))) == (3, 1, 2) - @test @inferred(stride_rank(DummyZeros(3,4)')) === missing - @test @inferred(stride_rank(PermutedDimsArray(DummyZeros(3,4), (2, 1)))) === missing - @test @inferred(stride_rank(view(DummyZeros(3,4), 1, :))) === missing + @test @inferred(stride_rank(DummyZeros(3,4)')) === nothing + @test @inferred(stride_rank(PermutedDimsArray(DummyZeros(3,4), (2, 1)))) === nothing + @test @inferred(stride_rank(view(DummyZeros(3,4), 1, :))) === nothing uA = reinterpret(reshape, UInt64, A) @test @inferred(stride_rank(uA)) === stride_rank(A) rA = reinterpret(reshape, SVector{3,Float64}, A) @@ -417,11 +417,11 @@ ArrayInterface.parent_type(::Type{DenseWrapper{T,N,P}}) where {T,N,P} = P # first need to develop a standard method for reconstructing arrays @test @inferred(dense_dims(vec(parent(A)))) == (true,) @test @inferred(dense_dims(vec(parent(A))')) == (true,true) - @test @inferred(dense_dims(DummyZeros(3,4))) === missing - @test @inferred(dense_dims(DummyZeros(3,4)')) === missing - @test @inferred(dense_dims(PermutedDimsArray(DummyZeros(3,4), (2, 1)))) === missing - @test @inferred(dense_dims(view(DummyZeros(3,4), :, 1))) === missing - @test @inferred(dense_dims(view(DummyZeros(3,4), :, 1)')) === missing + @test @inferred(dense_dims(DummyZeros(3,4))) === nothing + @test @inferred(dense_dims(DummyZeros(3,4)')) === nothing + @test @inferred(dense_dims(PermutedDimsArray(DummyZeros(3,4), (2, 1)))) === nothing + @test @inferred(dense_dims(view(DummyZeros(3,4), :, 1))) === nothing + @test @inferred(dense_dims(view(DummyZeros(3,4), :, 1)')) === nothing @test @inferred(ArrayInterface.is_dense(A)) === @inferred(ArrayInterface.is_dense(A)) === @inferred(ArrayInterface.is_dense(PermutedDimsArray(A,(3,1,2)))) === @inferred(ArrayInterface.is_dense(Array{Float64,0}(undef))) === True() @test @inferred(ArrayInterface.is_dense(@view(PermutedDimsArray(A,(3,1,2))[2:3,1:2,:]))) === @inferred(ArrayInterface.is_dense(@view(PermutedDimsArray(A,(3,1,2))[2:3,:,[1,2]]))) === @inferred(ArrayInterface.is_dense(@view(PermutedDimsArray(A,(3,1,2))[2:3,[1,2,3],:]))) === False() @@ -546,18 +546,18 @@ end @test @inferred(ArrayInterface.size(Mp2)) == size(Mp2) @test @inferred(ArrayInterface.size(D)) == size(D) - @test @inferred(ArrayInterface.known_size(A)) === (missing, missing, missing) - @test @inferred(ArrayInterface.known_size(Ap)) === (missing,missing) - @test @inferred(ArrayInterface.known_size(Wrapper(Ap))) === (missing,missing) + @test @inferred(ArrayInterface.known_size(A)) === (nothing, nothing, nothing) + @test @inferred(ArrayInterface.known_size(Ap)) === (nothing,nothing) + @test @inferred(ArrayInterface.known_size(Wrapper(Ap))) === (nothing,nothing) @test @inferred(ArrayInterface.known_size(R)) === (2,) @test @inferred(ArrayInterface.known_size(Wrapper(R))) === (2,) @test @inferred(ArrayInterface.known_size(Rnr)) === (4,) @test @inferred(ArrayInterface.known_size(Rnr, static(1))) === 4 - @test @inferred(ArrayInterface.known_size(Ar)) === (missing,missing, missing,) - @test @inferred(ArrayInterface.known_size(Ar, static(1))) === missing + @test @inferred(ArrayInterface.known_size(Ar)) === (nothing,nothing, nothing,) + @test @inferred(ArrayInterface.known_size(Ar, static(1))) === nothing @test @inferred(ArrayInterface.known_size(Ar, static(4))) === 1 - @test @inferred(ArrayInterface.known_size(A2)) === (missing, missing, missing) - @test @inferred(ArrayInterface.known_size(A2r)) === (missing, missing, missing) + @test @inferred(ArrayInterface.known_size(A2)) === (nothing, nothing, nothing) + @test @inferred(ArrayInterface.known_size(A2r)) === (nothing, nothing, nothing) @test @inferred(ArrayInterface.known_size(irev)) === (2, 3, 4) @test @inferred(ArrayInterface.known_size(igen)) === (2, 3, 4) @@ -569,19 +569,19 @@ end @test @inferred(ArrayInterface.known_size(ipairs)) === (2, 3, 4) @test @inferred(ArrayInterface.known_size(zip(S, A_trailingdim))) === (2, 3, 4, 1) @test @inferred(ArrayInterface.known_size(zip(A_trailingdim, S))) === (2, 3, 4, 1) - @test @inferred(ArrayInterface.known_length(Iterators.flatten(((x,y) for x in 0:1 for y in 'a':'c')))) === missing + @test @inferred(ArrayInterface.known_length(Iterators.flatten(((x,y) for x in 0:1 for y in 'a':'c')))) === nothing @test @inferred(ArrayInterface.known_size(S)) === (2, 3, 4) @test @inferred(ArrayInterface.known_size(Wrapper(S))) === (2, 3, 4) - @test @inferred(ArrayInterface.known_size(Sp)) === (missing, missing, 3) - @test @inferred(ArrayInterface.known_size(Wrapper(Sp))) === (missing, missing, 3) - @test @inferred(ArrayInterface.known_size(Sp2)) === (missing, 3, 2) - @test @inferred(ArrayInterface.known_size(Sp2, StaticInt(1))) === missing + @test @inferred(ArrayInterface.known_size(Sp)) === (nothing, nothing, 3) + @test @inferred(ArrayInterface.known_size(Wrapper(Sp))) === (nothing, nothing, 3) + @test @inferred(ArrayInterface.known_size(Sp2)) === (nothing, 3, 2) + @test @inferred(ArrayInterface.known_size(Sp2, StaticInt(1))) === nothing @test @inferred(ArrayInterface.known_size(Sp2, StaticInt(2))) === 3 @test @inferred(ArrayInterface.known_size(Sp2, StaticInt(3))) === 2 @test @inferred(ArrayInterface.known_size(M)) === (2, 3, 4) @test @inferred(ArrayInterface.known_size(Mp)) === (3, 4) - @test @inferred(ArrayInterface.known_size(Mp2)) === (2, missing) + @test @inferred(ArrayInterface.known_size(Mp2)) === (2, nothing) @test @inferred(ArrayInterface.strides(A)) === (StaticInt(1), 3, 12) @test @inferred(ArrayInterface.strides(Ap)) === (StaticInt(1), 12) @@ -608,12 +608,12 @@ end @test @inferred(ArrayInterface.strides(Mp2)) == strides(Mp2) @test_throws MethodError ArrayInterface.strides(DummyZeros(3,4)) - @test @inferred(ArrayInterface.known_strides(A)) === (1, missing, missing) - @test @inferred(ArrayInterface.known_strides(Ap)) === (1, missing) - @test @inferred(ArrayInterface.known_strides(Ar)) === (1, missing, missing) - @test @inferred(ArrayInterface.known_strides(reshape(view(zeros(100), 1:60), (3,4,5)))) === (1, missing, missing) - @test @inferred(ArrayInterface.known_strides(A2)) === (1, missing, missing) - @test @inferred(ArrayInterface.known_strides(A2r)) === (1, missing, missing) + @test @inferred(ArrayInterface.known_strides(A)) === (1, nothing, nothing) + @test @inferred(ArrayInterface.known_strides(Ap)) === (1, nothing) + @test @inferred(ArrayInterface.known_strides(Ar)) === (1, nothing, nothing) + @test @inferred(ArrayInterface.known_strides(reshape(view(zeros(100), 1:60), (3,4,5)))) === (1, nothing, nothing) + @test @inferred(ArrayInterface.known_strides(A2)) === (1, nothing, nothing) + @test @inferred(ArrayInterface.known_strides(A2r)) === (1, nothing, nothing) @test @inferred(ArrayInterface.known_strides(S)) === (1, 2, 6) @test @inferred(ArrayInterface.known_strides(Sp)) === (6, 1, 2) @@ -769,10 +769,10 @@ end @testset "known_length" begin @test ArrayInterface.known_length(@inferred(ArrayInterface.indices(SOneTo(7)))) == 7 - @test ArrayInterface.known_length(1:2) === missing + @test ArrayInterface.known_length(1:2) === nothing @test ArrayInterface.known_length((1,)) == 1 @test ArrayInterface.known_length((a=1,b=2)) == 2 - @test ArrayInterface.known_length([]) === missing + @test ArrayInterface.known_length([]) === nothing @test ArrayInterface.known_length(CartesianIndex((1,2,3))) === 3 x = view(SArray{Tuple{3,3,3}}(ones(3,3,3)), :, SOneTo(2), 2) From f0bc6379713492aa8ecaf9d12a6d3de0d599541f Mon Sep 17 00:00:00 2001 From: Christopher Rackauckas Date: Tue, 1 Mar 2022 09:59:47 -0500 Subject: [PATCH 02/11] Update Project.toml --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 0cd9808fe..e4446eb91 100644 --- a/Project.toml +++ b/Project.toml @@ -14,5 +14,5 @@ Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" Compat = "3.37" IfElse = "0.1" Requires = "0.5, 1.0" -Static = "0.5" +Static = "0.6" julia = "1.2" From ed14159ddd575de65c4331af11791a5396679d4b Mon Sep 17 00:00:00 2001 From: Christopher Rackauckas Date: Tue, 1 Mar 2022 10:03:37 -0500 Subject: [PATCH 03/11] Update Project.toml --- test/Project.toml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/test/Project.toml b/test/Project.toml index 9a96f6ef9..19d195983 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -2,12 +2,8 @@ Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" BandedMatrices = "aae01518-5342-5314-be14-df237901396f" BlockBandedMatrices = "ffab5731-97b5-5995-9138-79e8c1846df0" -IfElse = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173" -LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" -SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" -Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" SuiteSparse = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" @@ -16,7 +12,5 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Aqua = "0.5" BandedMatrices = "0.16" BlockBandedMatrices = "0.11" -IfElse = "0.1" OffsetArrays = "1" -Static = "0.5" StaticArrays = "1.2.5, 1.3" From 808f547cf787ed595ce4ed4fef6a4e836b1042f7 Mon Sep 17 00:00:00 2001 From: Christopher Rackauckas Date: Tue, 1 Mar 2022 10:07:58 -0500 Subject: [PATCH 04/11] Update Project.toml --- test/Project.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/Project.toml b/test/Project.toml index 19d195983..7f315c5bd 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -7,6 +7,10 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" SuiteSparse = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +IfElse = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" +Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" [compat] Aqua = "0.5" From c02efe9b7f38de87c99b170b8975ec4a9c988a4b Mon Sep 17 00:00:00 2001 From: Christopher Rackauckas Date: Tue, 1 Mar 2022 10:12:37 -0500 Subject: [PATCH 05/11] Update Project.toml --- test/Project.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/Project.toml b/test/Project.toml index 7f315c5bd..f9f4f8540 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -2,15 +2,15 @@ Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" BandedMatrices = "aae01518-5342-5314-be14-df237901396f" BlockBandedMatrices = "ffab5731-97b5-5995-9138-79e8c1846df0" +IfElse = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" +Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" SuiteSparse = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" -IfElse = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173" -LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" -Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" [compat] Aqua = "0.5" From af97a8ce90d8333dd187391184421f703c184575 Mon Sep 17 00:00:00 2001 From: Chris Rackauckas Date: Tue, 1 Mar 2022 10:34:37 -0500 Subject: [PATCH 06/11] only maybe use known_size in _maybe_known_length --- src/ArrayInterface.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ArrayInterface.jl b/src/ArrayInterface.jl index 8c4e122b8..f75af7021 100644 --- a/src/ArrayInterface.jl +++ b/src/ArrayInterface.jl @@ -93,7 +93,7 @@ known_length(::Type{<:Tuple{Vararg{Any,N}}}) where {N} = N known_length(::Type{<:Number}) = 1 known_length(::Type{<:AbstractCartesianIndex{N}}) where {N} = N known_length(::Type{T}) where {T} = _maybe_known_length(Base.IteratorSize(T), T) -_maybe_known_length(::Base.HasShape, ::Type{T}) where {T} = prod(known_size(T)) +_maybe_known_length(::Base.HasShape, ::Type{T}) where {T} = prod(Static.maybe_static(known_size, size, T)) _maybe_known_length(::Base.IteratorSize, ::Type) = nothing function known_length(::Type{<:Iterators.Flatten{I}}) where {I} known_length(I) * known_length(eltype(I)) From f9b16dc3b792140e85f511e9a9c1c2c6ee34d2ca Mon Sep 17 00:00:00 2001 From: Chris Elrod Date: Tue, 1 Mar 2022 15:08:22 -0500 Subject: [PATCH 07/11] Tests pass --- .github/workflows/ci.yml | 4 ++++ src/ArrayInterface.jl | 7 +++++-- src/dimensions.jl | 24 +++++++++++++----------- test/dimensions.jl | 14 +++++++------- 4 files changed, 29 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 97224ca3e..81ac89aa7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,6 +52,10 @@ jobs: - uses: julia-actions/setup-julia@latest with: version: '1.2' + - run: julia --color=yes -e 'using Pkg; VERSION >= v"1.5-" && !isdir(joinpath(DEPOT_PATH[1], "registries", "General")) && Pkg.Registry.add("General")' + shell: bash + env: + JULIA_PKG_SERVER: "" - run: julia --project=docs -e ' using Pkg; Pkg.develop(PackageSpec(; path=pwd())); diff --git a/src/ArrayInterface.jl b/src/ArrayInterface.jl index f75af7021..757575109 100644 --- a/src/ArrayInterface.jl +++ b/src/ArrayInterface.jl @@ -93,10 +93,13 @@ known_length(::Type{<:Tuple{Vararg{Any,N}}}) where {N} = N known_length(::Type{<:Number}) = 1 known_length(::Type{<:AbstractCartesianIndex{N}}) where {N} = N known_length(::Type{T}) where {T} = _maybe_known_length(Base.IteratorSize(T), T) -_maybe_known_length(::Base.HasShape, ::Type{T}) where {T} = prod(Static.maybe_static(known_size, size, T)) +@inline _prod_or_nothing(x, ::Tuple{}) = x +@inline _prod_or_nothing(_, ::Tuple{Nothing,Vararg}) = nothing +@inline _prod_or_nothing(x, y::Tuple{I,Vararg}) where {I} = _prod_or_nothing(x*first(y), Base.tail(y)) +_maybe_known_length(::Base.HasShape, ::Type{T}) where {T} = _prod_or_nothing(1, known_size(T)) _maybe_known_length(::Base.IteratorSize, ::Type) = nothing function known_length(::Type{<:Iterators.Flatten{I}}) where {I} - known_length(I) * known_length(eltype(I)) + _prod_or_nothing(1, (known_length(I),known_length(eltype(I)))) end """ diff --git a/src/dimensions.jl b/src/dimensions.jl index 105ef5fe2..f3c8a0977 100644 --- a/src/dimensions.jl +++ b/src/dimensions.jl @@ -146,24 +146,26 @@ function to_parent_dims(::Type{T}, ::StaticInt{dim}) where {T,dim} throw_dim_error(T, dim) end end - -_nunderscore(::Val{N}) where {N} = ntuple(Compat.Returns(:_), Val(N)) +struct Returns{T}; x::T; end; @inline (r::Returns)(_::Vararg{Any,K}) where {K} = r.x +_nunderscore(::Val{N}) where {N} = ntuple(Returns(nothing), Val(N)) """ has_dimnames(::Type{T}) -> StaticBool Returns `static(true)` if `x` has on or more named dimensions. If all dimensions correspond -to `static(:_)`, then `static(false)` is returned. +to `nothing`, then `static(false)` is returned. """ Compat.@constprop :aggressive has_dimnames(x) = static(_is_named(known_dimnames(x))) -_is_named(x::NTuple{N,Symbol}) where {N} = x !== _nunderscore(Val(N)) -_is_named(::Any) = true +_is_named(x::Tuple{Nothing,Vararg}) = _is_named(Base.tail(x)) +_is_named(x::Tuple{Nothing}) = false +_is_named(x::Tuple{Symbol,Vararg}) = true +_is_named(x::Tuple{}) = true """ known_dimnames(::Type{T}) -> Tuple{Vararg{Union{Symbol,Nothing}}} known_dimnames(::Type{T}, dim::Union{Int,StaticInt}) -> Union{Symbol,Nothing} -Return the names of the dimensions for `x`. `:_` is used to indicate a dimension does not +Return the names of the dimensions for `x`. `nothing` is used to indicate a dimension does not have a name. """ @inline known_dimnames(x, dim::Integer) = _known_dimname(known_dimnames(x), canonicalize(dim)) @@ -171,12 +173,12 @@ known_dimnames(x) = known_dimnames(typeof(x)) known_dimnames(::Type{T}) where {T} = _known_dimnames(T, parent_type(T)) _known_dimnames(::Type{T}, ::Type{T}) where {T} = _unknown_dimnames(Base.IteratorSize(T)) _unknown_dimnames(::Base.HasShape{N}) where {N} = _nunderscore(Val(N)) -_unknown_dimnames(::Any) = (:_,) +_unknown_dimnames(::Any) = (nothing,) function _known_dimnames(::Type{C}, ::Type{P}) where {C,P} eachop(_inbounds_known_dimname, to_parent_dims(C), known_dimnames(P)) end @inline function _known_dimname(x::Tuple{Vararg{Any,N}}, dim::CanonicalInt) where {N} - @boundscheck (dim > N || dim < 1) && return :_ + (dim > N || dim < 1) && return nothing return @inbounds(x[dim]) end @inline _inbounds_known_dimname(x, dim) = @inbounds(_known_dimname(x, dim)) @@ -185,7 +187,7 @@ end dimnames(x) -> Tuple{Vararg{Union{Symbol,StaticSymbol}}} dimnames(x, dim::Union{Int,StaticInt}) -> Union{Symbol,StaticSymbol} -Return the names of the dimensions for `x`. `:_` is used to indicate a dimension does not +Return the names of the dimensions for `x`. `nothing` is used to indicate a dimension does not have a name. """ @inline dimnames(x, dim::Integer) = _dimname(dimnames(x), canonicalize(dim)) @@ -193,9 +195,9 @@ have a name. @inline function _dimnames(::True, x) eachop(_inbounds_dimname, to_parent_dims(x), dimnames(parent(x))) end -_dimnames(::False, x) = ntuple(_->static(:_), Val(ndims(x))) +_dimnames(::False, x) = ntuple(_->nothing, Val(ndims(x))) @inline function _dimname(x::Tuple{Vararg{Any,N}}, dim::CanonicalInt) where {N} - @boundscheck (dim > N || dim < 1) && return static(:_) + @boundscheck (dim > N || dim < 1) && return nothing return @inbounds(x[dim]) end @inline _inbounds_dimname(x, dim) = @inbounds(_dimname(x, dim)) diff --git a/test/dimensions.jl b/test/dimensions.jl index 86cd6bb0e..07fc02d40 100644 --- a/test/dimensions.jl +++ b/test/dimensions.jl @@ -101,18 +101,18 @@ end @test @inferred(ArrayInterface.has_dimnames(typeof(view(x, :, 1, :)))) == true @test @inferred(dimnames(x)) === d @test @inferred(ArrayInterface.dimnames(z)) === (:x, static(:y)) - @test @inferred(dimnames(parent(x))) === (static(:_), static(:_)) + @test @inferred(dimnames(parent(x))) === (nothing, nothing) @test @inferred(dimnames(x')) === reverse(d) - @test @inferred(dimnames(y')) === (static(:_), static(:x)) + @test @inferred(dimnames(y')) === (nothing, static(:x)) @test @inferred(dimnames(PermutedDimsArray(x, (2, 1)))) === reverse(d) @test @inferred(dimnames(PermutedDimsArray(x', (2, 1)))) === d @test @inferred(dimnames(view(x, :, 1))) === (static(:x),) - @test @inferred(dimnames(view(x, :, :, :))) === (static(:x),static(:y), static(:_)) - @test @inferred(dimnames(view(x, :, 1, :))) === (static(:x), static(:_)) + @test @inferred(dimnames(view(x, :, :, :))) === (static(:x),static(:y), nothing) + @test @inferred(dimnames(view(x, :, 1, :))) === (static(:x), nothing) @test @inferred(dimnames(x, ArrayInterface.One())) === static(:x) - @test @inferred(dimnames(parent(x), ArrayInterface.One())) === static(:_) - @test @inferred(ArrayInterface.known_dimnames(Iterators.flatten(1:10))) === (:_,) - @test @inferred(ArrayInterface.known_dimnames(Iterators.flatten(1:10), static(1))) === :_ + @test @inferred(dimnames(parent(x), ArrayInterface.One())) === nothing + @test @inferred(ArrayInterface.known_dimnames(Iterators.flatten(1:10))) === (nothing,) + @test @inferred(ArrayInterface.known_dimnames(Iterators.flatten(1:10), static(1))) === nothing @test @inferred(ArrayInterface.known_dimnames(z)) === (nothing, :y) end From b020ccbdd2257d9b32cc71bfe348e12aef6bd92b Mon Sep 17 00:00:00 2001 From: Chris Elrod Date: Tue, 1 Mar 2022 15:15:15 -0500 Subject: [PATCH 08/11] Revert type inference fixes --- src/dimensions.jl | 24 +++++++++++------------- test/dimensions.jl | 14 +++++++------- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/src/dimensions.jl b/src/dimensions.jl index f3c8a0977..105ef5fe2 100644 --- a/src/dimensions.jl +++ b/src/dimensions.jl @@ -146,26 +146,24 @@ function to_parent_dims(::Type{T}, ::StaticInt{dim}) where {T,dim} throw_dim_error(T, dim) end end -struct Returns{T}; x::T; end; @inline (r::Returns)(_::Vararg{Any,K}) where {K} = r.x -_nunderscore(::Val{N}) where {N} = ntuple(Returns(nothing), Val(N)) + +_nunderscore(::Val{N}) where {N} = ntuple(Compat.Returns(:_), Val(N)) """ has_dimnames(::Type{T}) -> StaticBool Returns `static(true)` if `x` has on or more named dimensions. If all dimensions correspond -to `nothing`, then `static(false)` is returned. +to `static(:_)`, then `static(false)` is returned. """ Compat.@constprop :aggressive has_dimnames(x) = static(_is_named(known_dimnames(x))) -_is_named(x::Tuple{Nothing,Vararg}) = _is_named(Base.tail(x)) -_is_named(x::Tuple{Nothing}) = false -_is_named(x::Tuple{Symbol,Vararg}) = true -_is_named(x::Tuple{}) = true +_is_named(x::NTuple{N,Symbol}) where {N} = x !== _nunderscore(Val(N)) +_is_named(::Any) = true """ known_dimnames(::Type{T}) -> Tuple{Vararg{Union{Symbol,Nothing}}} known_dimnames(::Type{T}, dim::Union{Int,StaticInt}) -> Union{Symbol,Nothing} -Return the names of the dimensions for `x`. `nothing` is used to indicate a dimension does not +Return the names of the dimensions for `x`. `:_` is used to indicate a dimension does not have a name. """ @inline known_dimnames(x, dim::Integer) = _known_dimname(known_dimnames(x), canonicalize(dim)) @@ -173,12 +171,12 @@ known_dimnames(x) = known_dimnames(typeof(x)) known_dimnames(::Type{T}) where {T} = _known_dimnames(T, parent_type(T)) _known_dimnames(::Type{T}, ::Type{T}) where {T} = _unknown_dimnames(Base.IteratorSize(T)) _unknown_dimnames(::Base.HasShape{N}) where {N} = _nunderscore(Val(N)) -_unknown_dimnames(::Any) = (nothing,) +_unknown_dimnames(::Any) = (:_,) function _known_dimnames(::Type{C}, ::Type{P}) where {C,P} eachop(_inbounds_known_dimname, to_parent_dims(C), known_dimnames(P)) end @inline function _known_dimname(x::Tuple{Vararg{Any,N}}, dim::CanonicalInt) where {N} - (dim > N || dim < 1) && return nothing + @boundscheck (dim > N || dim < 1) && return :_ return @inbounds(x[dim]) end @inline _inbounds_known_dimname(x, dim) = @inbounds(_known_dimname(x, dim)) @@ -187,7 +185,7 @@ end dimnames(x) -> Tuple{Vararg{Union{Symbol,StaticSymbol}}} dimnames(x, dim::Union{Int,StaticInt}) -> Union{Symbol,StaticSymbol} -Return the names of the dimensions for `x`. `nothing` is used to indicate a dimension does not +Return the names of the dimensions for `x`. `:_` is used to indicate a dimension does not have a name. """ @inline dimnames(x, dim::Integer) = _dimname(dimnames(x), canonicalize(dim)) @@ -195,9 +193,9 @@ have a name. @inline function _dimnames(::True, x) eachop(_inbounds_dimname, to_parent_dims(x), dimnames(parent(x))) end -_dimnames(::False, x) = ntuple(_->nothing, Val(ndims(x))) +_dimnames(::False, x) = ntuple(_->static(:_), Val(ndims(x))) @inline function _dimname(x::Tuple{Vararg{Any,N}}, dim::CanonicalInt) where {N} - @boundscheck (dim > N || dim < 1) && return nothing + @boundscheck (dim > N || dim < 1) && return static(:_) return @inbounds(x[dim]) end @inline _inbounds_dimname(x, dim) = @inbounds(_dimname(x, dim)) diff --git a/test/dimensions.jl b/test/dimensions.jl index 07fc02d40..86cd6bb0e 100644 --- a/test/dimensions.jl +++ b/test/dimensions.jl @@ -101,18 +101,18 @@ end @test @inferred(ArrayInterface.has_dimnames(typeof(view(x, :, 1, :)))) == true @test @inferred(dimnames(x)) === d @test @inferred(ArrayInterface.dimnames(z)) === (:x, static(:y)) - @test @inferred(dimnames(parent(x))) === (nothing, nothing) + @test @inferred(dimnames(parent(x))) === (static(:_), static(:_)) @test @inferred(dimnames(x')) === reverse(d) - @test @inferred(dimnames(y')) === (nothing, static(:x)) + @test @inferred(dimnames(y')) === (static(:_), static(:x)) @test @inferred(dimnames(PermutedDimsArray(x, (2, 1)))) === reverse(d) @test @inferred(dimnames(PermutedDimsArray(x', (2, 1)))) === d @test @inferred(dimnames(view(x, :, 1))) === (static(:x),) - @test @inferred(dimnames(view(x, :, :, :))) === (static(:x),static(:y), nothing) - @test @inferred(dimnames(view(x, :, 1, :))) === (static(:x), nothing) + @test @inferred(dimnames(view(x, :, :, :))) === (static(:x),static(:y), static(:_)) + @test @inferred(dimnames(view(x, :, 1, :))) === (static(:x), static(:_)) @test @inferred(dimnames(x, ArrayInterface.One())) === static(:x) - @test @inferred(dimnames(parent(x), ArrayInterface.One())) === nothing - @test @inferred(ArrayInterface.known_dimnames(Iterators.flatten(1:10))) === (nothing,) - @test @inferred(ArrayInterface.known_dimnames(Iterators.flatten(1:10), static(1))) === nothing + @test @inferred(dimnames(parent(x), ArrayInterface.One())) === static(:_) + @test @inferred(ArrayInterface.known_dimnames(Iterators.flatten(1:10))) === (:_,) + @test @inferred(ArrayInterface.known_dimnames(Iterators.flatten(1:10), static(1))) === :_ @test @inferred(ArrayInterface.known_dimnames(z)) === (nothing, :y) end From f64135a61a00a7aa1536efb9fcce167df1196e12 Mon Sep 17 00:00:00 2001 From: Chris Elrod Date: Tue, 1 Mar 2022 15:41:59 -0500 Subject: [PATCH 09/11] remove @boundschecks --- src/dimensions.jl | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/dimensions.jl b/src/dimensions.jl index 105ef5fe2..ff25c41e9 100644 --- a/src/dimensions.jl +++ b/src/dimensions.jl @@ -176,7 +176,8 @@ function _known_dimnames(::Type{C}, ::Type{P}) where {C,P} eachop(_inbounds_known_dimname, to_parent_dims(C), known_dimnames(P)) end @inline function _known_dimname(x::Tuple{Vararg{Any,N}}, dim::CanonicalInt) where {N} - @boundscheck (dim > N || dim < 1) && return :_ + # we cannot have `@boundscheck`, else this will depend on bounds checking being enabled + (dim > N || dim < 1) && return :_ return @inbounds(x[dim]) end @inline _inbounds_known_dimname(x, dim) = @inbounds(_known_dimname(x, dim)) @@ -195,7 +196,9 @@ have a name. end _dimnames(::False, x) = ntuple(_->static(:_), Val(ndims(x))) @inline function _dimname(x::Tuple{Vararg{Any,N}}, dim::CanonicalInt) where {N} - @boundscheck (dim > N || dim < 1) && return static(:_) + # we cannot have `@boundscheck`, else this will depend on bounds checking being enabled + # for calls such as `dimnames(view(x, :, 1, :))` + (dim > N || dim < 1) && return static(:_) return @inbounds(x[dim]) end @inline _inbounds_dimname(x, dim) = @inbounds(_dimname(x, dim)) From 6148a9fe4481cbf9ca9d2ac45a5a661277abc2e9 Mon Sep 17 00:00:00 2001 From: Chris Elrod Date: Tue, 1 Mar 2022 16:24:59 -0500 Subject: [PATCH 10/11] skip failed inference test --- src/ArrayInterface.jl | 2 ++ test/runtests.jl | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/ArrayInterface.jl b/src/ArrayInterface.jl index 757575109..c33947719 100644 --- a/src/ArrayInterface.jl +++ b/src/ArrayInterface.jl @@ -93,9 +93,11 @@ known_length(::Type{<:Tuple{Vararg{Any,N}}}) where {N} = N known_length(::Type{<:Number}) = 1 known_length(::Type{<:AbstractCartesianIndex{N}}) where {N} = N known_length(::Type{T}) where {T} = _maybe_known_length(Base.IteratorSize(T), T) + @inline _prod_or_nothing(x, ::Tuple{}) = x @inline _prod_or_nothing(_, ::Tuple{Nothing,Vararg}) = nothing @inline _prod_or_nothing(x, y::Tuple{I,Vararg}) where {I} = _prod_or_nothing(x*first(y), Base.tail(y)) + _maybe_known_length(::Base.HasShape, ::Type{T}) where {T} = _prod_or_nothing(1, known_size(T)) _maybe_known_length(::Base.IteratorSize, ::Type) = nothing function known_length(::Type{<:Iterators.Flatten{I}}) where {I} diff --git a/test/runtests.jl b/test/runtests.jl index 7f8edd79b..d8372476a 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -518,7 +518,11 @@ end @test @inferred(ArrayInterface.size(irev)) === (StaticInt(2), StaticInt(3), StaticInt(4)) @test @inferred(ArrayInterface.size(iprod)) === (StaticInt(2), StaticInt(3), StaticInt(4)) - @test @inferred(ArrayInterface.size(iflat)) === (static(72),) + if VERSION >= v"1.7" + @test @inferred(ArrayInterface.size(iflat)) === (static(72),) + else + @test_skip @inferred(ArrayInterface.size(iflat)) === (static(72),) + end @test @inferred(ArrayInterface.size(igen)) === (StaticInt(2), StaticInt(3), StaticInt(4)) @test @inferred(ArrayInterface.size(iacc)) === (StaticInt(2), StaticInt(3), StaticInt(4)) @test @inferred(ArrayInterface.size(ienum)) === (StaticInt(2), StaticInt(3), StaticInt(4)) From d497de8829b6a493506847d5a38bbac8fd6c2e5a Mon Sep 17 00:00:00 2001 From: Chris Elrod Date: Tue, 1 Mar 2022 17:14:41 -0500 Subject: [PATCH 11/11] coax inference --- src/ArrayInterface.jl | 23 ++++++++++++++++++----- test/runtests.jl | 6 +----- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/ArrayInterface.jl b/src/ArrayInterface.jl index c33947719..be6dfc84b 100644 --- a/src/ArrayInterface.jl +++ b/src/ArrayInterface.jl @@ -94,14 +94,27 @@ known_length(::Type{<:Number}) = 1 known_length(::Type{<:AbstractCartesianIndex{N}}) where {N} = N known_length(::Type{T}) where {T} = _maybe_known_length(Base.IteratorSize(T), T) -@inline _prod_or_nothing(x, ::Tuple{}) = x -@inline _prod_or_nothing(_, ::Tuple{Nothing,Vararg}) = nothing -@inline _prod_or_nothing(x, y::Tuple{I,Vararg}) where {I} = _prod_or_nothing(x*first(y), Base.tail(y)) +@generated function _prod_or_nothing(x::Tuple) + p = 1 + for i in eachindex(x.parameters) + x.parameters[i] === Nothing && return nothing + p *= x.parameters[i].parameters[1] + end + StaticInt(p) +end + +function _maybe_known_length(::Base.HasShape, ::Type{T}) where {T} + t = map(_static_or_nothing, known_size(T)) + _int_or_nothing(_prod_or_nothing(t)) +end -_maybe_known_length(::Base.HasShape, ::Type{T}) where {T} = _prod_or_nothing(1, known_size(T)) _maybe_known_length(::Base.IteratorSize, ::Type) = nothing +_static_or_nothing(::Nothing) = nothing +@inline _static_or_nothing(x::Int) = StaticInt{x}() +_int_or_nothing(::StaticInt{N}) where {N} = N +_int_or_nothing(::Nothing) = nothing function known_length(::Type{<:Iterators.Flatten{I}}) where {I} - _prod_or_nothing(1, (known_length(I),known_length(eltype(I)))) + _int_or_nothing(_prod_or_nothing((_static_or_nothing(known_length(I)),_static_or_nothing(known_length(eltype(I)))))) end """ diff --git a/test/runtests.jl b/test/runtests.jl index d8372476a..7f8edd79b 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -518,11 +518,7 @@ end @test @inferred(ArrayInterface.size(irev)) === (StaticInt(2), StaticInt(3), StaticInt(4)) @test @inferred(ArrayInterface.size(iprod)) === (StaticInt(2), StaticInt(3), StaticInt(4)) - if VERSION >= v"1.7" - @test @inferred(ArrayInterface.size(iflat)) === (static(72),) - else - @test_skip @inferred(ArrayInterface.size(iflat)) === (static(72),) - end + @test @inferred(ArrayInterface.size(iflat)) === (static(72),) @test @inferred(ArrayInterface.size(igen)) === (StaticInt(2), StaticInt(3), StaticInt(4)) @test @inferred(ArrayInterface.size(iacc)) === (StaticInt(2), StaticInt(3), StaticInt(4)) @test @inferred(ArrayInterface.size(ienum)) === (StaticInt(2), StaticInt(3), StaticInt(4))