diff options
| author | Orange <89233794+Ang149@users.noreply.github.com> | 2024-10-07 17:59:49 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-10-07 09:59:49 +0000 |
| commit | bb39d8f10a3820a1fbda6c50d8df5745ccc11de2 (patch) | |
| tree | 43ca061ce3080edcb35197b67dfee10045bacb15 /crates | |
| parent | 2a40eb518c737f4644099881a23295a650eb9ea1 (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.rs | 64 |
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}", + ) +} |
