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

Make OverflowError more informative #22761

Merged
merged 1 commit into from
Aug 8, 2017
Merged
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
10 changes: 6 additions & 4 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -242,11 +242,12 @@ Deprecated or removed
* `fieldnames` now operates only on types. To get the names of fields in an object, use
`fieldnames(typeof(x))` ([#22350]).

* `InexactError` and `DomainError` now take
* `InexactError`, `DomainError`, and `OverflowError` now take
arguments. `InexactError(func::Symbol, type, -3)` now prints as
`ERROR: InexactError: func(type, -3)`, and `DomainError(val,
[msg])` prints as `ERROR: DomainError with val:\nmsg`. ([#20005],
[#22751])
"ERROR: InexactError: func(type, -3)", `DomainError(val,
[msg])` prints as "ERROR: DomainError with val:\nmsg",
and `OverflowError(msg)` prints as "ERROR: OverflowError: msg".
([#20005], [#22751], [#22761])

* The operating system identification functions: `is_linux`, `is_bsd`, `is_apple`, `is_unix`,
and `is_windows`, have been deprecated in favor of `Sys.islinux`, `Sys.isbsd`, `Sys.isapple`,
@@ -1118,6 +1119,7 @@ Command-line option changes
[#22723]: https://github.com/JuliaLang/julia/issues/22723
[#22732]: https://github.com/JuliaLang/julia/issues/22732
[#22751]: https://github.com/JuliaLang/julia/issues/22751
[#22761]: https://github.com/JuliaLang/julia/issues/22761
[#22762]: https://github.com/JuliaLang/julia/issues/22762
[#22793]: https://github.com/JuliaLang/julia/issues/22793
[#22796]: https://github.com/JuliaLang/julia/issues/22796
4 changes: 3 additions & 1 deletion base/boot.jl
Original file line number Diff line number Diff line change
@@ -212,7 +212,6 @@ struct BoundsError <: Exception
BoundsError(@nospecialize(a), i) = (@_noinline_meta; new(a,i))
end
struct DivideError <: Exception end
struct OverflowError <: Exception end
struct OutOfMemoryError <: Exception end
struct ReadOnlyMemoryError<: Exception end
struct SegmentationFault <: Exception end
@@ -241,6 +240,9 @@ struct InexactError <: Exception

InexactError(f::Symbol, @nospecialize(T), @nospecialize(val)) = (@_noinline_meta; new(f, T, val))
end
struct OverflowError <: Exception
msg
end

abstract type DirectIndexString <: AbstractString end

19 changes: 12 additions & 7 deletions base/checked.jl
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@ import Core.Intrinsics:
checked_srem_int,
checked_uadd_int, checked_usub_int, checked_umul_int, checked_udiv_int,
checked_urem_int
import Base: no_op_err, @_inline_meta
import Base: no_op_err, @_inline_meta, @_noinline_meta

# define promotion behavior for checked operations
checked_add(x::Integer, y::Integer) = checked_add(promote(x,y)...)
@@ -90,16 +90,18 @@ The overflow protection may impose a perceptible performance penalty.
function checked_neg(x::T) where T<:Integer
checked_sub(T(0), x)
end
throw_overflowerr_negation(x) = (@_noinline_meta;
throw(OverflowError("checked arithmetic: cannot compute -x for x = $x::$(typeof(x))")))
if BrokenSignedInt != Union{}
function checked_neg(x::BrokenSignedInt)
r = -x
(x<0) & (r<0) && throw(OverflowError())
(x<0) & (r<0) && throw_overflowerr_negation(x)
r
end
end
if BrokenUnsignedInt != Union{}
function checked_neg(x::T) where T<:BrokenUnsignedInt
x != 0 && throw(OverflowError())
x != 0 && throw_overflowerr_negation(x)
T(0)
end
end
@@ -117,7 +119,7 @@ function checked_abs end

function checked_abs(x::SignedInt)
r = ifelse(x<0, -x, x)
r<0 && throw(OverflowError())
r<0 && throw(OverflowError(string("checked arithmetic: cannot compute |x| for x = ", x, "::", typeof(x))))
r
end
checked_abs(x::UnsignedInt) = x
@@ -152,6 +154,9 @@ end
end


throw_overflowerr_binaryop(op, x, y) = (@_noinline_meta;
throw(OverflowError("$x $op $y overflowed for type $(typeof(x))")))

"""
Base.checked_add(x, y)

@@ -162,7 +167,7 @@ The overflow protection may impose a perceptible performance penalty.
function checked_add(x::T, y::T) where T<:Integer
@_inline_meta
z, b = add_with_overflow(x, y)
b && throw(OverflowError())
b && throw_overflowerr_binaryop(:+, x, y)
z
end

@@ -219,7 +224,7 @@ The overflow protection may impose a perceptible performance penalty.
function checked_sub(x::T, y::T) where T<:Integer
@_inline_meta
z, b = sub_with_overflow(x, y)
b && throw(OverflowError())
b && throw_overflowerr_binaryop(:-, x, y)
z
end

@@ -284,7 +289,7 @@ The overflow protection may impose a perceptible performance penalty.
function checked_mul(x::T, y::T) where T<:Integer
@_inline_meta
z, b = mul_with_overflow(x, y)
b && throw(OverflowError())
b && throw_overflowerr_binaryop(:*, x, y)
z
end

2 changes: 1 addition & 1 deletion base/combinatorics.jl
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@ end

function factorial_lookup(n::Integer, table, lim)
n < 0 && throw(DomainError(n, "`n` must not be negative."))
n > lim && throw(OverflowError())
n > lim && throw(OverflowError(string(n, " is too large to look up in the table")))
n == 0 && return one(n)
@inbounds f = table[n]
return oftype(n, f)
6 changes: 6 additions & 0 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
@@ -1549,6 +1549,12 @@ function DomainError()
DomainError(nothing)
end

# PR #22761
function OverflowError()
depwarn("OverflowError now supports a message string, use `OverflowError(msg)` instead.", :OverflowError)
OverflowError("")
end

# PR #22703
@deprecate Bidiagonal(dv::AbstractVector, ev::AbstractVector, isupper::Bool) Bidiagonal(dv, ev, ifelse(isupper, :U, :L))
@deprecate Bidiagonal(dv::AbstractVector, ev::AbstractVector, uplo::Char) Bidiagonal(dv, ev, ifelse(uplo == 'U', :U, :L))
2 changes: 1 addition & 1 deletion base/docs/helpdb/Base.jl
Original file line number Diff line number Diff line change
@@ -1509,7 +1509,7 @@ used only with extreme caution, as it can cause memory use to grow without bound
gc_enable

"""
OverflowError()
OverflowError(msg)

The result of an expression is too large for the specified type and will cause a wraparound.
"""
4 changes: 3 additions & 1 deletion base/gmp.jl
Original file line number Diff line number Diff line change
@@ -494,6 +494,8 @@ isqrt(x::BigInt) = MPZ.sqrt(x)

function bigint_pow(x::BigInt, y::Integer)
if y<0; throw(DomainError(y, "`y` cannot be negative.")); end
@noinline throw1(y) =
throw(OverflowError("exponent $y is too large and computation will overflow"))
if x== 1; return x; end
if x==-1; return isodd(y) ? x : -x; end
if y>typemax(Culong)
@@ -507,7 +509,7 @@ function bigint_pow(x::BigInt, y::Integer)
#
#Assume that the answer will definitely overflow.

throw(OverflowError())
throw1(y)
end
return x^convert(Culong, y)
end
6 changes: 4 additions & 2 deletions base/intfuncs.jl
Original file line number Diff line number Diff line change
@@ -28,6 +28,7 @@ end
# binary GCD (aka Stein's) algorithm
# about 1.7x (2.1x) faster for random Int64s (Int128s)
function gcd(a::T, b::T) where T<:Union{Int64,UInt64,Int128,UInt128}
@noinline throw1(a, b) = throw(OverflowError("gcd($a, $b) overflows"))
a == 0 && return abs(b)
b == 0 && return abs(a)
za = trailing_zeros(a)
@@ -44,7 +45,7 @@ function gcd(a::T, b::T) where T<:Union{Int64,UInt64,Int128,UInt128}
end
r = u << k
# T(r) would throw InexactError; we want OverflowError instead
r > typemax(T) && throw(OverflowError())
r > typemax(T) && throw1(a, b)
r % T
end

@@ -841,6 +842,7 @@ julia> factorial(5) ÷ (factorial(5-3) * factorial(3))
```
"""
function binomial(n::T, k::T) where T<:Integer
n0, k0 = n, k
k < 0 && return zero(T)
sgn = one(T)
if n < 0
@@ -861,7 +863,7 @@ function binomial(n::T, k::T) where T<:Integer
while rr <= k
xt = div(widemul(x, nn), rr)
x = xt
x == xt || throw(OverflowError())
x == xt || throw(OverflowError("binomial($n0, $k0) overflows"))
rr += 1
nn += 1
end
2 changes: 1 addition & 1 deletion base/parse.jl
Original file line number Diff line number Diff line change
@@ -112,7 +112,7 @@ function tryparse_internal(::Type{T}, s::AbstractString, startpos::Int, endpos::
n, ov_mul = mul_with_overflow(n, base)
n, ov_add = add_with_overflow(n, d)
if ov_mul | ov_add
raise && throw(OverflowError())
raise && throw(OverflowError("overflow parsing $(repr(SubString(s,startpos,endpos)))"))
return _n
end
(i > endpos) && return Nullable{T}(n)
4 changes: 2 additions & 2 deletions base/rational.jl
Original file line number Diff line number Diff line change
@@ -233,11 +233,11 @@ isinteger(x::Rational) = x.den == 1

-(x::Rational) = (-x.num) // x.den
function -(x::Rational{T}) where T<:Signed
x.num == typemin(T) && throw(OverflowError())
x.num == typemin(T) && throw(OverflowError("rational numerator is typemin(T)"))
(-x.num) // x.den
end
function -(x::Rational{T}) where T<:Unsigned
x.num != zero(T) && throw(OverflowError())
x.num != zero(T) && throw(OverflowError("cannot negate unsigned number"))
x
end

1 change: 1 addition & 0 deletions base/replutil.jl
Original file line number Diff line number Diff line change
@@ -275,6 +275,7 @@ showerror(io::IO, ex::KeyError) = print(io, "KeyError: key $(repr(ex.key)) not f
showerror(io::IO, ex::InterruptException) = print(io, "InterruptException:")
showerror(io::IO, ex::ArgumentError) = print(io, "ArgumentError: $(ex.msg)")
showerror(io::IO, ex::AssertionError) = print(io, "AssertionError: $(ex.msg)")
showerror(io::IO, ex::OverflowError) = print(io, "OverflowError: $(ex.msg)")

function showerror(io::IO, ex::UndefVarError)
if ex.var in [:UTF16String, :UTF32String, :WString, :utf16, :utf32, :wstring, :RepString]
1 change: 0 additions & 1 deletion src/codegen.cpp
Original file line number Diff line number Diff line change
@@ -6015,7 +6015,6 @@ static void init_julia_llvm_env(Module *m)
global_jlvalue_to_llvm("jl_emptytuple", &jl_emptytuple, m);
global_jlvalue_to_llvm("jl_diverror_exception", &jl_diverror_exception, m);
global_jlvalue_to_llvm("jl_undefref_exception", &jl_undefref_exception, m);
global_jlvalue_to_llvm("jl_overflow_exception", &jl_overflow_exception, m);

jlRTLD_DEFAULT_var =
new GlobalVariable(*m, T_pint8,
2 changes: 1 addition & 1 deletion src/datatype.c
Original file line number Diff line number Diff line change
@@ -347,7 +347,7 @@ void jl_compute_field_offsets(jl_datatype_t *st)
return;
throw_ovf:
if (descsz >= jl_page_size) free(desc);
jl_throw(jl_overflow_exception);
jl_errorf("type %s has field offset %d that exceeds the page size", jl_symbol_name(st->name), descsz);
}

extern int jl_boot_file_loaded;
1 change: 0 additions & 1 deletion src/init.c
Original file line number Diff line number Diff line change
@@ -785,7 +785,6 @@ void jl_get_builtin_hooks(void)
jl_errorexception_type = (jl_datatype_t*)core("ErrorException");
jl_stackovf_exception = jl_new_struct_uninit((jl_datatype_t*)core("StackOverflowError"));
jl_diverror_exception = jl_new_struct_uninit((jl_datatype_t*)core("DivideError"));
jl_overflow_exception = jl_new_struct_uninit((jl_datatype_t*)core("OverflowError"));
jl_undefref_exception = jl_new_struct_uninit((jl_datatype_t*)core("UndefRefError"));
jl_undefvarerror_type = (jl_datatype_t*)core("UndefVarError");
jl_interrupt_exception = jl_new_struct_uninit((jl_datatype_t*)core("InterruptException"));
1 change: 0 additions & 1 deletion src/julia.h
Original file line number Diff line number Diff line change
@@ -529,7 +529,6 @@ extern JL_DLLEXPORT jl_value_t *jl_stackovf_exception;
extern JL_DLLEXPORT jl_value_t *jl_memory_exception;
extern JL_DLLEXPORT jl_value_t *jl_readonlymemory_exception;
extern JL_DLLEXPORT jl_value_t *jl_diverror_exception;
extern JL_DLLEXPORT jl_value_t *jl_overflow_exception;
extern JL_DLLEXPORT jl_value_t *jl_undefref_exception;
extern JL_DLLEXPORT jl_value_t *jl_interrupt_exception;
extern JL_DLLEXPORT jl_datatype_t *jl_boundserror_type;