Skip to content

Commit 6fac0fa

Browse files
committed
Apply review suggestions
1 parent 3e78653 commit 6fac0fa

File tree

6 files changed

+216
-57
lines changed

6 files changed

+216
-57
lines changed

compiler/rustc_resolve/src/late/diagnostics.rs

Lines changed: 64 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,38 +1385,81 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
13851385
}
13861386

13871387
fn suggest_range_struct_destructuring(
1388-
&self,
1388+
&mut self,
13891389
err: &mut Diag<'_>,
13901390
path: &[Segment],
13911391
source: PathSource<'_, '_, '_>,
13921392
) {
1393-
// We accept Expr here because range bounds (start..end) are parsed as expressions
13941393
if !matches!(source, PathSource::Pat | PathSource::TupleStruct(..) | PathSource::Expr(..)) {
13951394
return;
13961395
}
13971396

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;
1397+
let Some(pat) = self.diag_metadata.current_pat else { return };
1398+
let ast::PatKind::Range(start, end, end_kind) = &pat.kind else { return };
14051399

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;
1400+
let [segment] = path else { return };
1401+
let failing_span = segment.ident.span;
14111402

1412-
err.span_suggestion_verbose(
1413-
pat.span,
1414-
"if you meant to destructure a `Range`, use a struct pattern",
1415-
format!("std::ops::Range {{ start: {}, end: {} }}", start_name, end_name),
1416-
Applicability::MaybeIncorrect,
1417-
);
1418-
}
1403+
let in_start = start.as_ref().is_some_and(|e| e.span.contains(failing_span));
1404+
let in_end = end.as_ref().is_some_and(|e| e.span.contains(failing_span));
1405+
1406+
if !in_start && !in_end {
1407+
return;
14191408
}
1409+
1410+
let start_snippet =
1411+
start.as_ref().and_then(|e| self.r.tcx.sess.source_map().span_to_snippet(e.span).ok());
1412+
let end_snippet =
1413+
end.as_ref().and_then(|e| self.r.tcx.sess.source_map().span_to_snippet(e.span).ok());
1414+
1415+
let field = |name: &str, val: String| {
1416+
if val == name { val } else { format!("{name}: {val}") }
1417+
};
1418+
1419+
let mut resolve_short_name = |short: Symbol, full: &str| -> String {
1420+
let ident = Ident::with_dummy_span(short);
1421+
let path = Segment::from_path(&Path::from_ident(ident));
1422+
1423+
match self.resolve_path(&path, Some(TypeNS), None, PathSource::Type) {
1424+
PathResult::NonModule(..) => short.to_string(),
1425+
_ => full.to_string(),
1426+
}
1427+
};
1428+
// FIXME(new_range): Also account for new range types
1429+
let (struct_path, fields) = match (start_snippet, end_snippet, &end_kind.node) {
1430+
(Some(start), Some(end), ast::RangeEnd::Excluded) => (
1431+
resolve_short_name(sym::Range, "std::ops::Range"),
1432+
vec![field("start", start), field("end", end)],
1433+
),
1434+
(Some(start), Some(end), ast::RangeEnd::Included(_)) => (
1435+
resolve_short_name(sym::RangeInclusive, "std::ops::RangeInclusive"),
1436+
vec![field("start", start), field("end", end)],
1437+
),
1438+
(Some(start), None, _) => (
1439+
resolve_short_name(sym::RangeFrom, "std::ops::RangeFrom"),
1440+
vec![field("start", start)],
1441+
),
1442+
(None, Some(end), ast::RangeEnd::Excluded) => {
1443+
(resolve_short_name(sym::RangeTo, "std::ops::RangeTo"), vec![field("end", end)])
1444+
}
1445+
(None, Some(end), ast::RangeEnd::Included(_)) => (
1446+
resolve_short_name(sym::RangeToInclusive, "std::ops::RangeToInclusive"),
1447+
vec![field("end", end)],
1448+
),
1449+
_ => return,
1450+
};
1451+
1452+
err.span_suggestion_verbose(
1453+
pat.span,
1454+
format!("if you meant to destructure a range use a struct pattern"),
1455+
format!("{} {{ {} }}", struct_path, fields.join(", ")),
1456+
Applicability::MaybeIncorrect,
1457+
);
1458+
1459+
err.note(
1460+
"range patterns match against the start and end of a range; \
1461+
to bind the components, use a struct pattern",
1462+
);
14201463
}
14211464

14221465
fn suggest_swapping_misplaced_self_ty_and_trait(

tests/ui/match/issue-92100.stderr

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,16 @@ error[E0425]: cannot find value `a` in this scope
44
LL | [a.., a] => {}
55
| ^ not found in this scope
66
|
7+
= note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
78
help: if you meant to collect the rest of the slice in `a`, use the at operator
89
|
910
LL | [a @ .., a] => {}
1011
| +
12+
help: if you meant to destructure a range use a struct pattern
13+
|
14+
LL - [a.., a] => {}
15+
LL + [std::ops::RangeFrom { start: a }, a] => {}
16+
|
1117

1218
error: aborting due to 1 previous error
1319

tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,16 @@ error[E0425]: cannot find value `rest` in this scope
1616
LL | [1, rest..] => println!("{rest}"),
1717
| ^^^^ not found in this scope
1818
|
19+
= note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
1920
help: if you meant to collect the rest of the slice in `rest`, use the at operator
2021
|
2122
LL | [1, rest @ ..] => println!("{rest}"),
2223
| +
24+
help: if you meant to destructure a range use a struct pattern
25+
|
26+
LL - [1, rest..] => println!("{rest}"),
27+
LL + [1, std::ops::RangeFrom { start: rest }] => println!("{rest}"),
28+
|
2329

2430
error[E0425]: cannot find value `rest` in this scope
2531
--> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:3:35
@@ -33,11 +39,17 @@ error[E0425]: cannot find value `tail` in this scope
3339
LL | [_, ..tail] => println!("{tail}"),
3440
| ^^^^ not found in this scope
3541
|
42+
= note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
3643
help: if you meant to collect the rest of the slice in `tail`, use the at operator
3744
|
3845
LL - [_, ..tail] => println!("{tail}"),
3946
LL + [_, tail @ ..] => println!("{tail}"),
4047
|
48+
help: if you meant to destructure a range use a struct pattern
49+
|
50+
LL - [_, ..tail] => println!("{tail}"),
51+
LL + [_, std::ops::RangeTo { end: tail }] => println!("{tail}"),
52+
|
4153

4254
error[E0425]: cannot find value `tail` in this scope
4355
--> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:11:35
@@ -51,11 +63,17 @@ error[E0425]: cannot find value `tail` in this scope
5163
LL | [_, ...tail] => println!("{tail}"),
5264
| ^^^^ not found in this scope
5365
|
66+
= note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
5467
help: if you meant to collect the rest of the slice in `tail`, use the at operator
5568
|
5669
LL - [_, ...tail] => println!("{tail}"),
5770
LL + [_, tail @ ..] => println!("{tail}"),
5871
|
72+
help: if you meant to destructure a range use a struct pattern
73+
|
74+
LL - [_, ...tail] => println!("{tail}"),
75+
LL + [_, std::ops::RangeToInclusive { end: tail }] => println!("{tail}"),
76+
|
5977

6078
error[E0425]: cannot find value `tail` in this scope
6179
--> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:17:36
Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,40 @@
1-
use std::ops::Range;
1+
use std::ops::{Range, RangeFrom, RangeInclusive, RangeTo, RangeToInclusive};
22

3-
fn test_basic_range(r: Range<u32>) {
3+
fn test_range(r: Range<u32>) {
44
let start..end = r;
5-
//~^ ERROR cannot find value `start` in this scope
6-
//~| ERROR cannot find value `end` in this scope
5+
//~^ ERROR cannot find value `start`
6+
//~| ERROR cannot find value `end`
77
}
88

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
9+
fn test_inclusive(r: RangeInclusive<u32>) {
10+
let start..=end = r;
11+
//~^ ERROR cannot find value `start`
12+
//~| ERROR cannot find value `end`
13+
}
14+
15+
fn test_from(r: RangeFrom<u32>) {
16+
let start.. = r;
17+
//~^ ERROR cannot find value `start`
18+
}
19+
20+
fn test_to(r: RangeTo<u32>) {
21+
let ..end = r;
22+
//~^ ERROR cannot find value `end`
23+
}
24+
25+
fn test_to_inclusive(r: RangeToInclusive<u32>) {
26+
let ..=end = r;
27+
//~^ ERROR cannot find value `end`
28+
}
29+
30+
// Case 6: Complex Path (Keep this! It works!)
31+
mod my {
32+
// We don't define MISSING here to trigger the error
33+
}
34+
fn test_path(r: Range<u32>) {
35+
let my::MISSING..end = r;
36+
//~^ ERROR cannot find value `MISSING`
37+
//~| ERROR cannot find value `end`
1338
}
1439

1540
fn main() {}

tests/ui/resolve/suggest-range-struct-destructuring.stderr

Lines changed: 89 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ error[E0425]: cannot find value `start` in this scope
44
LL | let start..end = r;
55
| ^^^^^ not found in this scope
66
|
7-
help: if you meant to destructure a `Range`, use a struct pattern
7+
= note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
8+
help: if you meant to destructure a range use a struct pattern
89
|
910
LL - let start..end = r;
10-
LL + let std::ops::Range { start: start, end: end } = r;
11+
LL + let Range { start, end } = r;
1112
|
1213

1314
error[E0425]: cannot find value `end` in this scope
@@ -16,51 +17,111 @@ error[E0425]: cannot find value `end` in this scope
1617
LL | let start..end = r;
1718
| ^^^ not found in this scope
1819
|
19-
help: if you meant to destructure a `Range`, use a struct pattern
20+
= note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
21+
help: if you meant to destructure a range use a struct pattern
2022
|
2123
LL - let start..end = r;
22-
LL + let std::ops::Range { start: start, end: end } = r;
24+
LL + let Range { start, end } = r;
2325
|
2426

25-
error[E0425]: cannot find value `min` in this scope
27+
error[E0425]: cannot find value `start` in this scope
2628
--> $DIR/suggest-range-struct-destructuring.rs:10:9
2729
|
28-
LL | let min..max = r;
29-
| ^^^
30-
...
31-
LL | fn main() {}
32-
| --------- similarly named function `main` defined here
30+
LL | let start..=end = r;
31+
| ^^^^^ not found in this scope
32+
|
33+
= note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
34+
help: if you meant to destructure a range use a struct pattern
35+
|
36+
LL - let start..=end = r;
37+
LL + let RangeInclusive { start, end } = r;
38+
|
39+
40+
error[E0425]: cannot find value `end` in this scope
41+
--> $DIR/suggest-range-struct-destructuring.rs:10:17
42+
|
43+
LL | let start..=end = r;
44+
| ^^^ not found in this scope
45+
|
46+
= note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
47+
help: if you meant to destructure a range use a struct pattern
48+
|
49+
LL - let start..=end = r;
50+
LL + let RangeInclusive { start, end } = r;
51+
|
52+
53+
error[E0425]: cannot find value `start` in this scope
54+
--> $DIR/suggest-range-struct-destructuring.rs:16:9
55+
|
56+
LL | let start.. = r;
57+
| ^^^^^ not found in this scope
58+
|
59+
= note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
60+
help: if you meant to collect the rest of the slice in `start`, use the at operator
61+
|
62+
LL | let start @ .. = r;
63+
| +
64+
help: if you meant to destructure a range use a struct pattern
65+
|
66+
LL - let start.. = r;
67+
LL + let RangeFrom { start } = r;
68+
|
69+
70+
error[E0425]: cannot find value `end` in this scope
71+
--> $DIR/suggest-range-struct-destructuring.rs:21:11
3372
|
34-
help: if you meant to destructure a `Range`, use a struct pattern
73+
LL | let ..end = r;
74+
| ^^^ not found in this scope
3575
|
36-
LL - let min..max = r;
37-
LL + let std::ops::Range { start: min, end: max } = r;
76+
= note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
77+
help: if you meant to collect the rest of the slice in `end`, use the at operator
3878
|
39-
help: a function with a similar name exists
79+
LL - let ..end = r;
80+
LL + let end @ .. = r;
4081
|
41-
LL | let main..max = r;
42-
| +
43-
help: consider importing this function
82+
help: if you meant to destructure a range use a struct pattern
4483
|
45-
LL + use std::cmp::min;
84+
LL - let ..end = r;
85+
LL + let RangeTo { end } = r;
4686
|
4787

48-
error[E0425]: cannot find value `max` in this scope
49-
--> $DIR/suggest-range-struct-destructuring.rs:10:14
88+
error[E0425]: cannot find value `end` in this scope
89+
--> $DIR/suggest-range-struct-destructuring.rs:26:12
90+
|
91+
LL | let ..=end = r;
92+
| ^^^ not found in this scope
5093
|
51-
LL | let min..max = r;
52-
| ^^^ not found in this scope
94+
= note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
95+
help: if you meant to collect the rest of the slice in `end`, use the at operator
5396
|
54-
help: if you meant to destructure a `Range`, use a struct pattern
97+
LL - let ..=end = r;
98+
LL + let end @ .. = r;
99+
|
100+
help: if you meant to destructure a range use a struct pattern
101+
|
102+
LL - let ..=end = r;
103+
LL + let RangeToInclusive { end } = r;
104+
|
105+
106+
error[E0425]: cannot find value `MISSING` in module `my`
107+
--> $DIR/suggest-range-struct-destructuring.rs:35:13
108+
|
109+
LL | let my::MISSING..end = r;
110+
| ^^^^^^^ not found in `my`
111+
112+
error[E0425]: cannot find value `end` in this scope
113+
--> $DIR/suggest-range-struct-destructuring.rs:35:22
55114
|
56-
LL - let min..max = r;
57-
LL + let std::ops::Range { start: min, end: max } = r;
115+
LL | let my::MISSING..end = r;
116+
| ^^^ not found in this scope
58117
|
59-
help: consider importing this function
118+
= note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
119+
help: if you meant to destructure a range use a struct pattern
60120
|
61-
LL + use std::cmp::max;
121+
LL - let my::MISSING..end = r;
122+
LL + let Range { start: my::MISSING, end } = r;
62123
|
63124

64-
error: aborting due to 4 previous errors
125+
error: aborting due to 9 previous errors
65126

66127
For more information about this error, try `rustc --explain E0425`.

tests/ui/typeck/issue-105946.stderr

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,16 @@ error[E0425]: cannot find value `_y` in this scope
44
LL | let [_y..] = [Box::new(1), Box::new(2)];
55
| ^^ not found in this scope
66
|
7+
= note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
78
help: if you meant to collect the rest of the slice in `_y`, use the at operator
89
|
910
LL | let [_y @ ..] = [Box::new(1), Box::new(2)];
1011
| +
12+
help: if you meant to destructure a range use a struct pattern
13+
|
14+
LL - let [_y..] = [Box::new(1), Box::new(2)];
15+
LL + let [std::ops::RangeFrom { start: _y }] = [Box::new(1), Box::new(2)];
16+
|
1117

1218
error[E0658]: `X..` patterns in slices are experimental
1319
--> $DIR/issue-105946.rs:7:10

0 commit comments

Comments
 (0)