mirror of
https://github.com/askama-rs/askama.git
synced 2025-09-29 22:11:17 +00:00
Better error messages using cuts
This commit is contained in:
parent
268d8250fb
commit
4123ec37a2
@ -1,7 +1,7 @@
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::{escaped, is_not, tag, take_until};
|
||||
use nom::character::complete::{anychar, char, digit1};
|
||||
use nom::combinator::{complete, map, opt, recognize, value};
|
||||
use nom::combinator::{complete, cut, map, opt, recognize, value};
|
||||
use nom::error::{Error, ParseError};
|
||||
use nom::multi::{fold_many0, many0, many1, separated_list0, separated_list1};
|
||||
use nom::sequence::{delimited, pair, preceded, terminated, tuple};
|
||||
@ -387,13 +387,13 @@ fn target(i: &[u8]) -> IResult<&[u8], Target<'_>> {
|
||||
}
|
||||
|
||||
let mut targets = vec![first_target];
|
||||
let (i, _) = tuple((
|
||||
let (i, _) = cut(tuple((
|
||||
fold_many0(preceded(ws(tag(",")), target), (), |_, target| {
|
||||
targets.push(target);
|
||||
}),
|
||||
opt(ws(tag(","))),
|
||||
ws(tag(")")),
|
||||
))(i)?;
|
||||
ws(cut(tag(")"))),
|
||||
)))(i)?;
|
||||
return Ok((i, Target::Tuple(Vec::new(), targets)));
|
||||
}
|
||||
|
||||
@ -408,8 +408,8 @@ fn target(i: &[u8]) -> IResult<&[u8], Target<'_>> {
|
||||
let (i, targets) = alt((
|
||||
map(tag(")"), |_| Vec::new()),
|
||||
terminated(
|
||||
separated_list1(ws(tag(",")), target),
|
||||
pair(opt(ws(tag(","))), ws(tag(")"))),
|
||||
cut(separated_list1(ws(tag(",")), target)),
|
||||
pair(opt(ws(tag(","))), ws(cut(tag(")")))),
|
||||
),
|
||||
))(i)?;
|
||||
return Ok((i, Target::Tuple(path, targets)));
|
||||
@ -420,8 +420,8 @@ fn target(i: &[u8]) -> IResult<&[u8], Target<'_>> {
|
||||
let (i, targets) = alt((
|
||||
map(tag("}"), |_| Vec::new()),
|
||||
terminated(
|
||||
separated_list1(ws(tag(",")), named_target),
|
||||
pair(opt(ws(tag(","))), ws(tag("}"))),
|
||||
cut(separated_list1(ws(tag(",")), named_target)),
|
||||
pair(opt(ws(tag(","))), ws(cut(tag("}")))),
|
||||
),
|
||||
))(i)?;
|
||||
return Ok((i, Target::Struct(path, targets)));
|
||||
@ -664,12 +664,11 @@ fn expr_any(i: &[u8]) -> IResult<&[u8], Expr<'_>> {
|
||||
fn expr_node<'a>(i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8], Node<'a>> {
|
||||
let mut p = tuple((
|
||||
|i| tag_expr_start(i, s),
|
||||
opt(tag("-")),
|
||||
ws(expr_any),
|
||||
opt(tag("-")),
|
||||
|i| tag_expr_end(i, s),
|
||||
cut(tuple((opt(tag("-")), ws(expr_any), opt(tag("-")), |i| {
|
||||
tag_expr_end(i, s)
|
||||
}))),
|
||||
));
|
||||
let (i, (_, pws, expr, nws, _)) = p(i)?;
|
||||
let (i, (_, (pws, expr, nws, _))) = p(i)?;
|
||||
Ok((i, Node::Expr(Ws(pws.is_some(), nws.is_some()), expr)))
|
||||
}
|
||||
|
||||
@ -677,12 +676,14 @@ fn block_call(i: &[u8]) -> IResult<&[u8], Node<'_>> {
|
||||
let mut p = tuple((
|
||||
opt(tag("-")),
|
||||
ws(tag("call")),
|
||||
opt(tuple((ws(identifier), ws(tag("::"))))),
|
||||
ws(identifier),
|
||||
ws(arguments),
|
||||
opt(tag("-")),
|
||||
cut(tuple((
|
||||
opt(tuple((ws(identifier), ws(tag("::"))))),
|
||||
ws(identifier),
|
||||
ws(arguments),
|
||||
opt(tag("-")),
|
||||
))),
|
||||
));
|
||||
let (i, (pws, _, scope, name, args, nws)) = p(i)?;
|
||||
let (i, (pws, _, (scope, name, args, nws))) = p(i)?;
|
||||
let scope = scope.map(|(scope, _)| scope);
|
||||
Ok((
|
||||
i,
|
||||
@ -691,23 +692,19 @@ fn block_call(i: &[u8]) -> IResult<&[u8], Node<'_>> {
|
||||
}
|
||||
|
||||
fn cond_if(i: &[u8]) -> IResult<&[u8], CondTest<'_>> {
|
||||
let mut p = tuple((
|
||||
let mut p = preceded(
|
||||
ws(tag("if")),
|
||||
opt(tuple((
|
||||
ws(alt((tag("let"), tag("set")))),
|
||||
ws(target),
|
||||
ws(tag("=")),
|
||||
cut(tuple((
|
||||
opt(delimited(
|
||||
ws(alt((tag("let"), tag("set")))),
|
||||
ws(target),
|
||||
ws(tag("=")),
|
||||
)),
|
||||
ws(expr_any),
|
||||
))),
|
||||
ws(expr_any),
|
||||
));
|
||||
let (i, (_, dest, expr)) = p(i)?;
|
||||
Ok((
|
||||
i,
|
||||
CondTest {
|
||||
target: dest.map(|(_, target, _)| target),
|
||||
expr,
|
||||
},
|
||||
))
|
||||
);
|
||||
let (i, (target, expr)) = p(i)?;
|
||||
Ok((i, CondTest { target, expr }))
|
||||
}
|
||||
|
||||
fn cond_block<'a>(i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8], Cond<'a>> {
|
||||
@ -715,12 +712,14 @@ fn cond_block<'a>(i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8], Cond<'a>>
|
||||
|i| tag_block_start(i, s),
|
||||
opt(tag("-")),
|
||||
ws(tag("else")),
|
||||
opt(cond_if),
|
||||
opt(tag("-")),
|
||||
|i| tag_block_end(i, s),
|
||||
|i| parse_template(i, s),
|
||||
cut(tuple((
|
||||
opt(cond_if),
|
||||
opt(tag("-")),
|
||||
|i| tag_block_end(i, s),
|
||||
cut(|i| parse_template(i, s)),
|
||||
))),
|
||||
));
|
||||
let (i, (_, pws, _, cond, nws, _, block)) = p(i)?;
|
||||
let (i, (_, pws, _, (cond, nws, _, block))) = p(i)?;
|
||||
Ok((i, (Ws(pws.is_some(), nws.is_some()), cond, block)))
|
||||
}
|
||||
|
||||
@ -728,16 +727,22 @@ fn block_if<'a>(i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8], Node<'a>> {
|
||||
let mut p = tuple((
|
||||
opt(tag("-")),
|
||||
cond_if,
|
||||
opt(tag("-")),
|
||||
|i| tag_block_end(i, s),
|
||||
|i| parse_template(i, s),
|
||||
many0(|i| cond_block(i, s)),
|
||||
|i| tag_block_start(i, s),
|
||||
opt(tag("-")),
|
||||
ws(tag("endif")),
|
||||
opt(tag("-")),
|
||||
cut(tuple((
|
||||
opt(tag("-")),
|
||||
|i| tag_block_end(i, s),
|
||||
cut(tuple((
|
||||
|i| parse_template(i, s),
|
||||
many0(|i| cond_block(i, s)),
|
||||
cut(tuple((
|
||||
|i| tag_block_start(i, s),
|
||||
opt(tag("-")),
|
||||
ws(tag("endif")),
|
||||
opt(tag("-")),
|
||||
))),
|
||||
))),
|
||||
))),
|
||||
));
|
||||
let (i, (pws1, cond, nws1, _, block, elifs, _, pws2, _, nws2)) = p(i)?;
|
||||
let (i, (pws1, cond, (nws1, _, (block, elifs, (_, pws2, _, nws2))))) = p(i)?;
|
||||
|
||||
let mut res = vec![(Ws(pws1.is_some(), nws1.is_some()), Some(cond), block)];
|
||||
res.extend(elifs);
|
||||
@ -749,11 +754,13 @@ fn match_else_block<'a>(i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8], Whe
|
||||
|i| tag_block_start(i, s),
|
||||
opt(tag("-")),
|
||||
ws(tag("else")),
|
||||
opt(tag("-")),
|
||||
|i| tag_block_end(i, s),
|
||||
|i| parse_template(i, s),
|
||||
cut(tuple((
|
||||
opt(tag("-")),
|
||||
|i| tag_block_end(i, s),
|
||||
cut(|i| parse_template(i, s)),
|
||||
))),
|
||||
));
|
||||
let (i, (_, pws, _, nws, _, block)) = p(i)?;
|
||||
let (i, (_, pws, _, (nws, _, block))) = p(i)?;
|
||||
Ok((
|
||||
i,
|
||||
(Ws(pws.is_some(), nws.is_some()), Target::Name("_"), block),
|
||||
@ -765,12 +772,14 @@ fn when_block<'a>(i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8], When<'a>>
|
||||
|i| tag_block_start(i, s),
|
||||
opt(tag("-")),
|
||||
ws(tag("when")),
|
||||
ws(target),
|
||||
opt(tag("-")),
|
||||
|i| tag_block_end(i, s),
|
||||
|i| parse_template(i, s),
|
||||
cut(tuple((
|
||||
ws(target),
|
||||
opt(tag("-")),
|
||||
|i| tag_block_end(i, s),
|
||||
cut(|i| parse_template(i, s)),
|
||||
))),
|
||||
));
|
||||
let (i, (_, pws, _, target, nws, _, block)) = p(i)?;
|
||||
let (i, (_, pws, _, (target, nws, _, block))) = p(i)?;
|
||||
Ok((i, (Ws(pws.is_some(), nws.is_some()), target, block)))
|
||||
}
|
||||
|
||||
@ -778,18 +787,26 @@ fn block_match<'a>(i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8], Node<'a>
|
||||
let mut p = tuple((
|
||||
opt(tag("-")),
|
||||
ws(tag("match")),
|
||||
ws(expr_any),
|
||||
opt(tag("-")),
|
||||
|i| tag_block_end(i, s),
|
||||
opt(|i| take_content(i, s)),
|
||||
many1(|i| when_block(i, s)),
|
||||
opt(|i| match_else_block(i, s)),
|
||||
ws(|i| tag_block_start(i, s)),
|
||||
opt(tag("-")),
|
||||
ws(tag("endmatch")),
|
||||
opt(tag("-")),
|
||||
cut(tuple((
|
||||
ws(expr_any),
|
||||
opt(tag("-")),
|
||||
|i| tag_block_end(i, s),
|
||||
cut(tuple((
|
||||
opt(|i| take_content(i, s)),
|
||||
many1(|i| when_block(i, s)),
|
||||
cut(tuple((
|
||||
opt(|i| match_else_block(i, s)),
|
||||
cut(tuple((
|
||||
ws(|i| tag_block_start(i, s)),
|
||||
opt(tag("-")),
|
||||
ws(tag("endmatch")),
|
||||
opt(tag("-")),
|
||||
))),
|
||||
))),
|
||||
))),
|
||||
))),
|
||||
));
|
||||
let (i, (pws1, _, expr, nws1, _, inter, arms, else_arm, _, pws2, _, nws2)) = p(i)?;
|
||||
let (i, (pws1, _, (expr, nws1, _, (inter, arms, (else_arm, (_, pws2, _, nws2)))))) = p(i)?;
|
||||
|
||||
let mut arms = arms;
|
||||
if let Some(arm) = else_arm {
|
||||
@ -828,11 +845,13 @@ fn block_let(i: &[u8]) -> IResult<&[u8], Node<'_>> {
|
||||
let mut p = tuple((
|
||||
opt(tag("-")),
|
||||
ws(alt((tag("let"), tag("set")))),
|
||||
ws(target),
|
||||
opt(tuple((ws(tag("=")), ws(expr_any)))),
|
||||
opt(tag("-")),
|
||||
cut(tuple((
|
||||
ws(target),
|
||||
opt(tuple((ws(tag("=")), ws(expr_any)))),
|
||||
opt(tag("-")),
|
||||
))),
|
||||
));
|
||||
let (i, (pws, _, var, val, nws)) = p(i)?;
|
||||
let (i, (pws, _, (var, val, nws))) = p(i)?;
|
||||
|
||||
Ok((
|
||||
i,
|
||||
@ -848,18 +867,26 @@ fn block_for<'a>(i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8], Node<'a>>
|
||||
let mut p = tuple((
|
||||
opt(tag("-")),
|
||||
ws(tag("for")),
|
||||
ws(target),
|
||||
ws(tag("in")),
|
||||
ws(expr_any),
|
||||
opt(tag("-")),
|
||||
|i| tag_block_end(i, s),
|
||||
|i| parse_template(i, s),
|
||||
|i| tag_block_start(i, s),
|
||||
opt(tag("-")),
|
||||
ws(tag("endfor")),
|
||||
opt(tag("-")),
|
||||
cut(tuple((
|
||||
ws(target),
|
||||
ws(tag("in")),
|
||||
cut(tuple((
|
||||
ws(expr_any),
|
||||
opt(tag("-")),
|
||||
|i| tag_block_end(i, s),
|
||||
cut(tuple((
|
||||
|i| parse_template(i, s),
|
||||
cut(tuple((
|
||||
|i| tag_block_start(i, s),
|
||||
opt(tag("-")),
|
||||
ws(tag("endfor")),
|
||||
opt(tag("-")),
|
||||
))),
|
||||
))),
|
||||
))),
|
||||
))),
|
||||
));
|
||||
let (i, (pws1, _, var, _, iter, nws1, _, block, _, pws2, _, nws2)) = p(i)?;
|
||||
let (i, (pws1, _, (var, _, (iter, nws1, _, (block, (_, pws2, _, nws2)))))) = p(i)?;
|
||||
Ok((
|
||||
i,
|
||||
Node::Loop(
|
||||
@ -881,21 +908,22 @@ fn block_block<'a>(i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8], Node<'a>
|
||||
let mut start = tuple((
|
||||
opt(tag("-")),
|
||||
ws(tag("block")),
|
||||
ws(identifier),
|
||||
opt(tag("-")),
|
||||
|i| tag_block_end(i, s),
|
||||
|i| parse_template(i, s),
|
||||
cut(tuple((ws(identifier), opt(tag("-")), |i| {
|
||||
tag_block_end(i, s)
|
||||
}))),
|
||||
));
|
||||
let (i, (pws1, _, name, nws1, _, contents)) = start(i)?;
|
||||
let (i, (pws1, _, (name, nws1, _))) = start(i)?;
|
||||
|
||||
let mut end = tuple((
|
||||
|i| tag_block_start(i, s),
|
||||
opt(tag("-")),
|
||||
ws(tag("endblock")),
|
||||
opt(ws(tag(name))),
|
||||
opt(tag("-")),
|
||||
));
|
||||
let (i, (_, pws2, _, _, nws2)) = end(i)?;
|
||||
let mut end = cut(tuple((
|
||||
|i| parse_template(i, s),
|
||||
cut(tuple((
|
||||
|i| tag_block_start(i, s),
|
||||
opt(tag("-")),
|
||||
ws(tag("endblock")),
|
||||
cut(tuple((opt(ws(tag(name))), opt(tag("-"))))),
|
||||
))),
|
||||
)));
|
||||
let (i, (contents, (_, pws2, _, (_, nws2)))) = end(i)?;
|
||||
|
||||
Ok((
|
||||
i,
|
||||
@ -912,10 +940,9 @@ fn block_include(i: &[u8]) -> IResult<&[u8], Node<'_>> {
|
||||
let mut p = tuple((
|
||||
opt(tag("-")),
|
||||
ws(tag("include")),
|
||||
ws(expr_str_lit),
|
||||
opt(tag("-")),
|
||||
cut(pair(ws(expr_str_lit), opt(tag("-")))),
|
||||
));
|
||||
let (i, (pws, _, name, nws)) = p(i)?;
|
||||
let (i, (pws, _, (name, nws))) = p(i)?;
|
||||
Ok((
|
||||
i,
|
||||
Node::Include(
|
||||
@ -932,12 +959,13 @@ fn block_import(i: &[u8]) -> IResult<&[u8], Node<'_>> {
|
||||
let mut p = tuple((
|
||||
opt(tag("-")),
|
||||
ws(tag("import")),
|
||||
ws(expr_str_lit),
|
||||
ws(tag("as")),
|
||||
ws(identifier),
|
||||
opt(tag("-")),
|
||||
cut(tuple((
|
||||
ws(expr_str_lit),
|
||||
ws(tag("as")),
|
||||
cut(pair(ws(identifier), opt(tag("-")))),
|
||||
))),
|
||||
));
|
||||
let (i, (pws, _, name, _, scope, nws)) = p(i)?;
|
||||
let (i, (pws, _, (name, _, (scope, nws)))) = p(i)?;
|
||||
Ok((
|
||||
i,
|
||||
Node::Import(
|
||||
@ -955,18 +983,24 @@ fn block_macro<'a>(i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8], Node<'a>
|
||||
let mut p = tuple((
|
||||
opt(tag("-")),
|
||||
ws(tag("macro")),
|
||||
ws(identifier),
|
||||
ws(parameters),
|
||||
opt(tag("-")),
|
||||
|i| tag_block_end(i, s),
|
||||
|i| parse_template(i, s),
|
||||
|i| tag_block_start(i, s),
|
||||
opt(tag("-")),
|
||||
ws(tag("endmacro")),
|
||||
opt(tag("-")),
|
||||
cut(tuple((
|
||||
ws(identifier),
|
||||
ws(parameters),
|
||||
opt(tag("-")),
|
||||
|i| tag_block_end(i, s),
|
||||
cut(tuple((
|
||||
|i| parse_template(i, s),
|
||||
cut(tuple((
|
||||
|i| tag_block_start(i, s),
|
||||
opt(tag("-")),
|
||||
ws(tag("endmacro")),
|
||||
opt(tag("-")),
|
||||
))),
|
||||
))),
|
||||
))),
|
||||
));
|
||||
|
||||
let (i, (pws1, _, name, params, nws1, _, contents, _, pws2, _, nws2)) = p(i)?;
|
||||
let (i, (pws1, _, (name, params, nws1, _, (contents, (_, pws2, _, nws2))))) = p(i)?;
|
||||
if name == "super" {
|
||||
panic!("invalid macro name 'super'");
|
||||
}
|
||||
@ -989,16 +1023,18 @@ fn block_raw<'a>(i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8], Node<'a>>
|
||||
let mut p = tuple((
|
||||
opt(tag("-")),
|
||||
ws(tag("raw")),
|
||||
opt(tag("-")),
|
||||
|i| tag_block_end(i, s),
|
||||
take_until("{% endraw %}"),
|
||||
|i| tag_block_start(i, s),
|
||||
opt(tag("-")),
|
||||
ws(tag("endraw")),
|
||||
opt(tag("-")),
|
||||
cut(tuple((
|
||||
opt(tag("-")),
|
||||
|i| tag_block_end(i, s),
|
||||
take_until("{% endraw %}"),
|
||||
|i| tag_block_start(i, s),
|
||||
opt(tag("-")),
|
||||
ws(tag("endraw")),
|
||||
opt(tag("-")),
|
||||
))),
|
||||
));
|
||||
|
||||
let (i, (pws1, _, nws1, _, contents, _, pws2, _, nws2)) = p(i)?;
|
||||
let (i, (pws1, _, (nws1, _, contents, _, pws2, _, nws2))) = p(i)?;
|
||||
let str_contents = str::from_utf8(contents).unwrap();
|
||||
Ok((
|
||||
i,
|
||||
@ -1026,7 +1062,7 @@ fn block_node<'a>(i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8], Node<'a>>
|
||||
|i| block_macro(i, s),
|
||||
|i| block_raw(i, s),
|
||||
)),
|
||||
|i| tag_block_end(i, s),
|
||||
cut(|i| tag_block_end(i, s)),
|
||||
));
|
||||
let (i, (_, contents, _)) = p(i)?;
|
||||
Ok((i, contents))
|
||||
@ -1053,11 +1089,13 @@ fn block_comment_body<'a>(mut i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8
|
||||
fn block_comment<'a>(i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8], Node<'a>> {
|
||||
let mut p = tuple((
|
||||
|i| tag_comment_start(i, s),
|
||||
opt(tag("-")),
|
||||
|i| block_comment_body(i, s),
|
||||
|i| tag_comment_end(i, s),
|
||||
cut(tuple((
|
||||
opt(tag("-")),
|
||||
|i| block_comment_body(i, s),
|
||||
|i| tag_comment_end(i, s),
|
||||
))),
|
||||
));
|
||||
let (i, (_, pws, tail, _)) = p(i)?;
|
||||
let (i, (_, (pws, tail, _))) = p(i)?;
|
||||
Ok((i, Node::Comment(Ws(pws.is_some(), tail.ends_with(b"-")))))
|
||||
}
|
||||
|
||||
@ -1099,12 +1137,29 @@ pub fn parse<'a>(src: &'a str, syntax: &'a Syntax<'a>) -> Result<Vec<Node<'a>>,
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
Err(nom::Err::Error(err)) => {
|
||||
Err(format!("problems parsing template source: {:?}", err).into())
|
||||
}
|
||||
Err(nom::Err::Failure(err)) => {
|
||||
Err(format!("problems parsing template source: {:?}", err).into())
|
||||
|
||||
Err(nom::Err::Error(err)) | Err(nom::Err::Failure(err)) => {
|
||||
let nom::error::Error { input, .. } = err;
|
||||
let offset = src.len() - input.len();
|
||||
let (source_before, source_after) = src.split_at(offset);
|
||||
|
||||
let source_after = match source_after.char_indices().enumerate().take(41).last() {
|
||||
Some((40, (i, _))) => format!("{:?}...", &source_after[..i]),
|
||||
_ => format!("{:?}", source_after),
|
||||
};
|
||||
|
||||
let (row, last_line) = source_before.lines().enumerate().last().unwrap();
|
||||
let column = last_line.chars().count();
|
||||
|
||||
let msg = format!(
|
||||
"problems parsing template source at row {}, column {} near:\n{}",
|
||||
row + 1,
|
||||
column,
|
||||
source_after,
|
||||
);
|
||||
Err(msg.into())
|
||||
}
|
||||
|
||||
Err(nom::Err::Incomplete(_)) => Err("parsing incomplete".into()),
|
||||
}
|
||||
}
|
||||
|
11
testing/tests/ui/typo_in_keyword.rs
Normal file
11
testing/tests/ui/typo_in_keyword.rs
Normal file
@ -0,0 +1,11 @@
|
||||
use askama::Template;
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(
|
||||
source = "{%for i in 1..=10%}{{i}}{%endfo%}\n1234567890123456789012345678901234567890",
|
||||
ext = "txt"
|
||||
)]
|
||||
struct MyTemplate;
|
||||
|
||||
fn main() {
|
||||
}
|
8
testing/tests/ui/typo_in_keyword.stderr
Normal file
8
testing/tests/ui/typo_in_keyword.stderr
Normal file
@ -0,0 +1,8 @@
|
||||
error: problems parsing template source at row 1, column 26 near:
|
||||
"endfo%}\n12345678901234567890123456789012"...
|
||||
--> $DIR/typo_in_keyword.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)
|
Loading…
x
Reference in New Issue
Block a user