Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

smarter BoundsError reporting #9534

Merged
merged 3 commits into from
Jan 2, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions base/base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const Bottom = Union()

# constructors for Core types in boot.jl
call(T::Type{BoundsError}) = Core.call(T)
call(T::Type{BoundsError}, args...) = Core.call(T, args...)
call(T::Type{DivideError}) = Core.call(T)
call(T::Type{DomainError}) = Core.call(T)
call(T::Type{OverflowError}) = Core.call(T)
Expand Down
27 changes: 17 additions & 10 deletions base/boot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -201,18 +201,25 @@ end

abstract Exception

type BoundsError <: Exception end
type DivideError <: Exception end
type DomainError <: Exception end
type OverflowError <: Exception end
type InexactError <: Exception end
type MemoryError <: Exception end
type StackOverflowError <: Exception end
type UndefRefError <: Exception end
type UndefVarError <: Exception
immutable BoundsError <: Exception
a::Any
i::Union(Tuple, Int)
BoundsError() = new()
BoundsError(a::ANY) = new(a)
BoundsError(a::ANY, i::Tuple) = new(a,i)
BoundsError(a::ANY, i::Int) = new(a,i)
end
immutable DivideError <: Exception end
immutable DomainError <: Exception end
immutable OverflowError <: Exception end
immutable InexactError <: Exception end
immutable MemoryError <: Exception end
immutable StackOverflowError <: Exception end
immutable UndefRefError <: Exception end
immutable UndefVarError <: Exception
var::Symbol
end
type InterruptException <: Exception end
immutable InterruptException <: Exception end

abstract AbstractString
abstract DirectIndexString <: AbstractString
Expand Down
15 changes: 15 additions & 0 deletions base/replutil.jl
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,21 @@ writemime(io::IO, ::MIME"text/plain", t::Union(KeyIterator, ValueIterator)) =

showerror(io::IO, e) = show(io, e)

function show(io::IO, be::BoundsError)
print(io, "BoundsError(")
if isdefined(be, :a)
print(io, "\n attempt to access ")
writemime(io, MIME"text/plain"(), be.a)
if isdefined(be, :i)
print(io, "\n at index [")
print_joined(io, be.i, ',')
print(io, ']')
end
print(io, "\n ")
end
print(io, ')')
end

function showerror(io::IO, e::TypeError)
ctx = isempty(e.context) ? "" : "in $(e.context), "
if e.expected === Bool
Expand Down
34 changes: 26 additions & 8 deletions src/alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,14 +120,28 @@ static jl_value_t *jl_new_bits_internal(jl_value_t *dt, void *data, size_t *len)
jl_tuple_t *tuple = (jl_tuple_t*)dt;
*len = LLT_ALIGN(*len, jl_new_bits_align(dt));
size_t i, l = jl_tuple_len(tuple);
jl_value_t *v = (jl_value_t*) jl_alloc_tuple(l);
jl_value_t *v = (jl_value_t*)jl_alloc_tuple(l);
JL_GC_PUSH1(v);
for (i = 0; i < l; i++) {
jl_tupleset(v,i,jl_new_bits_internal(jl_tupleref(tuple,i), (char*)data, len));
}
JL_GC_POP();
return v;
}
if (jl_is_ntuple_type(dt)) {
jl_value_t *lenvar = jl_tparam0(dt);
jl_value_t *elty = jl_tparam1(dt);
*len = LLT_ALIGN(*len, jl_new_bits_align(elty));
assert(jl_is_long(lenvar));
size_t i, l = jl_unbox_long(lenvar);
jl_value_t *v = (jl_value_t*)jl_alloc_tuple(l);
JL_GC_PUSH1(v);
for (i = 0; i < l; i++) {
jl_tupleset(v, i, jl_new_bits_internal(elty, (char*)data, len));
}
JL_GC_POP();
return v;
}

jl_datatype_t *bt = (jl_datatype_t*)dt;
size_t nb = jl_datatype_size(bt);
Expand Down Expand Up @@ -233,7 +247,7 @@ jl_value_t *jl_get_nth_field_checked(jl_value_t *v, size_t i)
{
jl_datatype_t *st = (jl_datatype_t*)jl_typeof(v);
if (i >= jl_tuple_len(st->names))
jl_throw(jl_bounds_exception);
jl_new_bounds_error_i(v, i+1);
size_t offs = jl_field_offset(st,i) + sizeof(void*);
if (st->fields[i].isptr) {
jl_value_t *fval = *(jl_value_t**)((char*)v + offs);
Expand Down Expand Up @@ -309,19 +323,23 @@ DLLEXPORT jl_tuple_t *jl_tuple(size_t n, ...)
va_list args;
if (n == 0) return jl_null;
va_start(args, n);
#ifdef OVERLAP_TUPLE_LEN
jl_tuple_t *jv = (jl_tuple_t*)newobj((jl_value_t*)jl_tuple_type, n);
#else
jl_tuple_t *jv = (jl_tuple_t*)newobj((jl_value_t*)jl_tuple_type, n+1);
#endif
jl_tuple_set_len_unsafe(jv, n);
jl_tuple_t *jv = jl_alloc_tuple_uninit(n);
for(size_t i=0; i < n; i++) {
jl_tupleset(jv, i, va_arg(args, jl_value_t*));
}
va_end(args);
return jv;
}

DLLEXPORT jl_tuple_t *jl_tuplev(size_t n, jl_value_t **v)
{
jl_tuple_t *jv = jl_alloc_tuple_uninit(n);
for(size_t i=0; i < n; i++) {
jl_tupleset(jv, i, v[i]);
}
return jv;
}

jl_tuple_t *jl_tuple1(void *a)
{
#ifdef OVERLAP_TUPLE_LEN
Expand Down
10 changes: 5 additions & 5 deletions src/array.c
Original file line number Diff line number Diff line change
Expand Up @@ -441,13 +441,13 @@ static size_t array_nd_index(jl_array_t *a, jl_value_t **args, size_t nidxs,
i += ii * stride;
size_t d = k>=nd ? 1 : jl_array_dim(a, k);
if (k < nidxs-1 && ii >= d)
jl_throw(jl_bounds_exception);
jl_new_bounds_error_v((jl_value_t*)a, args, nidxs);
stride *= d;
}
for(; k < nd; k++)
stride *= jl_array_dim(a, k);
if (i >= stride)
jl_throw(jl_bounds_exception);
jl_new_bounds_error_v((jl_value_t*)a, args, nidxs);
return i;
}

Expand Down Expand Up @@ -518,7 +518,7 @@ JL_CALLABLE(jl_f_arrayset)
void jl_arrayunset(jl_array_t *a, size_t i)
{
if (i >= jl_array_len(a))
jl_throw(jl_bounds_exception);
jl_new_bounds_error_i((jl_value_t*)a, i+1);
char *ptail = (char*)a->data + i*a->elsize;
if (a->ptrarray)
memset(ptail, 0, a->elsize);
Expand Down Expand Up @@ -619,7 +619,7 @@ void jl_array_del_end(jl_array_t *a, size_t dec)
{
if (dec == 0) return;
if (dec > a->nrows)
jl_throw(jl_bounds_exception);
jl_new_bounds_error_i((jl_value_t*)a, a->nrows - dec);
if (a->isshared) array_try_unshare(a);
if (a->elsize > 0) {
char *ptail = (char*)a->data + (a->nrows-dec)*a->elsize;
Expand Down Expand Up @@ -694,7 +694,7 @@ void jl_array_del_beg(jl_array_t *a, size_t dec)
{
if (dec == 0) return;
if (dec > a->nrows)
jl_throw(jl_bounds_exception);
jl_new_bounds_error_i((jl_value_t*)a, dec);
if (a->isshared) array_try_unshare(a);
size_t es = a->elsize;
size_t nb = dec*es;
Expand Down
75 changes: 62 additions & 13 deletions src/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ extern "C" {

// exceptions -----------------------------------------------------------------

DLLEXPORT void jl_error(const char *str)
DLLEXPORT void NORETURN jl_error(const char *str)
{
if (jl_errorexception_type == NULL) {
JL_PRINTF(JL_STDERR, "%s", str);
Expand All @@ -39,7 +39,7 @@ DLLEXPORT void jl_error(const char *str)
jl_throw(jl_new_struct(jl_errorexception_type, msg));
}

DLLEXPORT void jl_errorf(const char *fmt, ...)
DLLEXPORT void NORETURN jl_errorf(const char *fmt, ...)
{
va_list args;
ios_t buf;
Expand All @@ -56,18 +56,18 @@ DLLEXPORT void jl_errorf(const char *fmt, ...)
jl_throw(jl_new_struct(jl_errorexception_type, msg));
}

void jl_too_few_args(const char *fname, int min)
void NORETURN jl_too_few_args(const char *fname, int min)
{
// TODO: ArgumentError
jl_errorf("%s: too few arguments (expected %d)", fname, min);
}

void jl_too_many_args(const char *fname, int max)
void NORETURN jl_too_many_args(const char *fname, int max)
{
jl_errorf("%s: too many arguments (expected %d)", fname, max);
}

void jl_type_error_rt(const char *fname, const char *context,
void NORETURN jl_type_error_rt(const char *fname, const char *context,
jl_value_t *ty, jl_value_t *got)
{
jl_value_t *ctxt=NULL;
Expand All @@ -78,18 +78,18 @@ void jl_type_error_rt(const char *fname, const char *context,
jl_throw(ex);
}

void jl_type_error_rt_line(const char *fname, const char *context,
void NORETURN jl_type_error_rt_line(const char *fname, const char *context,
jl_value_t *ty, jl_value_t *got, int line)
{
jl_type_error_rt(fname, context, ty, got);
}

void jl_type_error(const char *fname, jl_value_t *expected, jl_value_t *got)
void NORETURN jl_type_error(const char *fname, jl_value_t *expected, jl_value_t *got)
{
jl_type_error_rt(fname, "", expected, got);
}

void jl_undefined_var_error(jl_sym_t *var)
DLLEXPORT void NORETURN jl_undefined_var_error(jl_sym_t *var)
{
if (var->name[0] == '#') {
// convention for renamed variables: #...#original_name
Expand All @@ -100,6 +100,54 @@ void jl_undefined_var_error(jl_sym_t *var)
jl_throw(jl_new_struct(jl_undefvarerror_type, var));
}

DLLEXPORT void NORETURN jl_new_bounds_error(jl_value_t* v, jl_value_t* t) // t::Union(Tuple, Int)
{
JL_GC_PUSH2(v, t); // root arguments so the caller doesn't need to
jl_throw(jl_new_struct((jl_datatype_t*)jl_bounds_exception->type, v, t));
}

DLLEXPORT void NORETURN jl_new_bounds_error_v(jl_value_t* v, jl_value_t **idxs, size_t nidxs)
{
jl_tuple_t *t = NULL;
JL_GC_PUSH2(v, t); // root arguments so the caller doesn't need to
t = jl_tuplev(nidxs, idxs);
jl_throw(jl_new_struct((jl_datatype_t*)jl_bounds_exception->type, v, t));
}

DLLEXPORT void NORETURN jl_new_v_bounds_error_i(jl_value_t** v, size_t nv, size_t i)
{
jl_new_bounds_error_i((jl_value_t*)jl_tuplev(nv, v), i);
}

DLLEXPORT void NORETURN jl_new_unboxed_bounds_error_i(void* data, jl_value_t *vt, size_t i)
{
jl_value_t *t = NULL, *v = NULL;
JL_GC_PUSH2(v, t);
v = jl_new_bits(vt, data);
t = jl_box_long(i);
jl_throw(jl_new_struct((jl_datatype_t*)jl_bounds_exception->type, v, t));
}

DLLEXPORT void NORETURN jl_new_bounds_error_i(jl_value_t* v, size_t i)
{
jl_value_t *t = NULL;
JL_GC_PUSH2(v, t); // root arguments so the caller doesn't need to
t = jl_box_long(i);
jl_throw(jl_new_struct((jl_datatype_t*)jl_bounds_exception->type, v, t));
}

DLLEXPORT void NORETURN jl_new_bounds_error_unboxed(jl_value_t* v, size_t *idxs, size_t nidxs)
{
size_t i;
jl_tuple_t *t = NULL;
JL_GC_PUSH2(v, t); // root arguments so the caller doesn't need to
t = jl_alloc_tuple(nidxs);
for (i = 0; i < nidxs; i++) {
jl_tupleset(t, i, jl_box_long(idxs[i]));
}
jl_throw(jl_new_struct((jl_datatype_t*)jl_bounds_exception->type, v, t));
}

JL_CALLABLE(jl_f_throw)
{
JL_NARGS(throw, 1, 1);
Expand Down Expand Up @@ -404,7 +452,8 @@ JL_CALLABLE(jl_f_kwcall)
assert(jl_is_gf(sorter));
jl_function_t *m = jl_method_lookup((jl_methtable_t*)sorter->env, args, nargs, 1);
if (m == jl_bottom_func) {
return jl_no_method_error(f, args+1, nargs-1);
jl_no_method_error(f, args+1, nargs-1);
// unreachable
}

return jl_apply(m, args, nargs);
Expand Down Expand Up @@ -523,7 +572,7 @@ JL_CALLABLE(jl_f_tupleref)
jl_tuple_t *t = (jl_tuple_t*)args[0];
size_t i = jl_unbox_long(args[1])-1;
if (i >= jl_tuple_len(t))
jl_throw(jl_bounds_exception);
jl_new_bounds_error(args[0], args[1]);
return jl_tupleref(t, i);
}

Expand Down Expand Up @@ -552,7 +601,7 @@ JL_CALLABLE(jl_f_get_field)
if (jl_is_long(args[1])) {
idx = jl_unbox_long(args[1])-1;
if (idx >= jl_tuple_len(st->names))
jl_throw(jl_bounds_exception);
jl_new_bounds_error(args[0], args[1]);
}
else {
JL_TYPECHK(getfield, symbol, args[1]);
Expand Down Expand Up @@ -581,7 +630,7 @@ JL_CALLABLE(jl_f_set_field)
if (jl_is_long(args[1])) {
idx = jl_unbox_long(args[1])-1;
if (idx >= jl_tuple_len(st->names))
jl_throw(jl_bounds_exception);
jl_new_bounds_error(args[0], args[1]);
}
else {
JL_TYPECHK(setfield!, symbol, args[1]);
Expand All @@ -605,7 +654,7 @@ JL_CALLABLE(jl_f_field_type)
if (jl_is_long(args[1])) {
field_index = jl_unbox_long(args[1]) - 1;
if (field_index < 0 || field_index >= jl_tuple_len(st->names))
jl_throw(jl_bounds_exception);
jl_new_bounds_error(args[0], args[1]);
}
else {
JL_TYPECHK(fieldtype, symbol, args[1]);
Expand Down
Loading