From 112b14996fdea642b125b32f16e8588b6e79ed8a Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Tue, 20 Mar 2018 16:31:06 -0400 Subject: [PATCH 1/4] Deprecate `similar(f, axes)` to calling f directly... and implement an AbstractArray constructor --- base/abstractarray.jl | 52 +++++++++++++++---------- base/array.jl | 15 ++++--- base/bitarray.jl | 8 ++-- base/deprecated.jl | 10 +++++ base/multidimensional.jl | 5 +-- base/reducedim.jl | 8 ++-- base/stat.jl | 34 ++++++++-------- base/sysimg.jl | 4 ++ stdlib/SparseArrays/src/sparsematrix.jl | 6 +-- test/TestHelpers.jl | 9 ++++- test/bitarray.jl | 2 +- test/compiler/compiler.jl | 2 +- 12 files changed, 93 insertions(+), 62 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 28aaebb6bffea..1ac1f54f7380f 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -15,12 +15,35 @@ convert(::Type{T}, a::T) where {T<:AbstractArray} = a convert(::Type{AbstractArray{T}}, a::AbstractArray) where {T} = AbstractArray{T}(a) convert(::Type{AbstractArray{T,N}}, a::AbstractArray{<:Any,N}) where {T,N} = AbstractArray{T,N}(a) -if nameof(@__MODULE__) === :Base # avoid method overwrite -# catch undefined constructors before the deprecation kicks in -# TODO: remove when deprecation is removed -function (::Type{T})(arg) where {T<:AbstractArray} - throw(MethodError(T, (arg,))) -end +to_axis(d::Integer) = OneTo(d) +to_axis(d::AbstractUnitRange) = d + +# AbstractArray constructors: Gather args into a `AbstractArray{T,N}(undef, ::Tuple)` method +if nameof(@__MODULE__) === Core # avoid method overwrite with Core + # These methods and the types in these methods are shared between Core and Base + AbstractArray{T}(::UndefInitializer, dims::Vararg{Integer,N}) where {T,N} = AbstractArray{T,N}(undef, dims) + AbstractArray{T}(::UndefInitializer, dims::NTuple{N,Integer}) where {T,N} = AbstractArray{T,N}(undef, dims) + + AbstractArray{T,N}(::UndefInitializer, dims::NTuple{N,Integer}) where {T,N} = Array{T,N}(undef, dims) + AbstractArray{Bool,N}(::UndefInitializer, dims::NTuple{N,Integer}) where {N} = BitArray{N}(undef, dims...) +elseif nameof(@__MODULE__) === :Base # avoid method overwrite with Core + # Add definitions supporting axes in Base alone — Core.OneTo is not shared with Base.OneTo + AbstractArray{T}(::UndefInitializer, dims::Vararg{DimOrInd,N}) where {T,N} = AbstractArray{T,N}(undef, dims) + AbstractArray{T}(::UndefInitializer, dims::NTuple{N,DimOrInd}) where {T,N} = AbstractArray{T,N}(undef, dims) + AbstractArray{T,N}(::UndefInitializer, dims::Vararg{DimOrInd,N}) where {T,N} = AbstractArray{T,N}(undef, dims) + + AbstractArray{T,N}(::UndefInitializer, dims::NTuple{N,Union{Integer, OneTo}}) where {T,N} = AbstractArray{T,N}(undef, map(to_axis, dims)) + + AbstractArray{T,N}(::UndefInitializer, dims::NTuple{N,OneTo}) where {T,N} = Array{T,N}(undef, map(last, dims)) + AbstractArray{T,0}(::UndefInitializer, ::Tuple{}) where {T} = Array{T,0}(undef) + AbstractArray{Bool,N}(::UndefInitializer, dims::NTuple{N,OneTo}) where {N} = BitArray{N}(undef, map(last, dims)...) + AbstractArray{Bool,0}(::UndefInitializer, ::Tuple{}) where {} = BitArray{0}(undef) + + # catch undefined constructors before the deprecation kicks in + # TODO: remove when deprecation is removed + function (::Type{T})(arg) where {T<:AbstractArray} + throw(MethodError(T, (arg,))) + end end """ @@ -590,14 +613,9 @@ indices of the result will match `A`. would create a 1-dimensional logical array whose indices match those of the columns of `A`. - - similar(dims->zeros(Int, dims), axes(A)) - -would create an array of `Int`, initialized to zero, matching the -indices of `A`. """ -similar(f, shape::Tuple) = f(to_shape(shape)) -similar(f, dims::DimOrInd...) = similar(f, dims) +similar(::Type{T}, shape::Tuple) where {T} = T(to_shape(shape)) +similar(::Type{T}, dims::DimOrInd...) where {T} = similar(T, dims) """ empty(v::AbstractVector, [eltype]) @@ -886,14 +904,6 @@ isempty(a::AbstractArray) = (_length(a) == 0) # keys with an IndexStyle keys(s::IndexStyle, A::AbstractArray, B::AbstractArray...) = eachindex(s, A, B...) -""" - of_indices(x, y) - -Represents the array `y` as an array having the same indices type as `x`. -""" -of_indices(x, y) = similar(dims->y, oftype(axes(x), axes(y))) - - ## range conversions ## map(::Type{T}, r::StepRange) where {T<:Real} = T(r.start):T(r.step):T(last(r)) diff --git a/base/array.jl b/base/array.jl index a9c8e46b0de28..085ce989730e3 100644 --- a/base/array.jl +++ b/base/array.jl @@ -347,8 +347,11 @@ julia> fill(1.0, (5,5)) If `x` is an object reference, all elements will refer to the same object. `fill(Foo(), dims)` will return an array filled with the result of evaluating `Foo()` once. """ -fill(v, dims::Dims) = fill!(Array{typeof(v)}(undef, dims), v) -fill(v, dims::Integer...) = fill!(Array{typeof(v)}(undef, dims...), v) +fill(v, dims::NTuple{N, Integer}) where {N} = fill!(Array{typeof(v), N}(undef, dims), v) +fill(v, dims::NTuple{N, OneTo}) where {N} = fill!(Array{typeof(v), N}(undef, map(last, dims)), v) +fill(v, dims::NTuple{N, Union{Integer, OneTo}}) where {N} = fill!(Array{typeof(v), N}(undef, map(to_axis, dims)), v) +fill(v, dims::Tuple{}) = fill!(Array{typeof(v), 0}(undef), v) +fill(v, dims::DimOrInd...) = fill(v, dims) """ zeros([T=Float64,] dims...) @@ -392,10 +395,10 @@ function ones end for (fname, felt) in ((:zeros, :zero), (:ones, :one)) @eval begin - $fname(::Type{T}, dims::NTuple{N, Any}) where {T, N} = fill!(Array{T,N}(undef, convert(Dims, dims)::Dims), $felt(T)) - $fname(dims::Tuple) = ($fname)(Float64, dims) - $fname(::Type{T}, dims...) where {T} = $fname(T, dims) - $fname(dims...) = $fname(dims) + $fname(::Type{T}, dims::NTuple{N,DimOrInd}) where {T,N} = fill!(AbstractArray{T,N}(undef, dims), $felt(T)) + $fname(dims::Tuple{Vararg{DimOrInd}}) = $fname(Float64, dims) + $fname(::Type{T}, dims::DimOrInd...) where {T} = $fname(T, dims) + $fname(dims::DimOrInd...) = $fname(dims) end end diff --git a/base/bitarray.jl b/base/bitarray.jl index c7b5921a37b88..6f769270f324d 100644 --- a/base/bitarray.jl +++ b/base/bitarray.jl @@ -366,8 +366,8 @@ julia> falses(2,3) false false false ``` """ -falses(dims::Dims) = fill!(BitArray(undef, dims), false) -falses(dims::Integer...) = falses(map(Int,dims)) +falses(dims::Tuple{Vararg{DimOrInd}}) = fill!(AbstractArray{Bool}(undef, dims), false) +falses(dims::DimOrInd...) = falses(dims) """ trues(dims) @@ -382,8 +382,8 @@ julia> trues(2,3) true true true ``` """ -trues(dims::Dims) = fill!(BitArray(undef, dims), true) -trues(dims::Integer...) = trues(map(Int,dims)) +trues(dims::Tuple{Vararg{DimOrInd}}) = fill!(AbstractArray{Bool}(undef, dims), true) +trues(dims::DimOrInd...) = trues(dims) function one(x::BitMatrix) m, n = size(x) diff --git a/base/deprecated.jl b/base/deprecated.jl index e127e89e5857d..596368e4822d3 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -1557,6 +1557,16 @@ end @deprecate Crand Libc.rand false @deprecate Csrand Libc.srand false +# Deprecate `similar(f, axes)` +@noinline function similar(f, shape::Tuple) + depwarn("using similar(f, shape) to call `f` with axes `shape` is deprecated; call `f` directly and/or add methods such that it supports axes", :similar) + f(to_shape(shape)) +end +@noinline function similar(f, dims::DimOrInd...) + depwarn("using similar(f, shape...) to call `f` with axes `shape` is deprecated; call `f` directly and/or add methods such that it supports axes", :similar) + f(to_shape(dims)) +end + @deprecate showcompact(x) show(IOContext(stdout, :compact => true), x) @deprecate showcompact(io, x) show(IOContext(io, :compact => true), x) @deprecate sprint(::typeof(showcompact), args...) sprint(show, args...; context=:compact => true) diff --git a/base/multidimensional.jl b/base/multidimensional.jl index 8c8997e053435..ec16d31338bda 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -1763,10 +1763,9 @@ julia> unique(A, 3) ``` """ @generated function unique(A::AbstractArray{T,N}, dim::Int) where {T,N} - inds = inds -> zeros(UInt, inds) quote 1 <= dim <= $N || return copy(A) - hashes = similar($inds, axes(A, dim)) + hashes = zeros(UInt, axes(A, dim)) # Compute hash for each row k = 0 @@ -1783,7 +1782,7 @@ julia> unique(A, 3) uniquerows = collect(values(firstrow)) # Check for collisions - collided = similar(falses, axes(A, dim)) + collided = falses(axes(A, dim)) @inbounds begin @nloops $N i A d->(if d == dim k = i_d diff --git a/base/reducedim.jl b/base/reducedim.jl index 89b01379f2f09..7585c91fba000 100644 --- a/base/reducedim.jl +++ b/base/reducedim.jl @@ -746,10 +746,10 @@ function _findmin(A, region) if prod(map(length, reduced_indices(A, region))) != 0 throw(ArgumentError("collection slices must be non-empty")) end - (similar(A, ri), similar(dims->zeros(eltype(keys(A)), dims), ri)) + (similar(A, ri), zeros(eltype(keys(A)), ri)) else findminmax!(isless, fill!(similar(A, ri), first(A)), - similar(dims->zeros(eltype(keys(A)), dims), ri), A) + zeros(eltype(keys(A)), ri), A) end end @@ -795,10 +795,10 @@ function _findmax(A, region) if prod(map(length, reduced_indices(A, region))) != 0 throw(ArgumentError("collection slices must be non-empty")) end - similar(A, ri), similar(dims->zeros(eltype(keys(A)), dims), ri) + similar(A, ri), zeros(eltype(keys(A)), ri) else findminmax!(isgreater, fill!(similar(A, ri), first(A)), - similar(dims->zeros(eltype(keys(A)), dims), ri), A) + zeros(eltype(keys(A)), ri), A) end end diff --git a/base/stat.jl b/base/stat.jl index 1f5aca7921864..65f8b7248ab1e 100644 --- a/base/stat.jl +++ b/base/stat.jl @@ -282,23 +282,23 @@ operm(st::StatStruct) = UInt8((filemode(st) ) & 0x7) # mode predicate methods for file names for f in Symbol[ - :ispath - :isfifo - :ischardev - :isdir - :isblockdev - :isfile - :issocket - :issetuid - :issetgid - :issticky - :uperm - :gperm - :operm - :filemode - :filesize - :mtime - :ctime + :ispath, + :isfifo, + :ischardev, + :isdir, + :isblockdev, + :isfile, + :issocket, + :issetuid, + :issetgid, + :issticky, + :uperm, + :gperm, + :operm, + :filemode, + :filesize, + :mtime, + :ctime, ] @eval ($f)(path...) = ($f)(stat(path...)) end diff --git a/base/sysimg.jl b/base/sysimg.jl index 6f1ba531e317f..706ea20953e9f 100644 --- a/base/sysimg.jl +++ b/base/sysimg.jl @@ -155,6 +155,7 @@ include("reinterpretarray.jl") # type and dimensionality specified, accepting dims as series of Integers Vector{T}(::UndefInitializer, m::Integer) where {T} = Vector{T}(undef, Int(m)) Matrix{T}(::UndefInitializer, m::Integer, n::Integer) where {T} = Matrix{T}(undef, Int(m), Int(n)) +Array{T,N}(::UndefInitializer, d::Vararg{Integer,N}) where {T,N} = Array{T,N}(undef, convert(Tuple{Vararg{Int}}, d)) # type but not dimensionality specified, accepting dims as series of Integers Array{T}(::UndefInitializer, m::Integer) where {T} = Array{T,1}(undef, Int(m)) Array{T}(::UndefInitializer, m::Integer, n::Integer) where {T} = Array{T,2}(undef, Int(m), Int(n)) @@ -163,6 +164,9 @@ Array{T}(::UndefInitializer, d::Integer...) where {T} = Array{T}(undef, convert( # dimensionality but not type specified, accepting dims as series of Integers Vector(::UndefInitializer, m::Integer) = Vector{Any}(undef, Int(m)) Matrix(::UndefInitializer, m::Integer, n::Integer) = Matrix{Any}(undef, Int(m), Int(n)) +# Dimensions as a single tuple +Array{T}(::UndefInitializer, d::NTuple{N,Integer}) where {T,N} = Array{T,N}(undef, convert(Tuple{Vararg{Int}}, d)) +Array{T,N}(::UndefInitializer, d::NTuple{N,Integer}) where {T,N} = Array{T,N}(undef, convert(Tuple{Vararg{Int}}, d)) # empty vector constructor Vector() = Vector{Any}(undef, 0) diff --git a/stdlib/SparseArrays/src/sparsematrix.jl b/stdlib/SparseArrays/src/sparsematrix.jl index bbf0797a0e8c3..821e4c396ff93 100644 --- a/stdlib/SparseArrays/src/sparsematrix.jl +++ b/stdlib/SparseArrays/src/sparsematrix.jl @@ -1607,9 +1607,9 @@ end # and computing reductions along columns into SparseMatrixCSC is # non-trivial, so use Arrays for output Base.reducedim_initarray(A::SparseMatrixCSC, region, v0, ::Type{R}) where {R} = - fill!(similar(dims->Array{R}(undef, dims), Base.reduced_indices(A,region)), v0) + fill(v0, Base.reduced_indices(A,region)) Base.reducedim_initarray0(A::SparseMatrixCSC, region, v0, ::Type{R}) where {R} = - fill!(similar(dims->Array{R}(undef, dims), Base.reduced_indices0(A,region)), v0) + fill(v0, Base.reduced_indices0(A,region)) # General mapreduce function _mapreducezeros(f, op, ::Type{T}, nzeros::Int, v0) where T @@ -1823,7 +1823,7 @@ function _findr(op, A, region, Tv) throw(ArgumentError("array slices must be non-empty")) else ri = Base.reduced_indices0(A, region) - return (similar(A, ri), similar(dims->zeros(Ti, dims), ri)) + return (similar(A, ri), zeros(Ti, ri)) end end diff --git a/test/TestHelpers.jl b/test/TestHelpers.jl index f44c81b93e39c..3d2fe3d7f0587 100644 --- a/test/TestHelpers.jl +++ b/test/TestHelpers.jl @@ -95,8 +95,6 @@ function Base.similar(A::AbstractArray, T::Type, inds::Tuple{UnitRange,Vararg{Un OffsetArray(B, map(indsoffset, inds)) end -Base.similar(f::Union{Function,Type}, shape::Tuple{UnitRange,Vararg{UnitRange}}) = - OffsetArray(f(map(length, shape)), map(indsoffset, shape)) Base.similar(::Type{T}, shape::Tuple{UnitRange,Vararg{UnitRange}}) where {T<:Array} = OffsetArray(T(undef, map(length, shape)), map(indsoffset, shape)) Base.similar(::Type{T}, shape::Tuple{UnitRange,Vararg{UnitRange}}) where {T<:BitArray} = @@ -104,6 +102,13 @@ Base.similar(::Type{T}, shape::Tuple{UnitRange,Vararg{UnitRange}}) where {T<:Bit Base.reshape(A::AbstractArray, inds::Tuple{UnitRange,Vararg{UnitRange}}) = OffsetArray(reshape(A, map(length, inds)), map(indsoffset, inds)) +Base.fill(v, inds::NTuple{N, AbstractUnitRange}) where{N} = + fill!(OffsetArray(Array{typeof(v), N}(undef, map(length, inds)), map(indsoffset, inds)), v) +Base.AbstractArray{T}(::UndefInitializer, inds::NTuple{N,AbstractUnitRange}) where {T,N} = + OffsetArray(Array{T, N}(undef, map(length, inds)), map(indsoffset, inds)) +Base.AbstractArray{T,N}(::UndefInitializer, inds::NTuple{N,AbstractUnitRange}) where {T,N} = + OffsetArray(Array{T, N}(undef, map(length, inds)), map(indsoffset, inds)) + @inline function Base.getindex(A::OffsetArray{T,N}, I::Vararg{Int,N}) where {T,N} checkbounds(A, I...) @inbounds ret = parent(A)[offset(A.offsets, I)...] diff --git a/test/bitarray.jl b/test/bitarray.jl index dea99ed0f6b4d..39acefadc1a72 100644 --- a/test/bitarray.jl +++ b/test/bitarray.jl @@ -16,7 +16,7 @@ bitcheck(x) = true function check_bitop_call(ret_type, func, args...; kwargs...) r1 = func(args...; kwargs...) r2 = func(map(x->(isa(x, BitArray) ? Array(x) : x), args)...; kwargs...) - ret_type ≢ nothing && !isa(r1, ret_type) && @show ret_type, r1 + ret_type ≢ nothing && !isa(r1, ret_type) && @show ret_type, typeof(r1) ret_type ≢ nothing && @test isa(r1, ret_type) @test tc(r1, r2) @test isequal(r1, ret_type ≡ nothing ? r2 : r2) diff --git a/test/compiler/compiler.jl b/test/compiler/compiler.jl index b33d92bc38ba9..516642bda6944 100644 --- a/test/compiler/compiler.jl +++ b/test/compiler/compiler.jl @@ -516,7 +516,7 @@ end # issue #5575 f5575() = zeros(Type[Float64][1], 1) -@test Base.return_types(f5575, ())[1] == Vector +@test Base.return_types(f5575, ())[1] == Union{Vector, BitVector} # make sure Tuple{unknown} handles the possibility that `unknown` is a Vararg function maybe_vararg_tuple_1() From 982b1a74c8072c91d95385f4f79250746e322484 Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Fri, 6 Apr 2018 09:56:48 -0400 Subject: [PATCH 2/4] Remove AbstractArray constructors; just use dispatch on functions --- base/abstractarray.jl | 35 ++++++----------------------------- base/array.jl | 18 +++++++++++------- base/bitarray.jl | 12 ++++++++---- test/TestHelpers.jl | 23 +++++++++++++++-------- test/compiler/compiler.jl | 2 +- 5 files changed, 41 insertions(+), 49 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 1ac1f54f7380f..2546f948c31e3 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -15,35 +15,12 @@ convert(::Type{T}, a::T) where {T<:AbstractArray} = a convert(::Type{AbstractArray{T}}, a::AbstractArray) where {T} = AbstractArray{T}(a) convert(::Type{AbstractArray{T,N}}, a::AbstractArray{<:Any,N}) where {T,N} = AbstractArray{T,N}(a) -to_axis(d::Integer) = OneTo(d) -to_axis(d::AbstractUnitRange) = d - -# AbstractArray constructors: Gather args into a `AbstractArray{T,N}(undef, ::Tuple)` method -if nameof(@__MODULE__) === Core # avoid method overwrite with Core - # These methods and the types in these methods are shared between Core and Base - AbstractArray{T}(::UndefInitializer, dims::Vararg{Integer,N}) where {T,N} = AbstractArray{T,N}(undef, dims) - AbstractArray{T}(::UndefInitializer, dims::NTuple{N,Integer}) where {T,N} = AbstractArray{T,N}(undef, dims) - - AbstractArray{T,N}(::UndefInitializer, dims::NTuple{N,Integer}) where {T,N} = Array{T,N}(undef, dims) - AbstractArray{Bool,N}(::UndefInitializer, dims::NTuple{N,Integer}) where {N} = BitArray{N}(undef, dims...) -elseif nameof(@__MODULE__) === :Base # avoid method overwrite with Core - # Add definitions supporting axes in Base alone — Core.OneTo is not shared with Base.OneTo - AbstractArray{T}(::UndefInitializer, dims::Vararg{DimOrInd,N}) where {T,N} = AbstractArray{T,N}(undef, dims) - AbstractArray{T}(::UndefInitializer, dims::NTuple{N,DimOrInd}) where {T,N} = AbstractArray{T,N}(undef, dims) - AbstractArray{T,N}(::UndefInitializer, dims::Vararg{DimOrInd,N}) where {T,N} = AbstractArray{T,N}(undef, dims) - - AbstractArray{T,N}(::UndefInitializer, dims::NTuple{N,Union{Integer, OneTo}}) where {T,N} = AbstractArray{T,N}(undef, map(to_axis, dims)) - - AbstractArray{T,N}(::UndefInitializer, dims::NTuple{N,OneTo}) where {T,N} = Array{T,N}(undef, map(last, dims)) - AbstractArray{T,0}(::UndefInitializer, ::Tuple{}) where {T} = Array{T,0}(undef) - AbstractArray{Bool,N}(::UndefInitializer, dims::NTuple{N,OneTo}) where {N} = BitArray{N}(undef, map(last, dims)...) - AbstractArray{Bool,0}(::UndefInitializer, ::Tuple{}) where {} = BitArray{0}(undef) - - # catch undefined constructors before the deprecation kicks in - # TODO: remove when deprecation is removed - function (::Type{T})(arg) where {T<:AbstractArray} - throw(MethodError(T, (arg,))) - end +if nameof(@__MODULE__) === :Base # avoid method overwrite +# catch undefined constructors before the deprecation kicks in +# TODO: remove when deprecation is removed +function (::Type{T})(arg) where {T<:AbstractArray} + throw(MethodError(T, (arg,))) +end end """ diff --git a/base/array.jl b/base/array.jl index 085ce989730e3..d4c0dd15294e8 100644 --- a/base/array.jl +++ b/base/array.jl @@ -327,6 +327,9 @@ function fill!(a::Array{T}, x) where T<:Union{Integer,AbstractFloat} return a end +to_dim(d::Integer) = d +to_dim(d::OneTo) = last(d) + """ fill(x, dims) @@ -347,11 +350,10 @@ julia> fill(1.0, (5,5)) If `x` is an object reference, all elements will refer to the same object. `fill(Foo(), dims)` will return an array filled with the result of evaluating `Foo()` once. """ -fill(v, dims::NTuple{N, Integer}) where {N} = fill!(Array{typeof(v), N}(undef, dims), v) -fill(v, dims::NTuple{N, OneTo}) where {N} = fill!(Array{typeof(v), N}(undef, map(last, dims)), v) -fill(v, dims::NTuple{N, Union{Integer, OneTo}}) where {N} = fill!(Array{typeof(v), N}(undef, map(to_axis, dims)), v) -fill(v, dims::Tuple{}) = fill!(Array{typeof(v), 0}(undef), v) fill(v, dims::DimOrInd...) = fill(v, dims) +fill(v, dims::NTuple{N, Union{Integer, OneTo}}) where {N} = fill(v, map(to_dim, dims)) +fill(v, dims::NTuple{N, Integer}) where {N} = fill!(Array{typeof(v),N}(undef, dims), v) +fill(v, dims::Tuple{}) = fill!(Array{typeof(v),0}(undef, dims), v) """ zeros([T=Float64,] dims...) @@ -395,10 +397,12 @@ function ones end for (fname, felt) in ((:zeros, :zero), (:ones, :one)) @eval begin - $fname(::Type{T}, dims::NTuple{N,DimOrInd}) where {T,N} = fill!(AbstractArray{T,N}(undef, dims), $felt(T)) - $fname(dims::Tuple{Vararg{DimOrInd}}) = $fname(Float64, dims) - $fname(::Type{T}, dims::DimOrInd...) where {T} = $fname(T, dims) $fname(dims::DimOrInd...) = $fname(dims) + $fname(::Type{T}, dims::DimOrInd...) where {T} = $fname(T, dims) + $fname(dims::Tuple{Vararg{DimOrInd}}) = $fname(Float64, dims) + $fname(::Type{T}, dims::NTuple{N, Union{Integer, OneTo}}) where {T,N} = $fname(T, map(to_dim, dims)) + $fname(::Type{T}, dims::NTuple{N, Integer}) where {T,N} = fill!(Array{T,N}(undef, map(to_dim, dims)), $felt(T)) + $fname(::Type{T}, dims::Tuple{}) where {T} = fill!(Array{T}(undef), $felt(T)) end end diff --git a/base/bitarray.jl b/base/bitarray.jl index 6f769270f324d..bac2ad07d6a79 100644 --- a/base/bitarray.jl +++ b/base/bitarray.jl @@ -56,8 +56,8 @@ julia> BitArray(undef, (3, 1)) """ BitArray(::UndefInitializer, dims::Integer...) = BitArray(undef, map(Int,dims)) BitArray{N}(::UndefInitializer, dims::Integer...) where {N} = BitArray{N}(undef, map(Int,dims)) -BitArray(::UndefInitializer, dims::NTuple{N,Int}) where {N} = BitArray{N}(undef, dims...) -BitArray{N}(::UndefInitializer, dims::NTuple{N,Int}) where {N} = BitArray{N}(undef, dims...) +BitArray(::UndefInitializer, dims::NTuple{N,Integer}) where {N} = BitArray{N}(undef, map(Int, dims)...) +BitArray{N}(::UndefInitializer, dims::NTuple{N,Integer}) where {N} = BitArray{N}(undef, map(Int, dims)...) const BitVector = BitArray{1} const BitMatrix = BitArray{2} @@ -366,8 +366,10 @@ julia> falses(2,3) false false false ``` """ -falses(dims::Tuple{Vararg{DimOrInd}}) = fill!(AbstractArray{Bool}(undef, dims), false) falses(dims::DimOrInd...) = falses(dims) +falses(dims::NTuple{N, Union{Integer, OneTo}}) where {N} = falses(map(to_dim, dims)) +falses(dims::NTuple{N, Integer}) where {N} = fill!(BitArray(undef, dims), false) +falses(dims::Tuple{}) = fill!(BitArray(undef, dims), false) """ trues(dims) @@ -382,8 +384,10 @@ julia> trues(2,3) true true true ``` """ -trues(dims::Tuple{Vararg{DimOrInd}}) = fill!(AbstractArray{Bool}(undef, dims), true) trues(dims::DimOrInd...) = trues(dims) +trues(dims::NTuple{N, Union{Integer, OneTo}}) where {N} = trues(map(to_dim, dims)) +trues(dims::NTuple{N, Integer}) where {N} = fill!(BitArray(undef, dims), true) +trues(dims::Tuple{}) = fill!(BitArray(undef, dims), true) function one(x::BitMatrix) m, n = size(x) diff --git a/test/TestHelpers.jl b/test/TestHelpers.jl index 3d2fe3d7f0587..1d1c3eba4e5fc 100644 --- a/test/TestHelpers.jl +++ b/test/TestHelpers.jl @@ -100,14 +100,18 @@ Base.similar(::Type{T}, shape::Tuple{UnitRange,Vararg{UnitRange}}) where {T<:Arr Base.similar(::Type{T}, shape::Tuple{UnitRange,Vararg{UnitRange}}) where {T<:BitArray} = OffsetArray(T(undef, map(length, shape)), map(indsoffset, shape)) -Base.reshape(A::AbstractArray, inds::Tuple{UnitRange,Vararg{UnitRange}}) = OffsetArray(reshape(A, map(length, inds)), map(indsoffset, inds)) - -Base.fill(v, inds::NTuple{N, AbstractUnitRange}) where{N} = - fill!(OffsetArray(Array{typeof(v), N}(undef, map(length, inds)), map(indsoffset, inds)), v) -Base.AbstractArray{T}(::UndefInitializer, inds::NTuple{N,AbstractUnitRange}) where {T,N} = - OffsetArray(Array{T, N}(undef, map(length, inds)), map(indsoffset, inds)) -Base.AbstractArray{T,N}(::UndefInitializer, inds::NTuple{N,AbstractUnitRange}) where {T,N} = - OffsetArray(Array{T, N}(undef, map(length, inds)), map(indsoffset, inds)) +Base.reshape(A::AbstractArray, inds::Tuple{UnitRange,Vararg{UnitRange}}) = OffsetArray(reshape(A, map(indslength, inds)), map(indsoffset, inds)) + +Base.fill(v, inds::NTuple{N, Union{Integer, AbstractUnitRange}}) where {N} = + fill!(OffsetArray(Array{typeof(v), N}(undef, map(indslength, inds)), map(indsoffset, inds)), v) +Base.zeros(::Type{T}, inds::NTuple{N, Union{Integer, AbstractUnitRange}}) where {T, N} = + fill!(OffsetArray(Array{T, N}(undef, map(indslength, inds)), map(indsoffset, inds)), zero(T)) +Base.ones(::Type{T}, inds::NTuple{N, Union{Integer, AbstractUnitRange}}) where {T, N} = + fill!(OffsetArray(Array{T, N}(undef, map(indslength, inds)), map(indsoffset, inds)), one(T)) +Base.trues(inds::NTuple{N, Union{Integer, AbstractUnitRange}}) where {N} = + fill!(OffsetArray(BitArray{N}(undef, map(indslength, inds)), map(indsoffset, inds)), true) +Base.falses(inds::NTuple{N, Union{Integer, AbstractUnitRange}}) where {N} = + fill!(OffsetArray(BitArray{N}(undef, map(indslength, inds)), map(indsoffset, inds)), false) @inline function Base.getindex(A::OffsetArray{T,N}, I::Vararg{Int,N}) where {T,N} checkbounds(A, I...) @@ -167,6 +171,9 @@ _offset(out, ::Tuple{}, ::Tuple{}) = out indsoffset(r::AbstractRange) = first(r) - 1 indsoffset(i::Integer) = 0 +indslength(r::AbstractRange) = length(r) +indslength(i::Integer) = i + Base.resize!(A::OffsetVector, nl::Integer) = (resize!(A.parent, nl); A) diff --git a/test/compiler/compiler.jl b/test/compiler/compiler.jl index 516642bda6944..b33d92bc38ba9 100644 --- a/test/compiler/compiler.jl +++ b/test/compiler/compiler.jl @@ -516,7 +516,7 @@ end # issue #5575 f5575() = zeros(Type[Float64][1], 1) -@test Base.return_types(f5575, ())[1] == Union{Vector, BitVector} +@test Base.return_types(f5575, ())[1] == Vector # make sure Tuple{unknown} handles the possibility that `unknown` is a Vararg function maybe_vararg_tuple_1() From db3751d427981a575fcfb741b816577d797b3486 Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Fri, 6 Apr 2018 14:05:46 -0400 Subject: [PATCH 3/4] Add NEWS and deprecations for... the tightening of signatures for zeros and ones. --- NEWS.md | 10 ++++++++++ base/deprecated.jl | 12 +++++++++++- test/arrayops.jl | 2 +- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index 4a52f28173a83..eed0eba2d8569 100644 --- a/NEWS.md +++ b/NEWS.md @@ -757,6 +757,16 @@ Deprecated or removed necessary, consider `fill!(similar(A[, opts...]), {one(eltype(A)) | zero(eltype(A))})`. For an algebraic multiplicative identity, consider `one(A)` ([#24656]). + * The `similar(dims->f(..., dims...), [T], axes...)` method to add offset array support + to a function `f` that would otherwise create a non-offset array has been deprecated. + Instead, call `f(..., axes...)` directly and, if needed, the offset array implementation + should add offset axis support to the function `f` directly ([#26733]). + + * The functions `ones` and `zeros` used to accept any objects as dimensional arguments, + implicitly converting them to `Int`s. This is now deprecated; only `Integer`s or + `AbstractUnitRange`s are accepted as arguments. Instead, convert the arguments before + calling `ones` or `zeros` ([#26733]). + * The `Operators` module is deprecated. Instead, import required operators explicitly from `Base`, e.g. `import Base: +, -, *, /` ([#22251]). diff --git a/base/deprecated.jl b/base/deprecated.jl index 596368e4822d3..e338de23ec0c6 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -1557,7 +1557,7 @@ end @deprecate Crand Libc.rand false @deprecate Csrand Libc.srand false -# Deprecate `similar(f, axes)` +# Deprecate `similar(f, axes)` (PR #26733) @noinline function similar(f, shape::Tuple) depwarn("using similar(f, shape) to call `f` with axes `shape` is deprecated; call `f` directly and/or add methods such that it supports axes", :similar) f(to_shape(shape)) @@ -1566,6 +1566,16 @@ end depwarn("using similar(f, shape...) to call `f` with axes `shape` is deprecated; call `f` directly and/or add methods such that it supports axes", :similar) f(to_shape(dims)) end +# Deprecate non-integer/axis arguments to zeros/ones to match fill/trues/falses +@deprecate zeros(::Type{T}, dims...) where {T} zeros(T, convert(Dims, dims)...) +@deprecate zeros(dims...) zeros(convert(Dims, dims)...) +@deprecate zeros(::Type{T}, dims::NTuple{N, Any}) where {T, N} zeros(T, convert(Dims, dims)) +@deprecate zeros(dims::Tuple) zeros(convert(Dims, dims)) +@deprecate ones(::Type{T}, dims...) where {T} ones(T, convert(Dims, dims)...) +@deprecate ones(dims...) ones(convert(Dims, dims)...) +@deprecate ones(::Type{T}, dims::NTuple{N, Any}) where {T, N} ones(T, convert(Dims, dims)) +@deprecate ones(dims::Tuple) ones(convert(Dims, dims)) + @deprecate showcompact(x) show(IOContext(stdout, :compact => true), x) @deprecate showcompact(io, x) show(IOContext(io, :compact => true), x) diff --git a/test/arrayops.jl b/test/arrayops.jl index 3c3db385315c0..cf9ef674fa8bc 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -2322,7 +2322,7 @@ end test_zeros(zeros(Int, (2, 3)), Matrix{Int}, (2,3)) # #19265" - @test_throws MethodError zeros(Float64, [1.]) + @test_throws Any zeros(Float64, [1.]) # TODO: Tighten back up to MethodError once 0.7 deprecations are removed end # issue #11053 From 7a089d661a2be3b5029dbd5d91982a6d9ff78272 Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Wed, 11 Apr 2018 16:15:41 -0400 Subject: [PATCH 4/4] Make compiler test use a local function that has the known properties that we want to test. The important thing is not necessarily zeros -- it is a relatively complex function. The `Base.zeros` method tree temporarily breaks this test due to its numerous deprecations, but this will be resolved in the future. --- test/compiler/compiler.jl | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/test/compiler/compiler.jl b/test/compiler/compiler.jl index b33d92bc38ba9..dc4e10f530a31 100644 --- a/test/compiler/compiler.jl +++ b/test/compiler/compiler.jl @@ -514,10 +514,22 @@ end @test h18679() === nothing -# issue #5575 -f5575() = zeros(Type[Float64][1], 1) +# issue #5575: inference with abstract types on a reasonably complex method tree +zeros5575(::Type{T}, dims::Tuple{Vararg{Any,N}}) where {T,N} = Array{T,N}(dims) +zeros5575(dims::Tuple) = zeros5575(Float64, dims) +zeros5575(::Type{T}, dims...) where {T} = zeros5575(T, dims) +zeros5575(a::AbstractArray) = zeros5575(a, Float64) +zeros5575(a::AbstractArray, ::Type{T}) where {T} = zeros5575(a, T, size(a)) +zeros5575(a::AbstractArray, ::Type{T}, dims::Tuple) where {T} = zeros5575(T, dims) +zeros5575(a::AbstractArray, ::Type{T}, dims...) where {T} = zeros5575(T, dims) +zeros5575(dims...) = zeros5575(dims) +f5575() = zeros5575(Type[Float64][1], 1) @test Base.return_types(f5575, ())[1] == Vector +g5575() = zeros(Type[Float64][1], 1) +@test_broken Base.return_types(g5575, ())[1] == Vector # This should be fixed by removing deprecations + + # make sure Tuple{unknown} handles the possibility that `unknown` is a Vararg function maybe_vararg_tuple_1() x = Any[Vararg{Int}][1]