Repository: djc/askama
Pull request #909 (2023-11-17 11:23:25)

Improve output error for non-matching number of arguments for macros
Instead of checking for each argument if it doesn't go over the size, I added the check before the loop, allowing to iterate without needing to check anything.

While working on this, I also realized that it was ok to call the macro without passing all arguments. Should I maintain this behaviour or not? If you want me to keep this behaviour, I'll simply update the check to:

```rust
if args.len() > def.args.len() {
```

GuillaumeGomez: Applied suggestions!

Patch:
diff --git a/askama_derive/src/generator.rs b/askama_derive/src/generator.rs
index eb293b0..8f0b7b3 100644
--- a/askama_derive/src/generator.rs
+++ b/askama_derive/src/generator.rs
@@ -719,11 +719,15 @@ impl<'a> Generator<'a> {
         let mut names = Buffer::new(0);
         let mut values = Buffer::new(0);
         let mut is_first_variable = true;
-        for (i, arg) in def.args.iter().enumerate() {
-            let expr = args.get(i).ok_or_else(|| {
-                CompileError::from(format!("macro {name:?} takes more than {i} arguments"))
-            })?;
-
+        if args.len() != def.args.len() {
+            return Err(CompileError::from(format!(
+                "macro {name:?} expected {} argument{}, found {}",
+                def.args.len(),
+                if def.args.len() != 1 { "s" } else { "" },
+                args.len()
+            )));
+        }
+        for (expr, arg) in std::iter::zip(args, &def.args) {
             match expr {
                 // If `expr` is already a form of variable then
                 // don't reintroduce a new variable. This is


Test patch:
diff --git a/testing/tests/ui/macro.rs b/testing/tests/ui/macro.rs
new file mode 100644
index 0000000..01c64bf
--- /dev/null
+++ b/testing/tests/ui/macro.rs
@@ -0,0 +1,27 @@
+use askama::Template;
+
+#[derive(Template)]
+#[template(source = "{%- macro thrice(param) -%}
+{{ param }}
+{%- endmacro -%}
+
+{%- call thrice(2, 3) -%}", ext = "html")]
+struct InvalidNumberOfArgs;
+
+#[derive(Template)]
+#[template(source = "{%- macro thrice(param, param2) -%}
+{{ param }} {{ param2 }}
+{%- endmacro -%}
+
+{%- call thrice() -%}", ext = "html")]
+struct InvalidNumberOfArgs2;
+
+#[derive(Template)]
+#[template(source = "{%- macro thrice() -%}
+{%- endmacro -%}
+
+{%- call thrice(1, 2) -%}", ext = "html")]
+struct InvalidNumberOfArgs3;
+
+fn main() {
+}
diff --git a/testing/tests/ui/macro.stderr b/testing/tests/ui/macro.stderr
new file mode 100644
index 0000000..5471c96
--- /dev/null
+++ b/testing/tests/ui/macro.stderr
@@ -0,0 +1,23 @@
+error: macro "thrice" expected 1 argument, found 2
+ --> tests/ui/macro.rs:3:10
+  |
+3 | #[derive(Template)]
+  |          ^^^^^^^^
+  |
+  = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: macro "thrice" expected 2 arguments, found 0
+  --> tests/ui/macro.rs:11:10
+   |
+11 | #[derive(Template)]
+   |          ^^^^^^^^
+   |
+   = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: macro "thrice" expected 0 arguments, found 2
+  --> tests/ui/macro.rs:19:10
+   |
+19 | #[derive(Template)]
+   |          ^^^^^^^^
+   |
+   = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info)