1
Fork 0

Made fail! and assert! accept both &'static str and ~str, as well as a fmt! like format list.

Unwinding through macros now happens as a call to the trait function `FailWithCause::fail_with()`, which consumes self, allowing to use a more generic failure object in the future.
This commit is contained in:
Marvin Löbel 2013-04-23 22:30:58 +02:00
parent 1d53babd2f
commit e1be9ae224
9 changed files with 90 additions and 26 deletions

View file

@ -165,7 +165,42 @@ pub fn log_str<T>(t: &T) -> ~str {
} }
} }
/** Initiate task failure */ /// Trait for initiating task failure.
pub trait FailWithCause {
/// Fail the current task, taking ownership of `cause`
fn fail_with(cause: Self, file: &'static str, line: uint) -> !;
}
impl FailWithCause for ~str {
fn fail_with(cause: ~str, file: &'static str, line: uint) -> ! {
do str::as_buf(cause) |msg_buf, _msg_len| {
do str::as_buf(file) |file_buf, _file_len| {
unsafe {
let msg_buf = cast::transmute(msg_buf);
let file_buf = cast::transmute(file_buf);
begin_unwind_(msg_buf, file_buf, line as libc::size_t)
}
}
}
}
}
impl FailWithCause for &'static str {
fn fail_with(cause: &'static str, file: &'static str, line: uint) -> ! {
do str::as_buf(cause) |msg_buf, _msg_len| {
do str::as_buf(file) |file_buf, _file_len| {
unsafe {
let msg_buf = cast::transmute(msg_buf);
let file_buf = cast::transmute(file_buf);
begin_unwind_(msg_buf, file_buf, line as libc::size_t)
}
}
}
}
}
// NOTE: remove function after snapshot
#[cfg(stage0)]
pub fn begin_unwind(msg: ~str, file: ~str, line: uint) -> ! { pub fn begin_unwind(msg: ~str, file: ~str, line: uint) -> ! {
do str::as_buf(msg) |msg_buf, _msg_len| { do str::as_buf(msg) |msg_buf, _msg_len| {
do str::as_buf(file) |file_buf, _file_len| { do str::as_buf(file) |file_buf, _file_len| {
@ -187,6 +222,8 @@ pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
} }
} }
// NOTE: remove function after snapshot
#[cfg(stage0)]
pub fn fail_assert(msg: &str, file: &str, line: uint) -> ! { pub fn fail_assert(msg: &str, file: &str, line: uint) -> ! {
let (msg, file) = (msg.to_owned(), file.to_owned()); let (msg, file) = (msg.to_owned(), file.to_owned());
begin_unwind(~"assertion failed: " + msg, file, line) begin_unwind(~"assertion failed: " + msg, file, line)
@ -297,6 +334,14 @@ mod tests {
assert!(new_f(20) == 30); assert!(new_f(20) == 30);
} }
} }
#[test]
#[should_fail]
fn fail_static() { FailWithCause::fail_with("cause", file!(), line!()) }
#[test]
#[should_fail]
fn fail_owned() { FailWithCause::fail_with(~"cause", file!(), line!()) }
} }
// Local Variables: // Local Variables:

View file

@ -1101,7 +1101,7 @@ fn mk_enum_deser_body(
}; };
let quoted_expr = copy quote_expr!( let quoted_expr = copy quote_expr!(
::core::sys::begin_unwind(~"explicit failure", ~"empty", 1); ::core::sys::FailWithCause::fail_with("explicit failure", "empty", 1);
).node; ).node;
let impossible_case = ast::arm { let impossible_case = ast::arm {

View file

@ -474,11 +474,12 @@ pub fn mk_unreachable(cx: @ext_ctxt, span: span) -> @ast::expr {
~[ ~[
cx.ident_of(~"core"), cx.ident_of(~"core"),
cx.ident_of(~"sys"), cx.ident_of(~"sys"),
cx.ident_of(~"begin_unwind"), cx.ident_of(~"FailWithCause"),
cx.ident_of(~"fail_with"),
], ],
~[ ~[
mk_uniq_str(cx, span, ~"internal error: entered unreachable code"), mk_base_str(cx, span, ~"internal error: entered unreachable code"),
mk_uniq_str(cx, span, loc.file.name), mk_base_str(cx, span, loc.file.name),
mk_uint(cx, span, loc.line), mk_uint(cx, span, loc.line),
] ]
) )

View file

@ -415,6 +415,7 @@ pub fn core_macros() -> ~str {
__log(1u32, fmt!( $($arg),+ )) __log(1u32, fmt!( $($arg),+ ))
) )
) )
macro_rules! warn ( macro_rules! warn (
($arg:expr) => ( ($arg:expr) => (
__log(2u32, fmt!( \"%?\", $arg )) __log(2u32, fmt!( \"%?\", $arg ))
@ -423,6 +424,7 @@ pub fn core_macros() -> ~str {
__log(2u32, fmt!( $($arg),+ )) __log(2u32, fmt!( $($arg),+ ))
) )
) )
macro_rules! info ( macro_rules! info (
($arg:expr) => ( ($arg:expr) => (
__log(3u32, fmt!( \"%?\", $arg )) __log(3u32, fmt!( \"%?\", $arg ))
@ -431,6 +433,7 @@ pub fn core_macros() -> ~str {
__log(3u32, fmt!( $($arg),+ )) __log(3u32, fmt!( $($arg),+ ))
) )
) )
macro_rules! debug ( macro_rules! debug (
($arg:expr) => ( ($arg:expr) => (
__log(4u32, fmt!( \"%?\", $arg )) __log(4u32, fmt!( \"%?\", $arg ))
@ -441,35 +444,48 @@ pub fn core_macros() -> ~str {
) )
macro_rules! fail( macro_rules! fail(
($msg: expr) => (
::core::sys::begin_unwind($msg, file!().to_owned(), line!())
);
() => ( () => (
fail!(~\"explicit failure\") fail!(\"explicit failure\")
);
($msg:expr) => (
::core::sys::FailWithCause::fail_with($msg, file!(), line!())
);
($( $arg:expr ),+) => (
::core::sys::FailWithCause::fail_with(fmt!( $($arg),+ ), file!(), line!())
) )
) )
macro_rules! assert( macro_rules! assert(
($cond:expr) => { ($cond:expr) => {
if !$cond { if !$cond {
::core::sys::fail_assert(stringify!($cond), file!(), line!()) ::core::sys::FailWithCause::fail_with(
~\"assertion failed: \" + stringify!($cond), file!(), line!())
} }
}; };
($cond:expr, $msg:expr) => { ($cond:expr, $msg:expr) => {
if !$cond { if !$cond {
::core::sys::fail_assert($msg, file!(), line!()) ::core::sys::FailWithCause::fail_with($msg, file!(), line!())
}
};
($cond:expr, $( $arg:expr ),+) => {
if !$cond {
::core::sys::FailWithCause::fail_with(fmt!( $($arg),+ ), file!(), line!())
} }
} }
) )
macro_rules! assert_eq ( macro_rules! assert_eq (
($given:expr , $expected:expr) => ($given:expr , $expected:expr) => (
({let given_val = $given; {
let given_val = $given;
let expected_val = $expected; let expected_val = $expected;
// check both directions of equality.... // check both directions of equality....
if !((given_val == expected_val) && (expected_val == given_val)) { if !((given_val == expected_val) && (expected_val == given_val)) {
fail!(fmt!(\"expected: %?, given: %?\",expected_val,given_val)); fail!(fmt!(\"left: %? != right: %?\", given_val, expected_val));
}})) }
}
)
)
macro_rules! condition ( macro_rules! condition (

View file

@ -0,0 +1,7 @@
// error-pattern:illegal borrow: borrowed value does not live long enough
fn main() {
let v = ~"test";
let sslice = str::slice(v, 0, v.len());
fail!(sslice);
}

View file

@ -1,5 +0,0 @@
// error-pattern:mismatched types
fn main() {
fail!("test");
}

View file

@ -8,6 +8,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// error-pattern:mismatched types // error-pattern:failed to find an implementation of trait core::sys::FailWithCause for int
fn main() { fail!(5); } fn main() { fail!(5); }

View file

@ -8,5 +8,5 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// error-pattern:expected `~str` but found `~[int]` // error-pattern:failed to find an implementation of trait core::sys::FailWithCause for ~[int]
fn main() { fail!(~[0i]); } fn main() { fail!(~[0i]); }

View file

@ -1,4 +1,4 @@
// error-pattern:expected: 15, given: 14 // error-pattern:left: 14 != right: 15
#[deriving(Eq)] #[deriving(Eq)]
struct Point { x : int } struct Point { x : int }