diff --git a/src/eval/args.rs b/src/eval/args.rs index aadd7d549..8617bd93a 100644 --- a/src/eval/args.rs +++ b/src/eval/args.rs @@ -158,7 +158,13 @@ impl Args { /// argument. pub fn finish(self) -> SourceResult<()> { if let Some(arg) = self.items.first() { - bail!(arg.span, "unexpected argument"); + bail!( + arg.span, + match &arg.name { + Some(name) => eco_format!("unexpected argument: {}", name), + _ => eco_format!("unexpected argument"), + } + ) } Ok(()) } diff --git a/src/eval/scope.rs b/src/eval/scope.rs index e241cac59..f2207188a 100644 --- a/src/eval/scope.rs +++ b/src/eval/scope.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; use std::fmt::{self, Debug, Formatter}; use std::hash::Hash; -use ecow::EcoString; +use ecow::{eco_format, EcoString}; use super::{Library, Value}; use crate::diag::StrResult; @@ -42,7 +42,7 @@ impl<'a> Scopes<'a> { .chain(self.scopes.iter().rev()) .chain(self.base.map(|base| base.global.scope())) .find_map(|scope| scope.get(var)) - .ok_or("unknown variable")?) + .ok_or(eco_format!("unknown variable: {}", var))?) } /// Try to access a variable immutably in math. @@ -51,7 +51,7 @@ impl<'a> Scopes<'a> { .chain(self.scopes.iter().rev()) .chain(self.base.map(|base| base.math.scope())) .find_map(|scope| scope.get(var)) - .ok_or("unknown variable")?) + .ok_or(eco_format!("unknown variable: {}", var))?) } /// Try to access a variable mutably. @@ -61,8 +61,8 @@ impl<'a> Scopes<'a> { .find_map(|scope| scope.get_mut(var)) .ok_or_else(|| { match self.base.and_then(|base| base.global.scope().get(var)) { - Some(_) => "cannot mutate a constant", - _ => "unknown variable", + Some(_) => eco_format!("cannot mutate a constant: {}", var), + _ => eco_format!("unknown variable: {}", var), } })? } diff --git a/src/syntax/lexer.rs b/src/syntax/lexer.rs index 7961d4cac..dcd2509af 100644 --- a/src/syntax/lexer.rs +++ b/src/syntax/lexer.rs @@ -217,7 +217,7 @@ impl Lexer<'_> { .and_then(std::char::from_u32) .is_none() { - return self.error("invalid unicode escape sequence"); + return self.error(eco_format!("invalid unicode codepoint: {}", hex)); } return SyntaxKind::Escape; @@ -585,10 +585,10 @@ impl Lexer<'_> { SyntaxKind::Float } else { return self.error(match base { - 2 => "invalid binary number", - 8 => "invalid octal number", - 16 => "invalid hexadecimal number", - _ => "invalid number", + 2 => eco_format!("invalid binary number: 0b{}", number), + 8 => eco_format!("invalid octal number: 0o{}", number), + 16 => eco_format!("invalid hexadecimal number: 0x{}", number), + _ => eco_format!("invalid number: {}", number), }); }; @@ -600,7 +600,7 @@ impl Lexer<'_> { suffix, "pt" | "mm" | "cm" | "in" | "deg" | "rad" | "em" | "fr" | "%" ) { - return self.error("invalid number suffix"); + return self.error(eco_format!("invalid number suffix: {}", suffix)); } SyntaxKind::Numeric diff --git a/src/syntax/parser.rs b/src/syntax/parser.rs index e68074045..4bc25a30d 100644 --- a/src/syntax/parser.rs +++ b/src/syntax/parser.rs @@ -1046,8 +1046,8 @@ fn validate_dict(p: &mut Parser, m: Marker) { None => first.text().clone(), }; - if !used.insert(key) { - first.convert_to_error("duplicate key"); + if !used.insert(key.clone()) { + first.convert_to_error(eco_format!("duplicate key: {}", key)); child.make_erroneous(); } } @@ -1073,13 +1073,19 @@ fn validate_params(p: &mut Parser, m: Marker) { match child.kind() { SyntaxKind::Ident => { if !used.insert(child.text().clone()) { - child.convert_to_error("duplicate parameter"); + child.convert_to_error(eco_format!( + "duplicate parameter: {}", + child.text() + )); } } SyntaxKind::Named => { let Some(within) = child.children_mut().first_mut() else { return }; if !used.insert(within.text().clone()) { - within.convert_to_error("duplicate parameter"); + within.convert_to_error(eco_format!( + "duplicate parameter: {}", + within.text() + )); child.make_erroneous(); } } @@ -1101,7 +1107,10 @@ fn validate_params(p: &mut Parser, m: Marker) { continue; } if !used.insert(within.text().clone()) { - within.convert_to_error("duplicate parameter"); + within.convert_to_error(eco_format!( + "duplicate parameter: {}", + within.text() + )); child.make_erroneous(); } } @@ -1122,7 +1131,10 @@ fn validate_args(p: &mut Parser, m: Marker) { if child.kind() == SyntaxKind::Named { let Some(within) = child.children_mut().first_mut() else { return }; if !used.insert(within.text().clone()) { - within.convert_to_error("duplicate argument"); + within.convert_to_error(eco_format!( + "duplicate argument: {}", + within.text() + )); child.make_erroneous(); } } diff --git a/tests/typ/compiler/array.typ b/tests/typ/compiler/array.typ index 97b5da521..c9e85ed77 100644 --- a/tests/typ/compiler/array.typ +++ b/tests/typ/compiler/array.typ @@ -224,7 +224,7 @@ // Error: 4-6 unexpected end of block comment #(1*/2) -// Error: 6-8 invalid number suffix +// Error: 6-8 invalid number suffix: u #(1, 1u 2) // Error: 3-4 unexpected comma diff --git a/tests/typ/compiler/block.typ b/tests/typ/compiler/block.typ index bb23c0fe7..81c719da5 100644 --- a/tests/typ/compiler/block.typ +++ b/tests/typ/compiler/block.typ @@ -61,7 +61,7 @@ // Block directly in markup also creates a scope. #{ let x = 1 } -// Error: 7-8 unknown variable +// Error: 7-8 unknown variable: x #test(x, 1) --- @@ -73,7 +73,7 @@ #test(a, 1) -// Error: 3-4 unknown variable +// Error: 3-4 unknown variable: b #{b} --- @@ -83,7 +83,7 @@ test(b, 1) }} -// Error: 2-3 unknown variable +// Error: 2-3 unknown variable: b #b --- @@ -106,13 +106,13 @@ // Content blocks also create a scope. #[#let x = 1] -// Error: 2-3 unknown variable +// Error: 2-3 unknown variable: x #x --- // Multiple unseparated expressions in one line. -// Error: 2-4 invalid number suffix +// Error: 2-4 invalid number suffix: u #1u // Should output `1`. diff --git a/tests/typ/compiler/call.typ b/tests/typ/compiler/call.typ index f78dec20b..04eb29064 100644 --- a/tests/typ/compiler/call.typ +++ b/tests/typ/compiler/call.typ @@ -44,7 +44,7 @@ } --- -// Error: 26-30 duplicate argument +// Error: 26-30 duplicate argument: font #set text(font: "Arial", font: "Helvetica") --- diff --git a/tests/typ/compiler/closure.typ b/tests/typ/compiler/closure.typ index a1e51d56c..915de8509 100644 --- a/tests/typ/compiler/closure.typ +++ b/tests/typ/compiler/closure.typ @@ -106,7 +106,7 @@ --- // Don't leak environment. #{ - // Error: 16-17 unknown variable + // Error: 16-17 unknown variable: x let func() = x let x = "hi" func() @@ -141,22 +141,22 @@ test(greet("Typst"), "Hey, Typst!") test(greet("Typst", birthday: true), "Happy Birthday, Typst!") - // Error: 23-35 unexpected argument + // Error: 23-35 unexpected argument: whatever test(greet("Typst", whatever: 10)) } --- -// Error: 11-12 duplicate parameter +// Error: 11-12 duplicate parameter: x #let f(x, x) = none --- -// Error: 14-15 duplicate parameter -// Error: 23-24 duplicate parameter -// Error: 35-36 duplicate parameter +// Error: 14-15 duplicate parameter: a +// Error: 23-24 duplicate parameter: b +// Error: 35-36 duplicate parameter: b #let f(a, b, a: none, b: none, c, b) = none --- -// Error: 13-14 duplicate parameter +// Error: 13-14 duplicate parameter: a #let f(a, ..a) = none --- diff --git a/tests/typ/compiler/dict.typ b/tests/typ/compiler/dict.typ index fb0a59a36..6c982ed44 100644 --- a/tests/typ/compiler/dict.typ +++ b/tests/typ/compiler/dict.typ @@ -56,11 +56,11 @@ #test(dict, (a: 3, b: 1)) --- -// Error: 24-29 duplicate key +// Error: 24-29 duplicate key: first #(first: 1, second: 2, first: 3) --- -// Error: 17-20 duplicate key +// Error: 17-20 duplicate key: a #(a: 1, "b": 2, "a": 3) --- diff --git a/tests/typ/compiler/include.typ b/tests/typ/compiler/include.typ index fa2e84c04..586e869bb 100644 --- a/tests/typ/compiler/include.typ +++ b/tests/typ/compiler/include.typ @@ -24,7 +24,7 @@ #include "modules/chap1.typ" // The variables of the file should not appear in this scope. -// Error: 2-6 unknown variable +// Error: 2-6 unknown variable: name #name --- diff --git a/tests/typ/compiler/methods.typ b/tests/typ/compiler/methods.typ index 86faefbcb..afcb024fd 100644 --- a/tests/typ/compiler/methods.typ +++ b/tests/typ/compiler/methods.typ @@ -42,5 +42,5 @@ #(numbers.sorted() = 1) --- -// Error: 2-5 cannot mutate a constant +// Error: 2-5 cannot mutate a constant: box #box.push(1) diff --git a/tests/typ/compiler/ops-invalid.typ b/tests/typ/compiler/ops-invalid.typ index 8ccbb8b77..3ab629296 100644 --- a/tests/typ/compiler/ops-invalid.typ +++ b/tests/typ/compiler/ops-invalid.typ @@ -97,7 +97,7 @@ } --- -// Error: 4-5 unknown variable +// Error: 4-5 unknown variable: x #((x) = "") --- @@ -110,15 +110,15 @@ #(not x = "a") --- -// Error: 7-8 unknown variable +// Error: 7-8 unknown variable: x #(1 + x += 3) --- -// Error: 3-4 unknown variable +// Error: 3-4 unknown variable: z #(z = 1) --- -// Error: 3-7 cannot mutate a constant +// Error: 3-7 cannot mutate a constant: rect #(rect = "hi") --- diff --git a/tests/typ/compiler/ops.typ b/tests/typ/compiler/ops.typ index 1a9a2169b..a6c64cbd6 100644 --- a/tests/typ/compiler/ops.typ +++ b/tests/typ/compiler/ops.typ @@ -116,11 +116,11 @@ #test(0xA + 0xa, 0x14) --- -// Error: 2-7 invalid binary number +// Error: 2-7 invalid binary number: 0b123 #0b123 --- -// Error: 2-8 invalid hexadecimal number +// Error: 2-8 invalid hexadecimal number: 0x123z #0x123z --- @@ -201,7 +201,7 @@ #(x += "thing") #test(x, "something") --- -// Error: 3-6 cannot mutate a constant +// Error: 3-6 cannot mutate a constant: box #(box = 1) --- diff --git a/tests/typ/compiler/recursion.typ b/tests/typ/compiler/recursion.typ index ae214631a..1bd53178f 100644 --- a/tests/typ/compiler/recursion.typ +++ b/tests/typ/compiler/recursion.typ @@ -15,7 +15,7 @@ --- // Test with unnamed function. -// Error: 17-18 unknown variable +// Error: 17-18 unknown variable: f #let f = (n) => f(n - 1) #f(10) diff --git a/tests/typ/text/escape.typ b/tests/typ/text/escape.typ index 95a8a027a..e7ec9023e 100644 --- a/tests/typ/text/escape.typ +++ b/tests/typ/text/escape.typ @@ -27,7 +27,7 @@ let f() , ; : | + - /= == 12 "string" --- // Unicode codepoint does not exist. -// Error: 1-11 invalid unicode escape sequence +// Error: 1-11 invalid unicode codepoint: FFFFFF \u{FFFFFF} --- diff --git a/tests/typ/text/font.typ b/tests/typ/text/font.typ index 9844d066e..07d00d143 100644 --- a/tests/typ/text/font.typ +++ b/tests/typ/text/font.typ @@ -56,5 +56,5 @@ Emoji: 🐪, 🌋, 🏞 #set text(size: 10pt, 12pt) --- -// Error: 11-31 unexpected argument +// Error: 11-31 unexpected argument: something #set text(something: "invalid") diff --git a/tests/typ/visualize/shape-circle.typ b/tests/typ/visualize/shape-circle.typ index cde4b112c..34238d9a4 100644 --- a/tests/typ/visualize/shape-circle.typ +++ b/tests/typ/visualize/shape-circle.typ @@ -54,5 +54,5 @@ Expanded by height. --- // Radius wins over width and height. -// Error: 23-34 unexpected argument +// Error: 23-34 unexpected argument: width #circle(radius: 10pt, width: 50pt, height: 100pt, fill: eastern) diff --git a/tests/typ/visualize/shape-square.typ b/tests/typ/visualize/shape-square.typ index cb6552e48..a321dc4a6 100644 --- a/tests/typ/visualize/shape-square.typ +++ b/tests/typ/visualize/shape-square.typ @@ -35,5 +35,5 @@ --- // Size wins over width and height. -// Error: 09-20 unexpected argument +// Error: 09-20 unexpected argument: width #square(width: 10cm, height: 20cm, size: 1cm, fill: rgb("eb5278"))