From 70f619e89600e954b431298e0eb69010b633e134 Mon Sep 17 00:00:00 2001 From: T0mstone Date: Wed, 23 Jul 2025 14:04:17 +0200 Subject: [PATCH] Add tests, fix bug, and improve symbol constructor errors --- .../typst-library/src/foundations/symbol.rs | 49 +++++++++++------- tests/ref/symbol-constructor.png | Bin 511 -> 558 bytes tests/suite/symbols/symbol.typ | 14 +++++ 3 files changed, 44 insertions(+), 19 deletions(-) diff --git a/crates/typst-library/src/foundations/symbol.rs b/crates/typst-library/src/foundations/symbol.rs index e4b12766d..c2e0a6ec7 100644 --- a/crates/typst-library/src/foundations/symbol.rs +++ b/crates/typst-library/src/foundations/symbol.rs @@ -8,7 +8,7 @@ use serde::{Serialize, Serializer}; use typst_syntax::{Span, Spanned, is_ident}; use typst_utils::hash128; -use crate::diag::{DeprecationSink, SourceResult, StrResult, bail}; +use crate::diag::{DeprecationSink, SourceResult, StrResult, bail, error}; use crate::foundations::{ Array, Content, Func, NativeElement, NativeFunc, Packed, PlainText, Repr as _, cast, elem, func, scope, ty, @@ -231,15 +231,30 @@ impl Symbol { // A list of modifiers, cleared & reused in each iteration. let mut modifiers = Vec::new(); + let mut errors = ecow::eco_vec![]; + // Validate the variants. - for (i, &Spanned { ref v, span }) in variants.iter().enumerate() { + 'variants: for (i, &Spanned { ref v, span }) in variants.iter().enumerate() { modifiers.clear(); + if v.1.is_empty() { + errors.push(if v.0.is_empty() { + error!(span, "empty default variant") + } else { + error!(span, "empty variant: {}", v.0.repr()) + }); + } + if !v.0.is_empty() { // Collect all modifiers. for modifier in v.0.split('.') { if !is_ident(modifier) { - bail!(span, "invalid symbol modifier: {}", modifier.repr()); + errors.push(error!( + span, + "invalid symbol modifier: {}", + modifier.repr() + )); + continue 'variants; } modifiers.push(modifier); } @@ -250,37 +265,34 @@ impl Symbol { // Ensure that there are no duplicate modifiers. if let Some(ms) = modifiers.windows(2).find(|ms| ms[0] == ms[1]) { - bail!( + errors.push(error!( span, "duplicate modifier within variant: {}", ms[0].repr(); hint: "modifiers are not ordered, so each one may appear only once" - ) + )); + continue 'variants; } // Check whether we had this set of modifiers before. let hash = hash128(&modifiers); if let Some(&i) = seen.get(&hash) { - if v.0.is_empty() { - bail!(span, "duplicate default variant"); + errors.push(if v.0.is_empty() { + error!(span, "duplicate default variant") } else if v.0 == variants[i].v.0 { - bail!(span, "duplicate variant: {}", v.0.repr()); + error!(span, "duplicate variant: {}", v.0.repr()) } else { - bail!( + error!( span, "duplicate variant: {}", v.0.repr(); hint: "variants with the same modifiers are identical, regardless of their order" ) - } - } - - if v.1.is_empty() { - if v.0.is_empty() { - bail!(span, "default variant is empty"); - } else { - bail!(span, "variant is empty: {}", v.0.repr()); - } + }); + continue 'variants; } seen.insert(hash, i); } + if !errors.is_empty() { + return Err(errors); + } let list = variants .into_iter() @@ -394,7 +406,6 @@ pub struct SymbolVariant(EcoString, EcoString); cast! { SymbolVariant, - c: char => Self(EcoString::new(), c.into()), s: EcoString => Self(EcoString::new(), s), array: Array => { let mut iter = array.into_iter(); diff --git a/tests/ref/symbol-constructor.png b/tests/ref/symbol-constructor.png index e6db9491d1e7a8bef885085f0935ae853b6f1c31..0cccd70f17361c75db741c0d14b8d7f0ef9ca884 100644 GIT binary patch delta 533 zcmV+w0_y$$1Fi&+B!BfuL_t(|+U=D&Pa8oLfJv7+RqC|qQbqiVB+3s+sx+yRBBDvd z&0-{sEF)}-Ls;fqFsvDj!4mgjzyi!=4q9G_zOzj9H#nmBvV^!k{#+m~ zZ!fjcKg4IZF1L}|YM=~Btv-S{y)9HVPYRI0cFwTBD~U4_RB$N3@P5)QW*-AMc(W1Z zyRrcd;C)EJ@PCf1g3|}%VKlf2_W_c4yAr{N{BVNi|2&y9JPLtzfRR-&hPN7ZOC8d2 zQMt*(*-fC-#aTG5%8}A+PaM!xkCh+Yb@|x*ddkMXsYk-#3^=Aigx5Tj9bw04A&Bzu zHJTrQhe4|jR>ir^{*NwfnIR?#-}a3}!CYLFV+X6P~oi$_cgx7hfh z7)u!mwpt*%L?%}QP7^XH?tV@#}5R0x3Wff1p*HR<&x=rgu|8 zh8U^zAn842jor!;dO!~=sqCR)D48ZCVu>Y2o{q3S=Ntztl zUt4)kt|yezlk|l%4H79Z(~2rE5vRJ*CI~TA4P~(*_91>-)x!}-; z2H(DQKoV6qet&)8eQ@6c?A?Mk{5Yvv`h|{TUekZc=!|TiicB6UvKPFA)AmN6@+uV&=+15WnP@IH783wA5zjhoI;E8u#EPg zhP`e;ZarvtFH4sZxQyuwXImtO*nw)6R7TJo+$O_#bdg