Skip to content

Commit f913710

Browse files
committed
include condition argument values in the output
1 parent 6d4aacd commit f913710

File tree

10 files changed

+147
-21
lines changed

10 files changed

+147
-21
lines changed

crates/formality-core/src/judgment.rs

Lines changed: 84 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -288,33 +288,104 @@ macro_rules! push_rules {
288288
// expression `v` is carried in from the conclusion and forms the final
289289
// output of this rule, once all the conditions are evaluated.
290290

291-
(@body $args:tt; $inputs:tt; $step_index:expr; (if $c:expr) $($m:tt)*) => {
292-
if $c {
291+
(@body $args:tt; $inputs:tt; $step_index:expr; (if let $p:pat = $e:expr) $($m:tt)*) => {
292+
let value = &$e;
293+
if let $p = Clone::clone(value) {
293294
$crate::push_rules!(@body $args; $inputs; $step_index + 1; $($m)*);
294295
} else {
295-
$crate::push_rules!(@record_failure $inputs; $step_index, $c; $crate::judgment::RuleFailureCause::IfFalse {
296-
expr: stringify!($c).to_string(),
296+
$crate::push_rules!(@record_failure $inputs; $step_index, $e; $crate::judgment::RuleFailureCause::IfLetDidNotMatch {
297+
pattern: stringify!($p).to_string(),
298+
value: format!("{:?}", value),
297299
});
298300
}
299301
};
300302

301-
(@body $args:tt; $inputs:tt; $step_index:expr; (assert $c:expr) $($m:tt)*) => {
302-
assert!($c);
303-
$crate::push_rules!(@body $args; $inputs; $step_index + 1; $($m)*);
303+
// For `(if ...)`, we have special treatment to try and extract the arguments so we can give better information
304+
// about why the expression evaluated to false.
305+
(@body $args:tt; $inputs:tt; $step_index:expr; (if $($c:tt)*) $($m:tt)*) => {
306+
$crate::push_rules!(@body_if $args; $inputs; $step_index; $($c)*; $($c)*; $($m)*)
304307
};
305308

306-
(@body $args:tt; $inputs:tt; $step_index:expr; (if let $p:pat = $e:expr) $($m:tt)*) => {
307-
let value = &$e;
308-
if let $p = Clone::clone(value) {
309+
(@body_if $args:tt; $inputs:tt; $step_index:expr; $arg0:ident . $method:ident ( ); $origcond:expr; $($m:tt)*) => {
310+
$crate::push_rules!(@structured_if $args; $inputs; $step_index; (arg0 = $arg0); arg0.$method(); $origcond; $($m)*)
311+
};
312+
313+
(@body_if $args:tt; $inputs:tt; $step_index:expr; ! $arg0:ident . $method:ident ( ); $origcond:expr; $($m:tt)*) => {
314+
$crate::push_rules!(@structured_if $args; $inputs; $step_index; (arg0 = $arg0); !arg0.$method(); $origcond; $($m)*)
315+
};
316+
317+
(@body_if $args:tt; $inputs:tt; $step_index:expr; $arg0:ident . $method:ident ( $arg1:expr $(,)? ); $origcond:expr; $($m:tt)*) => {
318+
$crate::push_rules!(@structured_if $args; $inputs; $step_index; (arg0 = $arg0, arg1 = $arg1); arg0.$method(arg1); $origcond; $($m)*)
319+
};
320+
321+
(@body_if $args:tt; $inputs:tt; $step_index:expr; ! $arg0:ident . $method:ident ( $arg1:expr $(,)? ); $origcond:expr; $($m:tt)*) => {
322+
$crate::push_rules!(@structured_if $args; $inputs; $step_index; (arg0 = $arg0, arg1 = $arg1); !arg0.$method(arg1); $origcond; $($m)*)
323+
};
324+
325+
(@body_if $args:tt; $inputs:tt; $step_index:expr; $arg0:ident . $method:ident ( $arg1:expr, $arg2:expr $(,)? ); $origcond:expr; $($m:tt)*) => {
326+
$crate::push_rules!(@structured_if $args; $inputs; $step_index; (arg0 = $arg0, arg1 = $arg1, arg2 = $arg2); arg0.$method(arg1, arg2); $origcond; $($m)*)
327+
};
328+
329+
(@body_if $args:tt; $inputs:tt; $step_index:expr; ! $arg0:ident . $method:ident ( $arg1:expr, $arg2:expr $(,)? ); $origcond:expr; $($m:tt)*) => {
330+
$crate::push_rules!(@structured_if $args; $inputs; $step_index; (arg0 = $arg0, arg1 = $arg1, arg2 = $arg2); !arg0.$method(arg1, arg2); $origcond; $($m)*)
331+
};
332+
333+
(@body_if $args:tt; $inputs:tt; $step_index:expr; $func:ident ( $arg0:expr $(,)? ); $origcond:expr; $($m:tt)*) => {
334+
$crate::push_rules!(@structured_if $args; $inputs; $step_index; (arg0 = $arg0); $func(arg0); $origcond; $($m)*)
335+
};
336+
337+
(@body_if $args:tt; $inputs:tt; $step_index:expr; ! $func:ident ( $arg0:expr $(,)? ); $origcond:expr; $($m:tt)*) => {
338+
$crate::push_rules!(@structured_if $args; $inputs; $step_index; (arg0 = $arg0); !$func(arg0); $origcond; $($m)*)
339+
};
340+
341+
(@body_if $args:tt; $inputs:tt; $step_index:expr; $func:ident ( $arg0:expr, $arg1:expr $(,)? ); $origcond:expr; $($m:tt)*) => {
342+
$crate::push_rules!(@structured_if $args; $inputs; $step_index; (arg0 = $arg0, arg1 = $arg1); $func(arg0, arg1); $origcond; $($m)*)
343+
};
344+
345+
(@body_if $args:tt; $inputs:tt; $step_index:expr; ! $func:ident ( $arg0:expr, $arg1:expr $(,)? ); $origcond:expr; $($m:tt)*) => {
346+
$crate::push_rules!(@structured_if $args; $inputs; $step_index; (arg0 = $arg0, arg1 = $arg1); ! $func(arg0, arg1); $origcond; $($m)*)
347+
};
348+
349+
(@body_if $args:tt; $inputs:tt; $step_index:expr; $arg0:ident == $arg1:ident; $origcond:expr; $($m:tt)*) => {
350+
$crate::push_rules!(@structured_if $args; $inputs; $step_index; (arg0 = $arg0, arg1 = $arg1); arg0 == arg1; $origcond; $($m)*)
351+
};
352+
353+
(@body_if $args:tt; $inputs:tt; $step_index:expr; $arg0:ident != $arg1:ident; $origcond:expr; $($m:tt)*) => {
354+
$crate::push_rules!(@structured_if $args; $inputs; $step_index; (arg0 = $arg0, arg1 = $arg1); arg0 != arg1; $origcond; $($m)*)
355+
};
356+
357+
(@body_if $args:tt; $inputs:tt; $step_index:expr; $e:expr; $origcond:expr; $($m:tt)*) => {
358+
$crate::push_rules!(@structured_if $args; $inputs; $step_index; (); $e; $origcond; $($m)*)
359+
};
360+
361+
(@structured_if $args:tt; $inputs:tt; $step_index:expr; ($($argn:ident = $arge:expr),*); $cond:expr; $origcond:expr; $($m:tt)*) => {
362+
$(
363+
let $argn = &$arge;
364+
)*
365+
if {
366+
$(
367+
let $argn = Clone::clone($argn);
368+
)*
369+
$cond
370+
} {
309371
$crate::push_rules!(@body $args; $inputs; $step_index + 1; $($m)*);
310372
} else {
311-
$crate::push_rules!(@record_failure $inputs; $step_index, $e; $crate::judgment::RuleFailureCause::IfLetDidNotMatch {
312-
pattern: stringify!($p).to_string(),
313-
value: format!("{:?}", value),
373+
$crate::push_rules!(@record_failure $inputs; $step_index, $origcond; $crate::judgment::RuleFailureCause::IfFalse {
374+
expr: stringify!($origcond).to_string(),
375+
args: vec![
376+
$(
377+
(stringify!($arge).to_string(), format!("{:?}", $argn)),
378+
)*
379+
],
314380
});
315381
}
316382
};
317383

384+
(@body $args:tt; $inputs:tt; $step_index:expr; (assert $c:expr) $($m:tt)*) => {
385+
assert!($c);
386+
$crate::push_rules!(@body $args; $inputs; $step_index + 1; $($m)*);
387+
};
388+
318389
(@body $args:tt; $inputs:tt; $step_index:expr; ($i:expr => $p:pat) $($m:tt)*) => {
319390
// Explicitly calling `into_iter` silences some annoying lints
320391
// in the case where `$i` is an `Option` or a `Result`

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

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{set, Set, SetExt};
1+
use crate::{set, Set};
22
use std::{
33
fmt::Debug,
44
hash::{Hash, Hasher},
@@ -385,7 +385,14 @@ impl FailedRule {
385385
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
386386
pub enum RuleFailureCause {
387387
/// The rule did not succeed because an `(if X)` condition evaluated to false.
388-
IfFalse { expr: String },
388+
IfFalse {
389+
/// The stringified form of the expression.
390+
expr: String,
391+
392+
/// A set of pairs with the stringified form of arguments within the expression plus the debug representation of its value.
393+
/// This is a best effort extraction via the macro.
394+
args: Vec<(String, String)>,
395+
},
389396

390397
/// The rule did not succeed because an `(if let)` pattern failed to match.
391398
IfLetDidNotMatch { pattern: String, value: String },
@@ -466,8 +473,12 @@ impl std::fmt::Display for FailedRule {
466473
impl std::fmt::Display for RuleFailureCause {
467474
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
468475
match self {
469-
RuleFailureCause::IfFalse { expr } => {
470-
write!(f, "condition evaluted to false: `{expr}`")
476+
RuleFailureCause::IfFalse { expr, args } => {
477+
write!(f, "condition evaluted to false: `{expr}`")?;
478+
for (arg_expr, arg_value) in args {
479+
write!(f, "\n {arg_expr} = {arg_value}")?;
480+
}
481+
Ok(())
471482
}
472483
RuleFailureCause::IfLetDidNotMatch { pattern, value } => {
473484
write!(f, "pattern `{pattern}` did not match value `{value}`")

crates/formality-prove/src/test/is_local.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ fn test_forall_not_local() {
2121
the rule "trait ref is local" failed at step #0 (src/file.rs:LL:CC) because
2222
judgment `is_local_trait_ref { goal: Debug(!ty_1), assumptions: {}, env: Env { variables: [!ty_1], coherence_mode: true }, decls: decls(222, [], [], [], [], [], [], {}, {}) }` failed at the following rule(s):
2323
the rule "local trait" failed at step #0 (src/file.rs:LL:CC) because
24-
condition evaluted to false: `decls.is_local_trait_id(&goal.trait_id)`"#]]);
24+
condition evaluted to false: `decls.is_local_trait_id(&goal.trait_id)`
25+
decls = decls(222, [], [], [], [], [], [], {}, {})
26+
&goal.trait_id = Debug"#]]);
2527
}
2628

2729
#[test]

tests/judgment-error-reporting/cyclic_judgment.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,9 @@ fn test() {
7474
expect_test::expect![[r#"
7575
judgment `sub { a: class(Foo), b: class(Bar) }` failed at the following rule(s):
7676
the rule "same class" failed at step #0 (src/file.rs:LL:CC) because
77-
condition evaluted to false: `name_a == name_b`"#]]
77+
condition evaluted to false: `name_a == name_b`
78+
name_a = Foo
79+
name_b = Bar"#]]
7880
);
7981
}
8082

@@ -93,37 +95,51 @@ fn test1() {
9395
judgment `sub { a: class(Foo), b: class(Bar) }` failed at the following rule(s):
9496
the rule "same class" failed at step #0 (src/file.rs:LL:CC) because
9597
condition evaluted to false: `name_a == name_b`
98+
name_a = Foo
99+
name_b = Bar
96100
the rule "equivalent" failed at step #3 (src/file.rs:LL:CC) because
97101
judgment `sub { a: class(Foo), b: my(class(Bar)) }` failed at the following rule(s):
98102
the rule "equivalent" failed at step #3 (src/file.rs:LL:CC) because
99103
judgment `sub { a: class(Foo), b: class(Bar) }` failed at the following rule(s):
100104
the rule "same class" failed at step #0 (src/file.rs:LL:CC) because
101105
condition evaluted to false: `name_a == name_b`
106+
name_a = Foo
107+
name_b = Bar
102108
the rule "equivalent" failed at step #3 (src/file.rs:LL:CC) because
103109
judgment `sub { a: my(class(Foo)), b: my(class(Bar)) }` failed at the following rule(s):
104110
the rule "both my" failed at step #0 (src/file.rs:LL:CC) because
105111
judgment `sub { a: class(Foo), b: class(Bar) }` failed at the following rule(s):
106112
the rule "same class" failed at step #0 (src/file.rs:LL:CC) because
107113
condition evaluted to false: `name_a == name_b`
114+
name_a = Foo
115+
name_b = Bar
108116
the rule "equivalent" failed at step #3 (src/file.rs:LL:CC) because
109117
judgment `sub { a: class(Foo), b: class(Bar) }` failed at the following rule(s):
110118
the rule "same class" failed at step #0 (src/file.rs:LL:CC) because
111119
condition evaluted to false: `name_a == name_b`
120+
name_a = Foo
121+
name_b = Bar
112122
the rule "equivalent" failed at step #3 (src/file.rs:LL:CC) because
113123
judgment `sub { a: my(class(Foo)), b: my(class(Bar)) }` failed at the following rule(s):
114124
the rule "both my" failed at step #0 (src/file.rs:LL:CC) because
115125
judgment `sub { a: class(Foo), b: class(Bar) }` failed at the following rule(s):
116126
the rule "same class" failed at step #0 (src/file.rs:LL:CC) because
117127
condition evaluted to false: `name_a == name_b`
128+
name_a = Foo
129+
name_b = Bar
118130
the rule "equivalent" failed at step #3 (src/file.rs:LL:CC) because
119131
judgment `sub { a: class(Foo), b: class(Bar) }` failed at the following rule(s):
120132
the rule "same class" failed at step #0 (src/file.rs:LL:CC) because
121133
condition evaluted to false: `name_a == name_b`
134+
name_a = Foo
135+
name_b = Bar
122136
the rule "equivalent" failed at step #3 (src/file.rs:LL:CC) because
123137
judgment `sub { a: class(Foo), b: my(class(Bar)) }` failed at the following rule(s):
124138
the rule "equivalent" failed at step #3 (src/file.rs:LL:CC) because
125139
judgment `sub { a: class(Foo), b: class(Bar) }` failed at the following rule(s):
126140
the rule "same class" failed at step #0 (src/file.rs:LL:CC) because
127-
condition evaluted to false: `name_a == name_b`"#]]
141+
condition evaluted to false: `name_a == name_b`
142+
name_a = Foo
143+
name_b = Bar"#]]
128144
);
129145
}

tests/judgment-error-reporting/fallible.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,5 +44,7 @@ fn test() {
4444
Caused by:
4545
judgment `sub { a: class(Foo), b: class(Bar) }` failed at the following rule(s):
4646
the rule "same class" failed at step #0 (src/file.rs:LL:CC) because
47-
condition evaluted to false: `name_a == name_b`"#]]);
47+
condition evaluted to false: `name_a == name_b`
48+
name_a = Foo
49+
name_b = Bar"#]]);
4850
}

tests/ui/coherence_orphan/CoreTrait_for_CoreStruct_in_Foo.stderr

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,13 @@ Caused by:
1010
judgment `is_local_parameter { goal: CoreStruct, assumptions: {}, env: Env { variables: [], coherence_mode: true }, decls: decls(222, [trait CoreTrait <ty> ], [impl CoreTrait(CoreStruct)], [], [], [], [adt CoreStruct ], {}, {}) }` failed at the following rule(s):
1111
the rule "fundamental rigid type" failed at step #0 (crates/formality-prove/src/prove/is_local.rs:148:17) because
1212
condition evaluted to false: `is_fundamental(&decls, &name)`
13+
&decls = decls(222, [trait CoreTrait <ty> ], [impl CoreTrait(CoreStruct)], [], [], [], [adt CoreStruct ], {}, {})
14+
&name = (adt CoreStruct)
1315
the rule "local rigid type" failed at step #0 (crates/formality-prove/src/prove/is_local.rs:156:17) because
1416
condition evaluted to false: `decls.is_local_adt_id(&a)`
17+
decls = decls(222, [trait CoreTrait <ty> ], [impl CoreTrait(CoreStruct)], [], [], [], [adt CoreStruct ], {}, {})
18+
&a = CoreStruct
1519
the rule "local trait" failed at step #0 (crates/formality-prove/src/prove/is_local.rs:70:17) because
1620
condition evaluted to false: `decls.is_local_trait_id(&goal.trait_id)`
21+
decls = decls(222, [trait CoreTrait <ty> ], [impl CoreTrait(CoreStruct)], [], [], [], [adt CoreStruct ], {}, {})
22+
&goal.trait_id = CoreTrait

tests/ui/coherence_orphan/alias_to_unit.stderr

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,9 @@ Caused by:
1212
judgment `is_local_parameter { goal: (), assumptions: {}, env: Env { variables: [], coherence_mode: true }, decls: decls(222, [trait CoreTrait <ty> , trait Unit <ty> ], [impl <ty> Unit(^ty0_0), impl CoreTrait(<FooStruct as Unit>::Assoc)], [], [alias <ty> <^ty0_0 as Unit>::Assoc = ()], [], [adt FooStruct ], {}, {FooStruct}) }` failed at the following rule(s):
1313
the rule "fundamental rigid type" failed at step #0 (crates/formality-prove/src/prove/is_local.rs:148:17) because
1414
condition evaluted to false: `is_fundamental(&decls, &name)`
15+
&decls = decls(222, [trait CoreTrait <ty> , trait Unit <ty> ], [impl <ty> Unit(^ty0_0), impl CoreTrait(<FooStruct as Unit>::Assoc)], [], [alias <ty> <^ty0_0 as Unit>::Assoc = ()], [], [adt FooStruct ], {}, {FooStruct})
16+
&name = tuple(0)
1517
the rule "local trait" failed at step #0 (crates/formality-prove/src/prove/is_local.rs:70:17) because
1618
condition evaluted to false: `decls.is_local_trait_id(&goal.trait_id)`
19+
decls = decls(222, [trait CoreTrait <ty> , trait Unit <ty> ], [impl <ty> Unit(^ty0_0), impl CoreTrait(<FooStruct as Unit>::Assoc)], [], [alias <ty> <^ty0_0 as Unit>::Assoc = ()], [], [adt FooStruct ], {}, {FooStruct})
20+
&goal.trait_id = CoreTrait

tests/ui/coherence_orphan/mirror_CoreStruct.stderr

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,13 @@ Caused by:
1212
judgment `is_local_parameter { goal: CoreStruct, assumptions: {}, env: Env { variables: [], coherence_mode: true }, decls: decls(222, [trait CoreTrait <ty> , trait Mirror <ty> ], [impl <ty> Mirror(^ty0_0), impl CoreTrait(<CoreStruct as Mirror>::Assoc)], [], [alias <ty> <^ty0_0 as Mirror>::Assoc = ^ty0_0], [], [adt CoreStruct ], {}, {}) }` failed at the following rule(s):
1313
the rule "fundamental rigid type" failed at step #0 (crates/formality-prove/src/prove/is_local.rs:148:17) because
1414
condition evaluted to false: `is_fundamental(&decls, &name)`
15+
&decls = decls(222, [trait CoreTrait <ty> , trait Mirror <ty> ], [impl <ty> Mirror(^ty0_0), impl CoreTrait(<CoreStruct as Mirror>::Assoc)], [], [alias <ty> <^ty0_0 as Mirror>::Assoc = ^ty0_0], [], [adt CoreStruct ], {}, {})
16+
&name = (adt CoreStruct)
1517
the rule "local rigid type" failed at step #0 (crates/formality-prove/src/prove/is_local.rs:156:17) because
1618
condition evaluted to false: `decls.is_local_adt_id(&a)`
19+
decls = decls(222, [trait CoreTrait <ty> , trait Mirror <ty> ], [impl <ty> Mirror(^ty0_0), impl CoreTrait(<CoreStruct as Mirror>::Assoc)], [], [alias <ty> <^ty0_0 as Mirror>::Assoc = ^ty0_0], [], [adt CoreStruct ], {}, {})
20+
&a = CoreStruct
1721
the rule "local trait" failed at step #0 (crates/formality-prove/src/prove/is_local.rs:70:17) because
1822
condition evaluted to false: `decls.is_local_trait_id(&goal.trait_id)`
23+
decls = decls(222, [trait CoreTrait <ty> , trait Mirror <ty> ], [impl <ty> Mirror(^ty0_0), impl CoreTrait(<CoreStruct as Mirror>::Assoc)], [], [alias <ty> <^ty0_0 as Mirror>::Assoc = ^ty0_0], [], [adt CoreStruct ], {}, {})
24+
&goal.trait_id = CoreTrait

tests/ui/coherence_orphan/neg_CoreTrait_for_CoreStruct_in_Foo.stderr

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,13 @@ Caused by:
1010
judgment `is_local_parameter { goal: CoreStruct, assumptions: {}, env: Env { variables: [], coherence_mode: true }, decls: decls(222, [trait CoreTrait <ty> ], [], [impl ! CoreTrait(CoreStruct)], [], [], [adt CoreStruct ], {}, {}) }` failed at the following rule(s):
1111
the rule "fundamental rigid type" failed at step #0 (crates/formality-prove/src/prove/is_local.rs:148:17) because
1212
condition evaluted to false: `is_fundamental(&decls, &name)`
13+
&decls = decls(222, [trait CoreTrait <ty> ], [], [impl ! CoreTrait(CoreStruct)], [], [], [adt CoreStruct ], {}, {})
14+
&name = (adt CoreStruct)
1315
the rule "local rigid type" failed at step #0 (crates/formality-prove/src/prove/is_local.rs:156:17) because
1416
condition evaluted to false: `decls.is_local_adt_id(&a)`
17+
decls = decls(222, [trait CoreTrait <ty> ], [], [impl ! CoreTrait(CoreStruct)], [], [], [adt CoreStruct ], {}, {})
18+
&a = CoreStruct
1519
the rule "local trait" failed at step #0 (crates/formality-prove/src/prove/is_local.rs:70:17) because
1620
condition evaluted to false: `decls.is_local_trait_id(&goal.trait_id)`
21+
decls = decls(222, [trait CoreTrait <ty> ], [], [impl ! CoreTrait(CoreStruct)], [], [], [adt CoreStruct ], {}, {})
22+
&goal.trait_id = CoreTrait

0 commit comments

Comments
 (0)