# Is this \`Test.detect\_unbound\_args\` result valid or a bug?

**URL:** https://discourse.julialang.org/t/is-this-test-detect-unbound-args-result-valid-or-a-bug/96987
**Category:** General Usage
**Tags:** potential-bug
**Created:** [April 2, 2023, 10:08pm UTC](https://discourse.julialang.org/t/is-this-test-detect-unbound-args-result-valid-or-a-bug/96987 "2023-04-02T22:08:18Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)
#### Post date: [April 2, 2023, 10:08pm UTC](https://discourse.julialang.org/t/is-this-test-detect-unbound-args-result-valid-or-a-bug/96987/1 "2023-04-02T22:08:18Z")

</div>

A module:

```julia
module M
  f(::Tuple{}) = nothing
  f(::NTuple{n, F}) where {n, F} = F
end

```

The second method gets flagged as having an unbound argument, even though the first method protects it from ever being called in such a situation:

```julia
julia> detect_unbound_args(M)
[1] f(::Tuple{Vararg{F, n}}) where {n, F} in Main.M at REPL[2]:3

```

Should this be considered a bug? If not, `detect_unbound_args` seems useless, as this seems like a very basic false positive. Hope I’m not misunderstanding Julia 101 or something.

This happens with both Julia nightly and with 1.8.5.

---

<div class="post-metadata">

### Author: ![Elrod](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/elrod/32/22461_2.png) [@Elrod](https://discourse.julialang.org/u/Elrod)
#### Post date: [April 3, 2023, 2:50am UTC](https://discourse.julialang.org/t/is-this-test-detect-unbound-args-result-valid-or-a-bug/96987/2 "2023-04-03T02:50:04Z")

</div>

> [@nsajko](#):
>
> Should this be considered a bug? If not, `detect_unbound_args` seems useless, as this seems like a very basic false positive.

It’s definitely annoying. I don’t even know how to call the second method with an empty tuple using `invoke`.

If you want to avoid it, instead write

```julia
f(::Tuple{F,Vararg{F,nMinus1}}) where {F,nMinus1} = ...

```

I do this. `detect_unbound_args` is useful, but less so now that you get warnings during precompilation.

---

<div class="post-metadata">

### Author: ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)
#### Post date: [April 3, 2023, 3:28am UTC](https://discourse.julialang.org/t/is-this-test-detect-unbound-args-result-valid-or-a-bug/96987/3 "2023-04-03T03:28:20Z")

</div>

Wow, I’ll definitely keep this “tuple type with minimal size” trick in mind.

---

<div class="post-metadata">

### Author: ![spirit-dev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/spirit-dev/32/211651_2.png) [@spirit-dev](https://discourse.julialang.org/u/spirit-dev)
#### Post date: [September 8, 2024, 4:23pm UTC](https://discourse.julialang.org/t/is-this-test-detect-unbound-args-result-valid-or-a-bug/96987/4 "2024-09-08T16:23:31Z")

</div>

Yeah its an issue,

> <https://github.com/JuliaTesting/Aqua.jl/issues/86>
>
> Let's say that I have a module
> \`\`\`julia
> module abcd
> 
> f(::NTuple{N, T}) where… {N,T} = (N,T)
> f(::Tuple{}) = (0,Any)
> 
> end # module
> \`\`\`
> Testing this using Aqua, I obtain
> \`\`\`julia
> Unbound type parameters: Test Failed at /home/jishnu/.julia/packages/Aqua/HWLbM/src/unbound\_args.jl:10
> Expression: detect\_unbound\_args\_recursively(m) == \[\]
> Evaluated: Any\[f(::Tuple{Vararg{T, N}}) where {N, T} in abcd at /home/jishnu/Dropbox/JuliaPackages/abcd/src/abcd.jl:3\] == Any\[\]
> Stacktrace:
> \[1\] macro expansion
> @ ~/packages/julias/julia-1.8/share/julia/stdlib/v1.8/Test/src/Test.jl:464 \[inlined\]
> \[2\] test\_unbound\_args(m::Module)
> @ Aqua ~/.julia/packages/Aqua/HWLbM/src/unbound\_args.jl:10
> \`\`\`
> The issue seems to be with the \`T\` argument, and I think it's because in the \`N=0\` case, \`T\` becomes an unbound argument in the first method. However, this method is not called in the \`N=0\` case because the second method is more specific. Perhaps this should be ignored from the report?
> The function calls are:
> \`\`\`julia
> julia\> abcd.f(())
> (0, Any)
> 
> julia\> abcd.f((1,))
> (1, Int64)
> \`\`\`
> 
> If I'm missing something here, could someone please clarify this?

> <https://github.com/JuliaLang/julia/issues/28086>
>
> EDIT: it's not entirely obvious this is a bug. Below the key comparison is reduc…ed to
> \`\`\`julia
> foo1(::Type{Tuple{R1,Vararg{R1,N}}}) where {N,T1,R1\<:AbstractUnitRange{T1}}
> \`\`\`
> vs
> \`\`\`julia
> foo2(::Type{NTuple{N,R1}}) where {N,T1,R1\<:AbstractUnitRange{T1}}
> \`\`\`
> 
> I think that what this really comes down to is
> \`\`\`julia
> julia\> Tuple{} \<: NTuple{0, T} where T\<:AbstractUnitRange
> true
> \`\`\`
> 
> \#### original post
> 
> \`\`\`julia
> julia\> using Test
> 
> julia\> foo(::Type{NTuple{N,R1}}, ::Type{NTuple{N,R2}}) where {N,R1\<:AbstractUnitRange{T1},R2\<:AbstractUnitRange{T2}} where {T1,T2} =
> NTuple{N,promote\_type(R1,R2)}
> foo (generic function with 1 method)
> 
> julia\> m = first(Base.MethodList(typeof(foo).name.mt))
> foo(::Type{Tuple{Vararg{R1,N}}}, ::Type{Tuple{Vararg{R2,N}}}) where {T1, T2, N, R1\<:AbstractUnitRange{T1}, R2\<:AbstractUnitRange{T2}} in Main at REPL\[2\]:1
> 
> julia\> Test.has\_unbound\_vars(m.sig)
> true
> \`\`\`
> I \*think\* it's fair to say that method definition does not have unbound typevars. I am guessing this is a consequence of \[the loop\](https://github.com/JuliaLang/julia/blob/b0f531e5f0b626f1ee91bb7cac2a0bb660f435f3/stdlib/Test/src/Test.jl#L1468-L1477) dropping old typevars.

its been there for a long time someone should fix it :3
