summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeedehai <18319900+Leedehai@users.noreply.github.com>2024-01-31 04:12:06 -0500
committerGitHub <noreply@github.com>2024-01-31 09:12:06 +0000
commit51854ba4df0e941bd17acee499fdb3a7e43b31e0 (patch)
tree32bde5fc13107df85d82aa8e1d5c0384e4b9db91
parentce5abf5a4e338a151f8c8a49bc5ba864c1319d9d (diff)
Adjust for-loop's pattern matching rules (#3308)
-rw-r--r--crates/typst/src/eval/flow.rs29
-rw-r--r--tests/typ/bugs/3275-loop-errors.typ49
2 files changed, 64 insertions, 14 deletions
diff --git a/crates/typst/src/eval/flow.rs b/crates/typst/src/eval/flow.rs
index 82b68192..d25d5472 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,28 +134,29 @@ 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(_), _) => {
- bail!(self.iterable().span(), "cannot loop over {}", iterable_type);
+ (Pattern::Destructuring(_), Value::Str(_)) => {
+ bail!(pattern.span(), "cannot destructure values of {}", iterable_type);
}
- (_, _) => {
- bail!(pattern.span(), "cannot destructure values of {}", iterable_type)
+ _ => {
+ bail!(self.iterable().span(), "cannot loop over {}", iterable_type);
}
}
diff --git a/tests/typ/bugs/3275-loop-errors.typ b/tests/typ/bugs/3275-loop-errors.typ
new file mode 100644
index 00000000..0f05d6af
--- /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) {}