Skip to content

Commit cb30175

Browse files
committed
Suggest struct pattern when destructuring Range with .. syntax
1 parent f2c7087 commit cb30175

File tree

3 files changed

+117
-0
lines changed

3 files changed

+117
-0
lines changed

compiler/rustc_resolve/src/late/diagnostics.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
440440

441441
self.detect_missing_binding_available_from_pattern(&mut err, path, following_seg);
442442
self.suggest_at_operator_in_slice_pat_with_range(&mut err, path);
443+
self.suggest_range_struct_destructuring(&mut err, path, source);
443444
self.suggest_swapping_misplaced_self_ty_and_trait(&mut err, source, res, base_error.span);
444445

445446
if let Some((span, label)) = base_error.span_label {
@@ -1383,6 +1384,41 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
13831384
}
13841385
}
13851386

1387+
fn suggest_range_struct_destructuring(
1388+
&self,
1389+
err: &mut Diag<'_>,
1390+
path: &[Segment],
1391+
source: PathSource<'_, '_, '_>,
1392+
) {
1393+
// We accept Expr here because range bounds (start..end) are parsed as expressions
1394+
if !matches!(source, PathSource::Pat | PathSource::TupleStruct(..) | PathSource::Expr(..)) {
1395+
return;
1396+
}
1397+
1398+
if let Some(pat) = self.diag_metadata.current_pat
1399+
&& let ast::PatKind::Range(Some(start_expr), Some(end_expr), _) = &pat.kind
1400+
&& let (ast::ExprKind::Path(None, start_path), ast::ExprKind::Path(None, end_path)) =
1401+
(&start_expr.kind, &end_expr.kind)
1402+
&& path.len() == 1
1403+
{
1404+
let ident = path[0].ident;
1405+
1406+
if (start_path.segments.len() == 1 && start_path.segments[0].ident == ident)
1407+
|| (end_path.segments.len() == 1 && end_path.segments[0].ident == ident)
1408+
{
1409+
let start_name = start_path.segments[0].ident;
1410+
let end_name = end_path.segments[0].ident;
1411+
1412+
err.span_suggestion_verbose(
1413+
pat.span,
1414+
"if you meant to destructure a `Range`, use the struct pattern",
1415+
format!("std::ops::Range {{ start: {}, end: {} }}", start_name, end_name),
1416+
Applicability::MaybeIncorrect,
1417+
);
1418+
}
1419+
}
1420+
}
1421+
13861422
fn suggest_swapping_misplaced_self_ty_and_trait(
13871423
&mut self,
13881424
err: &mut Diag<'_>,
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
use std::ops::Range;
2+
3+
fn test_basic_range(r: Range<u32>) {
4+
let start..end = r;
5+
//~^ ERROR cannot find value `start` in this scope
6+
//~| ERROR cannot find value `end` in this scope
7+
}
8+
9+
fn test_different_names(r: Range<u32>) {
10+
let min..max = r;
11+
//~^ ERROR cannot find value `min` in this scope
12+
//~| ERROR cannot find value `max` in this scope
13+
}
14+
15+
fn main() {}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
error[E0425]: cannot find value `start` in this scope
2+
--> $DIR/suggest-range-struct-destructuring.rs:4:9
3+
|
4+
LL | let start..end = r;
5+
| ^^^^^ not found in this scope
6+
|
7+
help: if you meant to destructure a `Range`, use the struct pattern
8+
|
9+
LL - let start..end = r;
10+
LL + let std::ops::Range { start: start, end: end } = r;
11+
|
12+
13+
error[E0425]: cannot find value `end` in this scope
14+
--> $DIR/suggest-range-struct-destructuring.rs:4:16
15+
|
16+
LL | let start..end = r;
17+
| ^^^ not found in this scope
18+
|
19+
help: if you meant to destructure a `Range`, use the struct pattern
20+
|
21+
LL - let start..end = r;
22+
LL + let std::ops::Range { start: start, end: end } = r;
23+
|
24+
25+
error[E0425]: cannot find value `min` in this scope
26+
--> $DIR/suggest-range-struct-destructuring.rs:10:9
27+
|
28+
LL | let min..max = r;
29+
| ^^^
30+
...
31+
LL | fn main() {}
32+
| --------- similarly named function `main` defined here
33+
|
34+
help: if you meant to destructure a `Range`, use the struct pattern
35+
|
36+
LL - let min..max = r;
37+
LL + let std::ops::Range { start: min, end: max } = r;
38+
|
39+
help: a function with a similar name exists
40+
|
41+
LL | let main..max = r;
42+
| +
43+
help: consider importing this function
44+
|
45+
LL + use std::cmp::min;
46+
|
47+
48+
error[E0425]: cannot find value `max` in this scope
49+
--> $DIR/suggest-range-struct-destructuring.rs:10:14
50+
|
51+
LL | let min..max = r;
52+
| ^^^ not found in this scope
53+
|
54+
help: if you meant to destructure a `Range`, use the struct pattern
55+
|
56+
LL - let min..max = r;
57+
LL + let std::ops::Range { start: min, end: max } = r;
58+
|
59+
help: consider importing this function
60+
|
61+
LL + use std::cmp::max;
62+
|
63+
64+
error: aborting due to 4 previous errors
65+
66+
For more information about this error, try `rustc --explain E0425`.

0 commit comments

Comments
 (0)