diff --git a/crates/typst/src/eval/flow.rs b/crates/typst/src/eval/flow.rs index 82b681923..d25d5472c 100644 --- a/crates/typst/src/eval/flow.rs +++ b/crates/typst/src/eval/flow.rs @@ -108,11 +108,11 @@ impl Eval for ast::ForLoop<'_> { let mut output = Value::None; macro_rules! iter { - (for $pat:ident in $iter:expr) => {{ + (for $pat:ident in $iterable:expr) => {{ vm.scopes.enter(); #[allow(unused_parens)] - for value in $iter { + for value in $iterable { destructure(vm, $pat, value.into_value())?; let body = self.body(); @@ -134,29 +134,30 @@ impl Eval for ast::ForLoop<'_> { }}; } + let pattern = self.pattern(); let iterable = self.iterable().eval(vm)?; let iterable_type = iterable.ty(); - let pattern = self.pattern(); - match (&pattern, iterable) { - (ast::Pattern::Normal(_), Value::Str(string)) => { - // Iterate over graphemes of string. - iter!(for pattern in string.as_str().graphemes(true)); + use ast::Pattern; + match (pattern, iterable) { + (_, Value::Array(array)) => { + // Iterate over values of array. + iter!(for pattern in array); } (_, Value::Dict(dict)) => { // Iterate over pairs of dict. iter!(for pattern in dict.pairs()); } - (_, Value::Array(array)) => { - // Iterate over values of array. - iter!(for pattern in array); + (Pattern::Normal(_) | Pattern::Placeholder(_), Value::Str(str)) => { + // Iterate over graphemes of string. + iter!(for pattern in str.as_str().graphemes(true)); } - (ast::Pattern::Normal(_), _) => { + (Pattern::Destructuring(_), Value::Str(_)) => { + bail!(pattern.span(), "cannot destructure values of {}", iterable_type); + } + _ => { bail!(self.iterable().span(), "cannot loop over {}", iterable_type); } - (_, _) => { - bail!(pattern.span(), "cannot destructure values of {}", iterable_type) - } } if flow.is_some() { diff --git a/tests/typ/bugs/3275-loop-errors.typ b/tests/typ/bugs/3275-loop-errors.typ new file mode 100644 index 000000000..0f05d6afe --- /dev/null +++ b/tests/typ/bugs/3275-loop-errors.typ @@ -0,0 +1,49 @@ +// Issue #3275: clearer errors for loops, https://github.com/typst/typst/issues/3275 +// Ref: false + +--- +// Normal variable. +#for x in (1, 2) {} +#for x in (a: 1, b: 2) {} +#for x in "foo" {} + +--- +// Placeholder. +#for _ in (1, 2) {} +#for _ in (a: 1, b: 2) {} +#for _ in "foo" {} + +--- +// Destructuring. +#for (k, v) in (("a", 1), ("b", 2), ("c", 3)) {} +#for (k, ..) in (("a", 1), ("b", 2), ("c", 3)) {} +#for (k, v) in (a: 1, b: 2, c: 3) {} +#for (.., v) in (a: 1, b: 2, c: 3) {} + +--- +// Error: 11-17 cannot loop over content +#for x in [1, 2] {} + +--- +// Error: 11-25 cannot loop over bytes +#for _ in bytes((22, 0)) {} + +--- +// Error: 16-21 cannot loop over integer +#for (x, y) in 12306 {} + +--- +// Error: 16-22 cannot loop over content +#for (x, y) in [1, 2] {} + +--- +// Error: 6-12 cannot destructure values of string +#for (x, y) in "foo" {} + +--- +// Error: 6-12 cannot destructure string +#for (x, y) in ("foo", "bar") {} + +--- +// Error: 6-12 cannot destructure integer +#for (x, y) in (1, 2) {}