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

Issue:
Compilation error when using nested template blocks with in a single template file
Hello! I Encountered a compilation error when using[ block fragments](https://github.com/djc/askama/pull/824) with Vec<&str> in a single template file. The error does not occur when the template is split into separate files.

This is working like expected
``` html
{% block index %}
Section 1: {{ s1 }}
{% endblock %}

{% block section %}
  Value ={{ value }}
{% endblock %}
```

``` rust
use askama::Template;

#[derive(Template)]
#[template(path = "combain.txt", block="index")]
struct RenderInPlace<'a> {
   s1: Section<'a>
}

#[derive(Template)]
#[template(path = "combain.txt", block="section")]
struct Section<'a> {
   value: &'a str,
}
fn main() {
    let value = "x";

    let t = RenderInPlace { s1: Section { value } };
    println!("{}", t);
}
```
``` sh
Section 1: 


  Value =x
```

When changing to Vec for the value i get a compilation error..
``` html 
{% block index %}
Section 1: {{ s1 }}
{% endblock %}

{% block section %}
  {% for value in  values %}
    Value = {{ value }}
  {% endfor %}
{% endblock %}
```
``` rust
use askama::Template;

#[derive(Template)]
#[template(path = "combain.txt", block="index")]
struct RenderInPlace<'a> {
   s1: Section<'a>
}

#[derive(Template)]
#[template(path = "combain.txt", block="section")]
struct Section<'a> {
   values: Vec<&'a str>,
}

fn main() {

    let values: Vec<&str>= vec!["a", "b", "c"];

    let t = RenderInPlace { s1: Section { values } };
    println!("{}", t);
}

```
``` sh
error[E0609]: no field `value` on type `&Section<'a>`
 --> src/main.rs:9:10
  |
9 | #[derive(Template)]
  |          ^^^^^^^^ unknown field
  |
  = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info)

```
However when i split the template file in two it is working as expected.
`index.html`
``` html
{% block index %}
Section 1: {{ s1 }}
{% endblock %}
```
`section.html`
``` html
{% block section %}
  {% for value in  values %}
    Value ={{ value }}
  {% endfor %}
{% endblock %}
```

``` rust
use askama::Template;

#[derive(Template)]
#[template(path = "index.txt", block="index")]
struct RenderInPlace<'a> {
   s1: Section<'a>
}

#[derive(Template)]
#[template(path = "section.txt", block="section")]
struct Section<'a> {
   values: Vec<&'a str>,
}

fn main() {

    let values: Vec<&str>= vec!["a", "b", "c"];

    let t = RenderInPlace { s1: Section { values } };
    println!("{}", t);
}
```
```sh 
Section 1: 
  
    Value =a
  
    Value =b
  
    Value =c
  
```



Discussion / hints:
I had the same issue, investigating what's going on.

Fix patch:
diff --git a/askama_derive/src/generator.rs b/askama_derive/src/generator.rs
index 58da7f72..6fcadc79 100644
--- a/askama_derive/src/generator.rs
+++ b/askama_derive/src/generator.rs
@@ -705,7 +705,7 @@ impl<'a> Generator<'a> {
                 break;
             }
         }
-        let current_buf = mem::take(&mut self.buf_writable);
+        let current_buf = mem::take(&mut self.buf_writable.buf);
 
         self.prepare_ws(filter.ws1);
         let mut size_hint = self.handle(ctx, &filter.nodes, buf, AstLevel::Nested)?;
@@ -734,7 +734,7 @@ impl<'a> Generator<'a> {
             }
         };
 
-        mem::drop(mem::replace(&mut self.buf_writable, current_buf));
+        self.buf_writable.buf = current_buf;
 
         let mut filter_buf = Buffer::new(buf.indent);
         let Filter {
@@ -892,13 +892,6 @@ impl<'a> Generator<'a> {
         name: Option<&'a str>,
         outer: Ws,
     ) -> Result<usize, CompileError> {
-        let block_fragment_write = self.input.block == name && self.buf_writable.discard;
-
-        // Allow writing to the buffer if we're in the block fragment
-        if block_fragment_write {
-            self.buf_writable.discard = false;
-        }
-
         // Flush preceding whitespace according to the outer WS spec
         self.flush_ws(outer);
 
@@ -917,6 +910,15 @@ impl<'a> Generator<'a> {
             (None, None) => return Err("cannot call 'super()' outside block".into()),
         };
 
+        self.write_buf_writable(buf)?;
+
+        let block_fragment_write = self.input.block == name && self.buf_writable.discard;
+        // Allow writing to the buffer if we're in the block fragment
+        if block_fragment_write {
+            self.buf_writable.discard = false;
+        }
+        let prev_buf_discard = mem::replace(&mut buf.discard, self.buf_writable.discard);
+
         // Get the block definition from the heritage chain
         let heritage = self
             .heritage
@@ -961,9 +963,9 @@ impl<'a> Generator<'a> {
             // Need to flush the buffer before popping the variable stack
             child.write_buf_writable(buf)?;
         }
+
         child.flush_ws(def.ws2);
-        let buf_writable = mem::take(&mut child.buf_writable);
-        self.buf_writable = buf_writable;
+        self.buf_writable = child.buf_writable;
 
         // Restore original block context and set whitespace suppression for
         // succeeding whitespace according to the outer WS spec
@@ -973,6 +975,7 @@ impl<'a> Generator<'a> {
         if block_fragment_write {
             self.buf_writable.discard = true;
         }
+        buf.discard = prev_buf_discard;
 
         Ok(size_hint)
     }
@@ -1024,7 +1027,7 @@ impl<'a> Generator<'a> {
             .all(|w| matches!(w, Writable::Lit(_)))
         {
             let mut buf_lit = Buffer::new(0);
-            for s in mem::take(&mut self.buf_writable) {
+            for s in mem::take(&mut self.buf_writable.buf) {
                 if let Writable::Lit(s) = s {
                     buf_lit.write(s);
                 };
@@ -1044,7 +1047,7 @@ impl<'a> Generator<'a> {
         let mut buf_format = Buffer::new(0);
         let mut buf_expr = Buffer::new(indent + 1);
 
-        for s in mem::take(&mut self.buf_writable) {
+        for s in mem::take(&mut self.buf_writable.buf) {
             match s {
                 Writable::Lit(s) => {
                     buf_format.write(&s.replace('{', "{{").replace('}', "}}"));
@@ -1814,6 +1817,7 @@ struct Buffer {
     indent: u8,
     // Whether the output buffer is currently at the start of a line
     start: bool,
+    discard: bool,
 }
 
 impl Buffer {
@@ -1822,10 +1826,14 @@ impl Buffer {
             buf: String::new(),
             indent,
             start: true,
+            discard: false,
         }
     }
 
     fn writeln(&mut self, s: &str) -> Result<(), CompileError> {
+        if self.discard {
+            return Ok(());
+        }
         if s == "}" {
             self.dedent()?;
         }
@@ -1841,6 +1849,9 @@ impl Buffer {
     }
 
     fn write(&mut self, s: &str) {
+        if self.discard {
+            return;
+        }
         if self.start {
             for _ in 0..(self.indent * 4) {
                 self.buf.push(' ');
@@ -2119,15 +2130,6 @@ impl<'a> WritableBuffer<'a> {
     }
 }
 
-impl<'a> IntoIterator for WritableBuffer<'a> {
-    type Item = Writable<'a>;
-    type IntoIter = <Vec<Writable<'a>> as IntoIterator>::IntoIter;
-
-    fn into_iter(self) -> Self::IntoIter {
-        self.buf.into_iter()
-    }
-}
-
 impl<'a> Deref for WritableBuffer<'a> {
     type Target = [Writable<'a>];
 


Test patch:
diff --git a/testing/templates/blocks.txt b/testing/templates/blocks.txt
new file mode 100644
index 00000000..2272d82d
--- /dev/null
+++ b/testing/templates/blocks.txt
@@ -0,0 +1,11 @@
+{% block index %}
+Section: {{ s1 }}
+{% endblock %}
+
+{% block section -%}
+  [
+  {%- for value in  values -%}
+    {{ value }}
+  {%- endfor -%}
+  ]
+{%- endblock %}
diff --git a/testing/tests/block_fragments.rs b/testing/tests/block_fragments.rs
index b84a5113..ae723b6d 100644
--- a/testing/tests/block_fragments.rs
+++ b/testing/tests/block_fragments.rs
@@ -11,7 +11,7 @@ struct FragmentSimple<'a> {
 fn test_fragment_simple() {
     let simple = FragmentSimple { name: "world" };
 
-    assert_eq!(simple.render().unwrap(), "\n\n<p>Hello world!</p>\n");
+    assert_eq!(simple.render().unwrap(), "\n<p>Hello world!</p>\n");
 }
 
 #[derive(Template)]
@@ -28,7 +28,7 @@ fn test_fragment_super() {
 
     assert_eq!(
         sup.render().unwrap(),
-        "\n\n<p>Hello world!</p>\n\n<p>Parent body content</p>\n\n"
+        "\n<p>Hello world!</p>\n\n<p>Parent body content</p>\n\n"
     );
 }
 
@@ -43,7 +43,7 @@ fn test_fragment_nested_block() {
 
     assert_eq!(
         nested_block.render().unwrap(),
-        "\n\n<p>I should be here.</p>\n"
+        "\n<p>I should be here.</p>\n"
     );
 }
 
@@ -61,7 +61,7 @@ fn test_fragment_nested_super() {
 
     assert_eq!(
         nested_sup.render().unwrap(),
-        "\n\n<p>Hello world!</p>\n\n[\n<p>Parent body content</p>\n]\n\n"
+        "\n<p>Hello world!</p>\n\n[\n<p>Parent body content</p>\n]\n\n"
     );
 }
 
@@ -79,5 +79,27 @@ fn test_fragment_unused_expression() {
         required: "Required",
     };
 
-    assert_eq!(unused_expr.render().unwrap(), "\n\n<p>Required</p>\n");
+    assert_eq!(unused_expr.render().unwrap(), "\n<p>Required</p>\n");
+}
+
+#[derive(Template)]
+#[template(path = "blocks.txt", block = "index")]
+struct RenderInPlace<'a> {
+    s1: Section<'a>,
+}
+
+#[derive(Template)]
+#[template(path = "blocks.txt", block = "section")]
+struct Section<'a> {
+    values: &'a [&'a str],
+}
+
+#[test]
+fn test_specific_block() {
+    let s1 = Section {
+        values: &["a", "b", "c"],
+    };
+    assert_eq!(s1.render().unwrap(), "[abc]");
+    let t = RenderInPlace { s1 };
+    assert_eq!(t.render().unwrap(), "\nSection: [abc]\n");
 }
diff --git a/testing/tests/inheritance.rs b/testing/tests/inheritance.rs
index 87232b37..926008f6 100644
--- a/testing/tests/inheritance.rs
+++ b/testing/tests/inheritance.rs
@@ -329,14 +329,9 @@ fn test_flat_deep() {
 
 #[derive(Template)]
 #[template(path = "let-base.html")]
+#[allow(dead_code)]
 struct LetBase {}
 
-#[test]
-fn test_let_base() {
-    let t = LetBase {};
-    assert_eq!(t.render().unwrap(), "");
-}
-
 #[derive(Template)]
 #[template(path = "let-child.html")]
 struct LetChild {}
diff --git a/testing/tests/simple.rs b/testing/tests/simple.rs
index 40121288..a8ecb76f 100644
--- a/testing/tests/simple.rs
+++ b/testing/tests/simple.rs
@@ -345,6 +345,7 @@ struct FunctionTemplate;
 
 impl FunctionTemplate {
     #[allow(clippy::trivially_copy_pass_by_ref)]
+    #[allow(dead_code)]
     fn world3(&self, s: &str, v: u8) -> String {
         format!("world{s}{v}")
     }