about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_resolve/src/late.rs8
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs27
-rw-r--r--tests/ui/match/issue-92100.stderr5
-rw-r--r--tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.rs9
-rw-r--r--tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr30
-rw-r--r--tests/ui/typeck/issue-105946.stderr5
6 files changed, 84 insertions, 0 deletions
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 3be962dab90..9b7897d69e7 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -603,6 +603,8 @@ struct DiagnosticMetadata<'ast> {
     /// Only used for better errors on `let <pat>: <expr, not type>;`.
     current_let_binding: Option<(Span, Option<Span>, Option<Span>)>,
 
+    current_pat: Option<&'ast Pat>,
+
     /// Used to detect possible `if let` written without `let` and to provide structured suggestion.
     in_if_condition: Option<&'ast Expr>,
 
@@ -703,6 +705,12 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
     fn visit_expr(&mut self, expr: &'ast Expr) {
         self.resolve_expr(expr, None);
     }
+    fn visit_pat(&mut self, p: &'ast Pat) {
+        let prev = self.diagnostic_metadata.current_pat;
+        self.diagnostic_metadata.current_pat = Some(p);
+        visit::walk_pat(self, p);
+        self.diagnostic_metadata.current_pat = prev;
+    }
     fn visit_local(&mut self, local: &'ast Local) {
         let local_spans = match local.pat.kind {
             // We check for this to avoid tuple struct fields.
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index fd5d6fabf02..6aecd3610c6 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -431,6 +431,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
             code,
         );
 
+        self.suggest_at_operator_in_slice_pat_with_range(&mut err, path);
         self.suggest_swapping_misplaced_self_ty_and_trait(&mut err, source, res, base_error.span);
 
         if let Some((span, label)) = base_error.span_label {
@@ -1063,6 +1064,32 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
         true
     }
 
+    fn suggest_at_operator_in_slice_pat_with_range(
+        &mut self,
+        err: &mut Diagnostic,
+        path: &[Segment],
+    ) {
+        if let Some(pat) = self.diagnostic_metadata.current_pat
+            && let ast::PatKind::Range(Some(start), None, range) = &pat.kind
+            && let ExprKind::Path(None, range_path) = &start.kind
+            && let [segment] = &range_path.segments[..]
+            && let [s] = path
+            && segment.ident == s.ident
+        {
+            // We've encountered `[first, rest..]` where the user might have meant
+            // `[first, rest @ ..]` (#88404).
+            err.span_suggestion_verbose(
+                segment.ident.span.between(range.span),
+                format!(
+                    "if you meant to collect the rest of the slice in `{}`, use the at operator",
+                    segment.ident,
+                ),
+                " @ ",
+                Applicability::MaybeIncorrect,
+            );
+        }
+    }
+
     fn suggest_swapping_misplaced_self_ty_and_trait(
         &mut self,
         err: &mut Diagnostic,
diff --git a/tests/ui/match/issue-92100.stderr b/tests/ui/match/issue-92100.stderr
index 0f694c587fc..d0e50f3ae16 100644
--- a/tests/ui/match/issue-92100.stderr
+++ b/tests/ui/match/issue-92100.stderr
@@ -3,6 +3,11 @@ error[E0425]: cannot find value `a` in this scope
    |
 LL |         [a.., a] => {}
    |          ^ not found in this scope
+   |
+help: if you meant to collect the rest of the slice in `a`, use the at operator
+   |
+LL |         [a @ .., a] => {}
+   |            +
 
 error: aborting due to previous error
 
diff --git a/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.rs b/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.rs
new file mode 100644
index 00000000000..a619fcafc86
--- /dev/null
+++ b/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.rs
@@ -0,0 +1,9 @@
+fn main() {
+    match &[1, 2, 3][..] {
+        [1, rest..] => println!("{rest:?}"),
+        //~^ ERROR cannot find value `rest` in this scope
+        //~| ERROR cannot find value `rest` in this scope
+        //~| ERROR `X..` patterns in slices are experimental
+        _ => {}
+    }
+}
diff --git a/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr b/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr
new file mode 100644
index 00000000000..cddd0121279
--- /dev/null
+++ b/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr
@@ -0,0 +1,30 @@
+error[E0425]: cannot find value `rest` in this scope
+  --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:3:13
+   |
+LL |         [1, rest..] => println!("{rest:?}"),
+   |             ^^^^ not found in this scope
+   |
+help: if you meant to collect the rest of the slice in `rest`, use the at operator
+   |
+LL |         [1, rest @ ..] => println!("{rest:?}"),
+   |                  +
+
+error[E0425]: cannot find value `rest` in this scope
+  --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:3:35
+   |
+LL |         [1, rest..] => println!("{rest:?}"),
+   |                                   ^^^^ not found in this scope
+
+error[E0658]: `X..` patterns in slices are experimental
+  --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:3:13
+   |
+LL |         [1, rest..] => println!("{rest:?}"),
+   |             ^^^^^^
+   |
+   = note: see issue #67264 <https://github.com/rust-lang/rust/issues/67264> for more information
+   = help: add `#![feature(half_open_range_patterns_in_slices)]` to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0425, E0658.
+For more information about an error, try `rustc --explain E0425`.
diff --git a/tests/ui/typeck/issue-105946.stderr b/tests/ui/typeck/issue-105946.stderr
index 26c3b7fbc84..2220271e581 100644
--- a/tests/ui/typeck/issue-105946.stderr
+++ b/tests/ui/typeck/issue-105946.stderr
@@ -3,6 +3,11 @@ error[E0425]: cannot find value `_y` in this scope
    |
 LL |     let [_y..] = [Box::new(1), Box::new(2)];
    |          ^^ not found in this scope
+   |
+help: if you meant to collect the rest of the slice in `_y`, use the at operator
+   |
+LL |     let [_y @ ..] = [Box::new(1), Box::new(2)];
+   |             +
 
 error[E0658]: `X..` patterns in slices are experimental
   --> $DIR/issue-105946.rs:6:10