Skip to content

Commit 58c22b7

Browse files
committed
Deprecate partial linear indexing
1 parent 4045aff commit 58c22b7

9 files changed

+130
-56
lines changed

base/abstractarray.jl

+32-14
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ See also [`checkindex`](@ref).
304304
"""
305305
function checkbounds(::Type{Bool}, A::AbstractArray, I...)
306306
@_inline_meta
307-
checkbounds_indices(Bool, indices(A), I)
307+
checkbounds_indices(Bool, A, indices(A), I)
308308
end
309309
# As a special extension, allow using logical arrays that match the source array exactly
310310
function checkbounds{_,N}(::Type{Bool}, A::AbstractArray{_,N}, I::AbstractArray{Bool,N})
@@ -325,15 +325,15 @@ end
325325
checkbounds(A::AbstractArray) = checkbounds(A, 1) # 0-d case
326326

327327
"""
328-
checkbounds_indices(Bool, IA, I)
328+
checkbounds_indices(Bool, A, IA, I)
329329
330330
Return `true` if the "requested" indices in the tuple `I` fall within
331331
the bounds of the "permitted" indices specified by the tuple
332332
`IA`. This function recursively consumes elements of these tuples,
333333
usually in a 1-for-1 fashion,
334334
335-
checkbounds_indices(Bool, (IA1, IA...), (I1, I...)) = checkindex(Bool, IA1, I1) &
336-
checkbounds_indices(Bool, IA, I)
335+
checkbounds_indices(Bool, A, (IA1, IA...), (I1, I...)) = checkindex(Bool, IA1, I1) &
336+
checkbounds_indices(Bool, A, IA, I)
337337
338338
Note that [`checkindex`](@ref) is being used to perform the actual
339339
bounds-check for a single dimension of the array.
@@ -342,25 +342,43 @@ There are two important exceptions to the 1-1 rule: linear indexing and
342342
CartesianIndex{N}, both of which may "consume" more than one element
343343
of `IA`.
344344
"""
345-
function checkbounds_indices(::Type{Bool}, IA::Tuple, I::Tuple)
345+
function checkbounds_indices(::Type{Bool}, A::AbstractArray, IA::Tuple, I::Tuple)
346346
@_inline_meta
347-
checkindex(Bool, IA[1], I[1]) & checkbounds_indices(Bool, tail(IA), tail(I))
347+
checkindex(Bool, IA[1], I[1]) & checkbounds_indices(Bool, A, tail(IA), tail(I))
348348
end
349-
checkbounds_indices(::Type{Bool}, ::Tuple{}, ::Tuple{}) = true
350-
checkbounds_indices(::Type{Bool}, ::Tuple{}, I::Tuple{Any}) = (@_inline_meta; checkindex(Bool, 1:1, I[1]))
351-
function checkbounds_indices(::Type{Bool}, ::Tuple{}, I::Tuple)
349+
checkbounds_indices(::Type{Bool}, ::AbstractArray, ::Tuple{}, ::Tuple{}) = true
350+
checkbounds_indices(::Type{Bool}, ::AbstractArray, ::Tuple{}, I::Tuple{Any}) = (@_inline_meta; checkindex(Bool, 1:1, I[1]))
351+
function checkbounds_indices(::Type{Bool}, A::AbstractArray, ::Tuple{}, I::Tuple)
352352
@_inline_meta
353-
checkindex(Bool, 1:1, I[1]) & checkbounds_indices(Bool, (), tail(I))
353+
checkindex(Bool, 1:1, I[1]) & checkbounds_indices(Bool, A, (), tail(I))
354354
end
355-
function checkbounds_indices(::Type{Bool}, IA::Tuple{Any}, I::Tuple{Any})
355+
function checkbounds_indices(::Type{Bool}, A::AbstractArray, IA::Tuple{Any}, I::Tuple{Any})
356356
@_inline_meta
357357
checkindex(Bool, IA[1], I[1])
358358
end
359-
function checkbounds_indices(::Type{Bool}, IA::Tuple, I::Tuple{Any})
359+
function checkbounds_indices(::Type{Bool}, A::AbstractArray, IA::Tuple, I::Tuple{Any})
360360
@_inline_meta
361-
checkindex(Bool, OneTo(trailingsize(IA)), I[1]) # linear indexing
361+
checkbounds_linear_indices(Bool, A, IA, I[1])
362362
end
363-
checkbounds_indices(::Type{Bool}, ::Tuple, ::Tuple{}) = true
363+
function checkbounds_linear_indices{T,N}(::Type{Bool}, A::AbstractArray{T,N}, ::NTuple{N}, i)
364+
@_inline_meta
365+
checkindex(Bool, linearindices(A), i) # linear indexing
366+
end
367+
function checkbounds_linear_indices(::Type{Bool}, A::AbstractArray, IA::Tuple, i)
368+
@_inline_meta
369+
if checkindex(Bool, IA[1], i)
370+
return true
371+
elseif checkindex(Bool, OneTo(trailingsize(IA)), i) # partial linear indexing
372+
partial_linear_indexing_warning(ndims(A) - length(IA) + 1)
373+
return true # TODO: Return false after the above function is removed in deprecated.jl
374+
end
375+
return false
376+
end
377+
function checkbounds_linear_indices(::Type{Bool}, A::AbstractArray, IA::Tuple, i::Union{Slice,Colon})
378+
partial_linear_indexing_warning(ndims(A) - length(IA) + 1)
379+
true
380+
end
381+
checkbounds_indices(::Type{Bool}, ::AbstractArray, ::Tuple, ::Tuple{}) = true
364382

365383
throw_boundserror(A, I) = (@_noinline_meta; throw(BoundsError(A, I)))
366384

base/deprecated.jl

+5
Original file line numberDiff line numberDiff line change
@@ -1745,6 +1745,11 @@ end
17451745
export @test_approx_eq
17461746
# END code from base/test.jl
17471747

1748+
# Deprecate partial linear indexing
1749+
function partial_linear_indexing_warning(n)
1750+
depwarn("Partial linear indexing is deprecated. Use `reshape(A, Val{$n})` to make the dimensionality of the array match the number of indices.", (:getindex, :setindex!, :view))
1751+
end
1752+
17481753
# Deprecate Array(T, dims...) in favor of proper type constructors
17491754
@deprecate Array{T,N}(::Type{T}, d::NTuple{N,Int}) Array{T,N}(d)
17501755
@deprecate Array{T}(::Type{T}, d::Int...) Array{T,length(d)}(d...)

base/multidimensional.jl

+16-16
Original file line numberDiff line numberDiff line change
@@ -166,12 +166,12 @@ end # IteratorsMD
166166
using .IteratorsMD
167167

168168
## Bounds-checking with CartesianIndex
169-
@inline checkbounds_indices(::Type{Bool}, ::Tuple{}, I::Tuple{CartesianIndex,Vararg{Any}}) =
170-
checkbounds_indices(Bool, (), (I[1].I..., tail(I)...))
171-
@inline checkbounds_indices(::Type{Bool}, IA::Tuple{Any}, I::Tuple{CartesianIndex,Vararg{Any}}) =
172-
checkbounds_indices(Bool, IA, (I[1].I..., tail(I)...))
173-
@inline checkbounds_indices(::Type{Bool}, IA::Tuple, I::Tuple{CartesianIndex,Vararg{Any}}) =
174-
checkbounds_indices(Bool, IA, (I[1].I..., tail(I)...))
169+
@inline checkbounds_indices(::Type{Bool}, A::AbstractArray, ::Tuple{}, I::Tuple{CartesianIndex,Vararg{Any}}) =
170+
checkbounds_indices(Bool, A, (), (I[1].I..., tail(I)...))
171+
@inline checkbounds_indices(::Type{Bool}, A::AbstractArray, IA::Tuple{Any}, I::Tuple{CartesianIndex,Vararg{Any}}) =
172+
checkbounds_indices(Bool, A, IA, (I[1].I..., tail(I)...))
173+
@inline checkbounds_indices(::Type{Bool}, A::AbstractArray, IA::Tuple, I::Tuple{CartesianIndex,Vararg{Any}}) =
174+
checkbounds_indices(Bool, A, IA, (I[1].I..., tail(I)...))
175175

176176
# Indexing into Array with mixtures of Integers and CartesianIndices is
177177
# extremely performance-sensitive. While the abstract fallbacks support this,
@@ -184,24 +184,24 @@ using .IteratorsMD
184184
# Support indexing with an array of CartesianIndex{N}s
185185
# Here we try to consume N of the indices (if there are that many available)
186186
# The first two simply handle ambiguities
187-
@inline function checkbounds_indices{N}(::Type{Bool}, ::Tuple{}, I::Tuple{AbstractArray{CartesianIndex{N}},Vararg{Any}})
188-
checkindex(Bool, (), I[1]) & checkbounds_indices(Bool, (), tail(I))
187+
@inline function checkbounds_indices{N}(::Type{Bool}, A::AbstractArray, ::Tuple{}, I::Tuple{AbstractArray{CartesianIndex{N}},Vararg{Any}})
188+
checkindex(Bool, A, (), I[1]) & checkbounds_indices(Bool, A, (), tail(I))
189189
end
190-
@inline function checkbounds_indices(::Type{Bool}, IA::Tuple{Any}, I::Tuple{AbstractArray{CartesianIndex{0}},Vararg{Any}})
191-
checkbounds_indices(Bool, IA, tail(I))
190+
@inline function checkbounds_indices(::Type{Bool}, A::AbstractArray, IA::Tuple{Any}, I::Tuple{AbstractArray{CartesianIndex{0}},Vararg{Any}})
191+
checkbounds_indices(Bool, A, IA, tail(I))
192192
end
193-
@inline function checkbounds_indices{N}(::Type{Bool}, IA::Tuple{Any}, I::Tuple{AbstractArray{CartesianIndex{N}},Vararg{Any}})
194-
checkindex(Bool, IA, I[1]) & checkbounds_indices(Bool, (), tail(I))
193+
@inline function checkbounds_indices{N}(::Type{Bool}, A::AbstractArray, IA::Tuple{Any}, I::Tuple{AbstractArray{CartesianIndex{N}},Vararg{Any}})
194+
checkindex(Bool, A, IA, I[1]) & checkbounds_indices(Bool, A, (), tail(I))
195195
end
196-
@inline function checkbounds_indices{N}(::Type{Bool}, IA::Tuple, I::Tuple{AbstractArray{CartesianIndex{N}},Vararg{Any}})
196+
@inline function checkbounds_indices{N}(::Type{Bool}, A::AbstractArray, IA::Tuple, I::Tuple{AbstractArray{CartesianIndex{N}},Vararg{Any}})
197197
IA1, IArest = IteratorsMD.split(IA, Val{N})
198-
checkindex(Bool, IA1, I[1]) & checkbounds_indices(Bool, IArest, tail(I))
198+
checkindex(Bool, A, IA1, I[1]) & checkbounds_indices(Bool, A, IArest, tail(I))
199199
end
200200

201-
function checkindex{N}(::Type{Bool}, inds::Tuple, I::AbstractArray{CartesianIndex{N}})
201+
function checkindex{N}(::Type{Bool}, A::AbstractArray, inds::Tuple, I::AbstractArray{CartesianIndex{N}})
202202
b = true
203203
for i in I
204-
b &= checkbounds_indices(Bool, inds, (i,))
204+
b &= checkbounds_indices(Bool, A, inds, (i,))
205205
end
206206
b
207207
end

src/array.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,7 @@ int jl_array_isdefined(jl_value_t **args0, int nargs)
530530
{
531531
assert(jl_is_array(args0[0]));
532532
jl_depwarn("`isdefined(a::Array, i::Int)` is deprecated, "
533-
"use `isassigned(a, i)` instead", jl_symbol("isdefined"));
533+
"use `isassigned(a, i)` instead", (jl_value_t*)jl_symbol("isdefined"));
534534

535535
jl_array_t *a = (jl_array_t*)args0[0];
536536
jl_value_t **args = &args0[1];

src/builtins.c

+23-3
Original file line numberDiff line numberDiff line change
@@ -1045,7 +1045,7 @@ JL_CALLABLE(jl_f_invoke)
10451045
if (jl_is_tuple(args[1])) {
10461046
jl_depwarn("`invoke(f, (types...), ...)` is deprecated, "
10471047
"use `invoke(f, Tuple{types...}, ...)` instead",
1048-
jl_symbol("invoke"));
1048+
(jl_value_t*)jl_symbol("invoke"));
10491049
argtypes = (jl_value_t*)jl_apply_tuple_type_v((jl_value_t**)jl_data_ptr(argtypes),
10501050
jl_nfields(argtypes));
10511051
}
@@ -1701,7 +1701,7 @@ JL_DLLEXPORT void jl_breakpoint(jl_value_t *v)
17011701
// put a breakpoint in your debugger here
17021702
}
17031703

1704-
void jl_depwarn(const char *msg, jl_sym_t *sym)
1704+
void jl_depwarn(const char *msg, jl_value_t *sym)
17051705
{
17061706
static jl_value_t *depwarn_func = NULL;
17071707
if (!depwarn_func && jl_base_module) {
@@ -1715,11 +1715,31 @@ void jl_depwarn(const char *msg, jl_sym_t *sym)
17151715
JL_GC_PUSHARGS(depwarn_args, 3);
17161716
depwarn_args[0] = depwarn_func;
17171717
depwarn_args[1] = jl_cstr_to_string(msg);
1718-
depwarn_args[2] = (jl_value_t*)sym;
1718+
depwarn_args[2] = sym;
17191719
jl_apply(depwarn_args, 3);
17201720
JL_GC_POP();
17211721
}
17221722

1723+
void jl_depwarn_partial_indexing(size_t n)
1724+
{
1725+
static jl_value_t *depwarn_func = NULL;
1726+
if (!depwarn_func && jl_base_module) {
1727+
depwarn_func = jl_get_global(jl_base_module, jl_symbol("partial_linear_indexing_warning"));
1728+
}
1729+
if (!depwarn_func) {
1730+
jl_safe_printf("WARNING: Partial linear indexing is deprecated. Use "
1731+
"`reshape(A, Val{%zd})` to make the dimensionality of the array match "
1732+
"the number of indices\n", n);
1733+
return;
1734+
}
1735+
jl_value_t **depwarn_args;
1736+
JL_GC_PUSHARGS(depwarn_args, 2);
1737+
depwarn_args[0] = depwarn_func;
1738+
depwarn_args[1] = jl_box_long(n);
1739+
jl_apply(depwarn_args, 2);
1740+
JL_GC_POP();
1741+
}
1742+
17231743
#ifdef __cplusplus
17241744
}
17251745
#endif

src/cgutils.cpp

+24-2
Original file line numberDiff line numberDiff line change
@@ -1352,8 +1352,30 @@ static Value *emit_array_nd_index(const jl_cgval_t &ainfo, jl_value_t *ex, ssize
13521352
if (linear_indexing) {
13531353
// Compare the linearized index `i` against the linearized size of
13541354
// the accessed array, i.e. `if !(i < alen) goto error`.
1355-
Value *alen = emit_arraylen(ainfo, ex, ctx);
1356-
builder.CreateCondBr(builder.CreateICmpULT(i, alen), endBB, failBB);
1355+
if (nidxs > 1) {
1356+
// TODO: REMOVE DEPWARN AND RETURN FALSE AFTER 0.6.
1357+
// We need to check if this is inside the non-linearized size
1358+
BasicBlock *partidx = BasicBlock::Create(jl_LLVMContext, "partlinidx");
1359+
BasicBlock *partidxwarn = BasicBlock::Create(jl_LLVMContext, "partlinidxwarn");
1360+
Value *d = emit_arraysize_for_unsafe_dim(ainfo, ex, nidxs, nd, ctx);
1361+
builder.CreateCondBr(builder.CreateICmpULT(ii, d), endBB, partidx);
1362+
1363+
// We failed the normal bounds check; check to see if we're
1364+
// inside the linearized size (partial linear indexing):
1365+
ctx->f->getBasicBlockList().push_back(partidx);
1366+
builder.SetInsertPoint(partidx);
1367+
Value *alen = emit_arraylen(ainfo, ex, ctx);
1368+
builder.CreateCondBr(builder.CreateICmpULT(i, alen), partidxwarn, failBB);
1369+
1370+
// We passed the linearized bounds check; now throw the depwarn:
1371+
ctx->f->getBasicBlockList().push_back(partidxwarn);
1372+
builder.SetInsertPoint(partidxwarn);
1373+
builder.CreateCall(prepare_call(jldepwarnpi_func), ConstantInt::get(T_size, nidxs));
1374+
builder.CreateBr(endBB);
1375+
} else {
1376+
Value *alen = emit_arraylen(ainfo, ex, ctx);
1377+
builder.CreateCondBr(builder.CreateICmpULT(i, alen), endBB, failBB);
1378+
}
13571379
} else {
13581380
// Compare the last index of the access against the last dimension of
13591381
// the accessed array, i.e. `if !(last_index < last_dimension) goto error`.

src/codegen.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ static Function *expect_func;
389389
static Function *jldlsym_func;
390390
static Function *jlnewbits_func;
391391
static Function *jltypeassert_func;
392+
static Function *jldepwarnpi_func;
392393
#if JL_LLVM_VERSION < 30600
393394
static Function *jlpow_func;
394395
static Function *jlpowf_func;
@@ -5767,6 +5768,13 @@ static void init_julia_llvm_env(Module *m)
57675768
"jl_typeassert", m);
57685769
add_named_global(jltypeassert_func, &jl_typeassert);
57695770

5771+
std::vector<Type*> argsdepwarnpi(0);
5772+
argsdepwarnpi.push_back(T_size);
5773+
jldepwarnpi_func = Function::Create(FunctionType::get(T_void, argsdepwarnpi, false),
5774+
Function::ExternalLinkage,
5775+
"jl_depwarn_partial_indexing", m);
5776+
add_named_global(jldepwarnpi_func, &jl_depwarn_partial_indexing);
5777+
57705778
queuerootfun = Function::Create(FunctionType::get(T_void, args_1ptr, false),
57715779
Function::ExternalLinkage,
57725780
"jl_gc_queue_root", m);

src/julia_internal.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -811,7 +811,8 @@ STATIC_INLINE void *jl_get_frame_addr(void)
811811
}
812812

813813
JL_DLLEXPORT jl_array_t *jl_array_cconvert_cstring(jl_array_t *a);
814-
void jl_depwarn(const char *msg, jl_sym_t *sym);
814+
void jl_depwarn(const char *msg, jl_value_t *sym);
815+
void jl_depwarn_partial_indexing(size_t n);
815816

816817
int isabspath(const char *in);
817818

0 commit comments

Comments
 (0)