about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <476013+matthiaskrgr@users.noreply.github.com>2025-05-21 15:38:08 +0200
committerGitHub <noreply@github.com>2025-05-21 15:38:08 +0200
commitaf081a42473979d094f71460e3b3f5bd18c0bb08 (patch)
treed7559111f8d7297712bfe73a57f3fc22ca4f4408
parentc43786c9b7b8d8dcc3f9c604e0e3074c16ed69d3 (diff)
parented983c21842be5e84f11b745c0c04ea23baa5509 (diff)
downloadrust-af081a42473979d094f71460e3b3f5bd18c0bb08.tar.gz
rust-af081a42473979d094f71460e3b3f5bd18c0bb08.zip
Rollup merge of #141267 - dianne:fix-141265, r=oli-obk
only resolve top-level guard patterns' guards once

We resolve guard patterns' guards in `resolve_pattern_inner`, so to avoid resolving them multiple times, we must avoid doing so earlier. To accomplish this, `LateResolutionVisitor::visit_pat` contains a case for guard patterns that avoids visiting their guards while walking patterns.

This PR fixes #141265, which was due to `visit::walk_pat` being used instead; this meant guards at the top level of a pattern would be visited twice. e.g. it would ICE on `for x if x in [] {}`, but not `for (x if x) in [] {}`. `visit_pat` was already used for the guard pattern in the second example, on account of the top-level pattern being parens.
-rw-r--r--compiler/rustc_resolve/src/late.rs4
-rw-r--r--tests/ui/pattern/rfc-3637-guard-patterns/only-resolve-top-level-guard-expr-once-ice-141265.rs12
-rw-r--r--tests/ui/pattern/rfc-3637-guard-patterns/only-resolve-top-level-guard-expr-once-ice-141265.stderr48
3 files changed, 63 insertions, 1 deletions
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 1b682d0cf8a..fd977a8eb6c 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -3901,7 +3901,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         // We walk the pattern before declaring the pattern's inner bindings,
         // so that we avoid resolving a literal expression to a binding defined
         // by the pattern.
-        visit::walk_pat(self, pat);
+        // NB: `Self::visit_pat` must be used rather than `visit::walk_pat` to avoid resolving guard
+        // patterns' guard expressions multiple times (#141265).
+        self.visit_pat(pat);
         self.resolve_pattern_inner(pat, pat_src, bindings);
         // This has to happen *after* we determine which pat_idents are variants:
         self.check_consistent_bindings(pat);
diff --git a/tests/ui/pattern/rfc-3637-guard-patterns/only-resolve-top-level-guard-expr-once-ice-141265.rs b/tests/ui/pattern/rfc-3637-guard-patterns/only-resolve-top-level-guard-expr-once-ice-141265.rs
new file mode 100644
index 00000000000..7dc9ef7161d
--- /dev/null
+++ b/tests/ui/pattern/rfc-3637-guard-patterns/only-resolve-top-level-guard-expr-once-ice-141265.rs
@@ -0,0 +1,12 @@
+//! Regression test for <https://github.com/rust-lang/rust/issues/141265>.
+//! Make sure expressions in top-level guard patterns are only resolved once.
+
+fn main() {
+    for
+    else if b 0 {}
+    //~^ ERROR expected identifier, found keyword `else`
+    //~| ERROR missing `in` in `for` loop
+    //~| ERROR cannot find value `b` in this scope
+    //~| ERROR guard patterns are experimental
+    //~| ERROR `{integer}` is not an iterator
+}
diff --git a/tests/ui/pattern/rfc-3637-guard-patterns/only-resolve-top-level-guard-expr-once-ice-141265.stderr b/tests/ui/pattern/rfc-3637-guard-patterns/only-resolve-top-level-guard-expr-once-ice-141265.stderr
new file mode 100644
index 00000000000..dae384137f5
--- /dev/null
+++ b/tests/ui/pattern/rfc-3637-guard-patterns/only-resolve-top-level-guard-expr-once-ice-141265.stderr
@@ -0,0 +1,48 @@
+error: expected identifier, found keyword `else`
+  --> $DIR/only-resolve-top-level-guard-expr-once-ice-141265.rs:6:5
+   |
+LL |     else if b 0 {}
+   |     ^^^^ expected identifier, found keyword
+
+error: missing `in` in `for` loop
+  --> $DIR/only-resolve-top-level-guard-expr-once-ice-141265.rs:6:14
+   |
+LL |     else if b 0 {}
+   |              ^
+   |
+help: try adding `in` here
+   |
+LL |     else if b in 0 {}
+   |               ++
+
+error[E0425]: cannot find value `b` in this scope
+  --> $DIR/only-resolve-top-level-guard-expr-once-ice-141265.rs:6:13
+   |
+LL |     else if b 0 {}
+   |             ^ not found in this scope
+
+error[E0658]: guard patterns are experimental
+  --> $DIR/only-resolve-top-level-guard-expr-once-ice-141265.rs:6:13
+   |
+LL |     else if b 0 {}
+   |             ^
+   |
+   = note: see issue #129967 <https://github.com/rust-lang/rust/issues/129967> for more information
+   = help: add `#![feature(guard_patterns)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = help: consider using match arm guards
+
+error[E0277]: `{integer}` is not an iterator
+  --> $DIR/only-resolve-top-level-guard-expr-once-ice-141265.rs:6:15
+   |
+LL |     else if b 0 {}
+   |               ^ `{integer}` is not an iterator
+   |
+   = help: the trait `Iterator` is not implemented for `{integer}`
+   = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+   = note: required for `{integer}` to implement `IntoIterator`
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0277, E0425, E0658.
+For more information about an error, try `rustc --explain E0277`.