Rollup merge of #106363 - estebank:mutability-mismatch-arg, r=Nilstrieb

Structured suggestion for `&mut dyn Iterator` when possible

Fix #37914.
This commit is contained in:
Michael Goulet 2023-01-08 19:57:53 -08:00 committed by GitHub
commit 334426b7a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 91 additions and 30 deletions

View File

@ -57,7 +57,12 @@ pub enum MethodError<'tcx> {
PrivateMatch(DefKind, DefId, Vec<DefId>), PrivateMatch(DefKind, DefId, Vec<DefId>),
// Found a `Self: Sized` bound where `Self` is a trait object. // Found a `Self: Sized` bound where `Self` is a trait object.
IllegalSizedBound(Vec<DefId>, bool, Span), IllegalSizedBound {
candidates: Vec<DefId>,
needs_mut: bool,
bound_span: Span,
self_expr: &'tcx hir::Expr<'tcx>,
},
// Found a match, but the return type is wrong // Found a match, but the return type is wrong
BadReturnType, BadReturnType,
@ -112,7 +117,7 @@ pub fn method_exists(
Err(NoMatch(..)) => false, Err(NoMatch(..)) => false,
Err(Ambiguity(..)) => true, Err(Ambiguity(..)) => true,
Err(PrivateMatch(..)) => allow_private, Err(PrivateMatch(..)) => allow_private,
Err(IllegalSizedBound(..)) => true, Err(IllegalSizedBound { .. }) => true,
Err(BadReturnType) => bug!("no return type expectations but got BadReturnType"), Err(BadReturnType) => bug!("no return type expectations but got BadReturnType"),
} }
} }
@ -236,7 +241,7 @@ pub fn lookup_method(
_ => Vec::new(), _ => Vec::new(),
}; };
return Err(IllegalSizedBound(candidates, needs_mut, span)); return Err(IllegalSizedBound { candidates, needs_mut, bound_span: span, self_expr });
} }
Ok(result.callee) Ok(result.callee)

View File

@ -176,10 +176,18 @@ pub fn report_method_error(
err.emit(); 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 msg = if needs_mut {
with_forced_trimmed_paths!(format!(
"the `{item_name}` method cannot be invoked on `{rcvr_ty}`"
))
} else {
format!("the `{item_name}` method cannot be invoked on a trait object")
};
let mut err = self.sess().struct_span_err(span, &msg); let mut err = self.sess().struct_span_err(span, &msg);
err.span_label(bound_span, "this has a `Sized` requirement"); if !needs_mut {
err.span_label(bound_span, "this has a `Sized` requirement");
}
if !candidates.is_empty() { if !candidates.is_empty() {
let help = format!( let help = format!(
"{an}other candidate{s} {were} found in the following trait{s}, perhaps \ "{an}other candidate{s} {were} found in the following trait{s}, perhaps \
@ -197,7 +205,32 @@ pub fn report_method_error(
*region, *region,
ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() }, 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(b)) = self.tcx.hir().find(hir_id)
&& let Some(hir::Node::Param(p)) = self.tcx.hir().find_parent(b.hir_id)
&& let Some(node) = self.tcx.hir().find_parent(p.hir_id)
&& let Some(decl) = node.fn_decl()
&& let Some(ty) = decl.inputs.iter().find(|ty| ty.span == p.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(); 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
}
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
}
fn main() {
let array = [0u64];
test(&mut array.iter());
}

View File

@ -0,0 +1,13 @@
error: the `min` method cannot be invoked on `&dyn Iterator<Item = &u64>`
--> $DIR/mutability-mismatch-arg.rs:3:9
|
LL | *t.min().unwrap()
| ^^^
|
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

@ -4,7 +4,6 @@ pub trait MutTrait {
fn function(&mut self) fn function(&mut self)
where where
Self: Sized; Self: Sized;
//~^ this has a `Sized` requirement
} }
impl MutTrait for MutType { impl MutTrait for MutType {
@ -17,7 +16,6 @@ pub trait Trait {
fn function(&self) fn function(&self)
where where
Self: Sized; Self: Sized;
//~^ this has a `Sized` requirement
} }
impl Trait for Type { impl Trait for Type {
@ -26,9 +24,9 @@ fn function(&self) {}
fn main() { fn main() {
(&MutType as &dyn MutTrait).function(); (&MutType as &dyn MutTrait).function();
//~^ ERROR the `function` method cannot be invoked on a trait object //~^ ERROR the `function` method cannot be invoked on `&dyn MutTrait`
//~| 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(); (&mut Type as &mut dyn Trait).function();
//~^ ERROR the `function` method cannot be invoked on a trait object //~^ ERROR the `function` method cannot be invoked on `&mut dyn Trait`
//~| NOTE you need `&dyn Trait` instead of `&mut dyn Trait` //~| HELP you need `&dyn Trait` instead of `&mut dyn Trait`
} }

View File

@ -1,24 +1,18 @@
error: the `function` method cannot be invoked on a trait object error: the `function` method cannot be invoked on `&dyn MutTrait`
--> $DIR/mutability-mismatch.rs:28:33 --> $DIR/mutability-mismatch.rs:26:33
| |
LL | Self: Sized;
| ----- this has a `Sized` requirement
...
LL | (&MutType as &dyn MutTrait).function(); 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 error: the `function` method cannot be invoked on `&mut dyn Trait`
--> $DIR/mutability-mismatch.rs:31:35 --> $DIR/mutability-mismatch.rs:29:35
| |
LL | Self: Sized;
| ----- this has a `Sized` requirement
...
LL | (&mut Type as &mut dyn Trait).function(); 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 error: aborting due to 2 previous errors

View File

@ -1,5 +1,5 @@
fn test(t: &dyn Iterator<Item=&u64>) -> u64 { fn test(t: &dyn Iterator<Item=&u64>) -> u64 {
t.min().unwrap() //~ ERROR the `min` method cannot be invoked on a trait object t.min().unwrap() //~ ERROR the `min` method cannot be invoked on `&dyn Iterator<Item = &u64>`
} }
fn main() { fn main() {

View File

@ -1,13 +1,13 @@
error: the `min` method cannot be invoked on a trait object error: the `min` method cannot be invoked on `&dyn Iterator<Item = &u64>`
--> $DIR/imm-ref-trait-object.rs:2:8 --> $DIR/imm-ref-trait-object.rs:2:8
| |
LL | t.min().unwrap() 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>`
| |
= note: 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 error: aborting due to previous error