Skip to content

Commit 75d8f75

Browse files
authored
test for suboptimal type inference and unnecessary allocation (#37)
Also otherwise somewhat tidied up the test suite and made it more comprehensive in a few places. Fixes #27
1 parent 0540043 commit 75d8f75

File tree

1 file changed

+122
-79
lines changed

1 file changed

+122
-79
lines changed

test/runtests.jl

Lines changed: 122 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,47 @@ import Aqua
55

66
const checked_dims = FixedSizeArrays.checked_dims
77

8-
function allocated(f::F, args::Vararg{Any,N}) where {F,N}
9-
@allocated f(args...)
8+
# helpers for testing for allocation or suboptimal inference
9+
10+
allocated(f::F, args::Tuple) where {F} = @allocated f(args...)
11+
allocated(::Type{T}, args::Tuple) where {T} = @allocated T(args...)
12+
test_noalloc(f::F, args::Tuple) where {F} = @test iszero(allocated(f, args))
13+
test_noalloc(::Type{T}, args::Tuple) where {T} = @test iszero(allocated(T, args))
14+
test_inferred(f::F, ::Type{R}, args::Tuple) where {F,R} = @test (@inferred f(args...)) isa R
15+
test_inferred(::Type{T}, ::Type{R}, args::Tuple) where {T,R} = @test (@inferred T(args...)) isa R
16+
test_inferred(::Type{T}, args::Tuple) where {T } = test_inferred(T, T, args)
17+
function test_inferred_noalloc(f::F, ::Type{R}, args::Tuple) where {F,R}
18+
test_noalloc(f, args)
19+
test_inferred(f, R, args)
20+
end
21+
function test_inferred_noalloc(::Type{T}, ::Type{R}, args::Tuple) where {T,R}
22+
test_noalloc(T, args)
23+
test_inferred(T, R, args)
24+
end
25+
function test_inferred_noalloc(::Type{T}, args::Tuple) where {T }
26+
test_noalloc(T, args)
27+
test_inferred(T, args)
1028
end
1129

1230
@testset "FixedSizeArrays" begin
31+
@testset "meta" begin
32+
@test isempty(detect_ambiguities(Main)) # test for ambiguities in this file
33+
end
34+
1335
@testset "Aqua.jl" begin
1436
Aqua.test_all(FixedSizeArrays)
1537
end
1638

1739
@testset "Constructors" begin
18-
@test FixedSizeArray{Float64,0}(undef) isa FixedSizeArray{Float64,0}
19-
@test FixedSizeArray{Float64,0}(undef, ()) isa FixedSizeArray{Float64,0}
40+
for dim_count 0:4
41+
siz = ntuple(Returns(2), dim_count)
42+
T = FixedSizeArray{Float64}
43+
R = FixedSizeArray{Float64,dim_count}
44+
for args ((undef, siz), (undef, siz...))
45+
test_inferred( R, args)
46+
test_inferred(T, R, args)
47+
end
48+
end
2049
for offset (-1, 0, 2, 3)
2150
ax = offset:(offset + 1)
2251
oa = OffsetArray([10, 20], ax)
@@ -57,41 +86,40 @@ end
5786
if 20 < n
5887
@test_throws ArgumentError checked_dims(t)
5988
else
60-
@test factorial(n) == prod(t) == @inferred checked_dims(t)
61-
@test iszero(allocated(checked_dims, t))
89+
@test factorial(n) == prod(t) == checked_dims(t)
90+
test_inferred_noalloc(checked_dims, Int, (t,))
6291
end
6392
end
6493
end
6594

6695
@testset "FixedSizeVector" begin
6796
v = FixedSizeVector{Float64}(undef, 3)
6897
@test length(v) == 3
69-
v .= 1:3
98+
test_inferred_noalloc(((a, b) -> a .= b), FixedSizeVector{Float64}, (v, 1:3))
7099
@test v == 1:3
71-
@test typeof(v) == typeof(similar(v)) == FixedSizeVector{Float64}
72-
@test similar(v, Int) isa FixedSizeVector{Int}
73-
@test eltype(similar(v, Int)) == Int
74-
@test copy(v) isa FixedSizeVector{Float64}
75-
@test zero(v) isa FixedSizeVector{Float64}
76-
@test similar(FixedSizeVector{Int}, (2,)) isa FixedSizeVector{Int}
77-
@test similar(FixedSizeArray{Int}, (2,)) isa FixedSizeVector{Int}
78-
@test FixedSizeArray{Int}(undef, 2) isa FixedSizeVector{Int}
100+
test_inferred(similar, FixedSizeVector{Float64}, (v,))
101+
test_inferred(similar, FixedSizeVector{Int}, (v, Int))
102+
test_inferred(copy, FixedSizeVector{Float64}, (v,))
103+
test_inferred(zero, FixedSizeVector{Float64}, (v,))
104+
test_inferred(similar, FixedSizeVector{Int}, (FixedSizeVector{Int}, (2,)))
105+
test_inferred(similar, FixedSizeVector{Int}, (FixedSizeArray{Int}, (2,)))
79106
example_abstract_vectors = (7:9, [7, 8, 9], OffsetArray([7, 8, 9], 1:3))
107+
test_convert = function(T, a)
108+
test_inferred(convert, FixedSizeVector{Int}, (T, a))
109+
c = convert(T, a)
110+
test_inferred(convert, FixedSizeVector{Int}, (T, c))
111+
@test c == a
112+
@test c === convert(T, c)
113+
end
80114
for T (FixedSizeArray, FixedSizeVector)
81115
for a example_abstract_vectors
82-
@test convert(T, a) isa FixedSizeVector{Int}
83-
@test convert(T, a) == a
84-
@test convert(T, convert(T, a)) isa FixedSizeVector{Int}
85-
@test convert(T, convert(T, a)) == a
116+
test_convert(T, a)
86117
end
87118
end
88119
for T (FixedSizeArray{Int}, FixedSizeVector{Int})
89120
for S (Int, Float64)
90121
for a map((c -> map(S, c)), example_abstract_vectors)
91-
@test convert(T, a) isa FixedSizeVector{Int}
92-
@test convert(T, a) == a
93-
@test convert(T, convert(T, a)) isa FixedSizeVector{Int}
94-
@test convert(T, convert(T, a)) == a
122+
test_convert(T, a)
95123
end
96124
end
97125
end
@@ -101,35 +129,34 @@ end
101129
m = FixedSizeMatrix{Float64}(undef, 3, 3)
102130
m_ref = reshape(1:9, size(m))
103131
@test length(m) == 9
104-
m .= m_ref
132+
test_inferred_noalloc(((a, b) -> a .= b), FixedSizeMatrix{Float64}, (m, m_ref))
105133
@test m == m_ref
106-
@test typeof(m) == typeof(similar(m)) == FixedSizeMatrix{Float64}
107-
@test similar(m, Int) isa FixedSizeMatrix{Int}
108-
@test eltype(similar(m, Int)) == Int
109-
@test copy(m) isa FixedSizeMatrix{Float64}
110-
@test zero(m) isa FixedSizeMatrix{Float64}
111-
@test similar(FixedSizeMatrix{Int}, (2, 3)) isa FixedSizeMatrix{Int}
112-
@test similar(FixedSizeArray{Int}, (2, 3)) isa FixedSizeMatrix{Int}
113-
@test FixedSizeArray{Int}(undef, 2, 3) isa FixedSizeMatrix{Int}
134+
test_inferred(similar, FixedSizeMatrix{Float64}, (m,))
135+
test_inferred(similar, FixedSizeMatrix{Int}, (m, Int))
136+
test_inferred(copy, FixedSizeMatrix{Float64}, (m,))
137+
test_inferred(zero, FixedSizeMatrix{Float64}, (m,))
138+
test_inferred(similar, FixedSizeMatrix{Int}, (FixedSizeMatrix{Int}, (2, 3)))
139+
test_inferred(similar, FixedSizeMatrix{Int}, (FixedSizeArray{Int}, (2, 3)))
114140
example_abstract_matrices = (
115141
reshape(1:9, (3, 3)),
116142
OffsetArray(reshape(1:9, (3, 3)), 1:3, 1:3),
117143
)
144+
test_convert = function(T, a)
145+
test_inferred(convert, FixedSizeMatrix{Int}, (T, a))
146+
c = convert(T, a)
147+
test_inferred(convert, FixedSizeMatrix{Int}, (T, c))
148+
@test c == a
149+
@test c === convert(T, c)
150+
end
118151
for T (FixedSizeArray, FixedSizeMatrix)
119152
for a example_abstract_matrices
120-
@test convert(T, a) isa FixedSizeMatrix{Int}
121-
@test convert(T, a) == a
122-
@test convert(T, convert(T, a)) isa FixedSizeMatrix{Int}
123-
@test convert(T, convert(T, a)) == a
153+
test_convert(T, a)
124154
end
125155
end
126156
for T (FixedSizeArray{Int}, FixedSizeMatrix{Int})
127157
for S (Int, Float64)
128158
for a map((c -> map(S, c)), example_abstract_matrices)
129-
@test convert(T, a) isa FixedSizeMatrix{Int}
130-
@test convert(T, a) == a
131-
@test convert(T, convert(T, a)) isa FixedSizeMatrix{Int}
132-
@test convert(T, convert(T, a)) == a
159+
test_convert(T, a)
133160
end
134161
end
135162
end
@@ -140,36 +167,51 @@ end
140167
size = ntuple(Returns(3), dim_count)
141168
a = FixedSizeArray{Int, dim_count}(undef, size)
142169
for v (3, 3.1, nothing)
143-
mapped = map(Returns(v), a)
144-
@test all(==(v), mapped)
145-
@test mapped isa FixedSizeArray{typeof(v), dim_count}
170+
args = (Returns(v), a)
171+
@test all(==(v), map(args...))
172+
test_inferred(map, FixedSizeArray{typeof(v), dim_count}, args)
146173
end
147174
end
148175
end
149176

150177
@testset "broadcasting" begin
151-
v3 = FixedSizeArray{Int}(undef, 3)
152-
@test v3 isa FixedSizeVector{Int}
153-
@test (@inferred (v3 + v3)) isa FixedSizeVector{Int}
154-
@test (@inferred (v3 .+ v3)) isa FixedSizeVector{Int}
155-
@test (@inferred (v3 .* v3)) isa FixedSizeVector{Int}
156-
@test (@inferred (v3 .+ 3)) isa FixedSizeVector{Int}
157-
@test (@inferred (v3 .* 3)) isa FixedSizeVector{Int}
158-
@test (@inferred (v3 .+ .3)) isa FixedSizeVector{Float64}
159-
@test (@inferred (v3 .* .3)) isa FixedSizeVector{Float64}
178+
TVI = FixedSizeVector{Int}
179+
TVF = FixedSizeVector{Float64}
180+
v3 = TVI(1:3)
181+
vf3 = TVF(1:3)
182+
bp = (x, y) -> x .+ y
183+
bm = (x, y) -> x .* y
184+
test_inferred(+, TVI, (v3, v3))
185+
test_inferred(bp, TVI, (v3, v3))
186+
test_inferred(bm, TVI, (v3, v3))
187+
test_inferred(+, TVF, (v3, vf3))
188+
test_inferred(bp, TVF, (v3, vf3))
189+
test_inferred(bm, TVF, (v3, vf3))
190+
test_inferred(bp, TVI, (v3, 3))
191+
test_inferred(bm, TVI, (v3, 3))
192+
test_inferred(bp, TVF, (v3, .3))
193+
test_inferred(bm, TVF, (v3, .3))
160194
@testset "matrices" begin
161-
m33 = FixedSizeArray{Int}(undef, 3, 3)
162-
m13 = FixedSizeArray{Int}(undef, 1, 3)
163-
m31 = FixedSizeArray{Int}(undef, 3, 1)
164-
@test m33 isa FixedSizeMatrix{Int}
165-
@test m13 isa FixedSizeMatrix{Int}
166-
@test m31 isa FixedSizeMatrix{Int}
167-
@test (@inferred (m33 .+ .3 )) isa FixedSizeMatrix{Float64}
168-
@test (@inferred (m33 .+ 3 )) isa FixedSizeMatrix{Int}
169-
@test (@inferred (m33 .+ v3 )) isa FixedSizeMatrix{Int}
170-
@test (@inferred (m33 .+ m13)) isa FixedSizeMatrix{Int}
171-
@test (@inferred (m33 .+ m31)) isa FixedSizeMatrix{Int}
172-
@test (@inferred (m33 .+ m33)) isa FixedSizeMatrix{Int}
195+
TMI = FixedSizeMatrix{Int}
196+
TMF = FixedSizeMatrix{Float64}
197+
m33 = TMI(undef, 3, 3)
198+
m13 = TMI(undef, 1, 3)
199+
m31 = TMI(undef, 3, 1)
200+
test_inferred(+, TMI, (m33, m33))
201+
test_inferred(bp, TMI, (m33, m33))
202+
test_inferred(bm, TMI, (m33, m33))
203+
test_inferred(bp, TMI, (m33, m13))
204+
test_inferred(bm, TMI, (m33, m13))
205+
test_inferred(bp, TMI, (m33, m31))
206+
test_inferred(bm, TMI, (m33, m31))
207+
test_inferred(bp, TMI, (m33, v3 ))
208+
test_inferred(bm, TMI, (m33, v3 ))
209+
test_inferred(bp, TMF, (m33, vf3))
210+
test_inferred(bm, TMF, (m33, vf3))
211+
test_inferred(bp, TMI, (m33, 3))
212+
test_inferred(bm, TMI, (m33, 3))
213+
test_inferred(bp, TMF, (m33, .3))
214+
test_inferred(bm, TMF, (m33, .3))
173215
end
174216
end
175217

@@ -181,6 +223,7 @@ end
181223
for i_style (IndexLinear(), IndexCartesian())
182224
for i eachindex(i_style, a)
183225
@test isassigned(a, i) == isbitstype(elem_type)
226+
test_inferred_noalloc(isassigned, Bool, (a, i))
184227
end
185228
end
186229
end
@@ -193,6 +236,7 @@ end
193236
end
194237
for ij Iterators.product(1:3, 1:3)
195238
@test isassigned(a, ij...) == (ij assigned_inds)
239+
test_inferred_noalloc(isassigned, Bool, (a, ij...))
196240
end
197241
end
198242
end
@@ -207,10 +251,11 @@ end
207251
s = S{E}(undef, 5)
208252
s .= 1:5
209253
d = D{Float64}(undef, 5)
210-
@test copyto!(d, s) isa D{Float64}
254+
test_inferred_noalloc(copyto!, D{Float64}, (d, s))
211255
@test copyto!(d, s) == 1:5
212-
@test copyto!(d, 1, s, 1, length(s)) isa D{Float64}
213-
@test copyto!(d, 1, s, 1, length(s)) == 1:5
256+
args = (d, 1, s, 1, length(s))
257+
test_inferred_noalloc(copyto!, D{Float64}, args)
258+
@test copyto!(args...) == 1:5
214259
@test_throws ArgumentError copyto!(d, 1, s, 1, -1)
215260
end
216261
end
@@ -220,20 +265,20 @@ end
220265
@testset "$T" for T in (Float16, Float32, Float64)
221266
v = randn(T, 8)
222267
v_fixed = FixedSizeVector(v)
223-
v_sum = @inferred v_fixed + v_fixed
224-
@test v_sum isa FixedSizeVector{T}
268+
test_inferred(+, FixedSizeVector{T}, (v_fixed, v_fixed))
269+
v_sum = v_fixed + v_fixed
225270
@test v_sum v + v
226-
v_mul = @inferred v_fixed * v_fixed'
227-
@test v_mul isa FixedSizeMatrix{T}
271+
test_inferred(((x, y) -> x * y'), FixedSizeMatrix{T}, (v_fixed, v_fixed))
272+
v_mul = v_fixed * v_fixed'
228273
@test v_mul v * v'
229274

230275
M = randn(T, 8, 8)
231276
M_fixed = FixedSizeMatrix(M)
232-
M_sum = @inferred M_fixed + M_fixed
233-
@test M_sum isa FixedSizeMatrix{T}
277+
test_inferred(+, FixedSizeMatrix{T}, (M_fixed, M_fixed))
278+
M_sum = M_fixed + M_fixed
234279
@test M_sum M + M
235-
M_mul = @inferred M_fixed * M_fixed
236-
@test M_mul isa FixedSizeMatrix{T}
280+
test_inferred(*, FixedSizeMatrix{T}, (M_fixed, M_fixed))
281+
M_mul = M_fixed * M_fixed
237282
@test M_mul M * M
238283
end
239284
end
@@ -244,10 +289,8 @@ end
244289
siz = ntuple(Returns(2), dim_count)
245290
arr = FixedSizeArray{elem_type, dim_count}(undef, siz)
246291
@test pointer(arr) === pointer(arr, 1) === pointer(arr, 2) - sizeof(elem_type)
247-
@test (@inferred pointer(arr)) isa Ptr{elem_type}
248-
@test (@inferred pointer(arr, 1)) isa Ptr{elem_type}
249-
@test iszero(allocated(pointer, arr))
250-
@test iszero(allocated(pointer, arr, 1))
292+
test_inferred_noalloc(pointer, Ptr{elem_type}, (arr,))
293+
test_inferred_noalloc(pointer, Ptr{elem_type}, (arr, 1))
251294
end
252295
end
253296
end

0 commit comments

Comments
 (0)