Skip to content

Commit 0578362

Browse files
committed
improve the spans for errors
1 parent fcf3935 commit 0578362

File tree

3 files changed

+76
-28
lines changed

3 files changed

+76
-28
lines changed

crates/formality-core/src/judgment.rs

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ macro_rules! push_rules {
190190

191191
if let Some(__JudgmentStruct($($input_names),*)) = Some($input_value) {
192192
$crate::push_rules!(@match
193+
$conclusion_name
193194
inputs($($input_names)*)
194195
patterns($($patterns)*,)
195196
args(@body
@@ -232,43 +233,43 @@ macro_rules! push_rules {
232233
// Matching phase: peel off the patterns one by one and match them against the values
233234
// extracted from the input. For anything that is not an identity pattern, invoke `downcast`.
234235

235-
(@match inputs() patterns() args(@body ($judgment_name:ident; $n:literal; $v:expr; $output:expr); $inputs:tt; $($m:tt)*)) => {
236+
(@match $conclusion_name:ident inputs() patterns() args(@body ($judgment_name:ident; $n:literal; $v:expr; $output:expr); $inputs:tt; $($m:tt)*)) => {
236237
tracing::trace_span!("matched rule", rule = $n, judgment = stringify!($judgment_name)).in_scope(|| {
237238
let mut step_index = 0;
238239
$crate::push_rules!(@body ($judgment_name, $n, $v, $output); $inputs; step_index; $($m)*);
239240
});
240241
};
241242

242-
(@match inputs() patterns(,) args $args:tt) => {
243-
$crate::push_rules!(@match inputs() patterns() args $args);
243+
(@match $conclusion_name:ident inputs() patterns(,) args $args:tt) => {
244+
$crate::push_rules!(@match $conclusion_name inputs() patterns() args $args);
244245
};
245246

246-
(@match inputs() patterns $patterns:tt args $args:tt) => {
247-
compile_error!("more patterns in rule than arguments on fn")
247+
(@match $conclusion_name:ident inputs() patterns ($pattern0:tt $($pattern1:tt)*) args $args:tt) => {
248+
$crate::respan!($pattern0 (compile_error!("more patterns in rule than arguments on fn")))
248249
};
249250

250-
(@match inputs $inputs:tt patterns() args $args:tt) => {
251-
compile_error!("fewer patterns in rule than arguments on fn")
251+
(@match $conclusion_name:ident inputs $inputs:tt patterns() args $args:tt) => {
252+
$crate::respan!($conclusion_name (compile_error!("fewer patterns in rule than arguments on fn")))
252253
};
253254

254-
(@match inputs($in0:ident $($inputs:tt)*) patterns($pat0:ident : $ty0:ty, $($pats:tt)*) args $args:tt) => {
255+
(@match $conclusion_name:ident inputs($in0:ident $($inputs:tt)*) patterns($pat0:ident : $ty0:ty, $($pats:tt)*) args $args:tt) => {
255256
{
256257
if let Some($pat0) = $crate::Downcast::downcast::<$ty0>($in0) {
257-
$crate::push_rules!(@match inputs($($inputs)*) patterns($($pats)*) args $args);
258+
$crate::push_rules!(@match $conclusion_name inputs($($inputs)*) patterns($($pats)*) args $args);
258259
}
259260
}
260261
};
261262

262-
(@match inputs($in0:ident $($inputs:tt)*) patterns($pat0:ident, $($pats:tt)*) args $args:tt) => {
263+
(@match $conclusion_name:ident inputs($in0:ident $($inputs:tt)*) patterns($pat0:ident, $($pats:tt)*) args $args:tt) => {
263264
{
264265
let $pat0 = Clone::clone($in0);
265-
$crate::push_rules!(@match inputs($($inputs)*) patterns($($pats)*) args $args);
266+
$crate::push_rules!(@match $conclusion_name inputs($($inputs)*) patterns($($pats)*) args $args);
266267
}
267268
};
268269

269-
(@match inputs($in0:ident $($inputs:tt)*) patterns($pat0:pat, $($pats:tt)*) args $args:tt) => {
270+
(@match $conclusion_name:ident inputs($in0:ident $($inputs:tt)*) patterns($pat0:pat, $($pats:tt)*) args $args:tt) => {
270271
if let Some($pat0) = $crate::Downcast::downcast(&$in0) {
271-
$crate::push_rules!(@match inputs($($inputs)*) patterns($($pats)*) args $args);
272+
$crate::push_rules!(@match $conclusion_name inputs($($inputs)*) patterns($($pats)*) args $args);
272273
}
273274
};
274275

@@ -288,7 +289,7 @@ macro_rules! push_rules {
288289
$step_index += 1;
289290
$crate::push_rules!(@body $args; $inputs; $step_index; $($m)*);
290291
} else {
291-
$crate::push_rules!(@record_failure $inputs; $step_index; $crate::judgment::RuleFailureCause::IfFalse {
292+
$crate::push_rules!(@record_failure $inputs; $step_index, $c; $crate::judgment::RuleFailureCause::IfFalse {
292293
expr: stringify!($c).to_string(),
293294
});
294295
}
@@ -306,7 +307,7 @@ macro_rules! push_rules {
306307
$step_index += 1;
307308
$crate::push_rules!(@body $args; $inputs; $step_index; $($m)*);
308309
} else {
309-
$crate::push_rules!(@record_failure $inputs; $step_index; $crate::judgment::RuleFailureCause::IfLetDidNotMatch {
310+
$crate::push_rules!(@record_failure $inputs; $step_index, $e; $crate::judgment::RuleFailureCause::IfLetDidNotMatch {
310311
pattern: stringify!($p).to_string(),
311312
value: format!("{:?}", value),
312313
});
@@ -324,7 +325,7 @@ macro_rules! push_rules {
324325
}
325326
}
326327
Err(e) => {
327-
$crate::push_rules!(@record_failure $inputs; $step_index; e);
328+
$crate::push_rules!(@record_failure $inputs; $step_index, $i; e);
328329
}
329330
}
330331
};
@@ -348,23 +349,26 @@ macro_rules! push_rules {
348349

349350
//
350351

351-
(@record_failure ($failed_rules:expr, $match_index:expr, $inputs:tt, $rule_name:literal); $step_index:ident; $cause:expr) => {
352+
(@record_failure ($failed_rules:expr, $match_index:expr, $inputs:tt, $rule_name:literal); $step_index:ident, $step_expr:expr; $cause:expr) => {
353+
let file = $crate::respan!($step_expr (file!()));
354+
let line = $crate::respan!($step_expr (line!()));
355+
let column = $crate::respan!($step_expr (column!()));
352356
if $step_index >= $match_index {
353357
tracing::debug!(
354358
"rule {rn} failed at step {s} because {cause} ({file}:{line}:{column})",
355359
rn = $rule_name,
356360
s = $step_index,
357361
cause = $cause,
358-
file = file!(),
359-
line = line!(),
360-
column = column!(),
362+
file = file,
363+
line = line,
364+
column = column,
361365
);
362366
$failed_rules.insert(
363367
$crate::judgment::FailedRule {
364368
rule_name_index: Some(($rule_name.to_string(), $step_index)),
365-
file: file!().to_string(),
366-
line: line!(),
367-
column: column!(),
369+
file: file.to_string(),
370+
line: line,
371+
column: column,
368372
cause: $cause,
369373
}
370374
);
@@ -374,9 +378,9 @@ macro_rules! push_rules {
374378
rn = $rule_name,
375379
s = $step_index,
376380
cause = $cause,
377-
file = file!(),
378-
line = line!(),
379-
column = column!(),
381+
file = file,
382+
line = line,
383+
column = column,
380384
);
381385
}
382386
}

crates/formality-core/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub use tracing::instrument;
1717
pub use tracing::trace;
1818

1919
// Re-export things from formality-macros.
20-
pub use formality_macros::{fixed_point, term, test, Visit};
20+
pub use formality_macros::{fixed_point, respan, term, test, Visit};
2121

2222
pub type Fallible<T> = anyhow::Result<T>;
2323

crates/formality-macros/src/lib.rs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use proc_macro::TokenStream;
1+
use proc_macro::{Span, TokenStream};
22
use quote::quote;
33
use spec::FormalitySpec;
44
// use syn::DeriveInput;
@@ -59,3 +59,47 @@ pub fn test(args: TokenStream, input: TokenStream) -> TokenStream {
5959
Err(e) => e.into_compile_error().into(),
6060
}
6161
}
62+
63+
/// Invoked like `respan!(X (Y...))` -- produces `Y...` with span from `X`.
64+
#[proc_macro]
65+
pub fn respan(t: TokenStream) -> TokenStream {
66+
let mut t = t.into_iter();
67+
let dummy = t.next().unwrap();
68+
let stream = t.next().unwrap();
69+
return match stream {
70+
proc_macro::TokenTree::Group(g) => set_span(pick_span(dummy), g.stream()),
71+
_ => unreachable!(),
72+
};
73+
74+
fn pick_span(dummy: proc_macro::TokenTree) -> Span {
75+
match dummy {
76+
// Careful! The compiler creates groups for fragments
77+
// (e.g., $x:expr) that have the span of the macro that parsed them.
78+
// We want the span of the fragment's contents in that case.
79+
proc_macro::TokenTree::Group(g)
80+
if g.delimiter() == proc_macro::Delimiter::None && !g.stream().is_empty() =>
81+
{
82+
g.stream().into_iter().next().unwrap().span()
83+
}
84+
_ => dummy.span(),
85+
}
86+
}
87+
88+
fn set_span(span: Span, tokens: TokenStream) -> TokenStream {
89+
tokens
90+
.into_iter()
91+
.map(|token| match token {
92+
proc_macro::TokenTree::Group(group) => {
93+
let mut fixed =
94+
proc_macro::Group::new(group.delimiter(), set_span(span, group.stream()));
95+
fixed.set_span(span);
96+
proc_macro::TokenTree::Group(fixed)
97+
}
98+
mut token => {
99+
token.set_span(span);
100+
token
101+
}
102+
})
103+
.collect()
104+
}
105+
}

0 commit comments

Comments
 (0)