From 0ee4de60df5194b380f847a1b747a591c713f077 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Jul 2026 23:47:49 +0000 Subject: [PATCH 1/5] Update JET requirement from 0.9, 0.10, 0.11 to 0.9, 0.10, 0.11, 0.12 Updates the requirements on [JET](https://github.com/aviatesk/JET.jl) to permit the latest version. Updates `JET` to 0.12.0 - [Release notes](https://github.com/aviatesk/JET.jl/releases) - [Changelog](https://github.com/aviatesk/JET.jl/blob/master/CHANGELOG.md) - [Commits](https://github.com/aviatesk/JET.jl/commits/v0.12.0) --- updated-dependencies: - dependency-name: JET dependency-version: 0.12.0 dependency-type: direct:production dependency-group: all-julia-packages ... Signed-off-by: dependabot[bot] --- test/Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Project.toml b/test/Project.toml index ca00312e2..6f58bb3b2 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -38,7 +38,7 @@ AllocCheck = "0.2" ChainRulesTestUtils = "1" Combinatorics = "1" cuTENSOR = "6" -JET = "0.9, 0.10, 0.11" +JET = "0.9, 0.10, 0.11, 0.12" ParallelTestRunner = "2" Test = "1" TestExtras = "0.2,0.3" From 3b858e6052b4dd06e9ca22e8adbbdf92fe1d6d72 Mon Sep 17 00:00:00 2001 From: lkdvos Date: Wed, 26 Aug 2026 06:15:30 -0400 Subject: [PATCH 2/5] use new JET functionality for skipping tests --- test/Project.toml | 3 ++- test/README.md | 20 ++++++++++++++------ test/mooncake/tangent.jl | 6 +++++- test/other/jet.jl | 10 ++++++++++ test/runtests.jl | 11 +++++++++++ 5 files changed, 42 insertions(+), 8 deletions(-) create mode 100644 test/other/jet.jl diff --git a/test/Project.toml b/test/Project.toml index 6f58bb3b2..3150a90c2 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -38,7 +38,8 @@ AllocCheck = "0.2" ChainRulesTestUtils = "1" Combinatorics = "1" cuTENSOR = "6" -JET = "0.9, 0.10, 0.11, 0.12" +JET = "0.9, 0.12" +Mooncake = "0.5.45" ParallelTestRunner = "2" Test = "1" TestExtras = "0.2,0.3" diff --git a/test/README.md b/test/README.md index d978612f6..2dfee0c38 100644 --- a/test/README.md +++ b/test/README.md @@ -1,8 +1,8 @@ # TensorKit.jl test suite -Tests use [ParallelTestRunner.jl](https://github.com/vchuravy/ParallelTestRunner.jl) for parallel -execution. Each test file runs in its own worker process. Shared helpers are loaded automatically -via `init_code` — test files do not need to include `setup.jl` themselves. +Tests use [ParallelTestRunner.jl](https://github.com/vchuravy/ParallelTestRunner.jl) for parallel execution. +Each test file runs in its own worker process. +Shared helpers are loaded automatically via `init_code` — test files do not need to include `setup.jl` themselves. ## Running tests @@ -37,17 +37,25 @@ julia --project=test test/runtests.jl --jobs=4 |-------|----------| | `symmetries` | Spaces and fusion trees | | `tensors` | Core tensor operations, factorizations, planar tensors, diagonal tensors | -| `other` | Aqua code-quality checks, bug-fix regressions | +| `other` | Aqua code-quality checks, JET static analysis, bug-fix regressions | | `chainrules` | ChainRulesCore AD tests | | `mooncake` | Mooncake AD tests | | `cuda` | CUDA GPU tests (only run when a functional GPU is present) | +JET only functions on the Julia versions it supports, which it reports through `JET.JET_AVAILABLE`. +`runtests.jl` drops the JET-dependent files from the testsuite when that is `false`: +`other/jet` (whole-package analysis, which additionally requires the JET 0.12 generation) +and `mooncake/tangent` (reaches JET through Mooncake's extension). + +Mooncake caps which JET versions it accepts, so the `Mooncake = "0.5.45"` floor in +`test/Project.toml` is what lets JET 0.12 be resolved at all — with an older Mooncake the +resolver settles on JET 0.11 and `other/jet` is silently dropped. + ## Fast mode (`--fast`) Skips `chainrules` and `mooncake` groups entirely, and reduces coverage in the remaining tests: -- **Sector types**: tests only `Z2Irrep`, `SU2Irrep`, `FermionParity ⊠ U1Irrep ⊠ SU2Irrep`, - and `FibonacciAnyon` (instead of the full `sectorlist`) +- **Sector types**: tests only `Z2Irrep`, `SU2Irrep`, `FermionParity ⊠ U1Irrep ⊠ SU2Irrep`, and `FibonacciAnyon` (instead of the full `sectorlist`) - **Space lists**: tests only `(Vtr, Vℤ₂, VSU₂)` (trivial, abelian, non-abelian) - **Scalar types**: tests only `Float64` and `ComplexF64` (instead of all integer/float variants) diff --git a/test/mooncake/tangent.jl b/test/mooncake/tangent.jl index 7b7c9ab4d..3c0c14fd2 100644 --- a/test/mooncake/tangent.jl +++ b/test/mooncake/tangent.jl @@ -10,8 +10,12 @@ rng = Random.default_rng() spacelist = ad_spacelist(fast_tests) eltypes = (Float64, ComplexF64) +# `test_data` reaches JET through Mooncake's extension, so it needs a functional JET; this is also +# gated in runtests.jl. JET < 0.12 does not define `JET_AVAILABLE`. +jet_available = !isdefined(JET, :JET_AVAILABLE) || JET.JET_AVAILABLE + # only run on Linux since allocation tests are broken on other versions -Sys.islinux() && @timedtestset "Mooncake - Tangent type: $(TensorKit.type_repr(sectortype(eltype(V)))) ($T)" for V in spacelist, T in eltypes +jet_available && Sys.islinux() && @timedtestset "Mooncake - Tangent type: $(TensorKit.type_repr(sectortype(eltype(V)))) ($T)" for V in spacelist, T in eltypes A = randn(T, V[1] ⊗ V[2] ⊗ V[3] ← (V[4] ⊗ V[5])') Mooncake.TestUtils.test_data(rng, A) diff --git a/test/other/jet.jl b/test/other/jet.jl new file mode 100644 index 000000000..412603a65 --- /dev/null +++ b/test/other/jet.jl @@ -0,0 +1,10 @@ +using TensorKit +using Test +using JET + +# also gated in runtests.jl; JET < 0.12 does not define `JET_AVAILABLE` +if isdefined(JET, :JET_AVAILABLE) && JET.JET_AVAILABLE + JET.test_package(TensorKit; target_modules = (TensorKit,)) +else + @info "Full JET functionality is unavailable on Julia $VERSION; skipping JET analysis" +end diff --git a/test/runtests.jl b/test/runtests.jl index 7e76a60e7..df8b70a30 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -13,6 +13,17 @@ CUDA.functional() || filter!(!startswith("cuda") ∘ first, testsuite) using AMDGPU AMDGPU.functional() || filter!(!startswith("amd") ∘ first, testsuite) +# JET tests: JET ≥ 0.12 (Julia 1.12+) signals through `JET_AVAILABLE` whether it is functional, +# and loads empty stubs when it is not. Older JET versions, still needed on Julia < 1.12, do not +# define it, hence the `isdefined` check instead of `using JET: JET_AVAILABLE`. +using JET: JET +const jet_new_generation = isdefined(JET, :JET_AVAILABLE) +const jet_available = !jet_new_generation || JET.JET_AVAILABLE +# whole-package analysis is pinned to the JET 0.12 generation, so its reports need not be curated for several JET/Julia combinations +(jet_new_generation && jet_available) || delete!(testsuite, "other/jet") +# Mooncake's tangent tests reach JET through Mooncake's extension: any functional JET works, the empty stubs do not +jet_available || delete!(testsuite, "mooncake/tangent") + # On Buildkite (GPU CI runner): only run CUDA and AMDGPU tests if get(ENV, "BUILDKITE", "false") == "true" f(str) = startswith(first(str), "cuda") || startswith(first(str), "amd") From 13e108e67c7f5ecef57042719da7547cb950b78c Mon Sep 17 00:00:00 2001 From: lkdvos Date: Wed, 26 Aug 2026 06:15:51 -0400 Subject: [PATCH 3/5] fix errors uncovered by JET --- src/planar/macros.jl | 2 +- src/planar/preprocessors.jl | 2 +- src/tensors/abstracttensor.jl | 8 ++++---- src/tensors/linalg.jl | 2 +- src/tensors/tensor.jl | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/planar/macros.jl b/src/planar/macros.jl index 16f7f1c0a..0568319a5 100644 --- a/src/planar/macros.jl +++ b/src/planar/macros.jl @@ -51,7 +51,7 @@ function planarparser(planarexpr, kwargs...) if name == :order isexpr(val, :tuple) || throw(ArgumentError("Invalid use of `order`, should be `order=(...,)`")) - indexorder = map(normalizeindex, val.args) + indexorder = map(TO.normalizeindex, val.args) parser.contractiontreebuilder = network -> TO.indexordertree( network, indexorder ) diff --git a/src/planar/preprocessors.jl b/src/planar/preprocessors.jl index e6b67eb64..f7bdc673c 100644 --- a/src/planar/preprocessors.jl +++ b/src/planar/preprocessors.jl @@ -591,7 +591,7 @@ function _extract_contraction_pairs(rhs, lhs, pre, temporaries) newarg = _extract_contraction_pairs(rhs.args[3], lhs, pre, temporaries) return Expr(:call, :\, rhs.args[2], newarg) else - throw(ArgumentError("unknown tensor expression $ex")) + throw(ArgumentError("unknown tensor expression $rhs")) end end diff --git a/src/tensors/abstracttensor.jl b/src/tensors/abstracttensor.jl index f3b6fa18a..38b558469 100644 --- a/src/tensors/abstracttensor.jl +++ b/src/tensors/abstracttensor.jl @@ -496,8 +496,8 @@ $_doc_subblock As a result, modifying the view will modify the data in the tensor. See also [`subblock`](@ref), [`subblocks`](@ref) and [`fusiontrees`](@ref). -""" Base.getindex(::AbstractTensorMap, ::Tuple{I, Vararg{I}}) where {I <: Sector}, - Base.getindex(::AbstractTensorMap, ::FusionTree, ::FusionTree) +""" Base.getindex(t::AbstractTensorMap, sectors::Tuple{I, Vararg{I}}) where {I <: Sector}, + Base.getindex(t::AbstractTensorMap, f₁::FusionTree, f₂::FusionTree) @inline Base.getindex(t::AbstractTensorMap, sectors::Tuple{I, Vararg{I}}) where {I <: Sector} = subblock(t, sectors) @@ -514,8 +514,8 @@ Copies `v` into the data slice of `t` corresponding to the splitting - fusion tr By default, `v` can be any object that can be copied into the view associated with `t[f₁, f₂]`. See also [`subblock`](@ref), [`subblocks`](@ref) and [`fusiontrees`](@ref). -""" Base.setindex!(::AbstractTensorMap, ::Any, ::Tuple{I, Vararg{I}}) where {I <: Sector}, - Base.setindex!(::AbstractTensorMap, ::Any, ::FusionTree, ::FusionTree) +""" Base.setindex!(t::AbstractTensorMap, v, sectors::Tuple{I, Vararg{I}}) where {I <: Sector}, + Base.setindex!(t::AbstractTensorMap, v, f₁::FusionTree, f₂::FusionTree) @inline Base.setindex!(t::AbstractTensorMap, v, sectors::Tuple{I, Vararg{I}}) where {I <: Sector} = copy!(subblock(t, sectors), v) diff --git a/src/tensors/linalg.jl b/src/tensors/linalg.jl index 4c885a6ed..2bc42cc8a 100644 --- a/src/tensors/linalg.jl +++ b/src/tensors/linalg.jl @@ -575,7 +575,7 @@ tdst[sub_axes...] .= tsrc[sub_axes...] absorb(tdst::AbstractTensorMap, tsrc::AbstractTensorMap) = absorb!(copy(tdst), tsrc) function absorb!(tdst::AbstractTensorMap, tsrc::AbstractTensorMap) numin(tdst) == numin(tsrc) && numout(tdst) == numout(tsrc) || - throw(DimensionError("Incompatible number of indices for source and destination")) + throw(IndexError("Incompatible number of indices for source and destination")) S = check_spacetype(tdst, tsrc) dom = mapreduce(infimum, ⊗, domain(tdst), domain(tsrc); init = one(S)) cod = mapreduce(infimum, ⊗, codomain(tdst), codomain(tsrc); init = one(S)) diff --git a/src/tensors/tensor.jl b/src/tensors/tensor.jl index ed5682367..e7255e119 100644 --- a/src/tensors/tensor.jl +++ b/src/tensors/tensor.jl @@ -393,7 +393,7 @@ for randf in (:rand, :randn, :randexp, :randisometry) function $randfun( rng::Random.AbstractRNG, ::Type{TorA}, codomain::TensorSpace ) where {TorA} - return $randfun(rng, TorA, codomain ← one(domain)) + return $randfun(rng, TorA, codomain ← one(codomain)) end # filling in default eltype From 5fa5947df1f4ecb5ce8dfbd119bb9f817e935b23 Mon Sep 17 00:00:00 2001 From: lkdvos Date: Wed, 26 Aug 2026 09:16:04 -0400 Subject: [PATCH 4/5] make JET happy --- src/auxiliary/caches.jl | 22 ++++++++++------------ src/fusiontrees/duality_manipulations.jl | 2 +- src/planar/preprocessors.jl | 8 ++------ src/tensors/tensoroperations.jl | 10 ++++++++-- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/auxiliary/caches.jl b/src/auxiliary/caches.jl index 4c5db4652..20238fbf8 100644 --- a/src/auxiliary/caches.jl +++ b/src/auxiliary/caches.jl @@ -53,18 +53,16 @@ macro cached(ex) error("cached macro can only be used on function definitions") fcall = ex.args[1] if Meta.isexpr(fcall, :where) - hasparams = true params = fcall.args[2:end] fcall = fcall.args[1] else - hasparams = false + params = nothing end if Meta.isexpr(fcall, :(::)) - typed = true typeex = fcall.args[2] fcall = fcall.args[1] else - typed = false + typeex = nothing end Meta.isexpr(fcall, :call) || error("cached macro can only be used on function definitions") @@ -82,14 +80,14 @@ macro cached(ex) # actual implenetation, with underscore name _fname = Symbol(:_, fname) _fcall = Expr(:call, _fname, fargs...) - if hasparams + if !isnothing(params) _fcall = Expr(:where, _fcall, params...) end _fex = Expr(:function, _fcall, _fbody) # implementation that chooses the cache style newfcall = fcall - if hasparams + if !isnothing(params) newfcall = Expr(:where, newfcall, params...) end cachestylevar = gensym(:cachestyle) @@ -103,11 +101,11 @@ macro cached(ex) # nocache implementation fnocachecall = Expr(:call, fname, fargs..., :(::NoCache)) - if hasparams + if !isnothing(params) fnocachecall = Expr(:where, fnocachecall, params...) end fnocachebody = Expr(:call, _fname, fargnames...) - if typed + if !isnothing(typeex) T = gensym(:T) fnocachebody = Expr(:block, Expr(:(=), T, typeex), Expr(:(::), fnocachebody, T)) end @@ -116,7 +114,7 @@ macro cached(ex) # tasklocal cache implementation Dvar = gensym(:D) flocalcachecall = Expr(:call, fname, fargs..., :(::TaskLocalCache{$Dvar})) - if hasparams + if !isnothing(params) flocalcachecall = Expr(:where, flocalcachecall, params..., Dvar) else flocalcachecall = Expr(:where, flocalcachecall, Dvar) @@ -139,7 +137,7 @@ macro cached(ex) return $_fname($(fargnames...)) end ) - if typed + if !isnothing(typeex) T = gensym(:T) flocalcachebody = Expr( :block, @@ -160,12 +158,12 @@ macro cached(ex) # # global cache implementation fglobalcachecall = Expr(:call, fname, fargs..., :(::GlobalLRUCache)) - if hasparams + if !isnothing(params) fglobalcachecall = Expr(:where, fglobalcachecall, params...) end globalcachename = Symbol(:GLOBAL_, uppercase(string(fname)), :_CACHE) getglobalcachex = Expr(:(=), cachevar, globalcachename) - if typed + if !isnothing(typeex) T = gensym(:T) fglobalcachebody = Expr( :block, diff --git a/src/fusiontrees/duality_manipulations.jl b/src/fusiontrees/duality_manipulations.jl index 4187868ad..4b64d5f90 100644 --- a/src/fusiontrees/duality_manipulations.jl +++ b/src/fusiontrees/duality_manipulations.jl @@ -653,7 +653,7 @@ function planar_trace(f::FusionTree, (q₁, q₂)::Index2Tuple) # We thus handle the total trace recursively, by first looking for and # tracing away neighbouring pairs. k = 1 - local i, j + i = j = 0 while k <= length(q₁) if mod1(q₁[k] + 1, length(f)) == q₂[k] i = q₁[k] diff --git a/src/planar/preprocessors.jl b/src/planar/preprocessors.jl index f7bdc673c..a43af2b75 100644 --- a/src/planar/preprocessors.jl +++ b/src/planar/preprocessors.jl @@ -166,22 +166,18 @@ function _construct_braidingtensors!(ex, preargs, indexmap, non_braiding) # ex i i1a, i2a, = rightind end - foundV1, foundV2 = false, false + V1 = V2 = nothing if haskey(indexmap, i1a) V1 = indexmap[i1a] - foundV1 = true elseif haskey(indexmap, i1b) V1 = Expr(:call, :dual, indexmap[i1b]) - foundV1 = true end if haskey(indexmap, i2a) V2 = indexmap[i2a] - foundV2 = true elseif haskey(indexmap, i2b) V2 = Expr(:call, :dual, indexmap[i2b]) - foundV2 = true end - if foundV1 && foundV2 + if !isnothing(V1) && !isnothing(V2) s = gensym(:τ) storageex = Expr(:call, GlobalRef(TensorKit, :promote_storagetype), non_braiding...) braidingex = Expr(:call, GlobalRef(TensorKit, :braidingtensortype), V1, V2, storageex) diff --git a/src/tensors/tensoroperations.jl b/src/tensors/tensoroperations.jl index 147d27b16..0c1742ff6 100644 --- a/src/tensors/tensoroperations.jl +++ b/src/tensors/tensoroperations.jl @@ -243,7 +243,10 @@ function trace_permute!( return tdst end -function _trace_permute!(::UniqueFusion, tdst, tsrc, (p₁, p₂), (q₁, q₂), α, β, backend) +function _trace_permute!( + ::UniqueFusion, tdst::AbstractTensorMap, tsrc::AbstractTensorMap, + (p₁, p₂), (q₁, q₂), α, β, backend + ) scale!(tdst, β) r₁, r₂ = (p₁..., q₁...), (p₂..., q₂...) N₁, N₂ = length(p₁), length(p₂) @@ -268,7 +271,10 @@ function _trace_permute!(::UniqueFusion, tdst, tsrc, (p₁, p₂), (q₁, q₂), return tdst end -function _trace_permute!(::FusionStyle, tdst, tsrc, (p₁, p₂), (q₁, q₂), α, β, backend) +function _trace_permute!( + ::FusionStyle, tdst::AbstractTensorMap, tsrc::AbstractTensorMap, + (p₁, p₂), (q₁, q₂), α, β, backend + ) scale!(tdst, β) r₁, r₂ = (p₁..., q₁...), (p₂..., q₂...) N₁, N₂ = length(p₁), length(p₂) From e40d1dad3414383abf47b726bcf54b80b05f50cb Mon Sep 17 00:00:00 2001 From: lkdvos Date: Wed, 26 Aug 2026 12:01:56 -0400 Subject: [PATCH 5/5] more JET happiness --- src/auxiliary/iterators.jl | 2 +- src/fusiontrees/fusiontrees.jl | 3 +-- src/pullbacks/tensoroperations.jl | 6 +++--- src/spaces/productspace.jl | 2 +- src/tensors/abstracttensor.jl | 9 +++++++-- src/tensors/adjoint.jl | 1 + test/other/jet.jl | 16 +++++++++++++++- 7 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/auxiliary/iterators.jl b/src/auxiliary/iterators.jl index 211c0dd93..6a4be06b7 100644 --- a/src/auxiliary/iterators.jl +++ b/src/auxiliary/iterators.jl @@ -4,7 +4,7 @@ struct OneOrNoneIterator{T} end function Base.iterate(it::OneOrNoneIterator, state = true) - if state && it.cond + if isone(state) && it.cond return (it.first, false) else return nothing diff --git a/src/fusiontrees/fusiontrees.jl b/src/fusiontrees/fusiontrees.jl index 13710ee5b..b95964462 100644 --- a/src/fusiontrees/fusiontrees.jl +++ b/src/fusiontrees/fusiontrees.jl @@ -334,8 +334,7 @@ function fusiontensor((f₁, f₂)::FusionTreePair) d1 = TupleTools.front(sz1) d2 = TupleTools.front(sz2) return reshape( - reshape(F₁, TupleTools.prod(d1), sz1[end]) * - reshape(F₂, TupleTools.prod(d2), sz2[end])', (d1..., d2...) + reshape(F₁, :, sz1[end]) * reshape(F₂, :, sz2[end])', (d1..., d2...) ) end fusiontensor(src::FusionTreeBlock) = sum(fusiontensor, fusiontrees(src)) diff --git a/src/pullbacks/tensoroperations.jl b/src/pullbacks/tensoroperations.jl index 64507861f..f9ebe0248 100644 --- a/src/pullbacks/tensoroperations.jl +++ b/src/pullbacks/tensoroperations.jl @@ -1,5 +1,5 @@ function blas_contract_pullback_ΔA!( - ΔA, ΔC, A, pA, B, pB, pAB, α, backend, allocator + ΔA, ΔC, A::AbstractTensorMap, pA, B::AbstractTensorMap, pB, pAB, α, backend, allocator ) ipAB = invperm(linearize(pAB)) pΔC = TO.repartition(ipAB, TO.numout(pA)) @@ -23,7 +23,7 @@ function blas_contract_pullback_ΔA!( end function blas_contract_pullback_ΔB!( - ΔB, ΔC, A, pA, B, pB, pAB, α, backend, allocator + ΔB, ΔC, A::AbstractTensorMap, pA, B::AbstractTensorMap, pB, pAB, α, backend, allocator ) ipAB = invperm(linearize(pAB)) pΔC = TO.repartition(ipAB, TO.numout(pA)) @@ -48,7 +48,7 @@ function blas_contract_pullback_ΔB!( end function trace_permute_pullback_ΔA!( - ΔA, ΔC, A, p, q, α, backend + ΔA, ΔC, A::AbstractTensorMap, p, q, α, backend ) ip = invperm((linearize(p)..., q[1]..., q[2]...)) pdA = TO.repartition(ip, numout(A)) diff --git a/src/spaces/productspace.jl b/src/spaces/productspace.jl index 1c4b790e4..d058c6f79 100644 --- a/src/spaces/productspace.jl +++ b/src/spaces/productspace.jl @@ -146,7 +146,7 @@ that make up the `ProductSpace` instance. """ function blocksectors(P::ProductSpace{S, N}) where {S, N} I = sectortype(S) - if I == Trivial + if I === Trivial return OneOrNoneIterator(dim(P) != 0, Trivial()) end bs = Vector{I}() diff --git a/src/tensors/abstracttensor.jl b/src/tensors/abstracttensor.jl index 38b558469..27c4a5451 100644 --- a/src/tensors/abstracttensor.jl +++ b/src/tensors/abstracttensor.jl @@ -237,7 +237,11 @@ See also [`numin`](@ref) and [`numind`](@ref). """ numout numout(x) = numout(typeof(x)) -numout(T::Type) = throw(MethodError(numout, T)) # avoid infinite recursion +numout(T::Type) = throw(MethodError(numout, (T,))) # avoid infinite recursion +# `typeintersect(Type{<:AbstractTensorMap}, Type{<:Union{FusionTreePair, FusionTreeBlock}})` is +# `Type{Union{}}`, which leaves the parametric methods mutually ambiguous. Resolve it explicitly so +# the intended `MethodError` is thrown instead of an ambiguity error. +numout(::Type{Union{}}) = throw(MethodError(numout, (Union{},))) numout(::Type{<:AbstractTensorMap{T, S, N₁}}) where {T, S, N₁} = N₁ @doc """ @@ -251,7 +255,8 @@ See also [`numout`](@ref) and [`numind`](@ref). """ numin numin(x) = numin(typeof(x)) -numin(T::Type) = throw(MethodError(numin, T)) # avoid infinite recursion +numin(T::Type) = throw(MethodError(numin, (T,))) # avoid infinite recursion +numin(::Type{Union{}}) = throw(MethodError(numin, (Union{},))) # see `numout(::Type{Union{}})` numin(::Type{<:AbstractTensorMap{T, S, N₁, N₂}}) where {T, S, N₁, N₂} = N₂ """ diff --git a/src/tensors/adjoint.jl b/src/tensors/adjoint.jl index 820e87375..6aa5810e4 100644 --- a/src/tensors/adjoint.jl +++ b/src/tensors/adjoint.jl @@ -13,6 +13,7 @@ end Base.parent(t::AdjointTensorMap) = t.parent parenttype(t::AdjointTensorMap) = parenttype(typeof(t)) parenttype(::Type{AdjointTensorMap{T, S, N₁, N₂, TT}}) where {T, S, N₁, N₂, TT} = TT +parenttype(::Type{Union{}}) = throw(MethodError(parenttype, (Union{},))) # Constructor: construct from taking adjoint of a tensor Base.adjoint(t::AdjointTensorMap) = parent(t) diff --git a/test/other/jet.jl b/test/other/jet.jl index 412603a65..35ba941a6 100644 --- a/test/other/jet.jl +++ b/test/other/jet.jl @@ -2,9 +2,23 @@ using TensorKit using Test using JET +# Reports that are not TensorKit's to fix. Each entry needs an upstream issue. +const IGNORED = ( + # `schur_full`/`schur_vals` route `Diagonal` inputs to `DiagonalAlgorithm`, which schur does + # not implement, so `schur_full(::DiagonalTensorMap)` throws a `MethodError`. This reproduces + # with a plain `LinearAlgebra.Diagonal` and no TensorKit involved: + # https://github.com/QuantumKitHub/MatrixAlgebraKit.jl/issues/276 + JET.LastFrameMethod(:schur_full!), + JET.LastFrameMethod(:schur_vals!), + # `local variable kwargs may be undefined` inside `GenericTreeTransformer`, coming entirely + # from Base's `@debug` expansion (`local msg, kwargs` bound in a short-circuit guard) rather + # than from any TensorKit code: https://github.com/aviatesk/JET.jl/issues/860 + JET.LastFrameMethod(:GenericTreeTransformer), +) + # also gated in runtests.jl; JET < 0.12 does not define `JET_AVAILABLE` if isdefined(JET, :JET_AVAILABLE) && JET.JET_AVAILABLE - JET.test_package(TensorKit; target_modules = (TensorKit,)) + JET.test_package(TensorKit; target_modules = (TensorKit,), ignored_modules = IGNORED) else @info "Full JET functionality is unavailable on Julia $VERSION; skipping JET analysis" end