diff options
| author | Esteban Küber <esteban@kuber.com.ar> | 2023-11-17 00:55:55 +0000 |
|---|---|---|
| committer | Esteban Küber <esteban@kuber.com.ar> | 2023-11-17 00:55:55 +0000 |
| commit | 5c3e01a340699069e1e8d9303fff0563fdbd09e2 (patch) | |
| tree | ae3cb3518643d4947e89d6e18604dc2bae1eccfb | |
| parent | 1be1e84872185c427de42f4d9e757d3e3e28d90e (diff) | |
| download | rust-5c3e01a340699069e1e8d9303fff0563fdbd09e2.tar.gz rust-5c3e01a340699069e1e8d9303fff0563fdbd09e2.zip | |
On resolve error of `[rest..]`, suggest `[rest @ ..]`
When writing a pattern to collect multiple entries of a slice in a
single binding, it is easy to misremember or typo the appropriate syntax
to do so, instead writing the experimental `X..` pattern syntax. When we
encounter a resolve error because `X` isn't available, we suggest
`X @ ..` as an alternative.
```
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:?}"),
| +
```
Fix #88404.
| -rw-r--r-- | compiler/rustc_resolve/src/late.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/late/diagnostics.rs | 27 | ||||
| -rw-r--r-- | tests/ui/match/issue-92100.stderr | 5 | ||||
| -rw-r--r-- | tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.rs | 9 | ||||
| -rw-r--r-- | tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr | 30 | ||||
| -rw-r--r-- | tests/ui/typeck/issue-105946.stderr | 5 |
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 |
