From 3493b4f3d0b61c21dc919b748846a75717dda611 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Fuhrmann?= Date: Fri, 17 Jul 2026 21:21:57 +0200 Subject: [PATCH 1/8] Fix inline complex plan When applying a complex inline plan to a real vector, '*' should throw similar to 'mul!'. --- src/fft.jl | 4 ++-- test/runtests.jl | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/fft.jl b/src/fft.jl index eb62f61..828b462 100644 --- a/src/fft.jl +++ b/src/fft.jl @@ -832,7 +832,7 @@ function *(p::cFFTWPlan{T,K,false}, x::StridedArray{T,N}) where {T,K,N} return y end -function *(p::cFFTWPlan{T,K,true}, x::StridedArray{T}) where {T,K} +function *(p::cFFTWPlan{T,K,true}, x::AbstractArray) where {T,K} assert_applicable(p, x) unsafe_execute!(p, x, x) return x @@ -1046,7 +1046,7 @@ function *(p::r2rFFTWPlan{T,K,false}, x::StridedArray{T,N}) where {T,K,N} return y end -function *(p::r2rFFTWPlan{T,K,true}, x::StridedArray{T}) where {T,K} +function *(p::r2rFFTWPlan{T,K,true}, x::AbstractArray) where {T,K} assert_applicable(p, x) unsafe_execute!(p, x, x) return x diff --git a/test/runtests.jl b/test/runtests.jl index d84eb50..c2ebb12 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -586,3 +586,28 @@ end AbstractFFTs.TestUtils.test_real_ffts(Array; copy_input=true) end end + + +@testset "Avoid copy with inline version" begin + complexplan = plan_fft!(zeros(ComplexF64, 4)) + realvec = [1,1,1,1] + + catched_typerror=false + try + FFTW.mul!(realvec, complexplan, realvec) + catch e; + println(e,"\n") + catched_typerror = true + end + @test catched_typerror + + catched_typerror=false + try + complexplan * realvec + catch e; + println(e,"\n") + catched_typerror = true + end + @test catched_typerror + +end From 6eee39ec8e595cb4d31ee49e368900e8ca9ad472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Fuhrmann?= Date: Fri, 17 Jul 2026 22:04:43 +0200 Subject: [PATCH 2/8] Add test case for r2r! --- test/runtests.jl | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index c2ebb12..70947d3 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -588,7 +588,7 @@ end end -@testset "Avoid copy with inline version" begin +@testset "Ensure inline version throws with wrong type" begin complexplan = plan_fft!(zeros(ComplexF64, 4)) realvec = [1,1,1,1] @@ -610,4 +610,24 @@ end end @test catched_typerror + complexvec=ones(ComplexF64,4) + realplan = FFTW.plan_r2r!(zeros(4), FFTW.REDFT10) + catched_typerror=false + try + FFTW.mul!(complexvec, realplan, complexvec) + catch e; + println(e,"\n") + catched_typerror = true + end + @test catched_typerror + + catched_typerror=false + try + realplan * complexvec + catch e; + println(e,"\n") + catched_typerror = true + end + @test catched_typerror + end From 0c53ddbede29e50b453ae2bc87fe6392b9eb915f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Fuhrmann?= Date: Sat, 18 Jul 2026 15:34:00 +0200 Subject: [PATCH 3/8] in-place instead of inline in runtests Co-authored-by: Steven G. Johnson --- test/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index 70947d3..6f6370d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -588,7 +588,7 @@ end end -@testset "Ensure inline version throws with wrong type" begin +@testset "Ensure in-place version throws with wrong type" begin complexplan = plan_fft!(zeros(ComplexF64, 4)) realvec = [1,1,1,1] From 08cb2c330bc4022c228ebf9fbaf8bfb810a986be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Fuhrmann?= Date: Sat, 18 Jul 2026 15:46:42 +0200 Subject: [PATCH 4/8] Replace reinvented wheel by @test_throws in runtests.jl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Mosè Giordano <765740+giordano@users.noreply.github.com> --- test/runtests.jl | 38 ++++---------------------------------- 1 file changed, 4 insertions(+), 34 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 6f6370d..f40b9ad 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -592,42 +592,12 @@ end complexplan = plan_fft!(zeros(ComplexF64, 4)) realvec = [1,1,1,1] - catched_typerror=false - try - FFTW.mul!(realvec, complexplan, realvec) - catch e; - println(e,"\n") - catched_typerror = true - end - @test catched_typerror - - catched_typerror=false - try - complexplan * realvec - catch e; - println(e,"\n") - catched_typerror = true - end - @test catched_typerror + @test_throws MethodError FFTW.mul!(realvec, complexplan, realvec) + @test_throws MethodError complexplan * realvec complexvec=ones(ComplexF64,4) realplan = FFTW.plan_r2r!(zeros(4), FFTW.REDFT10) - catched_typerror=false - try - FFTW.mul!(complexvec, realplan, complexvec) - catch e; - println(e,"\n") - catched_typerror = true - end - @test catched_typerror - - catched_typerror=false - try - realplan * complexvec - catch e; - println(e,"\n") - catched_typerror = true - end - @test catched_typerror + @test_throws MethodError FFTW.mul!(complexvec, realplan, complexvec) + @test_throws MethodError realplan * complexvec end From c93596e9d9e85ec6498072620fc9e1bb0928b025 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Fuhrmann?= Date: Sun, 19 Jul 2026 11:04:00 +0200 Subject: [PATCH 5/8] Let inplace_plan*wrongtypedvector throw ArgumentError --- src/fft.jl | 10 ++++++++++ test/runtests.jl | 4 ++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/fft.jl b/src/fft.jl index 828b462..4d13f96 100644 --- a/src/fft.jl +++ b/src/fft.jl @@ -503,6 +503,16 @@ function assert_applicable(p::FFTWPlan{T,K,inplace}, X::StridedArray{T}, Y::Stri end end + +function assert_applicable(p::FFTWPlan{T}, X::AbstractArray) where T + throw(ArgumentError("In-place plan FFTWPlan{$(T)} cannot be applied to a $(typeof(X))")) +end + +function assert_applicable(p::FFTWPlan{T}, X::AbstractArray, Y::AbstractArray) where T + throw(ArgumentError("In-place plan FFTWPlan{$(T)} cannot be applied to a $(typeof(X))")) +end + + # strides for a column-major (Julia-style) array of size == sz colmajorstrides(::Tuple{}) = () colmajorstrides(sz) = _colmajorstrides(1, sz...) diff --git a/test/runtests.jl b/test/runtests.jl index f40b9ad..7aca113 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -593,11 +593,11 @@ end realvec = [1,1,1,1] @test_throws MethodError FFTW.mul!(realvec, complexplan, realvec) - @test_throws MethodError complexplan * realvec + @test_throws ArgumentError complexplan * realvec complexvec=ones(ComplexF64,4) realplan = FFTW.plan_r2r!(zeros(4), FFTW.REDFT10) @test_throws MethodError FFTW.mul!(complexvec, realplan, complexvec) - @test_throws MethodError realplan * complexvec + @test_throws ArgumentError realplan * complexvec end From 9d260c8f2e3d65406cd33cae6662fde4beb6d17a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Fuhrmann?= Date: Sun, 19 Jul 2026 11:15:53 +0200 Subject: [PATCH 6/8] Add method for mul! which throws ArgumentError if applied to wrong types --- src/fft.jl | 8 ++++++++ test/runtests.jl | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/fft.jl b/src/fft.jl index 4d13f96..6bee52d 100644 --- a/src/fft.jl +++ b/src/fft.jl @@ -829,6 +829,10 @@ for (f,direction) in ((:fft,FORWARD), (:bfft,BACKWARD)) end end +function mul!(y::AbstractArray, p::cFFTWPlan{T}, x::AbstractArray) where T + throw(ArgumentError("mul!(x,::cFFTWPlan{$(T)},y) expects x and y be of type StridedArray{$(T)}")) +end + function mul!(y::StridedArray{T}, p::cFFTWPlan{T}, x::StridedArray{T}) where T assert_applicable(p, x, y) unsafe_execute!(p, x, y) @@ -1049,6 +1053,10 @@ function mul!(y::StridedArray{T}, p::r2rFFTWPlan{T}, x::StridedArray{T}) where T return y end +function mul!(y::AbstractArray, p::r2rFFTWPlan{T}, x::AbstractArray) where T + throw(ArgumentError("mul!(x,::r2rFFTWPlan{$(T)},y) expects x and y be of type StridedArray{$(T)}")) +end + function *(p::r2rFFTWPlan{T,K,false}, x::StridedArray{T,N}) where {T,K,N} assert_applicable(p, x) y = Array{T}(undef, p.osz)::Array{T,N} diff --git a/test/runtests.jl b/test/runtests.jl index 7aca113..84a2732 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -592,12 +592,12 @@ end complexplan = plan_fft!(zeros(ComplexF64, 4)) realvec = [1,1,1,1] - @test_throws MethodError FFTW.mul!(realvec, complexplan, realvec) + @test_throws ArgumentError FFTW.mul!(realvec, complexplan, realvec) @test_throws ArgumentError complexplan * realvec complexvec=ones(ComplexF64,4) realplan = FFTW.plan_r2r!(zeros(4), FFTW.REDFT10) - @test_throws MethodError FFTW.mul!(complexvec, realplan, complexvec) + @test_throws ArgumentError FFTW.mul!(complexvec, realplan, complexvec) @test_throws ArgumentError realplan * complexvec end From cb25120265ce20c70216aa0e63d052a0b519a137 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Fuhrmann?= Date: Mon, 20 Jul 2026 12:33:48 +0200 Subject: [PATCH 7/8] Explicitely dispatch on inplace in assert_applicable --- src/fft.jl | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/fft.jl b/src/fft.jl index 6bee52d..6246fd7 100644 --- a/src/fft.jl +++ b/src/fft.jl @@ -504,12 +504,16 @@ function assert_applicable(p::FFTWPlan{T,K,inplace}, X::StridedArray{T}, Y::Stri end -function assert_applicable(p::FFTWPlan{T}, X::AbstractArray) where T - throw(ArgumentError("In-place plan FFTWPlan{$(T)} cannot be applied to a $(typeof(X))")) +function assert_applicable(p::FFTWPlan{T,K, inplace}, X::AbstractArray) where {T,K, inplace} + if inplace + throw(ArgumentError("In-place plan FFTWPlan{$(T)} cannot be applied to a $(typeof(X))")) + end end -function assert_applicable(p::FFTWPlan{T}, X::AbstractArray, Y::AbstractArray) where T - throw(ArgumentError("In-place plan FFTWPlan{$(T)} cannot be applied to a $(typeof(X))")) +function assert_applicable(p::FFTWPlan{T, K, inplace}, X::AbstractArray, Y::AbstractArray) where {T,K, inplace} + if inplace + throw(ArgumentError("In-place plan FFTWPlan{$(T)} cannot be applied to a $(typeof(X))")) + end end From 35365011795ab108727cb7ba82dde4c82573d7ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Fuhrmann?= Date: Fri, 24 Jul 2026 16:41:56 +0200 Subject: [PATCH 8/8] Remove extra mul! methods introduced just for throwing ArgumentError instead of MethodError --- src/fft.jl | 8 -------- test/runtests.jl | 4 ++-- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/fft.jl b/src/fft.jl index 6246fd7..6c54d56 100644 --- a/src/fft.jl +++ b/src/fft.jl @@ -833,10 +833,6 @@ for (f,direction) in ((:fft,FORWARD), (:bfft,BACKWARD)) end end -function mul!(y::AbstractArray, p::cFFTWPlan{T}, x::AbstractArray) where T - throw(ArgumentError("mul!(x,::cFFTWPlan{$(T)},y) expects x and y be of type StridedArray{$(T)}")) -end - function mul!(y::StridedArray{T}, p::cFFTWPlan{T}, x::StridedArray{T}) where T assert_applicable(p, x, y) unsafe_execute!(p, x, y) @@ -1057,10 +1053,6 @@ function mul!(y::StridedArray{T}, p::r2rFFTWPlan{T}, x::StridedArray{T}) where T return y end -function mul!(y::AbstractArray, p::r2rFFTWPlan{T}, x::AbstractArray) where T - throw(ArgumentError("mul!(x,::r2rFFTWPlan{$(T)},y) expects x and y be of type StridedArray{$(T)}")) -end - function *(p::r2rFFTWPlan{T,K,false}, x::StridedArray{T,N}) where {T,K,N} assert_applicable(p, x) y = Array{T}(undef, p.osz)::Array{T,N} diff --git a/test/runtests.jl b/test/runtests.jl index 84a2732..7aca113 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -592,12 +592,12 @@ end complexplan = plan_fft!(zeros(ComplexF64, 4)) realvec = [1,1,1,1] - @test_throws ArgumentError FFTW.mul!(realvec, complexplan, realvec) + @test_throws MethodError FFTW.mul!(realvec, complexplan, realvec) @test_throws ArgumentError complexplan * realvec complexvec=ones(ComplexF64,4) realplan = FFTW.plan_r2r!(zeros(4), FFTW.REDFT10) - @test_throws ArgumentError FFTW.mul!(complexvec, realplan, complexvec) + @test_throws MethodError FFTW.mul!(complexvec, realplan, complexvec) @test_throws ArgumentError realplan * complexvec end