Skip to content

Commit b65bb73

Browse files
nikomatsakisNiko Matsakis
authored andcommitted
extend assertions so they can be results
1 parent 0d25b29 commit b65bb73

File tree

3 files changed

+63
-6
lines changed

3 files changed

+63
-6
lines changed

crates/formality-core/src/judgment.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ use std::cell::RefCell;
22

33
use crate::{fixed_point::FixedPointStack, Fallible, Set};
44

5+
mod assertion;
6+
pub use assertion::JudgmentAssertion;
7+
58
mod proven_set;
69
pub use proven_set::{FailedJudgment, FailedRule, ProvenSet, RuleFailureCause, TryIntoIter};
710

@@ -77,8 +80,18 @@ macro_rules! judgment_fn {
7780
$(let $input_name: $input_ty = $crate::Upcast::upcast($input_name);)*
7881

7982
$(
80-
// Assertions are preconditions
81-
assert!($assert_expr);
83+
// Assertions are preconditions.
84+
//
85+
// NB: we can't use `$crate` in this expression because of the `respan!` call,
86+
// which messes up `$crate` resolution. But we need the respan call for track_caller to properly
87+
// assign the span of the panic to the assertion expression and not the invocation of the judgment_fn
88+
// macro. Annoying! But our proc macros already reference `formality_core` so that seems ok.
89+
$crate::respan!(
90+
$assert_expr
91+
(
92+
formality_core::judgment::JudgmentAssertion::assert($assert_expr, stringify!($assert_expr));
93+
)
94+
);
8295
)*
8396

8497
$(
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
use std::fmt::Debug;
2+
3+
/// Helper trait for assertions in judgments.
4+
/// For each `assert(x)`, we will invoke `JudgmentAssertion::assert`.
5+
/// This allows us to support both booleans and results.
6+
pub trait JudgmentAssertion {
7+
fn assert(self, expr: &str);
8+
}
9+
10+
impl<E: Debug> JudgmentAssertion for Result<(), E> {
11+
#[track_caller]
12+
fn assert(self, expr: &str) {
13+
match self {
14+
Ok(()) => (),
15+
Err(e) => panic!("judgment assertion failed: `{expr}` got {e:?}"),
16+
}
17+
}
18+
}
19+
20+
impl JudgmentAssertion for bool {
21+
#[track_caller]
22+
fn assert(self, expr: &str) {
23+
assert!(self, "judgment assertion failed: `{expr}` is false");
24+
}
25+
}

crates/formality-core/src/judgment/test_fallible.rs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ impl Check {
2828
judgment_fn!(
2929
fn jfn(c: Check, x: u32) => u32 {
3030
debug(c, x)
31+
assert(x < 100)
32+
assert(check_x(x))
3133

3234
(
3335
(let y = c.is(x)?)
@@ -44,15 +46,20 @@ judgment_fn!(
4446
}
4547
);
4648

49+
fn check_x(x: u32) -> Fallible<()> {
50+
if x > 75 {
51+
bail!("invalid x: {x}")
52+
}
53+
Ok(())
54+
}
55+
4756
#[test]
4857
fn is_equal_22() {
49-
jfn(Check { x: 22 }, 22).assert_ok(expect_test::expect![
50-
[r#"
58+
jfn(Check { x: 22 }, 22).assert_ok(expect_test::expect![[r#"
5159
{
5260
22,
5361
}
54-
"#]
55-
]);
62+
"#]]);
5663
}
5764

5865
#[test]
@@ -74,3 +81,15 @@ fn is_not_equal() {
7481
the rule "rule" failed at step #0 (src/file.rs:LL:CC) because
7582
expected 22 got 23"#]]);
7683
}
84+
85+
#[test]
86+
#[should_panic(expected = "judgment assertion failed: `x < 100` is false")]
87+
fn bool_assertion_fails() {
88+
let _ = jfn(Check { x: 22 }, 110);
89+
}
90+
91+
#[test]
92+
#[should_panic(expected = "judgment assertion failed: `check_x(x)` got invalid x")]
93+
fn result_assertion_fails() {
94+
let _ = jfn(Check { x: 22 }, 76);
95+
}

0 commit comments

Comments
 (0)