Repository: rinja-rs/askama (language: rust)

Issue:
Is write_cond trying to return a size_hint?
It looks like `write_cond` is accumulating a contribution to `size_hint`:
https://github.com/djc/askama/blob/417cb924ae1f94d54e2eb13ebc7e9fab91b84588/askama_derive/src/generator.rs#L760

But it seems to be dropped on the floor:
https://github.com/djc/askama/blob/417cb924ae1f94d54e2eb13ebc7e9fab91b84588/askama_derive/src/generator.rs#L633

Should this instead be `size_hint += self.write_cond(ctx, buf, conds, ws)?;`?


Discussion / hints:
Same question for `write_match`, `write_loop`, `write_block`, maybe others?  I'm starting to think there's more to accumulating the `size_hint` than it looks like at first glance?

Fix patch:
diff --git a/askama_derive/src/generator.rs b/askama_derive/src/generator.rs
index fc74f342c..d8093c3d7 100644
--- a/askama_derive/src/generator.rs
+++ b/askama_derive/src/generator.rs
@@ -630,16 +630,16 @@ impl<'a> Generator<'a> {
                     self.write_let(buf, ws, var, val)?;
                 }
                 Node::Cond(ref conds, ws) => {
-                    self.write_cond(ctx, buf, conds, ws)?;
+                    size_hint += self.write_cond(ctx, buf, conds, ws)?;
                 }
                 Node::Match(ws1, ref expr, ref arms, ws2) => {
-                    self.write_match(ctx, buf, ws1, expr, arms, ws2)?;
+                    size_hint += self.write_match(ctx, buf, ws1, expr, arms, ws2)?;
                 }
                 Node::Loop(ref loop_block) => {
-                    self.write_loop(ctx, buf, loop_block)?;
+                    size_hint += self.write_loop(ctx, buf, loop_block)?;
                 }
                 Node::BlockDef(ws1, name, _, ws2) => {
-                    self.write_block(buf, Some(name), Ws(ws1.0, ws2.1))?;
+                    size_hint += self.write_block(buf, Some(name), Ws(ws1.0, ws2.1))?;
                 }
                 Node::Include(ws, path) => {
                     size_hint += self.handle_include(ctx, buf, ws, path)?;


Test patch:
diff --git a/testing/templates/size-child-super.txt b/testing/templates/size-child-super.txt
new file mode 100644
index 000000000..77c2916e7
--- /dev/null
+++ b/testing/templates/size-child-super.txt
@@ -0,0 +1,2 @@
+{% extends "size-parent.txt" %}
+{% block main %}{% call super() %}{% endblock %}
diff --git a/testing/templates/size-child.txt b/testing/templates/size-child.txt
new file mode 100644
index 000000000..86adbf89c
--- /dev/null
+++ b/testing/templates/size-child.txt
@@ -0,0 +1,2 @@
+{% extends "size-parent.txt" %}
+{% block main %}{% if true %}123{% endif %}{% endblock %}
diff --git a/testing/templates/size-parent.txt b/testing/templates/size-parent.txt
new file mode 100644
index 000000000..e277a24ac
--- /dev/null
+++ b/testing/templates/size-parent.txt
@@ -0,0 +1,1 @@
+{% block main %}{% if true %}12345{% endif %}{% endblock %}
diff --git a/testing/tests/size_hint.rs b/testing/tests/size_hint.rs
new file mode 100644
index 000000000..a9f84286a
--- /dev/null
+++ b/testing/tests/size_hint.rs
@@ -0,0 +1,47 @@
+use askama::Template;
+
+macro_rules! test_size {
+    ($source:literal, $expected:expr) => {{
+        #[derive(Template)]
+        #[template(source = $source, ext = "txt")]
+        struct T(bool);
+
+        assert_eq!(T::SIZE_HINT, $expected);
+    }};
+}
+
+#[test]
+fn test_cond_size_hint() {
+    test_size!("{% if self.0 %}12345{% else %}12345{% endif %}", 10);
+}
+
+#[test]
+fn test_match_size_hint() {
+    test_size!(
+        "{% match self.0 %}{% when true %}12345{% else %}12345{% endmatch %}",
+        5
+    );
+}
+
+#[test]
+fn test_loop_size_hint() {
+    test_size!("{% for i in 0..1 %}12345{% endfor %}", 7);
+}
+
+#[test]
+fn test_block_size_hint() {
+    #[derive(Template)]
+    #[template(path = "size-child.txt")]
+    struct T;
+
+    assert_eq!(T::SIZE_HINT, 3);
+}
+
+#[test]
+fn test_super_size_hint() {
+    #[derive(Template)]
+    #[template(path = "size-child-super.txt")]
+    struct T;
+
+    assert_eq!(T::SIZE_HINT, 5);
+}