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
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
10 changes: 6 additions & 4 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`,
Expand Down Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion base/boot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
19 changes: 12 additions & 7 deletions base/checked.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)...)
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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)

Expand All @@ -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

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion base/combinatorics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
6 changes: 6 additions & 0 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
2 changes: 1 addition & 1 deletion base/docs/helpdb/Base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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.
"""
Expand Down
4 changes: 3 additions & 1 deletion base/gmp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand Down
6 changes: 4 additions & 2 deletions base/intfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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

Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion base/parse.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions base/rational.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
1 change: 1 addition & 0 deletions base/replutil.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
1 change: 0 additions & 1 deletion src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion src/datatype.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 0 additions & 1 deletion src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
Expand Down
1 change: 0 additions & 1 deletion src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down