summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorOrange <89233794+Ang149@users.noreply.github.com>2024-10-07 17:59:49 +0800
committerGitHub <noreply@github.com>2024-10-07 09:59:49 +0000
commitbb39d8f10a3820a1fbda6c50d8df5745ccc11de2 (patch)
tree43ca061ce3080edcb35197b67dfee10045bacb15 /crates
parent2a40eb518c737f4644099881a23295a650eb9ea1 (diff)
Improve hint when provided array for destructuring has fewer elements than expected (#5139)
Co-authored-by: Laurenz <laurmaedje@gmail.com>
Diffstat (limited to 'crates')
-rw-r--r--crates/typst/src/eval/binding.rs64
1 files changed, 39 insertions, 25 deletions
diff --git a/crates/typst/src/eval/binding.rs b/crates/typst/src/eval/binding.rs
index 4201faed..89e536c0 100644
--- a/crates/typst/src/eval/binding.rs
+++ b/crates/typst/src/eval/binding.rs
@@ -1,6 +1,8 @@
use std::collections::HashSet;
-use crate::diag::{bail, At, SourceResult};
+use ecow::eco_format;
+
+use crate::diag::{bail, error, At, SourceDiagnostic, SourceResult};
use crate::eval::{Access, Eval, Vm};
use crate::foundations::{Array, Dict, Value};
use crate::syntax::ast::{self, AstNode};
@@ -96,10 +98,7 @@ where
match p {
ast::DestructuringItem::Pattern(pattern) => {
let Ok(v) = value.at(i as i64, None) else {
- bail!(
- pattern.span(), "not enough elements to destructure";
- hint: "the provided array has a length of {len}",
- );
+ bail!(wrong_number_of_elements(destruct, len));
};
destructure_impl(vm, pattern, v, f)?;
i += 1;
@@ -108,10 +107,7 @@ where
let sink_size = (1 + len).checked_sub(destruct.items().count());
let sink = sink_size.and_then(|s| value.as_slice().get(i..i + s));
let (Some(sink_size), Some(sink)) = (sink_size, sink) else {
- bail!(
- spread.span(), "not enough elements to destructure";
- hint: "the provided array has a length of {len}",
- );
+ bail!(wrong_number_of_elements(destruct, len));
};
if let Some(expr) = spread.sink_expr() {
f(vm, expr, Value::Array(sink.into()))?;
@@ -125,22 +121,7 @@ where
}
if i < len {
- if i == 0 {
- bail!(
- destruct.span(), "too many elements to destructure";
- hint: "the provided array has a length of {len}, but the pattern expects an empty array",
- )
- } else if i == 1 {
- bail!(
- destruct.span(), "too many elements to destructure";
- hint: "the provided array has a length of {len}, but the pattern expects a single element",
- );
- } else {
- bail!(
- destruct.span(), "too many elements to destructure";
- hint: "the provided array has a length of {len}, but the pattern expects {i} elements",
- );
- }
+ bail!(wrong_number_of_elements(destruct, len));
}
Ok(())
@@ -193,3 +174,36 @@ where
Ok(())
}
+
+/// The error message when the number of elements of the destructuring and the
+/// array is mismatched.
+#[cold]
+fn wrong_number_of_elements(
+ destruct: ast::Destructuring,
+ len: usize,
+) -> SourceDiagnostic {
+ let mut count = 0;
+ let mut spread = false;
+
+ for p in destruct.items() {
+ match p {
+ ast::DestructuringItem::Pattern(_) => count += 1,
+ ast::DestructuringItem::Spread(_) => spread = true,
+ ast::DestructuringItem::Named(_) => {}
+ }
+ }
+
+ let quantifier = if len > count { "too many" } else { "not enough" };
+ let expected = match (spread, count) {
+ (true, c) => eco_format!("at least {c} elements"),
+ (false, 0) => "an empty array".into(),
+ (false, 1) => "a single element".into(),
+ (false, c) => eco_format!("{c} elements",),
+ };
+
+ error!(
+ destruct.span(), "{quantifier} elements to destructure";
+ hint: "the provided array has a length of {len}, \
+ but the pattern expects {expected}",
+ )
+}