ok/jj
1
0
Fork 0
forked from mirrors/jj

templater: include actual type name in error messages

This commit is contained in:
Yuya Nishihara 2024-04-24 20:02:50 +09:00
parent 5394f342ce
commit a63dbcc329
4 changed files with 30 additions and 21 deletions

View file

@ -1094,9 +1094,11 @@ pub fn expect_boolean_expression<'a, L: TemplateLanguage<'a> + ?Sized>(
build_ctx: &BuildContext<L::Property>,
node: &ExpressionNode,
) -> TemplateParseResult<Box<dyn TemplateProperty<Output = bool> + 'a>> {
build_expression(language, build_ctx, node)?
let expression = build_expression(language, build_ctx, node)?;
let actual_type = expression.type_name();
expression
.try_into_boolean()
.ok_or_else(|| TemplateParseError::expected_type("Boolean", node.span))
.ok_or_else(|| TemplateParseError::expected_type("Boolean", actual_type, node.span))
}
pub fn expect_integer_expression<'a, L: TemplateLanguage<'a> + ?Sized>(
@ -1104,9 +1106,11 @@ pub fn expect_integer_expression<'a, L: TemplateLanguage<'a> + ?Sized>(
build_ctx: &BuildContext<L::Property>,
node: &ExpressionNode,
) -> TemplateParseResult<Box<dyn TemplateProperty<Output = i64> + 'a>> {
build_expression(language, build_ctx, node)?
let expression = build_expression(language, build_ctx, node)?;
let actual_type = expression.type_name();
expression
.try_into_integer()
.ok_or_else(|| TemplateParseError::expected_type("Integer", node.span))
.ok_or_else(|| TemplateParseError::expected_type("Integer", actual_type, node.span))
}
/// If the given expression `node` is of `Integer` type, converts it to `isize`.
@ -1138,9 +1142,11 @@ pub fn expect_plain_text_expression<'a, L: TemplateLanguage<'a> + ?Sized>(
) -> TemplateParseResult<Box<dyn TemplateProperty<Output = String> + 'a>> {
// Since any formattable type can be converted to a string property,
// the expected type is not a String, but a Template.
build_expression(language, build_ctx, node)?
let expression = build_expression(language, build_ctx, node)?;
let actual_type = expression.type_name();
expression
.try_into_plain_text()
.ok_or_else(|| TemplateParseError::expected_type("Template", node.span))
.ok_or_else(|| TemplateParseError::expected_type("Template", actual_type, node.span))
}
pub fn expect_template_expression<'a, L: TemplateLanguage<'a> + ?Sized>(
@ -1148,9 +1154,11 @@ pub fn expect_template_expression<'a, L: TemplateLanguage<'a> + ?Sized>(
build_ctx: &BuildContext<L::Property>,
node: &ExpressionNode,
) -> TemplateParseResult<Box<dyn Template + 'a>> {
build_expression(language, build_ctx, node)?
let expression = build_expression(language, build_ctx, node)?;
let actual_type = expression.type_name();
expression
.try_into_template()
.ok_or_else(|| TemplateParseError::expected_type("Template", node.span))
.ok_or_else(|| TemplateParseError::expected_type("Template", actual_type, node.span))
}
#[cfg(test)]
@ -1326,7 +1334,7 @@ mod tests {
1 | true && 123
| ^-^
|
= Expected expression of type "Boolean"
= Expected expression of type "Boolean", but actual type is "Integer"
"###);
insta::assert_snapshot!(env.parse_err(r#"description.first_line().foo()"#), @r###"
@ -1360,7 +1368,7 @@ mod tests {
1 | (-empty)
| ^---^
|
= Expected expression of type "Integer"
= Expected expression of type "Integer", but actual type is "Boolean"
"###);
insta::assert_snapshot!(env.parse_err(r#"("foo" ++ "bar").baz()"#), @r###"
@ -1430,7 +1438,7 @@ mod tests {
1 | if(label("foo", "bar"), "baz")
| ^-----------------^
|
= Expected expression of type "Boolean"
= Expected expression of type "Boolean", but actual type is "Template"
"###);
insta::assert_snapshot!(env.parse_err(r#"|x| description"#), @r###"
@ -1455,7 +1463,7 @@ mod tests {
1 | self
| ^--^
|
= Expected expression of type "Template"
= Expected expression of type "Template", but actual type is "Self"
"###);
}
@ -1480,7 +1488,7 @@ mod tests {
1 | if(0, true, false)
| ^
|
= Expected expression of type "Boolean"
= Expected expression of type "Boolean", but actual type is "Integer"
"###);
insta::assert_snapshot!(env.parse_err(r#"if(label("", ""), true, false)"#), @r###"
@ -1489,7 +1497,7 @@ mod tests {
1 | if(label("", ""), true, false)
| ^-----------^
|
= Expected expression of type "Boolean"
= Expected expression of type "Boolean", but actual type is "Template"
"###);
insta::assert_snapshot!(env.parse_err(r#"if(sl0.map(|x| x), true, false)"#), @r###"
--> 1:4
@ -1497,7 +1505,7 @@ mod tests {
1 | if(sl0.map(|x| x), true, false)
| ^------------^
|
= Expected expression of type "Boolean"
= Expected expression of type "Boolean", but actual type is "ListTemplate"
"###);
}

View file

@ -154,8 +154,9 @@ impl TemplateParseError {
)
}
pub fn expected_type(type_name: &str, span: pest::Span<'_>) -> Self {
let message = format!(r#"Expected expression of type "{type_name}""#);
pub fn expected_type(expected: &str, actual: &str, span: pest::Span<'_>) -> Self {
let message =
format!(r#"Expected expression of type "{expected}", but actual type is "{actual}""#);
TemplateParseError::expression(message, span)
}

View file

@ -54,13 +54,13 @@ fn test_log_parents() {
// Commit object isn't printable
let stderr = test_env.jj_cmd_failure(&repo_path, &["log", "-T", "parents"]);
insta::assert_snapshot!(stderr, @r###"
Error: Failed to parse template: Expected expression of type "Template"
Error: Failed to parse template: Expected expression of type "Template", but actual type is "List<Commit>"
Caused by: --> 1:1
|
1 | parents
| ^-----^
|
= Expected expression of type "Template"
= Expected expression of type "Template", but actual type is "List<Commit>"
"###);
// Redundant argument passed to keyword method

View file

@ -208,7 +208,7 @@ fn test_templater_alias() {
1 | identity(identity(commit_id.short("")))
| ^^
|
= Expected expression of type "Integer"
= Expected expression of type "Integer", but actual type is "String"
"###);
insta::assert_snapshot!(render_err("commit_id ++ recurse"), @r###"
@ -273,7 +273,7 @@ fn test_templater_alias() {
1 | coalesce(label("x", "not boolean"), "")
| ^-----------------------^
|
= Expected expression of type "Boolean"
= Expected expression of type "Boolean", but actual type is "Template"
"###);
}