diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 6b97d97c2327a..994136c9e41a1 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -202,13 +202,11 @@ julia> strides(A) (1, 3, 12) ``` """ -strides(A::AbstractArray) = _strides((1,), A) -_strides(out::Tuple{Int}, A::AbstractArray{<:Any,0}) = () -_strides(out::NTuple{N,Int}, A::AbstractArray{<:Any,N}) where {N} = out -function _strides(out::NTuple{M,Int}, A::AbstractArray) where M - @_inline_meta - _strides((out..., out[M]*size(A, M)), A) -end +strides(A::AbstractArray) = size_to_strides(1, size(A)...) +@inline size_to_strides(s, d, sz...) = (s, size_to_strides(s * d, sz...)...) +size_to_strides(s, d) = (s,) +size_to_strides(s) = () + function isassigned(a::AbstractArray, i::Int...) try @@ -1160,30 +1158,32 @@ cat_similar(A::AbstractArray, T, shape) = similar(A, T, shape) cat_shape(dims, shape::Tuple) = shape @inline cat_shape(dims, shape::Tuple, nshape::Tuple, shapes::Tuple...) = - cat_shape(dims, _cshp(dims, (), shape, nshape), shapes...) + cat_shape(dims, _cshp(1, dims, shape, nshape), shapes...) -_cshp(::Tuple{}, out, ::Tuple{}, ::Tuple{}) = out -_cshp(::Tuple{}, out, ::Tuple{}, nshape) = (out..., nshape...) -_cshp(dims, out, ::Tuple{}, ::Tuple{}) = (out..., map(b -> 1, dims)...) -@inline _cshp(dims, out, shape, ::Tuple{}) = - _cshp(tail(dims), (out..., shape[1] + dims[1]), tail(shape), ()) -@inline _cshp(dims, out, ::Tuple{}, nshape) = - _cshp(tail(dims), (out..., nshape[1]), (), tail(nshape)) -@inline function _cshp(::Tuple{}, out, shape, ::Tuple{}) - _cs(length(out) + 1, false, shape[1], 1) - _cshp((), (out..., 1), tail(shape), ()) +_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, ::Tuple{}) = () +_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, nshape) = nshape +_cshp(ndim::Int, dims, ::Tuple{}, ::Tuple{}) = ntuple(b -> 1, Val{length(dims)}) +@inline _cshp(ndim::Int, dims, shape, ::Tuple{}) = + (shape[1] + dims[1], _cshp(ndim + 1, tail(dims), tail(shape), ())...) +@inline _cshp(ndim::Int, dims, ::Tuple{}, nshape) = + (nshape[1], _cshp(ndim + 1, tail(dims), (), tail(nshape))...) +@inline function _cshp(ndim::Int, ::Tuple{}, shape, ::Tuple{}) + _cs(ndim, shape[1], 1) + (1, _cshp(ndim + 1, (), tail(shape), ())...) end -@inline function _cshp(::Tuple{}, out, shape, nshape) - next = _cs(length(out) + 1, false, shape[1], nshape[1]) - _cshp((), (out..., next), tail(shape), tail(nshape)) +@inline function _cshp(ndim::Int, ::Tuple{}, shape, nshape) + next = _cs(ndim, shape[1], nshape[1]) + (next, _cshp(ndim + 1, (), tail(shape), tail(nshape))...) end -@inline function _cshp(dims, out, shape, nshape) - next = _cs(length(out) + 1, dims[1], shape[1], nshape[1]) - _cshp(tail(dims), (out..., next), tail(shape), tail(nshape)) +@inline function _cshp(ndim::Int, dims, shape, nshape) + a = shape[1] + b = nshape[1] + next = dims[1] ? a + b : _cs(ndim, a, b) + (next, _cshp(ndim + 1, tail(dims), tail(shape), tail(nshape))...) end -_cs(d, concat, a, b) = concat ? (a + b) : (a == b ? a : throw(DimensionMismatch(string( - "mismatch in dimension ", d, " (expected ", a, " got ", b, ")")))) +_cs(d, a, b) = (a == b ? a : throw(DimensionMismatch( + "mismatch in dimension $d (expected $a got $b)"))) dims2cat{n}(::Type{Val{n}}) = ntuple(i -> (i == n), Val{n}) dims2cat(dims) = ntuple(i -> (i in dims), maximum(dims)) @@ -1668,15 +1668,15 @@ end function _sub2ind!(Iout, inds, Iinds, I) @_noinline_meta for i in Iinds - # Iout[i] = sub2ind(inds, map(Ij->Ij[i], I)...) + # Iout[i] = sub2ind(inds, map(Ij -> Ij[i], I)...) Iout[i] = sub2ind_vec(inds, i, I) end Iout end -sub2ind_vec(inds, i, I) = (@_inline_meta; _sub2ind_vec(inds, (), i, I...)) -_sub2ind_vec(inds, out, i, I1, I...) = (@_inline_meta; _sub2ind_vec(inds, (out..., I1[i]), i, I...)) -_sub2ind_vec(inds, out, i) = (@_inline_meta; sub2ind(inds, out...)) +sub2ind_vec(inds, i, I) = (@_inline_meta; sub2ind(inds, _sub2ind_vec(i, I...)...)) +_sub2ind_vec(i, I1, I...) = (@_inline_meta; (I1[i], _sub2ind_vec(i, I...)...)) +_sub2ind_vec(i) = () function ind2sub(inds::Union{DimsInteger{N},Indices{N}}, ind::AbstractVector{<:Integer}) where N M = length(ind) diff --git a/base/array.jl b/base/array.jl index e5dea7bc703b8..bbb2c3ec72a8d 100644 --- a/base/array.jl +++ b/base/array.jl @@ -73,12 +73,7 @@ end size(a::Array, d) = arraysize(a, d) size(a::Vector) = (arraysize(a,1),) size(a::Matrix) = (arraysize(a,1), arraysize(a,2)) -size(a::Array) = (@_inline_meta; _size((), a)) -_size(out::NTuple{N}, A::Array{_,N}) where {_,N} = out -function _size(out::NTuple{M}, A::Array{_,N}) where _ where M where N - @_inline_meta - _size((out..., size(A,M+1)), A) -end +size(a::Array{<:Any,N}) where {N} = (@_inline_meta; ntuple(M -> size(a, M), Val{N})) asize_from(a::Array, n) = n > ndims(a) ? () : (arraysize(a,n), asize_from(a, n+1)...) diff --git a/base/broadcast.jl b/base/broadcast.jl index 2d98b4031b0d9..44acd0569de02 100644 --- a/base/broadcast.jl +++ b/base/broadcast.jl @@ -45,23 +45,22 @@ promote_containertype(::Type{T}, ::Type{T}) where {T} = T ## Calculate the broadcast indices of the arguments, or error if incompatible # array inputs broadcast_indices() = () -broadcast_indices(A) = broadcast_indices(containertype(A), A) -broadcast_indices(::ScalarType, A) = () -broadcast_indices(::Type{Tuple}, A) = (OneTo(length(A)),) -broadcast_indices(::Type{Array}, A::Ref) = () -broadcast_indices(::Type{Array}, A) = indices(A) -@inline broadcast_indices(A, B...) = broadcast_shape((), broadcast_indices(A), map(broadcast_indices, B)...) +broadcast_indices(A) = _broadcast_indices(containertype(A), A) +@inline broadcast_indices(A, B...) = broadcast_shape(broadcast_indices(A), broadcast_indices(B...)) +_broadcast_indices(::Type, A) = () +_broadcast_indices(::Type{Tuple}, A) = (OneTo(length(A)),) +_broadcast_indices(::Type{Array}, A::Ref) = () +_broadcast_indices(::Type{Array}, A) = indices(A) # shape (i.e., tuple-of-indices) inputs broadcast_shape(shape::Tuple) = shape -@inline broadcast_shape(shape::Tuple, shape1::Tuple, shapes::Tuple...) = broadcast_shape(_bcs((), shape, shape1), shapes...) +@inline broadcast_shape(shape::Tuple, shape1::Tuple, shapes::Tuple...) = broadcast_shape(_bcs(shape, shape1), shapes...) # _bcs consolidates two shapes into a single output shape -_bcs(out, ::Tuple{}, ::Tuple{}) = out -@inline _bcs(out, ::Tuple{}, newshape) = _bcs((out..., newshape[1]), (), tail(newshape)) -@inline _bcs(out, shape, ::Tuple{}) = _bcs((out..., shape[1]), tail(shape), ()) -@inline function _bcs(out, shape, newshape) - newout = _bcs1(shape[1], newshape[1]) - _bcs((out..., newout), tail(shape), tail(newshape)) +_bcs(::Tuple{}, ::Tuple{}) = () +@inline _bcs(::Tuple{}, newshape::Tuple) = (newshape[1], _bcs((), tail(newshape))...) +@inline _bcs(shape::Tuple, ::Tuple{}) = (shape[1], _bcs(tail(shape), ())...) +@inline function _bcs(shape::Tuple, newshape::Tuple) + return (_bcs1(shape[1], newshape[1]), _bcs(tail(shape), tail(newshape))...) end # _bcs1 handles the logic for a single dimension _bcs1(a::Integer, b::Integer) = a == 1 ? b : (b == 1 ? a : (a == b ? a : throw(DimensionMismatch("arrays could not be broadcast to a common size")))) diff --git a/base/inference.jl b/base/inference.jl index 532b48917a26b..9f73259dafcf0 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -15,6 +15,7 @@ struct InferenceParams inlining::Bool # parameters limiting potentially-infinite types (configurable) + MAX_METHODS::Int MAX_TUPLETYPE_LEN::Int MAX_TUPLE_DEPTH::Int MAX_TUPLE_SPLAT::Int @@ -24,12 +25,13 @@ struct InferenceParams # reasonable defaults function InferenceParams(world::UInt; inlining::Bool = inlining_enabled(), + max_methods::Int = 4, tupletype_len::Int = 15, tuple_depth::Int = 4, tuple_splat::Int = 16, union_splitting::Int = 4, apply_union_enum::Int = 8) - return new(world, inlining, tupletype_len, + return new(world, inlining, max_methods, tupletype_len, tuple_depth, tuple_splat, union_splitting, apply_union_enum) end end @@ -1280,7 +1282,7 @@ function abstract_call_gf_by_type(f::ANY, atype::ANY, sv::InferenceState) end min_valid = UInt[typemin(UInt)] max_valid = UInt[typemax(UInt)] - applicable = _methods_by_ftype(argtype, 4, sv.params.world, min_valid, max_valid) + applicable = _methods_by_ftype(argtype, sv.params.MAX_METHODS, sv.params.world, min_valid, max_valid) rettype = Bottom if applicable === false # this means too many methods matched @@ -1431,7 +1433,7 @@ function precise_container_type(arg::ANY, typ::ANY, vtypes::VarTable, sv::Infere if isa(typ, Const) val = typ.val if isa(val, SimpleVector) || isa(val, Tuple) - return Any[ abstract_eval_constant(x) for x in val ] + return Any[ Const(val[i]) for i in 1:length(val) ] # avoid making a tuple Generator here! end end @@ -1499,44 +1501,64 @@ function abstract_iteration(itertype::ANY, vtypes::VarTable, sv::InferenceState) return Vararg{valtype} end +function tuple_tail_elem(init::ANY, ct) + return Vararg{widenconst(foldl((a, b) -> tmerge(a, unwrapva(b)), init, ct))} +end + # do apply(af, fargs...), where af is a function value -function abstract_apply(af::ANY, fargs::Vector{Any}, aargtypes::Vector{Any}, vtypes::VarTable, sv::InferenceState) +function abstract_apply(aft::ANY, fargs::Vector{Any}, aargtypes::Vector{Any}, vtypes::VarTable, sv::InferenceState) + if !isa(aft, Const) && !isconstType(aft) + if !(isleaftype(aft) || aft <: Type) || (aft <: Builtin) || (aft <: IntrinsicFunction) + return Any + end + # non-constant function, but type is known + end res = Union{} nargs = length(fargs) assert(nargs == length(aargtypes)) - splitunions = countunionsplit(aargtypes) <= sv.params.MAX_APPLY_UNION_ENUM - ctypes = Any[Any[]] + splitunions = 1 < countunionsplit(aargtypes) <= sv.params.MAX_APPLY_UNION_ENUM + ctypes = Any[Any[aft]] for i = 1:nargs if aargtypes[i] === Any # bail out completely and infer as f(::Any...) - # instead could keep what we got so far and just append a Vararg{Any} (by just - # using the normal logic from below), but that makes the time of the subarray - # test explode - ctypes = Any[Any[Vararg{Any}]] + # instead could infer the precise types for the types up to this point and just append a Vararg{Any} + # (by just using the normal logic from below), but that makes the time of the subarray test explode + push!(ctypes[1], Vararg{Any}) break end - ctypes´ = [] - for ti in (splitunions ? uniontypes(aargtypes[i]) : Any[aargtypes[i]]) - cti = precise_container_type(fargs[i], ti, vtypes, sv) - for ct in ctypes - if !isempty(ct) && isvarargtype(ct[end]) - tail = foldl((a,b)->tmerge(a,unwrapva(b)), unwrapva(ct[end]), cti) - push!(ctypes´, push!(ct[1:end-1], Vararg{widenconst(tail)})) - else - push!(ctypes´, append_any(ct, cti)) + end + if length(ctypes[1]) == 1 + for i = 1:nargs + ctypes´ = [] + for ti in (splitunions ? uniontypes(aargtypes[i]) : Any[aargtypes[i]]) + cti = precise_container_type(fargs[i], ti, vtypes, sv) + for ct in ctypes + if !isempty(ct) && isvarargtype(ct[end]) + tail = tuple_tail_elem(unwrapva(ct[end]), cti) + push!(ctypes´, push!(ct[1:(end - 1)], tail)) + else + push!(ctypes´, append_any(ct, cti)) + end end end + ctypes = ctypes´ end - ctypes = ctypes´ end for ct in ctypes if length(ct) > sv.params.MAX_TUPLETYPE_LEN - tail = foldl((a,b)->tmerge(a,unwrapva(b)), Bottom, ct[sv.params.MAX_TUPLETYPE_LEN:end]) + tail = tuple_tail_elem(Bottom, ct[sv.params.MAX_TUPLETYPE_LEN:end]) resize!(ct, sv.params.MAX_TUPLETYPE_LEN) - ct[end] = Vararg{widenconst(tail)} + ct[end] = tail + end + if isa(aft, Const) + rt = abstract_call(aft.val, (), ct, vtypes, sv) + elseif isconstType(aft) + rt = abstract_call(aft.parameters[1], (), ct, vtypes, sv) + else + astype = argtypes_to_type(ct) + rt = abstract_call_gf_by_type(nothing, astype, sv) end - at = append_any(Any[Const(af)], ct) - res = tmerge(res, abstract_call(af, (), at, vtypes, sv)) + res = tmerge(res, rt) if res === Any break end @@ -1651,20 +1673,7 @@ typename_static(t::ANY) = isType(t) ? _typename(t.parameters[1]) : Any function abstract_call(f::ANY, fargs::Union{Tuple{},Vector{Any}}, argtypes::Vector{Any}, vtypes::VarTable, sv::InferenceState) if f === _apply length(fargs) > 1 || return Any - aft = argtypes[2] - if isa(aft, Const) - af = aft.val - else - if isType(aft) && isleaftype(aft.parameters[1]) - af = aft.parameters[1] - elseif isleaftype(aft) && isdefined(aft, :instance) - af = aft.instance - else - # TODO jb/functions: take advantage of case where non-constant `af`'s type is known - return Any - end - end - return abstract_apply(af, fargs[3:end], argtypes[3:end], vtypes, sv) + return abstract_apply(argtypes[2], fargs[3:end], argtypes[3:end], vtypes, sv) end la = length(argtypes) @@ -2508,12 +2517,14 @@ function typeinf_edge(method::Method, atypes::ANY, sparams::SimpleVector, caller frame = resolve_call_cycle!(code, caller) if frame === nothing code.inInference = true - frame = InferenceState(code, true, true, caller.params) # always optimize and cache edge targets + frame = InferenceState(code, #=optimize=#true, #=cached=#true, caller.params) # always optimize and cache edge targets if frame === nothing code.inInference = false return Any, nothing end - frame.parent = caller + if caller.cached # don't involve uncached functions in cycle resolution + frame.parent = caller + end typeinf(frame) return frame.bestguess, frame.inferred ? frame.linfo : nothing end @@ -2849,6 +2860,7 @@ end #### finalize and record the result of running type inference #### function isinlineable(m::Method, src::CodeInfo) + # compute the cost (size) of inlining this code inlineable = false cost = 1000 if m.module === _topmod(m.module) @@ -2941,7 +2953,25 @@ function optimize(me::InferenceState) end # determine and cache inlineability - if !me.src.inlineable && !force_noinline && isdefined(me.linfo, :def) + if !force_noinline + # don't keep ASTs for functions specialized on a Union argument + # TODO: this helps avoid a type-system bug mis-computing sparams during intersection + sig = unwrap_unionall(me.linfo.specTypes) + if isa(sig, DataType) && sig.name === Tuple.name + for P in sig.parameters + P = unwrap_unionall(P) + if isa(P, Union) + force_noinline = true + break + end + end + else + force_noinline = true + end + end + if force_noinline + me.src.inlineable = false + elseif !me.src.inlineable && isdefined(me.linfo, :def) me.src.inlineable = isinlineable(me.linfo.def, me.src) end me.src.inferred = true diff --git a/base/int.jl b/base/int.jl index 1597c0320dd0a..bbbe846976f85 100644 --- a/base/int.jl +++ b/base/int.jl @@ -362,22 +362,24 @@ end # @doc isn't available when running in Core at this point. # Tuple syntax for documention two function signatures at the same time # doesn't work either at this point. -isdefined(Main, :Base) && for fname in (:mod, :rem) - @eval @doc """ - rem(x::Integer, T::Type{<:Integer}) -> T - mod(x::Integer, T::Type{<:Integer}) -> T - %(x::Integer, T::Type{<:Integer}) -> T - - Find `y::T` such that `x` ≡ `y` (mod n), where n is the number of integers representable - in `T`, and `y` is an integer in `[typemin(T),typemax(T)]`. - If `T` can represent any integer (e.g. `T == BigInt`), then this operation corresponds to - a conversion to `T`. - - ```jldoctest - julia> 129 % Int8 - -127 - ``` - """ -> $fname(x::Integer, T::Type{<:Integer}) +if module_name(current_module()) === :Base + for fname in (:mod, :rem) + @eval @doc (""" + rem(x::Integer, T::Type{<:Integer}) -> T + mod(x::Integer, T::Type{<:Integer}) -> T + %(x::Integer, T::Type{<:Integer}) -> T + + Find `y::T` such that `x` ≡ `y` (mod n), where n is the number of integers representable + in `T`, and `y` is an integer in `[typemin(T),typemax(T)]`. + If `T` can represent any integer (e.g. `T == BigInt`), then this operation corresponds to + a conversion to `T`. + + ```jldoctest + julia> 129 % Int8 + -127 + ``` + """ -> $fname(x::Integer, T::Type{<:Integer})) + end end rem(x::T, ::Type{T}) where {T<:Integer} = x diff --git a/base/multidimensional.jl b/base/multidimensional.jl index e85400ebd355a..a3b5ef5a97658 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -138,9 +138,10 @@ module IteratorsMD eachindex(::IndexCartesian, A::AbstractArray) = CartesianRange(indices(A)) @inline eachindex(::IndexCartesian, A::AbstractArray, B::AbstractArray...) = - CartesianRange(maxsize((), A, B...)) - maxsize(sz) = sz - @inline maxsize(sz, A, B...) = maxsize(maxt(sz, size(A)), B...) + CartesianRange(maxsize(A, B...)) + maxsize() = () + @inline maxsize(A) = size(A) + @inline maxsize(A, B...) = maxt(size(A), maxsize(B...)) @inline maxt(a::Tuple{}, b::Tuple{}) = () @inline maxt(a::Tuple{}, b::Tuple) = b @inline maxt(a::Tuple, b::Tuple{}) = a diff --git a/base/permuteddimsarray.jl b/base/permuteddimsarray.jl index c51b8cb34caff..7c483b8215a6b 100644 --- a/base/permuteddimsarray.jl +++ b/base/permuteddimsarray.jl @@ -74,10 +74,7 @@ end val end -# For some reason this is faster than ntuple(d->I[perm[d]], Val{N}) (#15276?) -@inline genperm(I::NTuple{N,Any}, perm::Dims{N}) where {N} = _genperm((), I, perm...) -_genperm(out, I) = out -@inline _genperm(out, I, p, perm...) = _genperm((out..., I[p]), I, perm...) +@inline genperm(I::NTuple{N,Any}, perm::Dims{N}) where {N} = ntuple(d -> I[perm[d]], Val{N}) @inline genperm(I, perm::AbstractVector{Int}) = genperm(I, (perm...,)) """ diff --git a/base/reshapedarray.jl b/base/reshapedarray.jl index 5109359421402..85c45e9e8739c 100644 --- a/base/reshapedarray.jl +++ b/base/reshapedarray.jl @@ -111,18 +111,25 @@ _throw_reshape_colon_dimmismatch(A, dims) = reshape(parent::AbstractArray{T,N}, ndims::Type{Val{N}}) where {T,N} = parent function reshape(parent::AbstractArray, ndims::Type{Val{N}}) where N - reshape(parent, rdims((), indices(parent), Val{N})) + reshape(parent, rdims(Val{N}, indices(parent))) end + # Move elements from inds to out until out reaches the desired # dimensionality N, either filling with OneTo(1) or collapsing the # product of trailing dims into the last element -@pure rdims(out::NTuple{N,Any}, inds::Tuple{}, ::Type{Val{N}}) where {N} = out -@pure function rdims(out::NTuple{N,Any}, inds::Tuple{Any, Vararg{Any}}, ::Type{Val{N}}) where N - l = length(last(out)) * prod(map(length, inds)) - (front(out)..., OneTo(l)) -end -@pure rdims(out::Tuple, inds::Tuple{}, ::Type{Val{N}}) where {N} = rdims((out..., OneTo(1)), (), Val{N}) -@pure rdims(out::Tuple, inds::Tuple{Any, Vararg{Any}}, ::Type{Val{N}}) where {N} = rdims((out..., first(inds)), tail(inds), Val{N}) +rdims_trailing(l, inds...) = length(l) * rdims_trailing(inds...) +rdims_trailing(l) = length(l) +rdims(out::Type{Val{N}}, inds::Tuple) where {N} = rdims(ntuple(i -> OneTo(1), Val{N}), inds) +rdims(out::Tuple{}, inds::Tuple{}) = () # N == 0, M == 0 +rdims(out::Tuple{}, inds::Tuple{Any}) = throw(ArgumentError("new dimensions cannot be empty")) # N == 0 +rdims(out::Tuple{}, inds::NTuple{M,Any}) where {M} = throw(ArgumentError("new dimensions cannot be empty")) # N == 0 +rdims(out::Tuple{Any}, inds::Tuple{}) = out # N == 1, M == 0 +rdims(out::NTuple{N,Any}, inds::Tuple{}) where {N} = out # N > 1, M == 0 +rdims(out::Tuple{Any}, inds::Tuple{Any}) = inds # N == 1, M == 1 +rdims(out::Tuple{Any}, inds::NTuple{M,Any}) where {M} = (OneTo(rdims_trailing(inds...)),) # N == 1, M > 1 +rdims(out::NTuple{N,Any}, inds::NTuple{N,Any}) where {N} = inds # N > 1, M == N +rdims(out::NTuple{N,Any}, inds::NTuple{M,Any}) where {N,M} = (first(inds), rdims(tail(out), tail(inds))...) # N > 1, M > 1, M != N + # _reshape on Array returns an Array _reshape(parent::Vector, dims::Dims{1}) = parent @@ -148,7 +155,7 @@ _reshape(R::ReshapedArray, dims::Dims) = _reshape(R.parent, dims) function __reshape(p::Tuple{AbstractArray,IndexCartesian}, dims::Dims) parent = p[1] - strds = front(size_strides(parent)) + strds = front(size_to_strides(size(parent)..., 1)) strds1 = map(s->max(1,s), strds) # for resizing empty arrays mi = map(SignedMultiplicativeInverse, strds1) ReshapedArray(parent, dims, reverse(mi)) @@ -159,10 +166,6 @@ function __reshape(p::Tuple{AbstractArray,IndexLinear}, dims::Dims) ReshapedArray(parent, dims, ()) end -@inline size_strides(A::AbstractArray) = tail(size_strides((1,), size(A)...)) -size_strides(out::Tuple) = out -@inline size_strides(out, s, sz...) = size_strides((out..., out[end]*s), sz...) - size(A::ReshapedArray) = A.dims similar(A::ReshapedArray, eltype::Type, dims::Dims) = similar(parent(A), eltype, dims) IndexStyle(::Type{<:ReshapedArrayLF}) = IndexLinear() @@ -171,11 +174,11 @@ parentindexes(A::ReshapedArray) = map(s->1:s, size(parent(A))) reinterpret(::Type{T}, A::ReshapedArray, dims::Dims) where {T} = reinterpret(T, parent(A), dims) @inline ind2sub_rs(::Tuple{}, i::Int) = i -@inline ind2sub_rs(strds, i) = ind2sub_rs((), strds, i-1) -@inline ind2sub_rs(out, ::Tuple{}, ind) = (ind+1, out...) -@inline function ind2sub_rs(out, strds, ind) +@inline ind2sub_rs(strds, i) = _ind2sub_rs(strds, i - 1) +@inline _ind2sub_rs(::Tuple{}, ind) = (ind + 1,) +@inline function _ind2sub_rs(strds, ind) d, r = divrem(ind, strds[1]) - ind2sub_rs((d+1, out...), tail(strds), r) + (_ind2sub_rs(tail(strds), r)..., d + 1) end @inline function getindex(A::ReshapedArrayLF, index::Int) diff --git a/base/show.jl b/base/show.jl index 9058f42485d41..3e39b419f284b 100644 --- a/base/show.jl +++ b/base/show.jl @@ -1036,7 +1036,9 @@ function show_unquoted(io::IO, ex::Expr, indent::Int, prec::Int) show_type = false # print anything else as "Expr(head, args...)" else - show_type = false + if head !== :invoke + show_type = false + end if emphstate && ex.head !== :lambda && ex.head !== :method io = IOContext(io, :TYPEEMPHASIZE => false) emphstate = false diff --git a/base/sparse/higherorderfns.jl b/base/sparse/higherorderfns.jl index 3e70ec228410a..87c83069e3299 100644 --- a/base/sparse/higherorderfns.jl +++ b/base/sparse/higherorderfns.jl @@ -6,7 +6,8 @@ module HigherOrderFns # particularly map[!]/broadcast[!] for SparseVectors and SparseMatrixCSCs at present. import Base: map, map!, broadcast, broadcast! import Base.Broadcast: _containertype, promote_containertype, - broadcast_indices, broadcast_c, broadcast_c! + broadcast_indices, _broadcast_indices, + broadcast_c, broadcast_c! using Base: front, tail, to_shape using ..SparseArrays: SparseVector, SparseMatrixCSC, AbstractSparseVector, @@ -325,10 +326,6 @@ function _map_zeropres!(f::Tf, C::SparseVecOrMat, As::Vararg{SparseVecOrMat,N}) rows = _rowforind_all(rowsentinel, ks, stopks, As) activerow = min(rows...) while activerow < rowsentinel - # activerows = _isactiverow_all(activerow, rows) - # Cx = f(_gatherargs(activerows, ks, As)...) - # ks = _updateind_all(activerows, ks) - # rows = _updaterow_all(rowsentinel, activerows, rows, ks, stopks, As) vals, ks, rows = _fusedupdate_all(rowsentinel, activerow, rows, ks, stopks, As) Cx = f(vals...) if !_iszero(Cx) @@ -359,10 +356,6 @@ function _map_notzeropres!(f::Tf, fillvalue, C::SparseVecOrMat, As::Vararg{Spars rows = _rowforind_all(rowsentinel, ks, stopks, As) activerow = min(rows...) while activerow < rowsentinel - # activerows = _isactiverow_all(activerow, rows) - # Cx = f(_gatherargs(activerows, ks, As)...) - # ks = _updateind_all(activerows, ks) - # rows = _updaterow_all(rowsentinel, activerows, rows, ks, stopks, As) vals, ks, rows = _fusedupdate_all(rowsentinel, activerow, rows, ks, stopks, As) Cx = f(vals...) Cx != fillvalue && (storedvals(C)[jo + activerow] = Cx) @@ -371,6 +364,7 @@ function _map_notzeropres!(f::Tf, fillvalue, C::SparseVecOrMat, As::Vararg{Spars end return C end + # helper methods for map/map! methods just above @inline _colstartind(j, A) = colstartind(A, j) @inline _colstartind_all(j, ::Tuple{}) = () @@ -388,28 +382,7 @@ end @inline _rowforind_all(rowsentinel, ks, stopks, As) = ( _rowforind(rowsentinel, first(ks), first(stopks), first(As)), _rowforind_all(rowsentinel, tail(ks), tail(stopks), tail(As))...) -# fusing the following defs. avoids a few branches, yielding 5-30% runtime reduction -# @inline _isactiverow(activerow, row) = row == activerow -# @inline _isactiverow_all(activerow, ::Tuple{}) = () -# @inline _isactiverow_all(activerow, rows) = ( -# _isactiverow(activerow, first(rows)), -# _isactiverow_all(activerow, tail(rows))...) -# @inline _gatherarg(isactiverow, k, A) = isactiverow ? storedvals(A)[k] : zero(eltype(A)) -# @inline _gatherargs(::Tuple{}, ::Tuple{}, ::Tuple{}) = () -# @inline _gatherargs(activerows, ks, As) = ( -# _gatherarg(first(activerows), first(ks), first(As)), -# _gatherargs(tail(activerows), tail(ks), tail(As))...) -# @inline _updateind(isactiverow, k) = isactiverow ? (k + oneunit(k)) : k -# @inline _updateind_all(::Tuple{}, ::Tuple{}) = () -# @inline _updateind_all(activerows, ks) = ( -# _updateind(first(activerows), first(ks)), -# _updateind_all(tail(activerows), tail(ks))...) -# @inline _updaterow(rowsentinel, isrowactive, presrow, k, stopk, A) = -# isrowactive ? (k < stopk ? storedinds(A)[k] : oftype(presrow, rowsentinel)) : presrow -# @inline _updaterow_all(rowsentinel, ::Tuple{}, ::Tuple{}, ::Tuple{}, ::Tuple{}, ::Tuple{}) = () -# @inline _updaterow_all(rowsentinel, activerows, rows, ks, stopks, As) = ( -# _updaterow(rowsentinel, first(activerows), first(rows), first(ks), first(stopks), first(As)), -# _updaterow_all(rowsentinel, tail(activerows), tail(rows), tail(ks), tail(stopks), tail(As))...) + @inline function _fusedupdate(rowsentinel, activerow, row, k, stopk, A) # returns (val, nextk, nextrow) if row == activerow @@ -419,14 +392,11 @@ end (zero(eltype(A)), k, row) end end -@inline _fusedupdate_all(rowsentinel, activerow, rows, ks, stopks, As) = - _fusedupdate_all((#=vals=#), (#=nextks=#), (#=nextrows=#), rowsentinel, activerow, rows, ks, stopks, As) -@inline _fusedupdate_all(vals, nextks, nextrows, rowsent, activerow, ::Tuple{}, ::Tuple{}, ::Tuple{}, ::Tuple{}) = - (vals, nextks, nextrows) -@inline function _fusedupdate_all(vals, nextks, nextrows, rowsentinel, activerow, rows, ks, stopks, As) +@inline _fusedupdate_all(rowsentinel, activerow, ::Tuple{}, ::Tuple{}, ::Tuple{}, ::Tuple{}) = ((#=vals=#), (#=nextks=#), (#=nextrows=#)) +@inline function _fusedupdate_all(rowsentinel, activerow, rows, ks, stopks, As) val, nextk, nextrow = _fusedupdate(rowsentinel, activerow, first(rows), first(ks), first(stopks), first(As)) - return _fusedupdate_all((vals..., val), (nextks..., nextk), (nextrows..., nextrow), - rowsentinel, activerow, tail(rows), tail(ks), tail(stopks), tail(As)) + vals, nextks, nextrows = _fusedupdate_all(rowsentinel, activerow, tail(rows), tail(ks), tail(stopks), tail(As)) + return ((val, vals...), (nextk, nextks...), (nextrow, nextrows...)) end @@ -803,10 +773,6 @@ function _broadcast_zeropres!(f::Tf, C::SparseVecOrMat, As::Vararg{SparseVecOrMa activerow = min(rows...) if _iszero(defaultCx) # zero-preserving column scan while activerow < rowsentinel - # activerows = _isactiverow_all(activerow, rows) - # Cx = f(_gatherbcargs(activerows, defargs, ks, As)...) - # ks = _updateind_all(activerows, ks) - # rows = _updaterow_all(rowsentinel, activerows, rows, ks, stopks, As) args, ks, rows = _fusedupdatebc_all(rowsentinel, activerow, rows, defargs, ks, stopks, As) Cx = f(args...) if !_iszero(Cx) @@ -820,10 +786,6 @@ function _broadcast_zeropres!(f::Tf, C::SparseVecOrMat, As::Vararg{SparseVecOrMa else # zero-non-preserving column scan for Ci in 1:numrows(C) if Ci == activerow - # activerows = _isactiverow_all(activerow, rows) - # Cx = f(_gatherbcargs(activerows, defargs, ks, As)...) - # ks = _updateind_all(activerows, ks) - # rows = _updaterow_all(rowsentinel, activerows, rows, ks, stopks, As) args, ks, rows = _fusedupdatebc_all(rowsentinel, activerow, rows, defargs, ks, stopks, As) Cx = f(args...) activerow = min(rows...) @@ -864,10 +826,6 @@ function _broadcast_notzeropres!(f::Tf, fillvalue, C::SparseVecOrMat, As::Vararg activerow = min(rows...) if defaultCx == fillvalue # fillvalue-preserving column scan while activerow < rowsentinel - # activerows = _isactiverow_all(activerow, rows) - # Cx = f(_gatherbcargs(activerows, defargs, ks, As)...) - # ks = _updateind_all(activerows, ks) - # rows = _updaterow_all(rowsentinel, activerows, rows, ks, stopks, As) args, ks, rows = _fusedupdatebc_all(rowsentinel, activerow, rows, defargs, ks, stopks, As) Cx = f(args...) Cx != fillvalue && (storedvals(C)[jo + activerow] = Cx) @@ -876,10 +834,6 @@ function _broadcast_notzeropres!(f::Tf, fillvalue, C::SparseVecOrMat, As::Vararg else # fillvalue-non-preserving column scan for Ci in 1:numrows(C) if Ci == activerow - # activerows = _isactiverow_all(activerow, rows) - # Cx = f(_gatherbcargs(activerows, defargs, ks, As)...) - # ks = _updateind_all(activerows, ks) - # rows = _updaterow_all(rowsentinel, activerows, rows, ks, stopks, As) args, ks, rows = _fusedupdatebc_all(rowsentinel, activerow, rows, defargs, ks, stopks, As) Cx = f(args...) activerow = min(rows...) @@ -892,6 +846,7 @@ function _broadcast_notzeropres!(f::Tf, fillvalue, C::SparseVecOrMat, As::Vararg end return C end + # helper method for broadcast/broadcast! methods just above @inline _expandsvert(C, A) = numrows(A) != numrows(C) @inline _expandsvert_all(C, ::Tuple{}) = () @@ -926,28 +881,6 @@ end @inline _defargforcol_all(j, isemptys, expandsverts, ks, As) = ( _defargforcol(j, first(isemptys), first(expandsverts), first(ks), first(As)), _defargforcol_all(j, tail(isemptys), tail(expandsverts), tail(ks), tail(As))...) -# fusing the following defs. avoids a few branches and construction of a tuple, yielding 1-20% runtime reduction -# @inline _isactiverow(activerow, row) = row == activerow -# @inline _isactiverow_all(activerow, ::Tuple{}) = () -# @inline _isactiverow_all(activerow, rows) = ( -# _isactiverow(activerow, first(rows)), -# _isactiverow_all(activerow, tail(rows))...) -# @inline _gatherbcarg(isactiverow, defarg, k, A) = isactiverow ? storedvals(A)[k] : defarg -# @inline _gatherbcargs(::Tuple{}, ::Tuple{}, ::Tuple{}, ::Tuple{}) = () -# @inline _gatherbcargs(activerows, defargs, ks, As) = ( -# _gatherbcarg(first(activerows), first(defargs), first(ks), first(As)), -# _gatherbcargs(tail(activerows), tail(defargs), tail(ks), tail(As))...) -# @inline _updateind(isactiverow, k) = isactiverow ? (k + oneunit(k)) : k -# @inline _updateind_all(::Tuple{}, ::Tuple{}) = () -# @inline _updateind_all(activerows, ks) = ( -# _updateind(first(activerows), first(ks)), -# _updateind_all(tail(activerows), tail(ks))...) -# @inline _updaterow(rowsentinel, isrowactive, presrow, k, stopk, A) = -# isrowactive ? (k < stopk ? storedinds(A)[k] : oftype(presrow, rowsentinel)) : presrow -# @inline _updaterow_all(rowsentinel, ::Tuple{}, ::Tuple{}, ::Tuple{}, ::Tuple{}, ::Tuple{}) = () -# @inline _updaterow_all(rowsentinel, activerows, rows, ks, stopks, As) = ( -# _updaterow(rowsentinel, first(activerows), first(rows), first(ks), first(stopks), first(As)), -# _updaterow_all(rowsentinel, tail(activerows), tail(rows), tail(ks), tail(stopks), tail(As))...) @inline function _fusedupdatebc(rowsentinel, activerow, row, defarg, k, stopk, A) # returns (val, nextk, nextrow) if row == activerow @@ -957,21 +890,18 @@ end (defarg, k, row) end end -@inline _fusedupdatebc_all(rowsentinel, activerow, rows, defargs, ks, stopks, As) = - _fusedupdatebc_all((#=vals=#), (#=nextks=#), (#=nextrows=#), rowsentinel, activerow, rows, defargs, ks, stopks, As) -@inline _fusedupdatebc_all(vals, nextks, nextrows, rowsent, activerow, ::Tuple{}, ::Tuple{}, ::Tuple{}, ::Tuple{}, ::Tuple{}) = - (vals, nextks, nextrows) -@inline function _fusedupdatebc_all(vals, nextks, nextrows, rowsentinel, activerow, rows, defargs, ks, stopks, As) +@inline _fusedupdatebc_all(rowsent, activerow, ::Tuple{}, ::Tuple{}, ::Tuple{}, ::Tuple{}, ::Tuple{}) = ((#=vals=#), (#=nextks=#), (#=nextrows=#)) +@inline function _fusedupdatebc_all(rowsentinel, activerow, rows, defargs, ks, stopks, As) val, nextk, nextrow = _fusedupdatebc(rowsentinel, activerow, first(rows), first(defargs), first(ks), first(stopks), first(As)) - return _fusedupdatebc_all((vals..., val), (nextks..., nextk), (nextrows..., nextrow), - rowsentinel, activerow, tail(rows), tail(defargs), tail(ks), tail(stopks), tail(As)) + vals, nextks, nextrows = _fusedupdatebc_all(rowsentinel, activerow, tail(rows), tail(defargs), tail(ks), tail(stopks), tail(As)) + return ((val, vals...), (nextk, nextks...), (nextrow, nextrows...)) end # (10) broadcast[!] over combinations of broadcast scalars and sparse vectors/matrices # broadcast shape promotion for combinations of sparse arrays and other types -broadcast_indices(::Type{AbstractSparseArray}, A) = indices(A) +_broadcast_indices(::Type{AbstractSparseArray}, A) = indices(A) # broadcast container type promotion for combinations of sparse arrays and other types _containertype(::Type{<:SparseVecOrMat}) = AbstractSparseArray # combinations of sparse arrays with broadcast scalars should yield sparse arrays @@ -996,22 +926,38 @@ end # evaluated f) and a reduced argument tuple (passedargstup) containing only the sparse # vectors/matrices in mixedargs in their orginal order, and such that the result of # broadcast(parevalf, passedargstup...) is broadcast(f, mixedargs...) -@inline capturescalars(f, mixedargs) = - capturescalars((passed, tofill) -> f(tofill...), (), mixedargs...) -# Recursion cases for capturescalars -@inline capturescalars(f, passedargstup, scalararg, mixedargs...) = - capturescalars(capturescalar(f, scalararg), passedargstup, mixedargs...) -@inline capturescalars(f, passedargstup, nonscalararg::SparseVecOrMat, mixedargs...) = - capturescalars(passnonscalar(f), (passedargstup..., nonscalararg), mixedargs...) -@inline passnonscalar(f) = (passed, tofill) -> f(Base.front(passed), (last(passed), tofill...)) -@inline capturescalar(f, scalararg) = (passed, tofill) -> f(passed, (scalararg, tofill...)) -# Base cases for capturescalars -@inline capturescalars(f, passedargstup, scalararg) = - (capturelastscalar(f, scalararg), passedargstup) -@inline capturescalars(f, passedargstup, nonscalararg::SparseVecOrMat) = - (passlastnonscalar(f), (passedargstup..., nonscalararg)) -@inline passlastnonscalar(f) = (passed...) -> f(Base.front(passed), (last(passed),)) -@inline capturelastscalar(f, scalararg) = (passed...) -> f(passed, (scalararg,)) +@inline function capturescalars(f, mixedargs) + let makeargs = _capturescalars(mixedargs...), + parevalf = (passed...) -> f(makeargs(passed...)...), + passedsrcargstup = _capturenonscalars(mixedargs...) + return (parevalf, passedsrcargstup) + end +end + +@inline _capturenonscalars(nonscalararg::SparseVecOrMat, mixedargs...) = + (nonscalararg, _capturenonscalars(mixedargs...)...) +@inline _capturenonscalars(scalararg, mixedargs...) = + _capturenonscalars(mixedargs...) +@inline _capturenonscalars() = () + +@inline _capturescalars(nonscalararg::SparseVecOrMat, mixedargs...) = + let f = _capturescalars(mixedargs...) + (head, tail...) -> (head, f(tail...)...) # pass-through + end +@inline _capturescalars(scalararg, mixedargs...) = + let f = _capturescalars(mixedargs...) + (tail...) -> (scalararg, f(tail...)...) # add scalararg + end +# TODO: use the implicit version once inference can handle it +# handle too-many-arguments explicitly +@inline function _capturescalars() + too_many_arguments() = () + too_many_arguments(tail...) = throw(ArgumentError("too many")) +end +#@inline _capturescalars(nonscalararg::SparseVecOrMat) = +# (head,) -> (head,) # pass-through +#@inline _capturescalars(scalararg) = +# () -> (scalararg,) # add scalararg # NOTE: The following two method definitions work around #19096. broadcast(f::Tf, ::Type{T}, A::SparseMatrixCSC) where {Tf,T} = broadcast(y -> f(T, y), A) @@ -1039,7 +985,7 @@ struct PromoteToSparse end # broadcast containertype definitions for structured matrices StructuredMatrix = Union{Diagonal,Bidiagonal,Tridiagonal,SymTridiagonal} _containertype(::Type{<:StructuredMatrix}) = PromoteToSparse -broadcast_indices(::Type{PromoteToSparse}, A) = indices(A) +_broadcast_indices(::Type{PromoteToSparse}, A) = indices(A) # combinations explicitly involving Tuples and PromoteToSparse collections # divert to the generic AbstractArray broadcast code diff --git a/base/sysimg.jl b/base/sysimg.jl index acfb4c7b68ee4..39c787e8b5359 100644 --- a/base/sysimg.jl +++ b/base/sysimg.jl @@ -195,6 +195,25 @@ include("nullable.jl") include("broadcast.jl") importall .Broadcast +# define the real ntuple functions +@generated function ntuple(f::F, ::Type{Val{N}}) where {F,N} + Core.typeassert(N, Int) + (N >= 0) || return :(throw($(ArgumentError(string("tuple length should be ≥0, got ", N))))) + return quote + $(Expr(:meta, :inline)) + @nexprs $N i -> t_i = f(i) + @ncall $N tuple t + end +end +@generated function fill_to_length(t::Tuple, val, ::Type{Val{N}}) where {N} + M = length(t.parameters) + M > N && return :(throw($(ArgumentError("input tuple of length $M, requested $N")))) + return quote + $(Expr(:meta, :inline)) + (t..., $(Any[ :val for i = (M + 1):N ]...)) + end +end + # base64 conversions (need broadcast) include("base64.jl") importall .Base64 diff --git a/base/tuple.jl b/base/tuple.jl index dc041a47937fb..f78502525a839 100644 --- a/base/tuple.jl +++ b/base/tuple.jl @@ -24,12 +24,13 @@ getindex(t::Tuple, r::AbstractArray{<:Any,1}) = ([t[ri] for ri in r]...) getindex(t::Tuple, b::AbstractArray{Bool,1}) = length(b) == length(t) ? getindex(t,find(b)) : throw(BoundsError(t, b)) # returns new tuple; N.B.: becomes no-op if i is out-of-bounds -setindex(x::Tuple, v, i::Integer) = _setindex((), x, v, i::Integer) -function _setindex(y::Tuple, r::Tuple, v, i::Integer) +setindex(x::Tuple, v, i::Integer) = (@_inline_meta; _setindex(v, i, x...)) +function _setindex(v, i::Integer, first, tail...) @_inline_meta - _setindex((y..., ifelse(length(y) + 1 == i, v, first(r))), tail(r), v, i) + return (ifelse(i == 1, v, first), _setindex(v, i - 1, tail...)...) end -_setindex(y::Tuple, r::Tuple{}, v, i::Integer) = y +_setindex(v, i::Integer) = () + ## iterating ## @@ -82,13 +83,13 @@ safe_tail(t::Tuple{}) = () function front(t::Tuple) @_inline_meta - _front((), t...) + _front(t...) end -front(::Tuple{}) = throw(ArgumentError("Cannot call front on an empty tuple")) -_front(out, v) = out -function _front(out, v, t...) +_front() = throw(ArgumentError("Cannot call front on an empty tuple")) +_front(v) = () +function _front(v, t...) @_inline_meta - _front((out..., v), t...) + (v, _front(t...)...) end ## mapping ## @@ -126,36 +127,11 @@ function _ntuple(f, n) ([f(i) for i = 1:n]...) end -# inferrable ntuple -ntuple(f, ::Type{Val{0}}) = (@_inline_meta; ()) +# inferrable ntuple (enough for bootstrapping) +ntuple(f, ::Type{Val{0}}) = () ntuple(f, ::Type{Val{1}}) = (@_inline_meta; (f(1),)) ntuple(f, ::Type{Val{2}}) = (@_inline_meta; (f(1), f(2))) ntuple(f, ::Type{Val{3}}) = (@_inline_meta; (f(1), f(2), f(3))) -ntuple(f, ::Type{Val{4}}) = (@_inline_meta; (f(1), f(2), f(3), f(4))) -ntuple(f, ::Type{Val{5}}) = (@_inline_meta; (f(1), f(2), f(3), f(4), f(5))) -ntuple(f, ::Type{Val{6}}) = (@_inline_meta; (f(1), f(2), f(3), f(4), f(5), f(6))) -ntuple(f, ::Type{Val{7}}) = (@_inline_meta; (f(1), f(2), f(3), f(4), f(5), f(6), f(7))) -ntuple(f, ::Type{Val{8}}) = (@_inline_meta; (f(1), f(2), f(3), f(4), f(5), f(6), f(7), f(8))) -ntuple(f, ::Type{Val{9}}) = (@_inline_meta; (f(1), f(2), f(3), f(4), f(5), f(6), f(7), f(8), f(9))) -ntuple(f, ::Type{Val{10}}) = (@_inline_meta; (f(1), f(2), f(3), f(4), f(5), f(6), f(7), f(8), f(9), f(10))) -ntuple(f, ::Type{Val{11}}) = (@_inline_meta; (f(1), f(2), f(3), f(4), f(5), f(6), f(7), f(8), f(9), f(10), f(11))) -ntuple(f, ::Type{Val{12}}) = (@_inline_meta; (f(1), f(2), f(3), f(4), f(5), f(6), f(7), f(8), f(9), f(10), f(11), f(12))) -ntuple(f, ::Type{Val{13}}) = (@_inline_meta; (f(1), f(2), f(3), f(4), f(5), f(6), f(7), f(8), f(9), f(10), f(11), f(12), f(13))) -ntuple(f, ::Type{Val{14}}) = (@_inline_meta; (f(1), f(2), f(3), f(4), f(5), f(6), f(7), f(8), f(9), f(10), f(11), f(12), f(13), f(14))) -ntuple(f, ::Type{Val{15}}) = (@_inline_meta; (f(1), f(2), f(3), f(4), f(5), f(6), f(7), f(8), f(9), f(10), f(11), f(12), f(13), f(14), f(15))) - -function ntuple(f::F, ::Type{Val{N}}) where {F,N} - Core.typeassert(N, Int) - (N >= 0) || throw(ArgumentError(string("tuple length should be ≥0, got ", N))) - _ntuple((), f, Val{N}) -end - -# Build up the output until it has length N -_ntuple(out::NTuple{N,Any}, f::F, ::Type{Val{N}}) where {F,N} = out -function _ntuple(out::NTuple{M,Any}, f::F, ::Type{Val{N}}) where {F,N,M} - @_inline_meta - _ntuple((out..., f(M+1)), f, Val{N}) -end # 1 argument function map(f, t::Tuple{}) = () @@ -211,20 +187,14 @@ end # type-stable padding -fill_to_length(t::Tuple, val, ::Type{Val{N}}) where {N} = _ftl((), val, Val{N}, t...) -_ftl(out::NTuple{N,Any}, val, ::Type{Val{N}}) where {N} = out -function _ftl(out::NTuple{N,Any}, val, ::Type{Val{N}}, t...) where N - @_inline_meta - throw(ArgumentError("input tuple of length $(N+length(t)), requested $N")) -end -function _ftl(out, val, ::Type{Val{N}}, t1, t...) where N - @_inline_meta - _ftl((out..., t1), val, Val{N}, t...) -end -function _ftl(out, val, ::Type{Val{N}}) where N - @_inline_meta - _ftl((out..., val), val, Val{N}) -end +fill_to_length(t::NTuple{N,Any}, val, ::Type{Val{N}}) where {N} = t +fill_to_length(t::Tuple{}, val, ::Type{Val{1}}) = (val,) +fill_to_length(t::Tuple{Any}, val, ::Type{Val{2}}) = (t..., val) +fill_to_length(t::Tuple{}, val, ::Type{Val{2}}) = (val, val) +#function fill_to_length(t::Tuple, val, ::Type{Val{N}}) where {N} +# @_inline_meta +# return (t..., ntuple(i -> val, N - length(t))...) +#end # constructing from an iterator diff --git a/src/codegen.cpp b/src/codegen.cpp index a3cd82040a16e..35061fe614f11 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3048,7 +3048,7 @@ static bool emit_builtin_call(jl_cgval_t *ret, jl_value_t *f, jl_value_t **args, jl_datatype_t *sty = (jl_datatype_t*)expr_type(args[1], ctx); rt1 = (jl_value_t*)sty; jl_datatype_t *uty = (jl_datatype_t*)jl_unwrap_unionall((jl_value_t*)sty); - if (jl_is_structtype(uty) && uty != jl_module_type) { + if (jl_is_structtype(uty) && uty != jl_module_type && ((jl_datatype_t*)uty)->layout) { size_t idx = (size_t)-1; if (jl_is_quotenode(args[2]) && jl_is_symbol(jl_fieldref(args[2],0))) { idx = jl_field_index(uty, (jl_sym_t*)jl_fieldref(args[2],0), 0); diff --git a/test/broadcast.jl b/test/broadcast.jl index 8e89a12e65a89..bb7fdeaf3db1c 100644 --- a/test/broadcast.jl +++ b/test/broadcast.jl @@ -3,21 +3,21 @@ module TestBroadcastInternals using Base.Broadcast: broadcast_indices, check_broadcast_indices, - check_broadcast_shape, newindex, _bcs, _bcsm + check_broadcast_shape, newindex, _bcs using Base: Test, OneTo -@test @inferred(_bcs((), (3,5), (3,5))) == (3,5) -@test @inferred(_bcs((), (3,1), (3,5))) == (3,5) -@test @inferred(_bcs((), (3,), (3,5))) == (3,5) -@test @inferred(_bcs((), (3,5), (3,))) == (3,5) -@test_throws DimensionMismatch _bcs((), (3,5), (4,5)) -@test_throws DimensionMismatch _bcs((), (3,5), (3,4)) -@test @inferred(_bcs((), (-1:1, 2:5), (-1:1, 2:5))) == (-1:1, 2:5) -@test @inferred(_bcs((), (-1:1, 2:5), (1, 2:5))) == (-1:1, 2:5) -@test @inferred(_bcs((), (-1:1, 1), (1, 2:5))) == (-1:1, 2:5) -@test @inferred(_bcs((), (-1:1,), (-1:1, 2:5))) == (-1:1, 2:5) -@test_throws DimensionMismatch _bcs((), (-1:1, 2:6), (-1:1, 2:5)) -@test_throws DimensionMismatch _bcs((), (-1:1, 2:5), (2, 2:5)) +@test @inferred(_bcs((3,5), (3,5))) == (3,5) +@test @inferred(_bcs((3,1), (3,5))) == (3,5) +@test @inferred(_bcs((3,), (3,5))) == (3,5) +@test @inferred(_bcs((3,5), (3,))) == (3,5) +@test_throws DimensionMismatch _bcs((3,5), (4,5)) +@test_throws DimensionMismatch _bcs((3,5), (3,4)) +@test @inferred(_bcs((-1:1, 2:5), (-1:1, 2:5))) == (-1:1, 2:5) +@test @inferred(_bcs((-1:1, 2:5), (1, 2:5))) == (-1:1, 2:5) +@test @inferred(_bcs((-1:1, 1), (1, 2:5))) == (-1:1, 2:5) +@test @inferred(_bcs((-1:1,), (-1:1, 2:5))) == (-1:1, 2:5) +@test_throws DimensionMismatch _bcs((-1:1, 2:6), (-1:1, 2:5)) +@test_throws DimensionMismatch _bcs((-1:1, 2:5), (2, 2:5)) @test @inferred(broadcast_indices(zeros(3,4), zeros(3,4))) == (OneTo(3),OneTo(4)) @test @inferred(broadcast_indices(zeros(3,4), zeros(3))) == (OneTo(3),OneTo(4))