Structured suggestion for `&mut dyn Iterator` when possible

Fix #37914.
This commit is contained in:
Esteban Küber 2023-01-01 21:28:03 -08:00
parent afe8c4537c
commit 1eb828ecb1
8 changed files with 73 additions and 9 deletions

View File

@ -57,7 +57,7 @@ pub enum MethodError<'tcx> {
PrivateMatch(DefKind, DefId, Vec<DefId>),
// Found a `Self: Sized` bound where `Self` is a trait object.
IllegalSizedBound(Vec<DefId>, bool, Span),
IllegalSizedBound(Vec<DefId>, bool, Span, &'tcx hir::Expr<'tcx>),
// Found a match, but the return type is wrong
BadReturnType,
@ -236,7 +236,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => Vec::new(),
};
return Err(IllegalSizedBound(candidates, needs_mut, span));
return Err(IllegalSizedBound(candidates, needs_mut, span, self_expr));
}
Ok(result.callee)

View File

@ -176,7 +176,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.emit();
}
MethodError::IllegalSizedBound(candidates, needs_mut, bound_span) => {
MethodError::IllegalSizedBound(candidates, needs_mut, bound_span, self_expr) => {
let msg = format!("the `{}` method cannot be invoked on a trait object", item_name);
let mut err = self.sess().struct_span_err(span, &msg);
err.span_label(bound_span, "this has a `Sized` requirement");
@ -197,7 +197,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
*region,
ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() },
);
err.note(&format!("you need `{}` instead of `{}`", trait_type, rcvr_ty));
let msg = format!("you need `{}` instead of `{}`", trait_type, rcvr_ty);
let mut kind = &self_expr.kind;
while let hir::ExprKind::AddrOf(_, _, expr)
| hir::ExprKind::Unary(hir::UnOp::Deref, expr) = kind
{
kind = &expr.kind;
}
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = kind
&& let hir::def::Res::Local(hir_id) = path.res
&& let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(hir_id)
&& let parent_hir_id = self.tcx.hir().get_parent_node(binding.hir_id)
&& let Some(hir::Node::Param(param)) = self.tcx.hir().find(parent_hir_id)
&& let parent_hir_id = self.tcx.hir().get_parent_node(param.hir_id)
&& let Some(node) = self.tcx.hir().find(parent_hir_id)
&& let Some(decl) = node.fn_decl()
&& let Some(ty) = decl.inputs.iter().find(|ty| ty.span == param.ty_span)
&& let hir::TyKind::Ref(_, mut_ty) = &ty.kind
&& let hir::Mutability::Not = mut_ty.mutbl
{
err.span_suggestion_verbose(
mut_ty.ty.span.shrink_to_lo(),
&msg,
"mut ",
Applicability::MachineApplicable,
);
} else {
err.help(&msg);
}
}
}
err.emit();

View File

@ -0,0 +1,9 @@
// run-rustfix
fn test(t: &mut dyn Iterator<Item=&u64>) -> u64 {
*t.min().unwrap() //~ ERROR the `min` method cannot be invoked on a trait object
}
fn main() {
let array = [0u64];
test(&mut array.iter());
}

View File

@ -0,0 +1,9 @@
// run-rustfix
fn test(t: &dyn Iterator<Item=&u64>) -> u64 {
*t.min().unwrap() //~ ERROR the `min` method cannot be invoked on a trait object
}
fn main() {
let array = [0u64];
test(&mut array.iter());
}

View File

@ -0,0 +1,16 @@
error: the `min` method cannot be invoked on a trait object
--> $DIR/mutability-mismatch-arg.rs:3:9
|
LL | *t.min().unwrap()
| ^^^
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
|
= note: this has a `Sized` requirement
|
help: you need `&mut dyn Iterator<Item = &u64>` instead of `&dyn Iterator<Item = &u64>`
|
LL | fn test(t: &mut dyn Iterator<Item=&u64>) -> u64 {
| +++
error: aborting due to previous error

View File

@ -27,8 +27,8 @@ impl Trait for Type {
fn main() {
(&MutType as &dyn MutTrait).function();
//~^ ERROR the `function` method cannot be invoked on a trait object
//~| NOTE you need `&mut dyn MutTrait` instead of `&dyn MutTrait`
//~| HELP you need `&mut dyn MutTrait` instead of `&dyn MutTrait`
(&mut Type as &mut dyn Trait).function();
//~^ ERROR the `function` method cannot be invoked on a trait object
//~| NOTE you need `&dyn Trait` instead of `&mut dyn Trait`
//~| HELP you need `&dyn Trait` instead of `&mut dyn Trait`
}

View File

@ -7,7 +7,7 @@ LL | Self: Sized;
LL | (&MutType as &dyn MutTrait).function();
| ^^^^^^^^
|
= note: you need `&mut dyn MutTrait` instead of `&dyn MutTrait`
= help: you need `&mut dyn MutTrait` instead of `&dyn MutTrait`
error: the `function` method cannot be invoked on a trait object
--> $DIR/mutability-mismatch.rs:31:35
@ -18,7 +18,7 @@ LL | Self: Sized;
LL | (&mut Type as &mut dyn Trait).function();
| ^^^^^^^^
|
= note: you need `&dyn Trait` instead of `&mut dyn Trait`
= help: you need `&dyn Trait` instead of `&mut dyn Trait`
error: aborting due to 2 previous errors

View File

@ -7,7 +7,10 @@ LL | t.min().unwrap()
|
= note: this has a `Sized` requirement
|
= note: you need `&mut dyn Iterator<Item = &u64>` instead of `&dyn Iterator<Item = &u64>`
help: you need `&mut dyn Iterator<Item = &u64>` instead of `&dyn Iterator<Item = &u64>`
|
LL | fn test(t: &mut dyn Iterator<Item=&u64>) -> u64 {
| +++
error: aborting due to previous error