Skip to content

Commit a137c1c

Browse files
committed
Suggest add bounding value for RangeTo
1 parent 235a4c0 commit a137c1c

File tree

3 files changed

+112
-0
lines changed

3 files changed

+112
-0
lines changed

compiler/rustc_hir_typeck/src/method/suggest.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1732,6 +1732,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
17321732
}
17331733

17341734
self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_ident, expected);
1735+
self.suggest_bounds_for_range_to_method(&mut err, source, item_ident);
17351736
err.emit()
17361737
}
17371738

@@ -3228,6 +3229,61 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
32283229
}
32293230
}
32303231

3232+
fn suggest_bounds_for_range_to_method(
3233+
&self,
3234+
err: &mut Diag<'_>,
3235+
source: SelfSource<'tcx>,
3236+
item_ident: Ident,
3237+
) {
3238+
if let SelfSource::MethodCall(rcvr_expr) = source
3239+
&& let hir::ExprKind::Struct(qpath, _, _) = rcvr_expr.kind
3240+
&& let hir::QPath::LangItem(lang_item, _) = qpath
3241+
{
3242+
let is_inclusive = match lang_item {
3243+
hir::LangItem::RangeTo => false,
3244+
hir::LangItem::RangeToInclusive => true,
3245+
_ => return,
3246+
};
3247+
3248+
// Check if the method exists on Iterator trait
3249+
let tcx = self.tcx;
3250+
if let Some(iterator_trait) = tcx.get_diagnostic_item(sym::Iterator) {
3251+
let has_method = tcx
3252+
.associated_items(iterator_trait)
3253+
.filter_by_name_unhygienic(item_ident.name)
3254+
.next()
3255+
.is_some();
3256+
3257+
if !has_method {
3258+
return;
3259+
}
3260+
}
3261+
3262+
let range_type = if is_inclusive { "RangeInclusive" } else { "Range" };
3263+
let source_map = self.tcx.sess.source_map();
3264+
3265+
if let Ok(snippet) = source_map.span_to_snippet(rcvr_expr.span) {
3266+
let offset = snippet
3267+
.chars()
3268+
.take_while(|&c| c == '(' || c.is_whitespace())
3269+
.map(|c| c.len_utf8())
3270+
.sum::<usize>();
3271+
3272+
let insert_span = rcvr_expr
3273+
.span
3274+
.with_lo(rcvr_expr.span.lo() + rustc_span::BytePos(offset as u32))
3275+
.shrink_to_lo();
3276+
3277+
err.span_suggestion_verbose(
3278+
insert_span,
3279+
format!("consider using a bounded `{range_type}` by adding a starting value"),
3280+
"0",
3281+
Applicability::MaybeIncorrect,
3282+
);
3283+
}
3284+
}
3285+
}
3286+
32313287
/// Print out the type for use in value namespace.
32323288
fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String {
32333289
match ty.kind() {
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
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 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 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+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
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 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 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: aborting due to 3 previous errors
38+
39+
For more information about this error, try `rustc --explain E0599`.

0 commit comments

Comments
 (0)