Skip to content

Commit

Permalink
fixup! make Tuple{Union{}} unconstructable
Browse files Browse the repository at this point in the history
  • Loading branch information
vtjnash committed Mar 24, 2023
1 parent e62b6e3 commit d2a4568
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 20 deletions.
16 changes: 10 additions & 6 deletions base/broadcast.jl
Original file line number Diff line number Diff line change
Expand Up @@ -732,17 +732,21 @@ broadcastable(x) = collect(x)
broadcastable(::Union{AbstractDict, NamedTuple}) = throw(ArgumentError("broadcasting over dictionaries and `NamedTuple`s is reserved"))

## Computation of inferred result type, for empty and concretely inferred cases only
_broadcast_getindex_eltype(bc::Broadcasted) = Base._return_type(bc.f, eltypes(bc.args))
_broadcast_getindex_eltype(bc::Broadcasted) = combine_eltypes(bc.f, bc.args)
_broadcast_getindex_eltype(A) = eltype(A) # Tuple, Array, etc.

eltypes(::Tuple{}) = Tuple{}
eltypes(t::Tuple{Any}) = Tuple{_broadcast_getindex_eltype(t[1])}
eltypes(t::Tuple{Any,Any}) = Tuple{_broadcast_getindex_eltype(t[1]), _broadcast_getindex_eltype(t[2])}
eltypes(t::Tuple) = Tuple{_broadcast_getindex_eltype(t[1]), eltypes(tail(t)).types...}
eltypes(t::Tuple{Any}) = Iterators.TupleOrBottom(_broadcast_getindex_eltype(t[1]))
eltypes(t::Tuple{Any,Any}) = Iterators.TupleOrBottom(_broadcast_getindex_eltype(t[1]), _broadcast_getindex_eltype(t[2]))
# eltypes(t::Tuple) = (TT = eltypes(tail(t)); TT === Union{} ? Union{} : Iterators.TupleOrBottom(_broadcast_getindex_eltype(t[1]), TT.parameters...))
eltypes(t::Tuple) = Iterators.TupleOrBottom(ntuple(i -> _broadcast_getindex_eltype(t[i]), Val(length(t)))...)

# Inferred eltype of result of broadcast(f, args...)
combine_eltypes(f, args::Tuple) =
promote_typejoin_union(Base._return_type(f, eltypes(args)))
function combine_eltypes(f, args::Tuple)
argT = eltypes(args)
argT === Union{} && return Union{}
return promote_typejoin_union(Base._return_type(f, argT))
end

## Broadcasting core

Expand Down
8 changes: 1 addition & 7 deletions base/iterators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ using .Base:
@inline, Pair, Pairs, AbstractDict, IndexLinear, IndexStyle, AbstractVector, Vector,
SizeUnknown, HasLength, HasShape, IsInfinite, EltypeUnknown, HasEltype, OneTo,
@propagate_inbounds, @isdefined, @boundscheck, @inbounds, Generator,
AbstractRange, AbstractUnitRange, UnitRange, LinearIndices,
AbstractRange, AbstractUnitRange, UnitRange, LinearIndices, TupleOrBottom,
(:), |, +, -, *, !==, !, ==, !=, <=, <, >, >=, missing,
any, _counttuple, eachindex, ntuple, zero, prod, reduce, in, firstindex, lastindex,
tail, fieldtypes, min, max, minimum, zero, oneunit, promote, promote_shape
Expand Down Expand Up @@ -41,12 +41,6 @@ if Base !== Core.Compiler
export partition
end

function TupleOrBottom(tt...)
any(p -> p === Union{}, tt) && return Union{}
return Tuple{tt...}
end


"""
Iterators.map(f, iterators...)
Expand Down
12 changes: 11 additions & 1 deletion base/promotion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,11 @@ else
_return_type(@nospecialize(f), @nospecialize(t)) = Any
end

function TupleOrBottom(tt...)
any(p -> p === Union{}, tt) && return Union{}
return Tuple{tt...}
end

"""
promote_op(f, argtypes...)
Expand All @@ -483,7 +488,12 @@ Guess what an appropriate container eltype would be for storing results of
the container eltype on the type of the actual elements. Only in the absence of any
elements (for an empty result container), it may be unavoidable to call `promote_op`.
"""
promote_op(f, S::Type...) = _return_type(f, Tuple{S...})
function promote_op(f, S::Type...)
argT = TupleOrBottom(S...)
argT === Union{} && return Union{}
return _return_type(f, argT)
end


## catch-alls to prevent infinite recursion when definitions are missing ##

Expand Down
3 changes: 2 additions & 1 deletion base/slicearray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ unitaxis(::AbstractArray) = Base.OneTo(1)

function Slices(A::P, slicemap::SM, ax::AX) where {P,SM,AX}
N = length(ax)
S = Base._return_type(view, Tuple{P, map((a,l) -> l === (:) ? Colon : eltype(a), axes(A), slicemap)...})
argT = map((a,l) -> l === (:) ? Colon : eltype(a), axes(A), slicemap)
S = Base.promote_op(view, P, argT...)
Slices{P,SM,AX,S,N}(A, slicemap, ax)
end

Expand Down
10 changes: 5 additions & 5 deletions stdlib/LinearAlgebra/src/uniformscaling.jl
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ for (t1, t2) in ((:UnitUpperTriangular, :UpperTriangular),
(:UnitLowerTriangular, :LowerTriangular))
@eval begin
function (+)(UL::$t1, J::UniformScaling)
ULnew = copymutable_oftype(UL.data, Base._return_type(+, Tuple{eltype(UL), typeof(J)}))
ULnew = copymutable_oftype(UL.data, Base.promote_op(+, eltype(UL), typeof(J)))
for i in axes(ULnew, 1)
ULnew[i,i] = one(ULnew[i,i]) + J
end
Expand All @@ -193,7 +193,7 @@ end
# However, to preserve type stability, we do not special-case a
# UniformScaling{<:Complex} that happens to be real.
function (+)(A::Hermitian, J::UniformScaling{<:Complex})
TS = Base._return_type(+, Tuple{eltype(A), typeof(J)})
TS = Base.promote_op(+, eltype(A), typeof(J))
B = copytri!(copymutable_oftype(parent(A), TS), A.uplo, true)
for i in diagind(B)
B[i] = A[i] + J
Expand All @@ -202,7 +202,7 @@ function (+)(A::Hermitian, J::UniformScaling{<:Complex})
end

function (-)(J::UniformScaling{<:Complex}, A::Hermitian)
TS = Base._return_type(+, Tuple{eltype(A), typeof(J)})
TS = Base.promote_op(+, eltype(A), typeof(J))
B = copytri!(copymutable_oftype(parent(A), TS), A.uplo, true)
B .= .-B
for i in diagind(B)
Expand All @@ -213,7 +213,7 @@ end

function (+)(A::AbstractMatrix, J::UniformScaling)
checksquare(A)
B = copymutable_oftype(A, Base._return_type(+, Tuple{eltype(A), typeof(J)}))
B = copymutable_oftype(A, Base.promote_op(+, eltype(A), typeof(J)))
for i in intersect(axes(A,1), axes(A,2))
@inbounds B[i,i] += J
end
Expand All @@ -222,7 +222,7 @@ end

function (-)(J::UniformScaling, A::AbstractMatrix)
checksquare(A)
B = convert(AbstractMatrix{Base._return_type(+, Tuple{eltype(A), typeof(J)})}, -A)
B = convert(AbstractMatrix{Base.promote_op(+, eltype(A), typeof(J))}, -A)
for i in intersect(axes(A,1), axes(A,2))
@inbounds B[i,i] += J
end
Expand Down

0 comments on commit d2a4568

Please sign in to comment.