diff --git a/base/contracts.jl b/base/contracts.jl new file mode 100644 index 0000000000000..b9ffc28dcc124 --- /dev/null +++ b/base/contracts.jl @@ -0,0 +1,21 @@ +# This file is a part of Julia. License is MIT: http://julialang.org/license + + +@noinline function precondition_error(msg) + io = IOBuffer() + StackTraces.show_spec_linfo(io, StackTraces.lookup(backtrace()[3])) + throw(ArgumentError("$(takebuf_string(io)) requires $msg")) +end + + +""" + @require precondition [message] + +Throw `ArgumentError` if `precondition` is false. +""" +macro require(precondition, msg = string(precondition)) + esc(:(if ! $precondition Base.precondition_error($msg) end)) +end +# FIXME +# Should this have a branch-prediction hint? (same for @assert?) +# http://llvm.org/docs/BranchWeightMetadata.html#built-in-expect-instructions diff --git a/base/exports.jl b/base/exports.jl index 4f0601ca50fae..83056577962fa 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -1436,6 +1436,7 @@ export @noinline, @assert, + @require, @enum, @label, @goto, diff --git a/base/sysimg.jl b/base/sysimg.jl index 8ad07fae6b782..851105ad4b854 100644 --- a/base/sysimg.jl +++ b/base/sysimg.jl @@ -90,6 +90,8 @@ include("arraymath.jl") include("simdloop.jl") importall .SimdLoop +include("contracts.jl") + # map-reduce operators include("reduce.jl") diff --git a/doc/stdlib/base.rst b/doc/stdlib/base.rst index 684d6e62e99af..b92123a552637 100644 --- a/doc/stdlib/base.rst +++ b/doc/stdlib/base.rst @@ -1068,6 +1068,12 @@ Errors Throw an ``AssertionError`` if ``cond`` is ``false``\ . Preferred syntax for writing assertions. Message ``text`` is optionally displayed upon assertion failure. +.. function:: @require precondition [message] + + .. Docstring generated from Julia source + + Throw ``ArgumentError`` if ``precondition`` is false. + .. function:: ArgumentError(msg) .. Docstring generated from Julia source diff --git a/test/misc.jl b/test/misc.jl index 1bd0217b43fa5..27a9c8b67773e 100644 --- a/test/misc.jl +++ b/test/misc.jl @@ -101,6 +101,31 @@ let deepthought(x, y) = 42 end end +# test @require +let + f1(n) = begin @require n > 0; n end + f2(n) = begin @require n != 0 "non-zero n"; n end + + @test f1(1) == 1 + @test f2(1) == 1 + + try + f1(0) + error("unexpected") + catch ex + @test isa(ex, ArgumentError) + @test ismatch(r"f1(.*) requires n > 0", ex.msg) + end + + try + f2(0) + error("unexpected") + catch ex + @test isa(ex, ArgumentError) + @test ismatch(r"f2(.*) requires non-zero n", ex.msg) + end +end + let # test the process title functions, issue #9957 oldtitle = Sys.get_process_title() Sys.set_process_title("julia0x1")