Skip to content

Commit 52af5b7

Browse files
Rollup merge of #147753 - chenyukang:yukang-147749, r=fmease
Suggest add bounding value for RangeTo Fixes #147749
2 parents 2636cb4 + 0b45ab3 commit 52af5b7

File tree

3 files changed

+218
-0
lines changed

3 files changed

+218
-0
lines changed

compiler/rustc_hir_typeck/src/method/suggest.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10791079
}
10801080

10811081
self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_ident, expected);
1082+
self.suggest_bounds_for_range_to_method(&mut err, source, item_ident);
10821083
err.emit()
10831084
}
10841085

@@ -3260,6 +3261,71 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
32603261
}
32613262
}
32623263

3264+
fn suggest_bounds_for_range_to_method(
3265+
&self,
3266+
err: &mut Diag<'_>,
3267+
source: SelfSource<'tcx>,
3268+
item_ident: Ident,
3269+
) {
3270+
let SelfSource::MethodCall(rcvr_expr) = source else { return };
3271+
let hir::ExprKind::Struct(qpath, fields, _) = rcvr_expr.kind else { return };
3272+
let Some(lang_item) = self.tcx.qpath_lang_item(*qpath) else {
3273+
return;
3274+
};
3275+
let is_inclusive = match lang_item {
3276+
hir::LangItem::RangeTo => false,
3277+
hir::LangItem::RangeToInclusive | hir::LangItem::RangeInclusiveCopy => true,
3278+
_ => return,
3279+
};
3280+
3281+
let Some(iterator_trait) = self.tcx.get_diagnostic_item(sym::Iterator) else { return };
3282+
let Some(_) = self
3283+
.tcx
3284+
.associated_items(iterator_trait)
3285+
.filter_by_name_unhygienic(item_ident.name)
3286+
.next()
3287+
else {
3288+
return;
3289+
};
3290+
3291+
let source_map = self.tcx.sess.source_map();
3292+
let range_type = if is_inclusive { "RangeInclusive" } else { "Range" };
3293+
let Some(end_field) = fields.iter().find(|f| f.ident.name == rustc_span::sym::end) else {
3294+
return;
3295+
};
3296+
3297+
let element_ty = self.typeck_results.borrow().expr_ty_opt(end_field.expr);
3298+
let is_integral = element_ty.is_some_and(|ty| ty.is_integral());
3299+
let end_is_negative = is_integral
3300+
&& matches!(end_field.expr.kind, hir::ExprKind::Unary(rustc_ast::UnOp::Neg, _));
3301+
3302+
let Ok(snippet) = source_map.span_to_snippet(rcvr_expr.span) else { return };
3303+
3304+
let offset = snippet
3305+
.chars()
3306+
.take_while(|&c| c == '(' || c.is_whitespace())
3307+
.map(|c| c.len_utf8())
3308+
.sum::<usize>();
3309+
3310+
let insert_span = rcvr_expr
3311+
.span
3312+
.with_lo(rcvr_expr.span.lo() + rustc_span::BytePos(offset as u32))
3313+
.shrink_to_lo();
3314+
3315+
let (value, appl) = if is_integral && !end_is_negative {
3316+
("0", Applicability::MachineApplicable)
3317+
} else {
3318+
("/* start */", Applicability::HasPlaceholders)
3319+
};
3320+
3321+
err.span_suggestion_verbose(
3322+
insert_span,
3323+
format!("consider using a bounded `{range_type}` by adding a concrete starting value"),
3324+
value,
3325+
appl,
3326+
);
3327+
}
3328+
32633329
/// Print out the type for use in value namespace.
32643330
fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String {
32653331
match ty.kind() {
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
fn main() {
2+
for x in (..4).rev() {
3+
//~^ ERROR `RangeTo<{integer}>` is not an iterator
4+
//~| HELP consider using a bounded `Range` by adding a concrete starting value
5+
let _ = x;
6+
}
7+
8+
for x in (..=4).rev() {
9+
//~^ ERROR `std::ops::RangeToInclusive<{integer}>` is not an iterator
10+
//~| HELP consider using a bounded `RangeInclusive` by adding a concrete starting value
11+
let _ = x;
12+
}
13+
14+
// should not suggest for `iter` method
15+
let _v: Vec<_> = (..5).iter().collect();
16+
//~^ ERROR no method named `iter` found
17+
18+
for _x in (..'a').rev() {}
19+
//~^ ERROR `RangeTo<char>` is not an iterator
20+
//~| HELP consider using a bounded `Range` by adding a concrete starting value
21+
22+
for _x in (..='a').rev() {}
23+
//~^ ERROR `std::ops::RangeToInclusive<char>` is not an iterator
24+
//~| HELP consider using a bounded `RangeInclusive` by adding a concrete starting value
25+
26+
for _x in (..-10).rev() {}
27+
//~^ ERROR `RangeTo<{integer}>` is not an iterator
28+
//~| HELP consider using a bounded `Range` by adding a concrete starting value
29+
30+
for _x in (..=-10).rev() {}
31+
//~^ ERROR `std::ops::RangeToInclusive<{integer}>` is not an iterator
32+
//~| HELP consider using a bounded `RangeInclusive` by adding a concrete starting value
33+
34+
let end_val = 10;
35+
for _x in (..-end_val).rev() {}
36+
//~^ ERROR `RangeTo<{integer}>` is not an iterator
37+
//~| HELP consider using a bounded `Range` by adding a concrete starting value
38+
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
error[E0599]: `RangeTo<{integer}>` is not an iterator
2+
--> $DIR/range-to-iterator-suggestion-issue-147749.rs:2:20
3+
|
4+
LL | for x in (..4).rev() {
5+
| ^^^ `RangeTo<{integer}>` is not an iterator
6+
|
7+
= note: the following trait bounds were not satisfied:
8+
`RangeTo<{integer}>: Iterator`
9+
which is required by `&mut RangeTo<{integer}>: Iterator`
10+
= note: you might have meant to use a bounded `Range`
11+
help: consider using a bounded `Range` by adding a concrete starting value
12+
|
13+
LL | for x in (0..4).rev() {
14+
| +
15+
16+
error[E0599]: `std::ops::RangeToInclusive<{integer}>` is not an iterator
17+
--> $DIR/range-to-iterator-suggestion-issue-147749.rs:8:21
18+
|
19+
LL | for x in (..=4).rev() {
20+
| ^^^ `std::ops::RangeToInclusive<{integer}>` is not an iterator
21+
|
22+
= note: the following trait bounds were not satisfied:
23+
`std::ops::RangeToInclusive<{integer}>: Iterator`
24+
which is required by `&mut std::ops::RangeToInclusive<{integer}>: Iterator`
25+
= note: you might have meant to use a bounded `RangeInclusive`
26+
help: consider using a bounded `RangeInclusive` by adding a concrete starting value
27+
|
28+
LL | for x in (0..=4).rev() {
29+
| +
30+
31+
error[E0599]: no method named `iter` found for struct `RangeTo<Idx>` in the current scope
32+
--> $DIR/range-to-iterator-suggestion-issue-147749.rs:15:28
33+
|
34+
LL | let _v: Vec<_> = (..5).iter().collect();
35+
| ^^^^ method not found in `RangeTo<{integer}>`
36+
37+
error[E0599]: `RangeTo<char>` is not an iterator
38+
--> $DIR/range-to-iterator-suggestion-issue-147749.rs:18:23
39+
|
40+
LL | for _x in (..'a').rev() {}
41+
| ^^^ `RangeTo<char>` is not an iterator
42+
|
43+
= note: the following trait bounds were not satisfied:
44+
`RangeTo<char>: Iterator`
45+
which is required by `&mut RangeTo<char>: Iterator`
46+
= note: you might have meant to use a bounded `Range`
47+
help: consider using a bounded `Range` by adding a concrete starting value
48+
|
49+
LL | for _x in (/* start */..'a').rev() {}
50+
| +++++++++++
51+
52+
error[E0599]: `std::ops::RangeToInclusive<char>` is not an iterator
53+
--> $DIR/range-to-iterator-suggestion-issue-147749.rs:22:24
54+
|
55+
LL | for _x in (..='a').rev() {}
56+
| ^^^ `std::ops::RangeToInclusive<char>` is not an iterator
57+
|
58+
= note: the following trait bounds were not satisfied:
59+
`std::ops::RangeToInclusive<char>: Iterator`
60+
which is required by `&mut std::ops::RangeToInclusive<char>: Iterator`
61+
= note: you might have meant to use a bounded `RangeInclusive`
62+
help: consider using a bounded `RangeInclusive` by adding a concrete starting value
63+
|
64+
LL | for _x in (/* start */..='a').rev() {}
65+
| +++++++++++
66+
67+
error[E0599]: `RangeTo<{integer}>` is not an iterator
68+
--> $DIR/range-to-iterator-suggestion-issue-147749.rs:26:23
69+
|
70+
LL | for _x in (..-10).rev() {}
71+
| ^^^ `RangeTo<{integer}>` is not an iterator
72+
|
73+
= note: the following trait bounds were not satisfied:
74+
`RangeTo<{integer}>: Iterator`
75+
which is required by `&mut RangeTo<{integer}>: Iterator`
76+
= note: you might have meant to use a bounded `Range`
77+
help: consider using a bounded `Range` by adding a concrete starting value
78+
|
79+
LL | for _x in (/* start */..-10).rev() {}
80+
| +++++++++++
81+
82+
error[E0599]: `std::ops::RangeToInclusive<{integer}>` is not an iterator
83+
--> $DIR/range-to-iterator-suggestion-issue-147749.rs:30:24
84+
|
85+
LL | for _x in (..=-10).rev() {}
86+
| ^^^ `std::ops::RangeToInclusive<{integer}>` is not an iterator
87+
|
88+
= note: the following trait bounds were not satisfied:
89+
`std::ops::RangeToInclusive<{integer}>: Iterator`
90+
which is required by `&mut std::ops::RangeToInclusive<{integer}>: Iterator`
91+
= note: you might have meant to use a bounded `RangeInclusive`
92+
help: consider using a bounded `RangeInclusive` by adding a concrete starting value
93+
|
94+
LL | for _x in (/* start */..=-10).rev() {}
95+
| +++++++++++
96+
97+
error[E0599]: `RangeTo<{integer}>` is not an iterator
98+
--> $DIR/range-to-iterator-suggestion-issue-147749.rs:35:28
99+
|
100+
LL | for _x in (..-end_val).rev() {}
101+
| ^^^ `RangeTo<{integer}>` is not an iterator
102+
|
103+
= note: the following trait bounds were not satisfied:
104+
`RangeTo<{integer}>: Iterator`
105+
which is required by `&mut RangeTo<{integer}>: Iterator`
106+
= note: you might have meant to use a bounded `Range`
107+
help: consider using a bounded `Range` by adding a concrete starting value
108+
|
109+
LL | for _x in (/* start */..-end_val).rev() {}
110+
| +++++++++++
111+
112+
error: aborting due to 8 previous errors
113+
114+
For more information about this error, try `rustc --explain E0599`.

0 commit comments

Comments
 (0)