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:
commit
4cd28dea58
3 changed files with 218 additions and 0 deletions
|
|
@ -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() {
|
||||
|
|
|
|||
38
tests/ui/range/range-to-iterator-suggestion-issue-147749.rs
Normal file
38
tests/ui/range/range-to-iterator-suggestion-issue-147749.rs
Normal 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
|
||||
}
|
||||
114
tests/ui/range/range-to-iterator-suggestion-issue-147749.stderr
Normal file
114
tests/ui/range/range-to-iterator-suggestion-issue-147749.stderr
Normal 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`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue