Skip to content

Commit 8ca9f97

Browse files
KijewskiGuillaumeGomez
authored andcommitted
Fix error messages
1 parent 979c60a commit 8ca9f97

File tree

3 files changed

+57
-43
lines changed

3 files changed

+57
-43
lines changed

rinja_derive/src/generator/node.rs

+53-39
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use std::borrow::Cow;
2-
use std::collections::HashSet;
32
use std::collections::hash_map::{Entry, HashMap};
4-
use std::fmt::Write;
3+
use std::fmt::{self, Write};
54
use std::mem;
65

76
use parser::node::{
@@ -1434,8 +1433,9 @@ fn macro_call_ensure_arg_count(
14341433
call.span(),
14351434
));
14361435
}
1437-
// First we list of arguments position then we remove them one by one.
1438-
let mut args = (0..def.args.len()).collect::<HashSet<_>>();
1436+
1437+
// First we list of arguments position, then we remove every argument with a value.
1438+
let mut args: Vec<_> = def.args.iter().map(|&(name, _)| Some(name)).collect();
14391439
for (pos, arg) in call.args.iter().enumerate() {
14401440
let pos = match **arg {
14411441
Expr::NamedArgument(name, ..) => {
@@ -1444,11 +1444,11 @@ fn macro_call_ensure_arg_count(
14441444
_ => Some(pos),
14451445
};
14461446
if let Some(pos) = pos {
1447-
if !args.remove(&pos) {
1447+
if mem::take(&mut args[pos]).is_none() {
14481448
// This argument was already passed, so error.
14491449
return Err(ctx.generate_error(
14501450
format_args!(
1451-
"argument `{}` is passed more than once when calling macro `{}`",
1451+
"argument `{}` was passed more than once when calling macro `{}`",
14521452
def.args[pos].0, def.name,
14531453
),
14541454
call.span(),
@@ -1457,41 +1457,55 @@ fn macro_call_ensure_arg_count(
14571457
}
14581458
}
14591459

1460-
// Now we need to filter out arguments with default value.
1461-
let args = args
1462-
.into_iter()
1463-
.filter(|pos| def.args[*pos].1.is_none())
1464-
.collect::<Vec<_>>();
1465-
let (extra, error) = match args.len() {
1466-
0 => return Ok(()),
1467-
1 => ("", format!("`{}`", def.args[0].0)),
1468-
2 => ("s", format!("`{}` and `{}`", def.args[0].0, def.args[1].0)),
1469-
_ => {
1470-
let mut error_s =
1471-
args.iter()
1472-
.take(args.len() - 2)
1473-
.fold(String::new(), |mut acc, arg| {
1474-
if !acc.is_empty() {
1475-
acc.push_str(", ");
1476-
}
1477-
acc.push_str(&format!("`{}`", def.args[*arg].0));
1478-
acc
1479-
});
1480-
error_s.push_str(&format!(
1481-
" and `{}`",
1482-
def.args[*args.last().expect("no last args")].0
1483-
));
1484-
("s", error_s)
1460+
// Now we can check off arguments with a default value, too.
1461+
for (pos, (_, dflt)) in def.args.iter().enumerate() {
1462+
if dflt.is_some() {
1463+
args[pos] = None;
14851464
}
1486-
};
1465+
}
1466+
1467+
// Now that we have a needed information, we can print an error message (if needed).
1468+
struct FmtMissing<'a, I> {
1469+
count: usize,
1470+
missing: I,
1471+
name: &'a str,
1472+
}
1473+
1474+
impl<'a, I: Iterator<Item = &'a str> + Clone> fmt::Display for FmtMissing<'a, I> {
1475+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1476+
if self.count == 1 {
1477+
let a = self.missing.clone().next().unwrap();
1478+
write!(
1479+
f,
1480+
"missing argument when calling macro `{}`: `{a}`",
1481+
self.name
1482+
)
1483+
} else {
1484+
write!(f, "missing arguments when calling macro `{}`: ", self.name)?;
1485+
for (idx, a) in self.missing.clone().enumerate() {
1486+
if idx == self.count - 1 {
1487+
write!(f, " and ")?;
1488+
} else if idx > 0 {
1489+
write!(f, ", ")?;
1490+
}
1491+
write!(f, "`{a}`")?;
1492+
}
1493+
Ok(())
1494+
}
1495+
}
1496+
}
14871497

1488-
Err(ctx.generate_error(
1489-
format_args!(
1490-
"missing argument{extra} when calling macro `{}`: {error}",
1491-
def.name
1492-
),
1493-
call.span(),
1494-
))
1498+
let missing = args.iter().filter_map(Option::as_deref);
1499+
let fmt_missing = FmtMissing {
1500+
count: missing.clone().count(),
1501+
missing,
1502+
name: def.name,
1503+
};
1504+
if fmt_missing.count == 0 {
1505+
Ok(())
1506+
} else {
1507+
Err(ctx.generate_error(fmt_missing, call.span()))
1508+
}
14951509
}
14961510

14971511
#[derive(Clone, Copy, PartialEq)]

testing/tests/ui/macro.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ error: expected `)` to close macro argument list
6868
39 | #[template(source = "{% macro thrice(a, b, c = %}{% endmacro %}", ext = "html")]
6969
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7070

71-
error: missing argument when calling macro `example`: `name`
71+
error: missing argument when calling macro `example`: `current`
7272
--> WrongNumberOfParams.txt:4:10
7373
" call example(name=\"name\", value=\"\") %}\n "
7474
--> tests/ui/macro.rs:44:14
@@ -81,7 +81,7 @@ error: missing argument when calling macro `example`: `name`
8181
48 | | "#,
8282
| |______^
8383

84-
error: argument `name` is passed more than once when calling macro `example`
84+
error: argument `name` was passed more than once when calling macro `example`
8585
--> DuplicatedArg.txt:4:10
8686
" call example(0, name=\"name\", value=\"\") %}\n "
8787
--> tests/ui/macro.rs:55:14

testing/tests/ui/macro_named_argument.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error: missing argument when calling macro `thrice`: `param1`
1+
error: missing argument when calling macro `thrice`: `param2`
22
--> InvalidNamedArg.html:5:2
33
"- call thrice(param1=2, param3=3) -%}"
44
--> tests/ui/macro_named_argument.rs:4:21
@@ -49,7 +49,7 @@ error: named arguments must always be passed last
4949
33 | | {%- call thrice(param1=2, 3) -%}", ext = "html")]
5050
| |_________________________________^
5151

52-
error: argument `param1` is passed more than once when calling macro `thrice`
52+
error: argument `param1` was passed more than once when calling macro `thrice`
5353
--> InvalidNamedArg5.html:4:2
5454
"- call thrice(3, param1=2) -%}"
5555
--> tests/ui/macro_named_argument.rs:38:21

0 commit comments

Comments
 (0)