Skip to content

Commit 5efcdaa

Browse files
committed
Add more checks for similar_type with eltype changed.
The `typeintersect` must return a concrete type now. And it's `fieldtypes` should match our doc example.
1 parent 8bcf749 commit 5efcdaa

File tree

2 files changed

+30
-4
lines changed

2 files changed

+30
-4
lines changed

src/FieldArray.jl

+6-4
Original file line numberDiff line numberDiff line change
@@ -125,12 +125,14 @@ Base.cconvert(::Type{<:Ptr}, a::FieldArray) = Base.RefValue(a)
125125
Base.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 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.
131128
function similar_type(::Type{A}, ::Type{T}, S::Size) where {T,A<:FieldArray}
129+
# We can preserve FieldArrays in array operations which do not change their `Size` and `eltype`.
130+
has_eltype(A) && eltype(A) === T && has_size(A) && Size(A) === S && return A
131+
# FieldArrays with parametric `eltype` would be adapted to the new `eltype` automatically.
132132
A′ = Base.typeintersect(base_type(A), StaticArray{Tuple{Tuple(S)...},T,length(S)})
133-
isabstracttype(A′) || A′ === Union{} || return A′
133+
# But extra parameters are disallowed here. Also we check `fieldtypes` to make sure the result is valid.
134+
isconcretetype(A′) && fieldtypes(A′) === ntuple(Returns(T), Val(prod(S))) && return A′
135+
# Otherwise, we fallback to `S/MArray` based on it's mutability.
134136
if ismutabletype(A)
135137
return mutable_similar_type(T, S, length_val(S))
136138
else

test/FieldVector.jl

+24
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,28 @@
126126
@test @inferred(similar_type(FVT{Float64}, Size(3))) == SVector{3,Float64}
127127
@test @inferred(similar_type(FVT{Float64}, Float32, Size(3))) == SVector{3,Float32}
128128
end
129+
130+
@testset "similar_type for some ill FieldVector" begin
131+
# extra parameters
132+
struct IllFV{T,N} <: FieldVector{3,T}
133+
x::T
134+
y::T
135+
z::T
136+
end
137+
138+
@test @inferred(similar_type(IllFV{Float64}, Float64)) == IllFV{Float64}
139+
@test @inferred(similar_type(IllFV{Float64,Int}, Float64)) == IllFV{Float64,Int}
140+
@test @inferred(similar_type(IllFV{Float64}, Float32)) == SVector{3,Float32}
141+
@test @inferred(similar_type(IllFV{Float64,Int}, Float32)) == SVector{3,Float32}
142+
143+
# invalid `eltype`
144+
struct IllFV2{T} <: FieldVector{3,T}
145+
x::Int
146+
y::Float64
147+
z::Int8
148+
end
149+
150+
@test @inferred(similar_type(IllFV2{Float64}, Float64)) == IllFV2{Float64}
151+
@test @inferred(similar_type(IllFV2{Float64}, Float32)) == SVector{3,Float32}
152+
end
129153
end

0 commit comments

Comments
 (0)