@@ -125,14 +125,19 @@ Base.cconvert(::Type{<:Ptr}, a::FieldArray) = Base.RefValue(a)
125125Base. unsafe_convert (:: Type{Ptr{T}} , m:: Base.RefValue{FA} ) where {N,T,D,FA<: FieldArray{N,T,D} } =
126126 Ptr {T} (Base. unsafe_convert (Ptr{FA}, m))
127127
128- # We can automatically preserve FieldArrays in array operations which do not
129- # change their eltype or Size. This should cover all non-parametric FieldArray,
130- # but for those which are parametric on the eltype the user will still need to
131- # overload similar_type themselves.
132- similar_type (:: Type{A} , :: Type{T} , S:: Size ) where {N, T, A<: FieldArray{N, T} } =
133- _fieldarray_similar_type (A, T, S, Size (A))
134-
135- # Extra layer of dispatch to match NewSize and OldSize
136- _fieldarray_similar_type (A, T, NewSize:: S , OldSize:: S ) where {S} = A
137- _fieldarray_similar_type (A, T, NewSize, OldSize) =
138- default_similar_type (T, NewSize, length_val (NewSize))
128+ # We can preserve FieldArrays in array operations which do not change their `Size` and `eltype`.
129+ # FieldArrays with parametric `eltype` would be adapted to the new `eltype` automatically.
130+ # Otherwise, we fallback to `S/MArray` based on it's mutability.
131+ function similar_type (:: Type{A} , :: Type{T} , S:: Size ) where {T,A<: FieldArray }
132+ A′ = Base. typeintersect (base_type (A), StaticArray{Tuple{Tuple (S)... },T,length (S)})
133+ isabstracttype (A′) || A′ === Union{} || return A′
134+ if ismutabletype (A)
135+ return mutable_similar_type (T, S, length_val (S))
136+ else
137+ return default_similar_type (T, S, length_val (S))
138+ end
139+ end
140+ @pure base_type (@nospecialize (T:: Type )) = Base. unwrap_unionall (T). name. wrapper
141+ if VERSION < v " 1.7"
142+ @pure ismutabletype (@nospecialize (T:: Type )) = Base. unwrap_unionall (T). mutable
143+ end
0 commit comments