Skip to content

Commit

Permalink
Merge pull request #62 from ggggggggg/pull-request/77313054
Browse files Browse the repository at this point in the history
readable DimensionError message
  • Loading branch information
ajkeller34 authored Mar 24, 2017
2 parents 9bd5c18 + 1dac617 commit e7e67e9
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 22 deletions.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
- v0.1.5
- Patch for Julia PR [#20889](https://github.com/JuliaLang/julia/pull/20889), which changes how lowering is done for exponentiation of integer literals.
- Bug fix to enable registering Main as a module for `u_str` (fixes [#61](https://github.com/ajkeller34/Unitful.jl/issues/61)).
- Implement readable message for `DimensionError` [#62](https://github.com/ajkeller34/Unitful.jl/pull/62).
- v0.1.4
- Critical bug fix owing to `mod_fast` changes.
- v0.1.3
Expand Down
8 changes: 4 additions & 4 deletions src/Conversion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ function uconvert(a::Units, x::Number)
if dimension(a) == NoDims
Quantity(x * convfact(a, NoUnits), a)
else
throw(DimensionError())
throw(DimensionError(a,x))
end
end

Expand All @@ -47,7 +47,7 @@ Find the conversion factor from unit `t` to unit `s`, e.g. `convfact(m,cm) = 0.0
# Check if conversion is possible in principle
sdim = dimension(s())
tdim = dimension(t())
sdim != tdim && throw(DimensionError())
sdim != tdim && throw(DimensionError(s(),t()))

# first convert to base SI units.
# fact1 is what would need to be multiplied to get to base SI units
Expand Down Expand Up @@ -133,7 +133,7 @@ function convert{T,D,U}(::Type{Quantity{T,D,U}}, x::Number)
if dimension(x) == D()
Quantity(T(uconvert(U(),x).val), U())
else
throw(DimensionError())
throw(DimensionError(U(),x))
end
end

Expand Down Expand Up @@ -179,7 +179,7 @@ function convert{T,U}(::Type{DimensionlessQuantity{T,U}}, x::Quantity)
if dimension(x) == NoDims
Quantity(T(x.val), U())
else
throw(DimensionError())
throw(DimensionError(NoDims,x))
end
end

Expand Down
10 changes: 5 additions & 5 deletions src/Promotion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
if dimension(S())==dimension(T())
promote_type(S,T)
else
throw(DimensionError())
throw(DimensionError(S(),T()))
end
end
end
Expand All @@ -18,7 +18,7 @@
if dimension(S())==dimension(T())
promote_type(S,T)
else
throw(DimensionError())
throw(DimensionError(S(),T()))
end
end
end
Expand All @@ -35,7 +35,7 @@
::Type{Quantity{T1,D1,U1}}, ::Type{Quantity{T2,D2,U2}})
# figuring out numeric type can be subtle if D1 == D2 but U1 != U2.
# in particular, consider adding 1m + 1cm... the numtype is not Int.
D1 != D2 && throw(DimensionError())
D1 != D2 && throw(DimensionError(U1(),U2()))
return Bool
end
function promote_op{T1,D1,U1,T2,D2,U2}(op, x::Type{Quantity{T1,D1,U1}},
Expand All @@ -62,7 +62,7 @@
::Type{R}, ::Type{Quantity{S,D,U}})
# figuring out numeric type can be subtle if D1 == D2 but U1 != U2.
# in particular, consider adding 1m + 1cm... the numtype is not Int.
D != Dimensions{()} && throw(DimensionError())
D != Dimensions{()} && throw(DimensionError(NoDims,U()))
return Bool
end
function promote_op{R<:Number,S,D,U}(op, ::Type{R}, ::Type{Quantity{S,D,U}})
Expand All @@ -86,7 +86,7 @@
::Type{Quantity{S,D,U}}, ::Type{R})
# figuring out numeric type can be subtle if D1 == D2 but U1 != U2.
# in particular, consider adding 1m + 1cm... the numtype is not Int.
D != Dimensions{()} && throw(DimensionError())
D != Dimensions{()} && throw(DimensionError(NoDims,U()))
return Bool
end
function promote_op{R<:Number,S,D,U}(op, x::Type{Quantity{S,D,U}}, y::Type{R})
Expand Down
29 changes: 19 additions & 10 deletions src/Unitful.jl
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,21 @@ const NoDims = Dimensions{()}()

"""
```
type DimensionError <: Exception end
type DimensionError{T,S} <: Exception
x::T
y::S
end
```
Thrown when dimensions don't match in an operation that demands they do.
Display `x` and `y` in error message.
"""
type DimensionError <: Exception end
type DimensionError{T,S} <: Exception
x::T
y::S
end
Base.showerror(io::IO, e::DimensionError) =
print(io,"DimensionError: $(e.x) and $(e.y) are not dimensionally compatible.");

"""
```
Expand Down Expand Up @@ -403,19 +412,19 @@ for op in [:+, :-]
:($($op)(uconvert($result_units, x), uconvert($result_units, y)))
end

@eval ($op)(::Quantity, ::Quantity) = throw(DimensionError())
@eval ($op)(x::Quantity, y::Quantity) = throw(DimensionError(x,y))
@eval function ($op)(x::Quantity, y::Number)
if isa(x, DimensionlessQuantity)
($op)(promote(x,y)...)
else
throw(DimensionError())
throw(DimensionError(x,y))
end
end
@eval function ($op)(x::Number, y::Quantity)
if isa(y, DimensionlessQuantity)
($op)(promote(x,y)...)
else
throw(DimensionError())
throw(DimensionError(x,y))
end
end

Expand Down Expand Up @@ -673,7 +682,7 @@ for (_x,_y) in [(:fma, :_fma), (:muladd, :_muladd)]
# It seems like most of this is optimized out by the compiler, including the
# apparent runtime check of dimensions, which does not appear in @code_llvm.
@eval @inline function ($_y)(x,y,z)
dimension(x) * dimension(y) != dimension(z) && throw(DimensionError())
dimension(x) * dimension(y) != dimension(z) && throw(DimensionError(x*y,z))
uI = unit(x)*unit(y)
uF = promote_type(typeof(uI), typeof(unit(z)))()
c = ($_x)(ustrip(x), ustrip(y), ustrip(uconvert(uI, z)))
Expand Down Expand Up @@ -722,14 +731,14 @@ end
atan2(y::Quantity, x::Quantity) = atan2(promote(y,x)...)
atan2{T,D,U}(y::Quantity{T,D,U}, x::Quantity{T,D,U}) = atan2(y.val,x.val)
atan2{T,D1,U1,D2,U2}(y::Quantity{T,D1,U1}, x::Quantity{T,D2,U2}) =
throw(DimensionError())
throw(DimensionError(x,y))

for (f, F) in [(:min, :<), (:max, :>)]
@eval @generated function ($f)(x::Quantity, y::Quantity)
xdim = x.parameters[2]()
ydim = y.parameters[2]()
if xdim != ydim
return :(throw(DimensionError()))
return :(throw(DimensionError(x,y)))
end

xunits = x.parameters[3].parameters[1]
Expand Down Expand Up @@ -768,7 +777,7 @@ flipsign(x::Quantity, y::Number) = Quantity(flipsign(x.val,y/unit(y)), unit(x))

@inline isless{T,D,U}(x::Quantity{T,D,U}, y::Quantity{T,D,U}) = _isless(x,y)
@inline _isless{T,D,U}(x::Quantity{T,D,U}, y::Quantity{T,D,U}) = isless(x.val, y.val)
@inline _isless{T,D1,D2,U1,U2}(x::Quantity{T,D1,U1}, y::Quantity{T,D2,U2}) = throw(DimensionError())
@inline _isless{T,D1,D2,U1,U2}(x::Quantity{T,D1,U1}, y::Quantity{T,D2,U2}) = throw(DimensionError(x,y))
@inline _isless(x,y) = isless(x,y)

isless(x::Quantity, y::Quantity) = _isless(promote(x,y)...)
Expand All @@ -777,7 +786,7 @@ isless(x::Number, y::Quantity) = _isless(promote(x,y)...)

@inline <{T,D,U}(x::Quantity{T,D,U}, y::Quantity{T,D,U}) = _lt(x,y)
@inline _lt{T,D,U}(x::Quantity{T,D,U}, y::Quantity{T,D,U}) = <(x.val,y.val)
@inline _lt{T,D1,D2,U1,U2}(x::Quantity{T,D1,U1}, y::Quantity{T,D2,U2}) = throw(DimensionError())
@inline _lt{T,D1,D2,U1,U2}(x::Quantity{T,D1,U1}, y::Quantity{T,D2,U2}) = throw(DimensionError(x,y))
@inline _lt(x,y) = <(x,y)

<(x::Quantity, y::Quantity) = _lt(promote(x,y)...)
Expand Down
6 changes: 3 additions & 3 deletions src/range.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,18 @@
linspace(Float64, ustrip(start), ustrip(stop), len, 1)*unit(T)

function _linspace{T}(start::Quantity{T}, stop::Quantity{T}, len::Integer)
dimension(start) != dimension(stop) && throw(DimensionError())
dimension(start) != dimension(stop) && throw(DimensionError(start, stop))
linspace(start, stop, len)
end

@compat function colon(start::Quantity{<:Real}, step, stop::Quantity{<:Real})
dimension(start) != dimension(stop) && throw(DimensionError())
dimension(start) != dimension(stop) && throw(DimensionError(start, stop))
T = promote_type(typeof(start),typeof(stop))
return colon(convert(T,start), step, convert(T,stop))
end

function colon(start::A, step::B, stop::A) where A<:Quantity{<:Real} where B<:Quantity{<:Real}
dimension(start) != dimension(step) && throw(DimensionError())
dimension(start) != dimension(step) && throw(DimensionError(start, step))
colon(promote(start, step, stop)...)
end

Expand Down
11 changes: 11 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -839,6 +839,17 @@ end
end
end

@testset "DimensionError message" begin
function errorstr(e)
b = IOBuffer()
Base.showerror(b,e)
String(b)
end
@test errorstr(DimensionError(1u"m",2)) == "DimensionError: 1 m and 2 are not dimensionally compatible."
@test errorstr(DimensionError(1u"m",NoDims)) == "DimensionError: 1 m and are not dimensionally compatible."
@test errorstr(DimensionError(u"m",2)) == "DimensionError: m and 2 are not dimensionally compatible."
end

# Test that the @u_str macro will find units in other modules.
module ShadowUnits
using Unitful
Expand Down

0 comments on commit e7e67e9

Please sign in to comment.