Rollup merge of #147753 - chenyukang:yukang-147749, r=fmease

Suggest add bounding value for RangeTo

Fixes rust-lang/rust#147749
This commit is contained in:
Stuart Cook 2025-11-12 12:26:35 +11:00 committed by GitHub
commit 4cd28dea58
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 218 additions and 0 deletions

View file

@ -1079,6 +1079,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_ident, expected);
self.suggest_bounds_for_range_to_method(&mut err, source, item_ident);
err.emit()
}
@ -3260,6 +3261,71 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
fn suggest_bounds_for_range_to_method(
&self,
err: &mut Diag<'_>,
source: SelfSource<'tcx>,
item_ident: Ident,
) {
let SelfSource::MethodCall(rcvr_expr) = source else { return };
let hir::ExprKind::Struct(qpath, fields, _) = rcvr_expr.kind else { return };
let Some(lang_item) = self.tcx.qpath_lang_item(*qpath) else {
return;
};
let is_inclusive = match lang_item {
hir::LangItem::RangeTo => false,
hir::LangItem::RangeToInclusive | hir::LangItem::RangeInclusiveCopy => true,
_ => return,
};
let Some(iterator_trait) = self.tcx.get_diagnostic_item(sym::Iterator) else { return };
let Some(_) = self
.tcx
.associated_items(iterator_trait)
.filter_by_name_unhygienic(item_ident.name)
.next()
else {
return;
};
let source_map = self.tcx.sess.source_map();
let range_type = if is_inclusive { "RangeInclusive" } else { "Range" };
let Some(end_field) = fields.iter().find(|f| f.ident.name == rustc_span::sym::end) else {
return;
};
let element_ty = self.typeck_results.borrow().expr_ty_opt(end_field.expr);
let is_integral = element_ty.is_some_and(|ty| ty.is_integral());
let end_is_negative = is_integral
&& matches!(end_field.expr.kind, hir::ExprKind::Unary(rustc_ast::UnOp::Neg, _));
let Ok(snippet) = source_map.span_to_snippet(rcvr_expr.span) else { return };
let offset = snippet
.chars()
.take_while(|&c| c == '(' || c.is_whitespace())
.map(|c| c.len_utf8())
.sum::<usize>();
let insert_span = rcvr_expr
.span
.with_lo(rcvr_expr.span.lo() + rustc_span::BytePos(offset as u32))
.shrink_to_lo();
let (value, appl) = if is_integral && !end_is_negative {
("0", Applicability::MachineApplicable)
} else {
("/* start */", Applicability::HasPlaceholders)
};
err.span_suggestion_verbose(
insert_span,
format!("consider using a bounded `{range_type}` by adding a concrete starting value"),
value,
appl,
);
}
/// Print out the type for use in value namespace.
fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String {
match ty.kind() {

View file

@ -0,0 +1,38 @@
fn main() {
for x in (..4).rev() {
//~^ ERROR `RangeTo<{integer}>` is not an iterator
//~| HELP consider using a bounded `Range` by adding a concrete starting value
let _ = x;
}
for x in (..=4).rev() {
//~^ ERROR `std::ops::RangeToInclusive<{integer}>` is not an iterator
//~| HELP consider using a bounded `RangeInclusive` by adding a concrete starting value
let _ = x;
}
// should not suggest for `iter` method
let _v: Vec<_> = (..5).iter().collect();
//~^ ERROR no method named `iter` found
for _x in (..'a').rev() {}
//~^ ERROR `RangeTo<char>` is not an iterator
//~| HELP consider using a bounded `Range` by adding a concrete starting value
for _x in (..='a').rev() {}
//~^ ERROR `std::ops::RangeToInclusive<char>` is not an iterator
//~| HELP consider using a bounded `RangeInclusive` by adding a concrete starting value
for _x in (..-10).rev() {}
//~^ ERROR `RangeTo<{integer}>` is not an iterator
//~| HELP consider using a bounded `Range` by adding a concrete starting value
for _x in (..=-10).rev() {}
//~^ ERROR `std::ops::RangeToInclusive<{integer}>` is not an iterator
//~| HELP consider using a bounded `RangeInclusive` by adding a concrete starting value
let end_val = 10;
for _x in (..-end_val).rev() {}
//~^ ERROR `RangeTo<{integer}>` is not an iterator
//~| HELP consider using a bounded `Range` by adding a concrete starting value
}

View file

@ -0,0 +1,114 @@
error[E0599]: `RangeTo<{integer}>` is not an iterator
--> $DIR/range-to-iterator-suggestion-issue-147749.rs:2:20
|
LL | for x in (..4).rev() {
| ^^^ `RangeTo<{integer}>` is not an iterator
|
= note: the following trait bounds were not satisfied:
`RangeTo<{integer}>: Iterator`
which is required by `&mut RangeTo<{integer}>: Iterator`
= note: you might have meant to use a bounded `Range`
help: consider using a bounded `Range` by adding a concrete starting value
|
LL | for x in (0..4).rev() {
| +
error[E0599]: `std::ops::RangeToInclusive<{integer}>` is not an iterator
--> $DIR/range-to-iterator-suggestion-issue-147749.rs:8:21
|
LL | for x in (..=4).rev() {
| ^^^ `std::ops::RangeToInclusive<{integer}>` is not an iterator
|
= note: the following trait bounds were not satisfied:
`std::ops::RangeToInclusive<{integer}>: Iterator`
which is required by `&mut std::ops::RangeToInclusive<{integer}>: Iterator`
= note: you might have meant to use a bounded `RangeInclusive`
help: consider using a bounded `RangeInclusive` by adding a concrete starting value
|
LL | for x in (0..=4).rev() {
| +
error[E0599]: no method named `iter` found for struct `RangeTo<Idx>` in the current scope
--> $DIR/range-to-iterator-suggestion-issue-147749.rs:15:28
|
LL | let _v: Vec<_> = (..5).iter().collect();
| ^^^^ method not found in `RangeTo<{integer}>`
error[E0599]: `RangeTo<char>` is not an iterator
--> $DIR/range-to-iterator-suggestion-issue-147749.rs:18:23
|
LL | for _x in (..'a').rev() {}
| ^^^ `RangeTo<char>` is not an iterator
|
= note: the following trait bounds were not satisfied:
`RangeTo<char>: Iterator`
which is required by `&mut RangeTo<char>: Iterator`
= note: you might have meant to use a bounded `Range`
help: consider using a bounded `Range` by adding a concrete starting value
|
LL | for _x in (/* start */..'a').rev() {}
| +++++++++++
error[E0599]: `std::ops::RangeToInclusive<char>` is not an iterator
--> $DIR/range-to-iterator-suggestion-issue-147749.rs:22:24
|
LL | for _x in (..='a').rev() {}
| ^^^ `std::ops::RangeToInclusive<char>` is not an iterator
|
= note: the following trait bounds were not satisfied:
`std::ops::RangeToInclusive<char>: Iterator`
which is required by `&mut std::ops::RangeToInclusive<char>: Iterator`
= note: you might have meant to use a bounded `RangeInclusive`
help: consider using a bounded `RangeInclusive` by adding a concrete starting value
|
LL | for _x in (/* start */..='a').rev() {}
| +++++++++++
error[E0599]: `RangeTo<{integer}>` is not an iterator
--> $DIR/range-to-iterator-suggestion-issue-147749.rs:26:23
|
LL | for _x in (..-10).rev() {}
| ^^^ `RangeTo<{integer}>` is not an iterator
|
= note: the following trait bounds were not satisfied:
`RangeTo<{integer}>: Iterator`
which is required by `&mut RangeTo<{integer}>: Iterator`
= note: you might have meant to use a bounded `Range`
help: consider using a bounded `Range` by adding a concrete starting value
|
LL | for _x in (/* start */..-10).rev() {}
| +++++++++++
error[E0599]: `std::ops::RangeToInclusive<{integer}>` is not an iterator
--> $DIR/range-to-iterator-suggestion-issue-147749.rs:30:24
|
LL | for _x in (..=-10).rev() {}
| ^^^ `std::ops::RangeToInclusive<{integer}>` is not an iterator
|
= note: the following trait bounds were not satisfied:
`std::ops::RangeToInclusive<{integer}>: Iterator`
which is required by `&mut std::ops::RangeToInclusive<{integer}>: Iterator`
= note: you might have meant to use a bounded `RangeInclusive`
help: consider using a bounded `RangeInclusive` by adding a concrete starting value
|
LL | for _x in (/* start */..=-10).rev() {}
| +++++++++++
error[E0599]: `RangeTo<{integer}>` is not an iterator
--> $DIR/range-to-iterator-suggestion-issue-147749.rs:35:28
|
LL | for _x in (..-end_val).rev() {}
| ^^^ `RangeTo<{integer}>` is not an iterator
|
= note: the following trait bounds were not satisfied:
`RangeTo<{integer}>: Iterator`
which is required by `&mut RangeTo<{integer}>: Iterator`
= note: you might have meant to use a bounded `Range`
help: consider using a bounded `Range` by adding a concrete starting value
|
LL | for _x in (/* start */..-end_val).rev() {}
| +++++++++++
error: aborting due to 8 previous errors
For more information about this error, try `rustc --explain E0599`.