Skip to content

Commit af7b57c

Browse files
devmotionjishnub
andauthored
Make error messages lazy strings (#420)
Based on #419 since `LazyString` and `lazy"..."` are only available in Julia >= 1.8. --- The PR changes all error messages to lazy strings to delay string interpolation and `print`ing of the involved quantities until the error message is displayed (and hence skip it completely if the error path is not hit). Using `LazyString`s in error messages generally also helps with type inference (see e.g. JuliaLang/julia#58672 and JuliaLang/julia#54737). --------- Co-authored-by: Jishnu Bhattacharya <[email protected]>
1 parent 62c9f34 commit af7b57c

File tree

4 files changed

+41
-46
lines changed

4 files changed

+41
-46
lines changed

src/FillArrays.jl

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -48,18 +48,18 @@ Base.@propagate_inbounds getindex(F::AbstractFill{T, N}, kj::Vararg{Integer, N})
4848

4949
@inline function setindex!(F::AbstractFill, v, k::Integer)
5050
@boundscheck checkbounds(F, k)
51-
v == getindex_value(F) || throw(ArgumentError("Cannot setindex! to $v for an AbstractFill with value $(getindex_value(F))."))
51+
v == getindex_value(F) || throw(ArgumentError(LazyString("Cannot setindex! to ", v, " for an AbstractFill with value ", getindex_value(F), ".")))
5252
F
5353
end
5454

5555
@inline function setindex!(F::AbstractFill{T, N}, v, kj::Vararg{Integer, N}) where {T, N}
5656
@boundscheck checkbounds(F, kj...)
57-
v == getindex_value(F) || throw(ArgumentError("Cannot setindex! to $v for an AbstractFill with value $(getindex_value(F))."))
57+
v == getindex_value(F) || throw(ArgumentError(LazyString("Cannot setindex! to ", v, " for an AbstractFill with value ", getindex_value(F), ".")))
5858
F
5959
end
6060

6161
@inline function fill!(F::AbstractFill, v)
62-
v == getindex_value(F) || throw(ArgumentError("Cannot fill! with $v an AbstractFill with value $(getindex_value(F))."))
62+
v == getindex_value(F) || throw(ArgumentError(LazyString("Cannot fill! with ", v, " an AbstractFill with value ", getindex_value(F), ".")))
6363
F
6464
end
6565

@@ -182,7 +182,7 @@ function unique_value(arr::AbstractArray)
182182
val = first(arr)
183183
for x in arr
184184
if x !== val
185-
error("Input array contains both $x and $val. Cannot convert to Fill")
185+
error(LazyString("Input array contains both ", x, " and ", val, ". Cannot convert to Fill"))
186186
end
187187
end
188188
return val
@@ -255,12 +255,9 @@ end
255255

256256
svdvals!(a::AbstractFillMatrix) = [getindex_value(a)*sqrt(prod(size(a))); Zeros(min(size(a)...)-1)]
257257

258-
@noinline function _throw_dmrs(n, str, dims)
259-
throw(DimensionMismatch("parent has $n elements, which is incompatible with $str $dims"))
260-
end
261258
function fill_reshape(parent, dims::Integer...)
262259
n = length(parent)
263-
prod(dims) == n || _throw_dmrs(n, "size", dims)
260+
prod(dims) == n || throw(DimensionMismatch(LazyString("parent has ", n, " elements, which is incompatible with size ", dims)))
264261
fillsimilar(parent, dims...)
265262
end
266263

@@ -339,10 +336,10 @@ for (AbsTyp, Typ, funcs, func) in ((:AbstractZeros, :Zeros, :zeros, :zero), (:Ab
339336
convert(::Type{$Typ{T,N}}, A::$AbsTyp{V,N,Axes}) where {T,V,N,Axes} = convert($Typ{T,N,Axes}, A)
340337
convert(::Type{$Typ{T}}, A::$AbsTyp{V,N,Axes}) where {T,V,N,Axes} = convert($Typ{T,N,Axes}, A)
341338
function convert(::Type{Typ}, A::AbstractFill{V,N}) where {T,V,N,Axes,Typ<:$AbsTyp{T,N,Axes}}
342-
axes(A) isa Axes || throw(ArgumentError("cannot convert, as axes of array are not $Axes"))
339+
axes(A) isa Axes || throw(ArgumentError(LazyString("cannot convert, as axes of array are not ", Axes)))
343340
val = getindex_value(A)
344341
y = convert(T, val)
345-
y == $func(T) || throw(ArgumentError(string("cannot convert an array containinig $val to ", $Typ)))
342+
y == $func(T) || throw(ArgumentError(LazyString("cannot convert an array containinig ", val, " to ", Typ)))
346343
Typ(axes(A))
347344
end
348345
function convert(::Type{$Typ{T,N}}, A::AbstractFill{<:Any,N}) where {T,N}
@@ -381,7 +378,7 @@ fillsimilar(a::AbstractFill, axes...) = Fill(getindex_value(a), axes...)
381378
# functions
382379
function Base.sqrt(a::AbstractFillMatrix{<:Union{Real, Complex}})
383380
Base.require_one_based_indexing(a)
384-
size(a,1) == size(a,2) || throw(DimensionMismatch("matrix is not square: dimensions are $(size(a))"))
381+
size(a,1) == size(a,2) || throw(DimensionMismatch(LazyString("matrix is not square: dimensions are ", size(a))))
385382
_sqrt(a)
386383
end
387384
_sqrt(a::AbstractZerosMatrix) = float(a)
@@ -393,7 +390,7 @@ function _sqrt(a::AbstractFillMatrix)
393390
end
394391
function Base.cbrt(a::AbstractFillMatrix{<:Real})
395392
Base.require_one_based_indexing(a)
396-
size(a,1) == size(a,2) || throw(DimensionMismatch("matrix is not square: dimensions are $(size(a))"))
393+
size(a,1) == size(a,2) || throw(DimensionMismatch(LazyString("matrix is not square: dimensions are ", size(a))))
397394
_cbrt(a)
398395
end
399396
_cbrt(a::AbstractZerosMatrix) = float(a)
@@ -452,7 +449,7 @@ function setindex!(rd::RectDiagonal, v, i::Integer, j::Integer)
452449
if i == j
453450
@inbounds rd.diag[i] = v
454451
elseif !iszero(v)
455-
throw(ArgumentError("cannot set off-diagonal entry ($i, $j) to a nonzero value ($v)"))
452+
throw(ArgumentError(LazyString("cannot set off-diagonal entry (", i, ", ", j, ") to a nonzero value (", v, ")")))
456453
end
457454
return v
458455
end
@@ -851,11 +848,9 @@ end
851848
function _repeat(A; inner=ntuple(x->1, ndims(A)), outer=ntuple(x->1, ndims(A)))
852849
Base.require_one_based_indexing(A)
853850
length(inner) >= ndims(A) ||
854-
throw(ArgumentError("number of inner repetitions $(length(inner)) cannot be "*
855-
"less than number of dimensions of input array $(ndims(A))"))
851+
throw(ArgumentError(LazyString("number of inner repetitions ", length(inner), " cannot be less than number of dimensions of input array ", ndims(A))))
856852
length(outer) >= ndims(A) ||
857-
throw(ArgumentError("number of outer repetitions $(length(outer)) cannot be "*
858-
"less than number of dimensions of input array $(ndims(A))"))
853+
throw(ArgumentError(LazyString("number of outer repetitions ", length(outer), " cannot be less than number of dimensions of input array ", ndims(A))))
859854
sz = _repeat_size(size(A), Tuple(inner), Tuple(outer))
860855
fillsimilar(A, sz)
861856
end

src/fillalgebra.jl

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ end
6565
function mult_axes(a, b)
6666
Base.require_one_based_indexing(a, b)
6767
size(a, 2) size(b, 1) &&
68-
throw(DimensionMismatch("A has dimensions $(size(a)) but B has dimensions $(size(b))"))
68+
throw(DimensionMismatch(LazyString("A has dimensions ", size(a), " but B has dimensions ", size(b))))
6969
return (axes(a, 1), axes(b)[2:end]...)
7070
end
7171

@@ -115,11 +115,11 @@ function *(F::AbstractFillMatrix, v::AbstractVector)
115115
end
116116

117117
function lmul_diag(a::Diagonal, b)
118-
size(a,2) == size(b,1) || throw(DimensionMismatch("A has dimensions $(size(a)) but B has dimensions $(size(b))"))
118+
size(a,2) == size(b,1) || throw(DimensionMismatch(LazyString("A has dimensions ", size(a), " but B has dimensions ", size(b))))
119119
parent(a) .* b # use special broadcast
120120
end
121121
function rmul_diag(a, b::Diagonal)
122-
size(a,2) == size(b,1) || throw(DimensionMismatch("A has dimensions $(size(a)) but B has dimensions $(size(b))"))
122+
size(a,2) == size(b,1) || throw(DimensionMismatch(LazyString("A has dimensions ", size(a), " but B has dimensions ", size(b))))
123123
a .* permutedims(parent(b)) # use special broadcast
124124
end
125125

@@ -132,26 +132,26 @@ end
132132
@noinline function check_matmul_sizes(A::AbstractMatrix, x::AbstractVector)
133133
Base.require_one_based_indexing(A, x)
134134
size(A,2) == size(x,1) ||
135-
throw(DimensionMismatch("second dimension of A, $(size(A,2)) does not match length of x $(length(x))"))
135+
throw(DimensionMismatch(LazyString("second dimension of A, ", size(A,2), ", does not match length of x, ", length(x))))
136136
end
137137
@noinline function check_matmul_sizes(A::AbstractMatrix, B::AbstractMatrix)
138138
Base.require_one_based_indexing(A, B)
139139
size(A,2) == size(B,1) ||
140-
throw(DimensionMismatch("second dimension of A, $(size(A,2)) does not match first dimension of B, $(size(B,1))"))
140+
throw(DimensionMismatch(LazyString("second dimension of A, ", size(A,2), ", does not match first dimension of B, ", size(B,1))))
141141
end
142142
@noinline function check_matmul_sizes(y::AbstractVector, A::AbstractMatrix, x::AbstractVector)
143143
Base.require_one_based_indexing(A, x, y)
144144
size(A,2) == size(x,1) ||
145-
throw(DimensionMismatch("second dimension of A, $(size(A,2)) does not match length of x $(length(x))"))
145+
throw(DimensionMismatch(LazyString("second dimension of A, ", size(A,2), ", does not match length of x, ", length(x))))
146146
size(y,1) == size(A,1) ||
147-
throw(DimensionMismatch("first dimension of A, $(size(A,1)) does not match length of y $(length(y))"))
147+
throw(DimensionMismatch(LazyString("first dimension of A, ", size(A,1), ", does not match length of y, ", length(y))))
148148
end
149149
@noinline function check_matmul_sizes(C::AbstractMatrix, A::AbstractMatrix, B::AbstractMatrix)
150150
Base.require_one_based_indexing(A, B, C)
151151
size(A,2) == size(B,1) ||
152-
throw(DimensionMismatch("second dimension of A, $(size(A,2)) does not match first dimension of B, $(size(B,1))"))
152+
throw(DimensionMismatch(LazyString("second dimension of A, ", size(A,2), ", does not match first dimension of B, ", size(B,1))))
153153
size(C,1) == size(A,1) && size(C,2) == size(B,2) ||
154-
throw(DimensionMismatch("A has size $(size(A)), B has size $(size(B)), C has size $(size(C))"))
154+
throw(DimensionMismatch(LazyString("A has size ", size(A), ", B has size ", size(B), ", C has size ", size(C))))
155155
end
156156

157157
function mul!(y::AbstractVector, A::AbstractFillMatrix, b::AbstractFillVector, alpha::Number, beta::Number)
@@ -314,7 +314,7 @@ end
314314
function _adjvec_mul_zeros(a, b)
315315
la, lb = length(a), length(b)
316316
if la lb
317-
throw(DimensionMismatch("dot product arguments have lengths $la and $lb"))
317+
throw(DimensionMismatch(LazyString("dot product arguments have lengths ", la, " and ", lb)))
318318
end
319319
# ensure that all the elements of `a` are of the same size,
320320
# so that ∑ᵢaᵢbᵢ = b₁∑ᵢaᵢ makes sense
@@ -324,7 +324,7 @@ function _adjvec_mul_zeros(a, b)
324324
end
325325
a1 = a[1]
326326
sza1 = size(a1)
327-
all(x -> size(x) == sza1, a) || throw(DimensionMismatch("not all elements of A are of size $sza1"))
327+
all(x -> size(x) == sza1, a) || throw(DimensionMismatch(LazyString("not all elements of A are of size ", sza1)))
328328
# we replace b₁∑ᵢaᵢ by b₁a₁, as we know that b₁ is zero.
329329
# Each term in the summation is zero, so the sum is equal to the first term
330330
return a1 * b[1]
@@ -365,7 +365,7 @@ end
365365
*(a::TransposeAbsVec{<:Any,<:AbstractZerosVector}, D::Diagonal) = transpose(D*transpose(a))
366366
function _triple_zeromul(x, D::Diagonal, y)
367367
if !(length(x) == length(D.diag) == length(y))
368-
throw(DimensionMismatch("x has length $(length(x)), D has size $(size(D)), and y has $(length(y))"))
368+
throw(DimensionMismatch(LazyString("x has length ", length(x), ", D has size ", size(D), ", and y has ", length(y))))
369369
end
370370
zero(promote_type(eltype(x), eltype(D), eltype(y)))
371371
end
@@ -381,7 +381,7 @@ end
381381
function *(a::Transpose{T, <:AbstractVector}, b::AbstractZerosVector{T}) where T<:Real
382382
la, lb = length(a), length(b)
383383
if la lb
384-
throw(DimensionMismatch("dot product arguments have lengths $la and $lb"))
384+
throw(DimensionMismatch(LazyString("dot product arguments have lengths ", la, " and ", lb)))
385385
end
386386
return zero(T)
387387
end
@@ -391,12 +391,12 @@ end
391391
# infinite cases should be supported in InfiniteArrays.jl
392392
# type issues of Bool dot are ignored at present.
393393
function _fill_dot(a::AbstractFillVector{T}, b::AbstractVector{V}) where {T,V}
394-
axes(a) == axes(b) || throw(DimensionMismatch("dot product arguments have lengths $(length(a)) and $(length(b))"))
394+
axes(a) == axes(b) || throw(DimensionMismatch(LazyString("dot product arguments have lengths ", length(a), " and ", length(b))))
395395
dot(getindex_value(a), sum(b))
396396
end
397397

398398
function _fill_dot_rev(a::AbstractVector{T}, b::AbstractFillVector{V}) where {T,V}
399-
axes(a) == axes(b) || throw(DimensionMismatch("dot product arguments have lengths $(length(a)) and $(length(b))"))
399+
axes(a) == axes(b) || throw(DimensionMismatch(LazyString("dot product arguments have lengths ", length(a), " and ", length(b))))
400400
dot(sum(a), getindex_value(b))
401401
end
402402

@@ -406,21 +406,21 @@ dot(a::AbstractVector, b::AbstractFillVector) = _fill_dot_rev(a, b)
406406

407407
function dot(u::AbstractVector, E::Eye, v::AbstractVector)
408408
length(u) == size(E,1) && length(v) == size(E,2) ||
409-
throw(DimensionMismatch("dot product arguments have dimensions $(length(u))×$(size(E))×$(length(v))"))
409+
throw(DimensionMismatch(LazyString("dot product arguments have dimensions ", length(u), "×", size(E), "×", length(v))))
410410
d = dot(u,v)
411411
T = typeof(one(eltype(E)) * d)
412412
convert(T, d)
413413
end
414414

415415
function dot(u::AbstractVector, D::Diagonal{<:Any,<:Fill}, v::AbstractVector)
416416
length(u) == size(D,1) && length(v) == size(D,2) ||
417-
throw(DimensionMismatch("dot product arguments have dimensions $(length(u))×$(size(D))×$(length(v))"))
417+
throw(DimensionMismatch(LazyString("dot product arguments have dimensions ", length(u), "×", size(D), "×", length(v))))
418418
D.diag.value*dot(u, v)
419419
end
420420

421421
function dot(u::AbstractVector{T}, D::Diagonal{U,<:Zeros}, v::AbstractVector{V}) where {T,U,V}
422422
length(u) == size(D,1) && length(v) == size(D,2) ||
423-
throw(DimensionMismatch("dot product arguments have dimensions $(length(u))×$(size(D))×$(length(v))"))
423+
throw(DimensionMismatch(LazyString("dot product arguments have dimensions ", length(u), "×", size(D), "×", length(v))))
424424
zero(promote_type(T,U,V))
425425
end
426426

@@ -516,21 +516,21 @@ function lmul!(x::Number, z::AbstractFill)
516516
λ = getindex_value(z)
517517
# Following check ensures consistency w/ lmul!(x, Array(z))
518518
# for, e.g., lmul!(NaN, z)
519-
x*λ == λ || throw(ArgumentError("Cannot scale by $x"))
519+
x*λ == λ || throw(ArgumentError(LazyString("Cannot scale by ", x)))
520520
z
521521
end
522522

523523
function rmul!(z::AbstractFill, x::Number)
524524
λ = getindex_value(z)
525525
# Following check ensures consistency w/ lmul!(x, Array(z))
526526
# for, e.g., lmul!(NaN, z)
527-
λ*x == λ || throw(ArgumentError("Cannot scale by $x"))
527+
λ*x == λ || throw(ArgumentError(LazyString("Cannot scale by ", x)))
528528
z
529529
end
530530

531531
fillzero(::Type{Fill{T,N,AXIS}}, n, m) where {T,N,AXIS} = Fill{T,N,AXIS}(zero(T), (n, m))
532532
fillzero(::Type{<:AbstractZeros{T,N,AXIS}}, n, m) where {T,N,AXIS} = Zeros{T,N,AXIS}((n, m))
533-
fillzero(::Type{F}, n, m) where F = throw(ArgumentError("Cannot create a zero array of type $F"))
533+
fillzero(::Type{F}, n, m) where F = throw(ArgumentError(LazyString("Cannot create a zero array of type ", F)))
534534

535535
diagzero(D::Diagonal{F}, i, j) where F<:AbstractFill = fillzero(F, axes(D.diag[i], 1), axes(D.diag[j], 2))
536536

src/fillbroadcast.jl

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ function _maplinear(rs...) # tries to match Base's behaviour, could perhaps hook
2424
r1 = axes(first(rs))
2525
for r in rs
2626
axes(r) == r1 || throw(DimensionMismatch(
27-
"dimensions must match: a has dims $r1, b has dims $(axes(r))"))
27+
LazyString("dimensions must match: a has dims ", r1, ", b has dims ", axes(r))))
2828
end
2929
return false
3030
end
@@ -206,27 +206,27 @@ _range_convert(::Type{AbstractVector{T}}, a::ZerosVector) where T = ZerosVector{
206206
# end
207207

208208
function broadcasted(::DefaultArrayStyle{1}, ::typeof(*), a::AbstractOnesVector, b::AbstractRange)
209-
broadcast_shape(axes(a), axes(b)) == axes(b) || throw(ArgumentError("Cannot broadcast $a and $b. Convert $b to a Vector first."))
209+
broadcast_shape(axes(a), axes(b)) == axes(b) || throw(ArgumentError(LazyString("Cannot broadcast ", a, " and ", b, ". Convert ", b, " to a Vector first.")))
210210
TT = typeof(zero(eltype(a)) * zero(eltype(b)))
211211
return _range_convert(AbstractVector{TT}, b)
212212
end
213213

214214
function broadcasted(::DefaultArrayStyle{1}, ::typeof(*), a::AbstractRange, b::AbstractOnesVector)
215-
broadcast_shape(axes(a), axes(b)) == axes(a) || throw(ArgumentError("Cannot broadcast $a and $b. Convert $b to a Vector first."))
215+
broadcast_shape(axes(a), axes(b)) == axes(a) || throw(ArgumentError(LazyString("Cannot broadcast ", a, " and ", b, ". Convert ", b, " to a Vector first.")))
216216
TT = typeof(zero(eltype(a)) * zero(eltype(b)))
217217
return _range_convert(AbstractVector{TT}, a)
218218
end
219219

220220
for op in (:+, :-)
221221
@eval begin
222222
function broadcasted(::DefaultArrayStyle{1}, ::typeof($op), a::AbstractVector, b::AbstractZerosVector)
223-
broadcast_shape(axes(a), axes(b)) == axes(a) || throw(ArgumentError("Cannot broadcast $a and $b. Convert $b to a Vector first."))
223+
broadcast_shape(axes(a), axes(b)) == axes(a) || throw(ArgumentError(LazyString("Cannot broadcast ", a, " and ", b, ". Convert ", b, " to a Vector first.")))
224224
TT = typeof($op(zero(eltype(a)), zero(eltype(b))))
225225
# Use `TT ∘ (+)` to fix AD issues with `broadcasted(TT, x)`
226226
eltype(a) === TT ? a : broadcasted(TT (+), a)
227227
end
228228
function broadcasted(::DefaultArrayStyle{1}, ::typeof($op), a::AbstractZerosVector, b::AbstractVector)
229-
broadcast_shape(axes(a), axes(b)) == axes(b) || throw(ArgumentError("Cannot broadcast $a and $b. Convert $a to a Vector first."))
229+
broadcast_shape(axes(a), axes(b)) == axes(b) || throw(ArgumentError(LazyString("Cannot broadcast ", a, " and ", b, ". Convert ", a, " to a Vector first.")))
230230
TT = typeof($op(zero(eltype(a)), zero(eltype(b))))
231231
$op === (+) && eltype(b) === TT ? b : broadcasted(TT ($op), b)
232232
end
@@ -245,12 +245,12 @@ _broadcast_getindex_value(a::AbstractFill) = Ref(getindex_value(a))
245245

246246

247247
function broadcasted(::DefaultArrayStyle{1}, ::typeof(*), a::AbstractFill, b::AbstractRange)
248-
broadcast_shape(axes(a), axes(b)) == axes(b) || throw(ArgumentError("Cannot broadcast $a and $b. Convert $b to a Vector first."))
248+
broadcast_shape(axes(a), axes(b)) == axes(b) || throw(ArgumentError(LazyString("Cannot broadcast ", a, " and ", b, ". Convert ", b, " to a Vector first.")))
249249
return broadcasted(*, _broadcast_getindex_value(a), b)
250250
end
251251

252252
function broadcasted(::DefaultArrayStyle{1}, ::typeof(*), a::AbstractRange, b::AbstractFill)
253-
broadcast_shape(axes(a), axes(b)) == axes(a) || throw(ArgumentError("Cannot broadcast $a and $b. Convert $b to a Vector first."))
253+
broadcast_shape(axes(a), axes(b)) == axes(a) || throw(ArgumentError(LazyString("Cannot broadcast ", a, " and ", b, ". Convert ", b, " to a Vector first.")))
254254
return broadcasted(*, a, _broadcast_getindex_value(b))
255255
end
256256

src/oneelement.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ end
423423
# reshape
424424

425425
function Base.reshape(A::OneElement, shape::Tuple{Vararg{Int}})
426-
prod(shape) == length(A) || throw(DimensionMismatch("new dimension $shape must be consistent with array size $(length(A))"))
426+
prod(shape) == length(A) || throw(DimensionMismatch(LazyString("new dimension ", shape, " must be consistent with array size ", length(A))))
427427
if all(in.(A.ind, axes(A)))
428428
# we use the fact that the linear index of the non-zero value is preserved
429429
oldlinind = LinearIndices(A)[A.ind...]

0 commit comments

Comments
 (0)