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 DomainError more informative #22751

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

* `InexactError` now takes arguments: `InexactError(func::Symbol,
type, -3)` now prints as `ERROR: InexactError: func(type, -3)`. ([#20005])
* `InexactError` and `DomainError` 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])

Julia v0.6.0 Release Notes
==========================
Expand Down
7 changes: 6 additions & 1 deletion base/boot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,6 @@ struct BoundsError <: Exception
BoundsError(a::ANY, i) = (@_noinline_meta; new(a,i))
end
struct DivideError <: Exception end
struct DomainError <: Exception end
struct OverflowError <: Exception end
struct OutOfMemoryError <: Exception end
struct ReadOnlyMemoryError<: Exception end
Expand All @@ -216,6 +215,12 @@ struct UndefVarError <: Exception
var::Symbol
end
struct InterruptException <: Exception end
struct DomainError <: Exception
val
msg
DomainError(val::ANY) = (@_noinline_meta; new(val))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keep an eye on whether @nospecialize gets merged before this

DomainError(val::ANY, msg::ANY) = (@_noinline_meta; new(val, msg))
end
mutable struct TypeError <: Exception
func::Symbol
context::AbstractString
Expand Down
4 changes: 2 additions & 2 deletions base/combinatorics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ for n in 2:34
end

function factorial_lookup(n::Integer, table, lim)
n < 0 && throw(DomainError())
n < 0 && throw(DomainError(n, "`n` must not be negative."))
n > lim && throw(OverflowError())
n == 0 && return one(n)
@inbounds f = table[n]
Expand All @@ -34,7 +34,7 @@ else
end

function gamma(n::Union{Int8,UInt8,Int16,UInt16,Int32,UInt32,Int64,UInt64})
n < 0 && throw(DomainError())
n < 0 && throw(DomainError(n, "`n` must not be negative."))
n == 0 && return Inf
n <= 2 && return 1.0
n > 20 && return gamma(Float64(n))
Expand Down
2 changes: 1 addition & 1 deletion base/dSFMT.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ mutable struct DSFMT_state
val::Vector{Int32}

DSFMT_state(val::Vector{Int32} = zeros(Int32, JN32)) =
new(length(val) == JN32 ? val : throw(DomainError()))
new(length(val) == JN32 ? val : throw(DomainError(length(val), string("Expected length ", JN32, '.'))))
end

copy!(dst::DSFMT_state, src::DSFMT_state) = (copy!(dst.val, src.val); dst)
Expand Down
12 changes: 6 additions & 6 deletions base/dates/rounding.jl
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ Takes the given `DateTime` and returns the number of milliseconds since the roun
datetime2epochms(dt::DateTime) = value(dt) - DATETIMEEPOCH

function Base.floor(dt::Date, p::Year)
value(p) < 1 && throw(DomainError())
value(p) < 1 && throw(DomainError(p))
years = year(dt)
return Date(years - mod(years, value(p)))
end

function Base.floor(dt::Date, p::Month)
value(p) < 1 && throw(DomainError())
value(p) < 1 && throw(DomainError(p))
y, m = yearmonth(dt)
months_since_epoch = y * 12 + m - 1
month_offset = months_since_epoch - mod(months_since_epoch, value(p))
Expand All @@ -56,22 +56,22 @@ function Base.floor(dt::Date, p::Month)
end

function Base.floor(dt::Date, p::Week)
value(p) < 1 && throw(DomainError())
value(p) < 1 && throw(DomainError(p))
days = value(dt) - WEEKEPOCH
days = days - mod(days, value(Day(p)))
return Date(UTD(WEEKEPOCH + Int64(days)))
end

function Base.floor(dt::Date, p::Day)
value(p) < 1 && throw(DomainError())
value(p) < 1 && throw(DomainError(p))
days = date2epochdays(dt)
return epochdays2date(days - mod(days, value(p)))
end

Base.floor(dt::DateTime, p::DatePeriod) = DateTime(Base.floor(Date(dt), p))

function Base.floor(dt::DateTime, p::TimePeriod)
value(p) < 1 && throw(DomainError())
value(p) < 1 && throw(DomainError(p))
milliseconds = datetime2epochms(dt)
return epochms2datetime(milliseconds - mod(milliseconds, value(Millisecond(p))))
end
Expand Down Expand Up @@ -166,7 +166,7 @@ Base.round(dt::TimeType, p::Period, r::RoundingMode{:Up}) = Base.ceil(dt, p)
# No implementation of other `RoundingMode`s: rounding to nearest "even" is skipped because
# "even" is not defined for Period; rounding toward/away from zero is skipped because ISO
# 8601's year 0000 is not really "zero".
Base.round(::TimeType, ::Period, ::RoundingMode) = throw(DomainError())
Base.round(::TimeType, p::Period, ::RoundingMode) = throw(DomainError(p))

# Default to RoundNearestTiesUp.
Base.round(dt::TimeType, p::Period) = Base.round(dt, p, RoundNearestTiesUp)
Expand Down
6 changes: 6 additions & 0 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1561,6 +1561,12 @@ function InexactError()
InexactError(:none, Any, nothing)
end

# PR #22751
function DomainError()
depwarn("DomainError now supports arguments, use `DomainError(value)` or `DomainError(value, msg)` instead.", :DomainError)
DomainError(nothing)
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
7 changes: 4 additions & 3 deletions base/docs/helpdb/Base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1402,14 +1402,15 @@ The highest value representable by the given (real) numeric `DataType`.
typemax

"""
DomainError()
DomainError(val)
DomainError(val, msg)

The arguments to a function or constructor are outside the valid domain.
The argument `val` to a function or constructor is outside the valid domain.

# Examples
```jldoctest
julia> sqrt(-1)
ERROR: DomainError:
ERROR: DomainError with -1:
sqrt will only return a complex result if called with a complex argument. Try sqrt(complex(x)).
Stacktrace:
[1] sqrt(::Int64) at ./math.jl:443
Expand Down
7 changes: 4 additions & 3 deletions base/float.jl
Original file line number Diff line number Diff line change
Expand Up @@ -443,17 +443,18 @@ for op in (:<, :<=, :isless)
end

function cmp(x::AbstractFloat, y::AbstractFloat)
(isnan(x) || isnan(y)) && throw(DomainError())
isnan(x) && throw(DomainError(x, "`x` cannot be NaN."))
isnan(y) && throw(DomainError(y, "`y` cannot be NaN."))
ifelse(x<y, -1, ifelse(x>y, 1, 0))
end

function cmp(x::Real, y::AbstractFloat)
isnan(y) && throw(DomainError())
isnan(y) && throw(DomainError(y, "`y` cannot be NaN."))
ifelse(x<y, -1, ifelse(x>y, 1, 0))
end

function cmp(x::AbstractFloat, y::Real)
isnan(x) && throw(DomainError())
isnan(x) && throw(DomainError(x, "`x` cannot be NaN."))
ifelse(x<y, -1, ifelse(x>y, 1, 0))
end

Expand Down
2 changes: 1 addition & 1 deletion base/floatfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ function _signif_og(x, digits, base)
end

function signif(x::Real, digits::Integer, base::Integer=10)
digits < 1 && throw(DomainError())
digits < 1 && throw(DomainError(digits, "`digits` cannot be less than 1."))

x = float(x)
(x == 0 || !isfinite(x)) && return x
Expand Down
8 changes: 4 additions & 4 deletions base/gmp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ function invmod(x::BigInt, y::BigInt)
return z
end
if (y==0 || MPZ.invert!(z, x, ya) == 0)
throw(DomainError())
throw(DomainError(y))
end
# GMP always returns a positive inverse; we instead want to
# normalize such that div(z, y) == 0, i.e. we want a negative z
Expand Down Expand Up @@ -474,15 +474,15 @@ cmp(x::BigInt, y::CulongMax) = MPZ.cmp_ui(x, y)
cmp(x::BigInt, y::Integer) = cmp(x, big(y))
cmp(x::Integer, y::BigInt) = -cmp(y, x)

cmp(x::BigInt, y::CdoubleMax) = isnan(y) ? throw(DomainError()) : MPZ.cmp_d(x, y)
cmp(x::BigInt, y::CdoubleMax) = isnan(y) ? throw(DomainError(y, "`y` cannot be NaN.")) : MPZ.cmp_d(x, y)
cmp(x::CdoubleMax, y::BigInt) = -cmp(y, x)

isqrt(x::BigInt) = MPZ.sqrt(x)

^(x::BigInt, y::Culong) = MPZ.pow_ui(x, y)

function bigint_pow(x::BigInt, y::Integer)
if y<0; throw(DomainError()); end
if y<0; throw(DomainError(y, "`y` cannot be negative.")); end
if x== 1; return x; end
if x==-1; return isodd(y) ? x : -x; end
if y>typemax(Culong)
Expand Down Expand Up @@ -607,7 +607,7 @@ function base(b::Integer, n::BigInt, pad::Integer)
end

function ndigits0zpb(x::BigInt, b::Integer)
b < 2 && throw(DomainError())
b < 2 && throw(DomainError(b, "`b` cannot be less than 2."))
x.size == 0 && return 0 # for consistency with other ndigits0z methods
if ispow2(b) && 2 <= b <= 62 # GMP assumes b is in this range
MPZ.sizeinbase(x, b)
Expand Down
23 changes: 15 additions & 8 deletions base/intfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,8 @@ julia> invmod(5,6)
"""
function invmod(n::T, m::T) where T<:Integer
g, x, y = gcdx(n, m)
(g != 1 || m == 0) && throw(DomainError())
g != 1 && throw(DomainError((n, m), "Greatest common divisor is $g."))
m == 0 && throw(DomainError(m, "`m` must not be 0."))
# Note that m might be negative here.
# For unsigned T, x might be close to typemax; add m to force a wrap-around.
r = mod(x + m, m)
Expand All @@ -159,6 +160,10 @@ invmod(n::Integer, m::Integer) = invmod(promote(n,m)...)
# ^ for any x supporting *
to_power_type(x::Number) = oftype(x*x, x)
to_power_type(x) = x
@noinline throw_domerr_powbysq(p) = throw(DomainError(p,
string("Cannot raise an integer x to a negative power ", p, '.',
"\nMake x a float by adding a zero decimal (e.g., 2.0^$p instead ",
"of 2^$p), or write 1/x^$(-p), float(x)^$p, or (x//1)^$p")))
function power_by_squaring(x_, p::Integer)
x = to_power_type(x_)
if p == 1
Expand All @@ -170,7 +175,7 @@ function power_by_squaring(x_, p::Integer)
elseif p < 0
x == 1 && return copy(x)
x == -1 && return iseven(p) ? one(x) : copy(x)
throw(DomainError())
throw_domerr_powbysq(p)
end
t = trailing_zeros(p) + 1
p >>= t
Expand All @@ -190,7 +195,7 @@ function power_by_squaring(x_, p::Integer)
end
power_by_squaring(x::Bool, p::Unsigned) = ((p==0) | x)
function power_by_squaring(x::Bool, p::Integer)
p < 0 && !x && throw(DomainError())
p < 0 && !x && throw_domerr_powbysq(p)
return (p==0) | x
end

Expand Down Expand Up @@ -348,7 +353,8 @@ julia> nextpow(4, 16)
See also [`prevpow`](@ref).
"""
function nextpow(a::Real, x::Real)
(a <= 1 || x <= 0) && throw(DomainError())
a <= 1 && throw(DomainError(a, "`a` must be greater than 1."))
x <= 0 && throw(DomainError(x, "`x` must be positive."))
x <= 1 && return one(a)
n = ceil(Integer,log(a, x))
p = a^(n-1)
Expand Down Expand Up @@ -379,7 +385,8 @@ julia> prevpow(4, 16)
See also [`nextpow`](@ref).
"""
function prevpow(a::Real, x::Real)
(a <= 1 || x < 1) && throw(DomainError())
a <= 1 && throw(DomainError(a, "`a` must be greater than 1."))
x < 1 && throw(DomainError(x, "`x` must be ≥ 1."))
n = floor(Integer,log(a, x))
p = a^(n+1)
p <= x ? p : a^n
Expand Down Expand Up @@ -498,7 +505,7 @@ function ndigits0z(x::Integer, b::Integer)
elseif b > 1
ndigits0zpb(x, b)
else
throw(DomainError())
throw(DomainError(b, "The base `b` must not be in `[-1, 0, 1]`."))
end
end

Expand Down Expand Up @@ -582,7 +589,7 @@ const base62digits = ['0':'9';'A':'Z';'a':'z']


function base(b::Int, x::Integer, pad::Int, neg::Bool)
(x >= 0) | (b < 0) || throw(DomainError())
(x >= 0) | (b < 0) || throw(DomainError(x, "For negative `x`, `b` must be negative."))
2 <= abs(b) <= 62 || throw(ArgumentError("base must satisfy 2 ≤ abs(base) ≤ 62, got $b"))
digits = abs(b) <= 36 ? base36digits : base62digits
i = neg + ndigits(x, b, pad)
Expand Down Expand Up @@ -800,7 +807,7 @@ function isqrt(x::Union{Int64,UInt64,Int128,UInt128})
end

function factorial(n::Integer)
n < 0 && throw(DomainError())
n < 0 && throw(DomainError(n, "`n` must be nonnegative."))
local f::typeof(n*n), i::typeof(n*n)
f = 1
for i = 2:n
Expand Down
4 changes: 2 additions & 2 deletions base/libuv.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ include(string(length(Core.ARGS) >= 2 ? Core.ARGS[2] : "", "uv_constants.jl"))
# convert UV handle data to julia object, checking for null
function uv_sizeof_handle(handle)
if !(UV_UNKNOWN_HANDLE < handle < UV_HANDLE_TYPE_MAX)
throw(DomainError())
throw(DomainError(handle))
end
ccall(:uv_handle_size,Csize_t,(Int32,),handle)
end

function uv_sizeof_req(req)
if !(UV_UNKNOWN_REQ < req < UV_REQ_TYPE_MAX)
throw(DomainError())
throw(DomainError(req))
end
ccall(:uv_req_size,Csize_t,(Int32,),req)
end
Expand Down
10 changes: 6 additions & 4 deletions base/linalg/eigen.jl
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,8 @@ julia> A = [0 im; -1 0]
-1+0im 0+0im

julia> eigmax(A)
ERROR: DomainError:
ERROR: DomainError with Complex{Int64}[0+0im 0+1im; -1+0im 0+0im]:
`A` cannot have complex eigenvalues.
Stacktrace:
[1] #eigmax#52(::Bool, ::Bool, ::Function, ::Array{Complex{Int64},2}) at ./linalg/eigen.jl:238
[2] eigmax(::Array{Complex{Int64},2}) at ./linalg/eigen.jl:236
Expand All @@ -235,7 +236,7 @@ Stacktrace:
function eigmax(A::Union{Number, StridedMatrix}; permute::Bool=true, scale::Bool=true)
v = eigvals(A, permute = permute, scale = scale)
if eltype(v)<:Complex
throw(DomainError())
throw(DomainError(A, "`A` cannot have complex eigenvalues."))
end
maximum(v)
end
Expand Down Expand Up @@ -268,7 +269,8 @@ julia> A = [0 im; -1 0]
-1+0im 0+0im

julia> eigmin(A)
ERROR: DomainError:
ERROR: DomainError with Complex{Int64}[0+0im 0+1im; -1+0im 0+0im]:
`A` cannot have complex eigenvalues.
Stacktrace:
[1] #eigmin#53(::Bool, ::Bool, ::Function, ::Array{Complex{Int64},2}) at ./linalg/eigen.jl:280
[2] eigmin(::Array{Complex{Int64},2}) at ./linalg/eigen.jl:278
Expand All @@ -277,7 +279,7 @@ Stacktrace:
function eigmin(A::Union{Number, StridedMatrix}; permute::Bool=true, scale::Bool=true)
v = eigvals(A, permute = permute, scale = scale)
if eltype(v)<:Complex
throw(DomainError())
throw(DomainError(A, "`A` cannot have complex eigenvalues."))
end
minimum(v)
end
Expand Down
Loading