Skip to content

Commit 763a99d

Browse files
committed
Check in setting zero elements
1 parent ff5139e commit 763a99d

File tree

2 files changed

+41
-28
lines changed

2 files changed

+41
-28
lines changed

src/triangular.jl

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -278,43 +278,38 @@ Base.@constprop :aggressive @propagate_inbounds function getindex(A::Union{Lower
278278
end
279279
end
280280

281-
_zero_triangular_half_str(::Type{<:UpperOrUnitUpperTriangular}) = "lower"
282-
_zero_triangular_half_str(::Type{<:LowerOrUnitLowerTriangular}) = "upper"
283-
284-
@noinline function throw_nonzeroerror(T, @nospecialize(x), i, j)
285-
Ts = _zero_triangular_half_str(T)
286-
Tn = nameof(T)
281+
@noinline function throw_nonzeroerror(Tn, @nospecialize(x), i, j)
282+
Ts = Tn in (:UpperTriangular, :UnitUpperTriangular) ? "lower" : "upper"
287283
throw(ArgumentError(
288-
lazy"cannot set index in the $Ts triangular part ($i, $j) of an $Tn matrix to a nonzero value ($x)"))
284+
lazy"cannot set index in the $Ts triangular part ($i, $j) of a $Tn matrix to a nonzero value ($x)"))
289285
end
290-
@noinline function throw_nonuniterror(T, @nospecialize(x), i, j)
291-
check_compatible_type(T, x)
292-
Tn = nameof(T)
286+
@noinline function throw_nonuniterror(Tn, @nospecialize(x), i, j)
293287
throw(ArgumentError(
294-
lazy"cannot set index on the diagonal ($i, $j) of an $Tn matrix to a non-unit value ($x)"))
295-
end
296-
function check_compatible_type(T, @nospecialize(x))
297-
ET = eltype(T)
298-
convert(ET, x) # check that the types are compatible with setindex!
288+
lazy"cannot set index ($i, $j) on the diagonal of a $Tn matrix to a non-unit value ($x)"))
299289
end
300290

301291
@propagate_inbounds function setindex!(A::UpperTriangular, x, i::Integer, j::Integer)
302292
if i > j
303293
@boundscheck checkbounds(A, i, j)
304-
iszero(x) || throw_nonzeroerror(typeof(A), x, i, j)
294+
# the value must be convertible to the eltype for setindex! to be meaningful
295+
xT = convert(eltype(A), x)
296+
iszero(xT) || throw_nonzeroerror(:UpperTriangular, x, i, j)
305297
else
306298
A.data[i,j] = x
307299
end
308300
return A
309301
end
310302

311303
@propagate_inbounds function setindex!(A::UnitUpperTriangular, x, i::Integer, j::Integer)
312-
if i > j
313-
@boundscheck checkbounds(A, i, j)
314-
iszero(x) || throw_nonzeroerror(typeof(A), x, i, j)
315-
elseif i == j
304+
if i >= j
316305
@boundscheck checkbounds(A, i, j)
317-
x == oneunit(eltype(A)) || throw_nonuniterror(typeof(A), x, i, j)
306+
# the value must be convertible to the eltype for setindex! to be meaningful
307+
xT = convert(eltype(A), x)
308+
if i > j
309+
iszero(xT) || throw_nonzeroerror(:UnitUpperTriangular, x, i, j)
310+
else
311+
xT == oneunit(eltype(A)) || throw_nonuniterror(:UnitUpperTriangular, x, i, j)
312+
end
318313
else
319314
A.data[i,j] = x
320315
end
@@ -324,20 +319,25 @@ end
324319
@propagate_inbounds function setindex!(A::LowerTriangular, x, i::Integer, j::Integer)
325320
if i < j
326321
@boundscheck checkbounds(A, i, j)
327-
iszero(x) || throw_nonzeroerror(typeof(A), x, i, j)
322+
# the value must be convertible to the eltype for setindex! to be meaningful
323+
xT = convert(eltype(A), x)
324+
iszero(xT) || throw_nonzeroerror(:LowerTriangular, x, i, j)
328325
else
329326
A.data[i,j] = x
330327
end
331328
return A
332329
end
333330

334331
@propagate_inbounds function setindex!(A::UnitLowerTriangular, x, i::Integer, j::Integer)
335-
if i < j
332+
if i <= j
336333
@boundscheck checkbounds(A, i, j)
337-
iszero(x) || throw_nonzeroerror(typeof(A), x, i, j)
338-
elseif i == j
339-
@boundscheck checkbounds(A, i, j)
340-
x == oneunit(eltype(A)) || throw_nonuniterror(typeof(A), x, i, j)
334+
# the value must be convertible to the eltype for setindex! to be meaningful
335+
xT = convert(eltype(A), x)
336+
if i < j
337+
iszero(xT) || throw_nonzeroerror(:UnitLowerTriangular, x, i, j)
338+
else
339+
xT == oneunit(eltype(A)) || throw_nonuniterror(:UnitLowerTriangular, x, i, j)
340+
end
341341
else
342342
A.data[i,j] = x
343343
end
@@ -593,7 +593,7 @@ for (T, UT) in ((:UpperTriangular, :UnitUpperTriangular), (:LowerTriangular, :Un
593593
@eval @inline function _copy!(A::$UT, B::$T)
594594
for dind in diagind(A, IndexStyle(A))
595595
if A[dind] != B[dind]
596-
throw_nonuniterror(typeof(A), B[dind], Tuple(dind)...)
596+
throw_nonuniterror(nameof(typeof(A)), B[dind], Tuple(dind)...)
597597
end
598598
end
599599
_copy!($T(parent(A)), B)

test/triangular.jl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -998,8 +998,21 @@ end
998998
M = fill(A, 2, 2)
999999
U = UnitUpperTriangular(M)
10001000
@test_throws "Cannot `convert` an object of type $Int" U[1,1] = 1
1001+
non_unit_msg = "cannot set index $((1,1)) on the diagonal of a UnitUpperTriangular matrix to a non-unit value"
1002+
@test_throws non_unit_msg U[1,1] = A
10011003
L = UnitLowerTriangular(M)
10021004
@test_throws "Cannot `convert` an object of type $Int" L[1,1] = 1
1005+
non_unit_msg = "cannot set index $((1,1)) on the diagonal of a UnitLowerTriangular matrix to a non-unit value"
1006+
@test_throws non_unit_msg L[1,1] = A
1007+
1008+
for UT in (UnitUpperTriangular, UpperTriangular)
1009+
U = UT(M)
1010+
@test_throws "Cannot `convert` an object of type $Int" U[2,1] = 0
1011+
end
1012+
for LT in (UnitLowerTriangular, LowerTriangular)
1013+
L = LT(M)
1014+
@test_throws "Cannot `convert` an object of type $Int" L[1,2] = 0
1015+
end
10031016

10041017
U = UnitUpperTriangular(P)
10051018
@test_throws BoundsError U[0,0] = 1

0 commit comments

Comments
 (0)