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]
Test()
Why is that?
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]
Test()
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(),)
(nothing,)
julia> a[1]
julia> a[2]
julia> a[3]
but
julia> struct Zs; x::Int end
julia> a = (Zs(2),)
(Zs(2),)
julia> a[4]
ERROR: BoundsError: attempt to access (Zs(2),)
at index [4]
Stacktrace:
[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)
(CodeInfo(
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.