mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-22 18:15:07 +03:00
Rollup merge of #156121 - thiago-fealves:suggest-collect-string, r=estebank
compiler: suggest `.collect()` when `String` is expected and `Iterator` is found This commit adds a diagnostic suggestion to help users who forget to call `.collect()` when they have an iterator and the function or variable expects a `String`. The logic checks if the expected type is `std::string::String` and if the found type implements the `Iterator` trait, if so the compiler provides a suggestion to add `.collect()` Includes also a UI test to verify if the suggestion appears correctly
This commit is contained in:
@@ -40,6 +40,7 @@ pub(crate) fn emit_type_mismatch_suggestions(
|
||||
|| self.suggest_semicolon_in_repeat_expr(err, expr, expr_ty)
|
||||
|| self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr)
|
||||
|| self.suggest_option_to_bool(err, expr, expr_ty, expected)
|
||||
|| self.suggest_collect(err, expr, expected, expr_ty)
|
||||
|| self.suggest_compatible_variants(err, expr, expected, expr_ty)
|
||||
|| self.suggest_non_zero_new_unwrap(err, expr, expected, expr_ty)
|
||||
|| self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty)
|
||||
|
||||
@@ -250,6 +250,74 @@ pub(crate) fn suggest_two_fn_call(
|
||||
}
|
||||
}
|
||||
|
||||
/// Suggests calling `.collect()` on an `Iterator` it can be collected in the return type
|
||||
/// ```compile_fail
|
||||
/// let x: String = "foo".chars().map(|c| c); // with a .collect() here the code compiles
|
||||
/// ```
|
||||
pub(crate) fn suggest_collect(
|
||||
&self,
|
||||
err: &mut Diag<'_>,
|
||||
expr: &hir::Expr<'_>,
|
||||
expected_type: Ty<'tcx>,
|
||||
found_type: Ty<'tcx>,
|
||||
) -> bool {
|
||||
let tcx = self.tcx;
|
||||
let expected = self.resolve_vars_if_possible(expected_type);
|
||||
let found = self.resolve_vars_if_possible(found_type);
|
||||
|
||||
if expected.references_error() || found.references_error() || expected.is_unit() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let Some(iterator_trait_id) = tcx.get_diagnostic_item(sym::Iterator) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
if !self
|
||||
.infcx
|
||||
.type_implements_trait(iterator_trait_id, [found], self.param_env)
|
||||
.must_apply_modulo_regions()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
let Some(from_iterator_trait_id) = tcx.get_diagnostic_item(sym::FromIterator) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let Some(iterator_item_id) = tcx
|
||||
.associated_items(iterator_trait_id)
|
||||
.in_definition_order()
|
||||
.find(|item| item.name() == sym::Item)
|
||||
.map(|item| item.def_id)
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let item_type = Ty::new_projection(tcx, iterator_item_id, [found]);
|
||||
let item_type =
|
||||
self.normalize(expr.span, rustc_middle::ty::Unnormalized::new_wip(item_type));
|
||||
|
||||
let can_collect = self
|
||||
.infcx
|
||||
.type_implements_trait(from_iterator_trait_id, [expected, item_type], self.param_env)
|
||||
.may_apply();
|
||||
|
||||
if can_collect {
|
||||
err.span_suggestion_verbose(
|
||||
expr.span.shrink_to_hi(),
|
||||
format!(
|
||||
"consider using `.collect()` to convert the `Iterator` into a `{expected}`"
|
||||
),
|
||||
".collect()",
|
||||
rustc_errors::Applicability::MaybeIncorrect,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub(crate) fn suggest_remove_last_method_call(
|
||||
&self,
|
||||
err: &mut Diag<'_>,
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
fn main() {
|
||||
let _x: String = "hello".chars().map(|c| c);
|
||||
//~^ ERROR mismatched types
|
||||
//~| HELP consider using `.collect()` to convert the `Iterator` into a `String`
|
||||
|
||||
let _y: Vec<i32> = vec![1, 2, 3].into_iter().map(|x| x);
|
||||
//~^ ERROR mismatched types
|
||||
//~| HELP consider using `.collect()` to convert the `Iterator` into a `Vec<i32>`
|
||||
|
||||
let res: Result<Vec<i32>, _> = ["1", "2"].into_iter().map(|s| s.parse::<i32>());
|
||||
//~^ ERROR mismatched types
|
||||
//~| HELP consider using `.collect()` to convert the `Iterator` into a `Result<Vec<i32>, _>`
|
||||
let (a, b): (Vec<i32>, Vec<i32>) = vec![1, 2].into_iter().map(|x| (x, x));
|
||||
//~^ ERROR mismatched types
|
||||
//~| HELP consider using `.collect()` to convert the `Iterator` into a `(Vec<i32>, Vec<i32>)`
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/suggest-collect.rs:2:22
|
||||
|
|
||||
LL | let _x: String = "hello".chars().map(|c| c);
|
||||
| ------ ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `String`, found `Map<Chars<'_>, {closure@...}>`
|
||||
| |
|
||||
| expected due to this
|
||||
|
|
||||
= note: expected struct `String`
|
||||
found struct `Map<Chars<'_>, {closure@$DIR/suggest-collect.rs:2:42: 2:45}>`
|
||||
help: consider using `.collect()` to convert the `Iterator` into a `String`
|
||||
|
|
||||
LL | let _x: String = "hello".chars().map(|c| c).collect();
|
||||
| ++++++++++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/suggest-collect.rs:6:24
|
||||
|
|
||||
LL | let _y: Vec<i32> = vec![1, 2, 3].into_iter().map(|x| x);
|
||||
| -------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Vec<i32>`, found `Map<IntoIter<{integer}>, {closure@...}>`
|
||||
| |
|
||||
| expected due to this
|
||||
|
|
||||
= note: expected struct `Vec<i32>`
|
||||
found struct `Map<std::vec::IntoIter<{integer}>, {closure@$DIR/suggest-collect.rs:6:54: 6:57}>`
|
||||
help: consider using `.collect()` to convert the `Iterator` into a `Vec<i32>`
|
||||
|
|
||||
LL | let _y: Vec<i32> = vec![1, 2, 3].into_iter().map(|x| x).collect();
|
||||
| ++++++++++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/suggest-collect.rs:10:36
|
||||
|
|
||||
LL | let res: Result<Vec<i32>, _> = ["1", "2"].into_iter().map(|s| s.parse::<i32>());
|
||||
| ------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Result<Vec<i32>, _>`, found `Map<Iter<'_, &str>, {closure@...}>`
|
||||
| |
|
||||
| expected due to this
|
||||
|
|
||||
= note: expected enum `Result<Vec<i32>, _>`
|
||||
found struct `Map<std::slice::Iter<'_, &str>, {closure@$DIR/suggest-collect.rs:10:63: 10:66}>`
|
||||
help: consider using `.collect()` to convert the `Iterator` into a `Result<Vec<i32>, _>`
|
||||
|
|
||||
LL | let res: Result<Vec<i32>, _> = ["1", "2"].into_iter().map(|s| s.parse::<i32>()).collect();
|
||||
| ++++++++++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/suggest-collect.rs:13:40
|
||||
|
|
||||
LL | let (a, b): (Vec<i32>, Vec<i32>) = vec![1, 2].into_iter().map(|x| (x, x));
|
||||
| -------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(Vec<i32>, Vec<i32>)`, found `Map<IntoIter<{integer}>, {closure@...}>`
|
||||
| |
|
||||
| expected due to this
|
||||
|
|
||||
= note: expected tuple `(Vec<i32>, Vec<i32>)`
|
||||
found struct `Map<std::vec::IntoIter<{integer}>, {closure@$DIR/suggest-collect.rs:13:67: 13:70}>`
|
||||
help: consider using `.collect()` to convert the `Iterator` into a `(Vec<i32>, Vec<i32>)`
|
||||
|
|
||||
LL | let (a, b): (Vec<i32>, Vec<i32>) = vec![1, 2].into_iter().map(|x| (x, x)).collect();
|
||||
| ++++++++++
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
Reference in New Issue
Block a user