Inconsistent bounds-checking of tuples


As expected, (1,)[2] throws an out-of-bounds error:

julia> (1,)[2]
ERROR: BoundsError: attempt to access (1,)
  at index [2]

Doing this, however, does not throw an error:

julia> struct Test end

julia> (Test(),)[2]

Why is that?


That’s incredibly strange. It looks like a bug.

For me it only occurs when types are declared interactively, types from pre-compiled modules behave as expected. The @edit macro isn’t able to find the getindex call when I do this interactively either.


It looks to happen when there is no fields because (Void(),)[2] does not throw on v0.6.3.

julia> a = (Void(),)

julia> a[1]

julia> a[2]

julia> a[3]


julia> struct Zs; x::Int end

julia> a = (Zs(2),)

julia> a[4]
ERROR: BoundsError: attempt to access (Zs(2),)
  at index [4]
 [1] getindex(::Tuple{Zs}, ::Int64) at ./tuple.jl:21


That’s amusing! Also does the same on 0.7; as far as I could gather, whenever you have a homogeneous tuple of singletons like also

julia> ((),())[500]
julia> (((),()),)[100]
((), ())
julia> ((((),),),)[100][100][100]


Yes, this is a bug. Please file an issue.


It looks like Base.getindex(%%x, 2) is incorrectly inferred to Core.Compiler.Const(Test(), false):

julia> struct Test end

julia> g2(x) = x[2];

julia> m = first(methods(g2));

julia> params = Core.Compiler.Params(typemax(UInt));

julia> Core.Compiler.typeinf_code(m, Tuple{Tuple{Test}}, Core.svec(), false, params)
1 1 ─ %1 = Base.getindex(%%x, 2)::Core.Compiler.Const(Test(), false)                                                                                                                                           │
  └──      return %1                                                                                                                                                                                           │
), Test)


That inference is correct. I suspect the problem is that the optimizer later doesn’t recognize that it can’t rely on it without performing the bounds checking.