From ac0367b31f61545295562542bd92103ea0615559 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Thu, 18 Aug 2016 03:39:59 -0500 Subject: [PATCH 1/2] Make similar faster and safer By converting the eltype argument into a ::Type{T} parameter, we avoid runtime method lookup. Perhaps more importantly, the introduction of NeedsShaping makes `similar` safer, by preventing any possibility of an infinite recursion. --- base/abstractarray.jl | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 252a7b271316d..fbecc43efa4f8 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -9,6 +9,7 @@ typealias RangeIndex Union{Int, Range{Int}, AbstractUnitRange{Int}, Colon} typealias DimOrInd Union{Integer, AbstractUnitRange} typealias IntOrInd Union{Int, AbstractUnitRange} typealias DimsOrInds{N} NTuple{N,DimOrInd} +typealias NeedsShaping Union{Tuple{Integer,Vararg{Integer}}, Tuple{OneTo,Vararg{OneTo}}} macro _inline_pure_meta() Expr(:meta, :inline, :pure) @@ -420,14 +421,14 @@ different element type it will create a regular `Array` instead: 2.18425e-314 2.18425e-314 2.18425e-314 2.18425e-314 """ -similar{T}(a::AbstractArray{T}) = similar(a, T) -similar( a::AbstractArray, T::Type) = similar(a, T, to_shape(indices(a))) -similar{T}(a::AbstractArray{T}, dims::Tuple) = similar(a, T, to_shape(dims)) -similar{T}(a::AbstractArray{T}, dims::DimOrInd...) = similar(a, T, to_shape(dims)) -similar( a::AbstractArray, T::Type, dims::DimOrInd...) = similar(a, T, to_shape(dims)) -similar( a::AbstractArray, T::Type, dims) = similar(a, T, to_shape(dims)) +similar{T}(a::AbstractArray{T}) = similar(a, T) +similar{T}(a::AbstractArray, ::Type{T}) = similar(a, T, to_shape(indices(a))) +similar{T}(a::AbstractArray{T}, dims::Tuple) = similar(a, T, to_shape(dims)) +similar{T}(a::AbstractArray{T}, dims::DimOrInd...) = similar(a, T, to_shape(dims)) +similar{T}(a::AbstractArray, ::Type{T}, dims::DimOrInd...) = similar(a, T, to_shape(dims)) +similar{T}(a::AbstractArray, ::Type{T}, dims::NeedsShaping) = similar(a, T, to_shape(dims)) # similar creates an Array by default -similar{N}(a::AbstractArray, T::Type, dims::Dims{N}) = Array{T,N}(dims) +similar{T,N}(a::AbstractArray, ::Type{T}, dims::Dims{N}) = Array{T,N}(dims) to_shape(::Tuple{}) = () to_shape(dims::Dims) = dims From c33848526fcb22ca4a190c41fa2e4a519d6454a6 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Thu, 18 Aug 2016 17:34:38 -0500 Subject: [PATCH 2/2] Test that similar throws a MethodError for unsupported dims types --- test/offsetarray.jl | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/offsetarray.jl b/test/offsetarray.jl index 6d99433d03d61..854712b721d02 100644 --- a/test/offsetarray.jl +++ b/test/offsetarray.jl @@ -369,3 +369,20 @@ for s = -5:5 end end # let + +# Check that similar throws a MethodError rather than a +# StackOverflowError if no appropriate method has been defined +# (#18107) +module SimilarUR + using Base.Test + immutable MyURange <: AbstractUnitRange{Int} + start::Int + stop::Int + end + ur = MyURange(1,3) + a = Array{Int}(2) + @test_throws MethodError similar(a, ur) + @test_throws MethodError similar(a, Float64, ur) + @test_throws MethodError similar(a, Float64, (ur,)) + @test_throws MethodError similar(a, (2.0,3.0)) +end