From d1a1cc6896f4bacc3ec3fb91249ca9591b5e64d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hans=20W=C3=BCrfel?= Date: Mon, 13 Jul 2026 19:28:23 +0200 Subject: [PATCH] can_setindex is false for CUSPARSE arrays CuSparseVector and the CuSparseMatrix formats implement no setindex! at all, but can_setindex fell back to the `true` default for them, so callers guarding mutation with it (e.g. NonlinearSolveBase's safe_similar) hit a CanonicalIndexError instead of taking their non-mutating path. Co-Authored-By: Claude Opus 4.8 --- ext/ArrayInterfaceCUDAExt.jl | 12 ++++++++++++ test/gpu/cuda.jl | 8 ++++++++ 2 files changed, 20 insertions(+) diff --git a/ext/ArrayInterfaceCUDAExt.jl b/ext/ArrayInterfaceCUDAExt.jl index 715f8107..7ba6216a 100644 --- a/ext/ArrayInterfaceCUDAExt.jl +++ b/ext/ArrayInterfaceCUDAExt.jl @@ -3,6 +3,7 @@ module ArrayInterfaceCUDAExt using ArrayInterface using CUDA using CUDA.CUSOLVER +using CUDA.CUSPARSE using LinearAlgebra function ArrayInterface.lu_instance(A::CuMatrix{T}) where {T} @@ -13,6 +14,17 @@ end ArrayInterface.device(::Type{<:CUDA.CuArray}) = ArrayInterface.GPU() +# CUSPARSE arrays implement no `setindex!` at all, so the `true` default is wrong +# for them and callers guarding mutation with `can_setindex` hit a CanonicalIndexError. +const CuSparseArray = Union{ + CUSPARSE.CuSparseVector, + CUSPARSE.CuSparseMatrixCSC, + CUSPARSE.CuSparseMatrixCSR, + CUSPARSE.CuSparseMatrixBSR, + CUSPARSE.CuSparseMatrixCOO, +} +ArrayInterface.can_setindex(::Type{<:CuSparseArray}) = false + function ArrayInterface.promote_eltype( ::Type{<:CUDA.CuArray{T, N, M}}, ::Type{T2} ) where {T, N, M, T2} diff --git a/test/gpu/cuda.jl b/test/gpu/cuda.jl index 2651a638..b60c356e 100644 --- a/test/gpu/cuda.jl +++ b/test/gpu/cuda.jl @@ -18,3 +18,11 @@ lu_sparse = lu!(lu_inst_sparse, A_sparse) #test that the resulting lu works b = CuVector([1f0, 1f0]) @test CUDA.@allowscalar lu_sparse \ b == [1, 1] + +# CUSPARSE arrays have no `setindex!`, so `can_setindex` must not claim they do +@test ArrayInterface.can_setindex(A_dense) +@test !ArrayInterface.can_setindex(A_sparse) +@test !ArrayInterface.can_setindex(CuSparseMatrixCSC(sparse(A_cpu))) +@test !ArrayInterface.can_setindex(CuSparseMatrixCOO(sparse(A_cpu))) +@test !ArrayInterface.can_setindex(CuSparseVector(sparsevec([1], [1.0f0], 2))) +@test_throws CanonicalIndexError A_sparse[1, 2] = 1.0f0