From ed983c21842be5e84f11b745c0c04ea23baa5509 Mon Sep 17 00:00:00 2001 From: dianne Date: Mon, 19 May 2025 18:02:54 -0700 Subject: [PATCH] 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 fixes an ICE due to `visit::walk_pat` being used instead, which meant guards at the top level of a pattern would be visited twice. --- compiler/rustc_resolve/src/late.rs | 4 +- ...ve-top-level-guard-expr-once-ice-141265.rs | 12 +++++ ...op-level-guard-expr-once-ice-141265.stderr | 48 +++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 tests/ui/pattern/rfc-3637-guard-patterns/only-resolve-top-level-guard-expr-once-ice-141265.rs create mode 100644 tests/ui/pattern/rfc-3637-guard-patterns/only-resolve-top-level-guard-expr-once-ice-141265.stderr diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 1b682d0cf8ae9..fd977a8eb6c0b 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 0000000000000..7dc9ef7161d1b --- /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 . +//! 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 0000000000000..dae384137f529 --- /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 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`.